diff options
Diffstat (limited to 'Transactional Emails/Transactions')
3 files changed, 179 insertions, 0 deletions
diff --git a/Transactional Emails/Transactions/EmailTransactionValidator.cs b/Transactional Emails/Transactions/EmailTransactionValidator.cs new file mode 100644 index 0000000..09571bf --- /dev/null +++ b/Transactional Emails/Transactions/EmailTransactionValidator.cs @@ -0,0 +1,109 @@ +using FluentValidation; + +using VNLib.Plugins.Extensions.Validation; + + +namespace Emails.Transactional.Transactions +{ + internal class EmailTransactionValidator : AbstractValidator<EmailTransaction> + { + public const int MAX_SUBJECT_LEN = 50; + public EmailTransactionValidator() + { + //Catch to make sure user-id is set + RuleFor(static t => t.UserId) + .NotEmpty(); + //validate from addres/name + RuleFor(static t => t.FromName) + .NotEmpty() + .WithName("from_name") + .AlphaNumericOnly() + .WithName("from_name"); + RuleFor(static t => t.From) + .NotEmpty() + .EmailAddress() + .WithName("from"); + + //Rule names must be their json propery name, so clients can properly log errors + //must include a template id + RuleFor(static t => t.TemplateId) + .NotEmpty() + .MaximumLength(200) + .WithName("template_id"); + + //From address must not be empty + RuleFor(static t => t.From) + .NotEmpty() + .EmailAddress(); + //Subject is required alpha num + RuleFor(static t => t.Subject) + .NotEmpty() + .AlphaNumericOnly() + .MaximumLength(MAX_SUBJECT_LEN) + .WithName("subject"); + + //To address must not be empty, and must be valid email addresses + RuleFor(static t => t.ToAddresses) + .NotEmpty() + .ChildRules(static to => { + //Check keys (address) + to.RuleForEach(static b => b.Keys) + .NotEmpty() + .EmailAddress() + .WithName("to"); + + //Check values (names) + to.RuleForEach(static b => b.Values) + .NotEmpty() + .AlphaNumericOnly() + .WithName("to_name"); + }) + .WithName("to"); + //Check bcc addresses, allowed to be empty + RuleFor(static t => t.BccAddresses) + .ChildRules(static bcc => { + //Check keys (address) + bcc.RuleForEach(static b => b.Keys) + .NotEmpty() + .EmailAddress() + .WithName("bcc"); + + //Check values (names) + bcc.RuleForEach(static b => b.Values) + .NotEmpty() + .AlphaNumericOnly() + .WithName("bcc_names"); + }) + .When(static t => t.BccAddresses != null) + .WithName("bcc"); + //Check cc, also allowed to be empty + RuleFor(static t => t.CcAddresses) + .ChildRules(static cc => { + //Check keys (names) + cc.RuleForEach(static b => b.Keys) + .NotEmpty() + .EmailAddress() + .WithName("cc"); + + //Check values (addresses) + cc.RuleForEach(static b => b.Values) + .NotEmpty() + .AlphaNumericOnly() + .WithName("cc_names"); + }) + .When(static t => t.BccAddresses != null) + .WithName("cc"); + + RuleFor(static t => t.ReplyTo) + //Allow the reply to email to be empty, if its not, then validate the address + .EmailAddress() + .When(static t => t.BccAddresses != null) + .WithName("reply_to"); + + //Make sure a variable table is defined + RuleFor(static t => t.Variables) + .NotNull() + .WithName("variables"); + } + } +} diff --git a/Transactional Emails/Transactions/TransactionResult.cs b/Transactional Emails/Transactions/TransactionResult.cs new file mode 100644 index 0000000..2f14875 --- /dev/null +++ b/Transactional Emails/Transactions/TransactionResult.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +using VNLib.Plugins.Extensions.Validation; + +namespace Emails.Transactional.Transactions +{ + public class TransactionResult : ValErrWebMessage + { + [JsonPropertyName("transaction_id")] + public string TransactionId { get; set; } + [JsonPropertyName("smtp_status")] + public string SmtpStatus { get; set; } + + [JsonPropertyName("error_code")] + public string ErrorCode { get; set; } + + [JsonPropertyName("error_description")] + public string ErrorDescription { get; set; } + } +} diff --git a/Transactional Emails/Transactions/TransactionStore.cs b/Transactional Emails/Transactions/TransactionStore.cs new file mode 100644 index 0000000..9a700ae --- /dev/null +++ b/Transactional Emails/Transactions/TransactionStore.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; + +using Microsoft.EntityFrameworkCore; + +using VNLib.Plugins.Extensions.Data; + +namespace Emails.Transactional.Transactions +{ + + internal class TransactionStore : DbStore<EmailTransaction> + { + private readonly DbContextOptions Options; + + public TransactionStore(DbContextOptions options) + { + Options = options; + } + + public override TransactionalDbContext NewContext() => new EmailDbCtx(Options); + + public override string RecordIdBuilder => Guid.NewGuid().ToString("N"); + + protected override void OnRecordUpdate(EmailTransaction newRecord, EmailTransaction oldRecord) + { + oldRecord.LastModified = DateTime.UtcNow; + } + + protected override IQueryable<EmailTransaction> GetCollectionQueryBuilder(TransactionalDbContext context, params string[] constraints) + { + string userId = constraints[0]; + //Get the last transactions for the specifed user + EmailDbCtx ctx = context as EmailDbCtx; + return from trans in ctx.EmailTransactions + where trans.UserId == userId + orderby trans.LastModified descending + select trans; + } + + protected override IQueryable<EmailTransaction> GetSingleQueryBuilder(TransactionalDbContext context, params string[] constraints) + { + string transactionid = constraints[0]; + EmailDbCtx ctx = context as EmailDbCtx; + //Selet the exact transaction from its id + return from trans in ctx.EmailTransactions + where trans.Id == transactionid + select trans; + } + } +} |