diff options
author | vnugent <public@vaughnnugent.com> | 2023-01-12 17:47:40 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-01-12 17:47:40 -0500 |
commit | d797953c74798252d7153a20e788ed034c71b0ae (patch) | |
tree | bb295b619a4c0ed13d18691063ddaebd3961faf5 /Transactional Emails | |
parent | d8ef5d21416c4a9deaa5cae7d3c8a11fae6a15f7 (diff) |
Large project reorder and consolidation
Diffstat (limited to 'Transactional Emails')
-rw-r--r-- | Transactional Emails/Api Endpoints/SendEndpoint.cs | 273 | ||||
-rw-r--r-- | Transactional Emails/EmailDbCtx.cs | 40 | ||||
-rw-r--r-- | Transactional Emails/EmailTransaction.cs | 162 | ||||
-rw-r--r-- | Transactional Emails/SmtpProvider.cs | 118 | ||||
-rw-r--r-- | Transactional Emails/TEmailEntryPoint.cs | 88 | ||||
-rw-r--r-- | Transactional Emails/Transactional Emails.csproj | 62 | ||||
-rw-r--r-- | Transactional Emails/Transactions/EmailTransactionValidator.cs | 133 | ||||
-rw-r--r-- | Transactional Emails/Transactions/TransactionResult.cs | 44 | ||||
-rw-r--r-- | Transactional Emails/Transactions/TransactionStore.cs | 74 |
9 files changed, 0 insertions, 994 deletions
diff --git a/Transactional Emails/Api Endpoints/SendEndpoint.cs b/Transactional Emails/Api Endpoints/SendEndpoint.cs deleted file mode 100644 index c464f6b..0000000 --- a/Transactional Emails/Api Endpoints/SendEndpoint.cs +++ /dev/null @@ -1,273 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: SendEndpoint.cs -* -* SendEndpoint.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using System.Collections.Generic; - -using Fluid; - -using Minio; -using Minio.DataModel; -using Minio.Exceptions; - -using MimeKit.Text; - -using VNLib.Utils.Extensions; -using VNLib.Utils.Logging; -using VNLib.Utils.Memory.Caching; -using VNLib.Plugins; -using VNLib.Plugins.Essentials; -using VNLib.Plugins.Essentials.Extensions; -using VNLib.Plugins.Essentials.Oauth; -using VNLib.Plugins.Extensions.Validation; -using VNLib.Plugins.Extensions.Loading; -using VNLib.Plugins.Extensions.Loading.Sql; - -using Emails.Transactional.Transactions; -using static Emails.Transactional.TEmailEntryPoint; - -#nullable enable - -namespace Emails.Transactional.Endpoints -{ - [ConfigurationName("transaction_endpoint")] - internal class SendEndpoint : O2EndpointBase - { - public const string OAUTH2_USER_SCOPE_PERMISSION = "email:send"; - - private class FluidCache : ICacheable - { - public FluidCache(IFluidTemplate temp) - { - this.Template = temp; - } - - public IFluidTemplate Template { get; } - - DateTime ICacheable.Expires { get; set; } - - bool IEquatable<ICacheable>.Equals(ICacheable? other) - { - return ReferenceEquals(Template, (other as FluidCache)?.Template); - } - - void ICacheable.Evicted() - {} - } - - private static readonly EmailTransactionValidator Validator = new(); - private static readonly FluidParser Parser = new(); - - private readonly string FromAddress; - private readonly string? BaseObjectPath; - private readonly SmtpProvider EmailService; - private readonly TransactionStore Transactions; - - private readonly Dictionary<string, FluidCache> TemplateCache; - private readonly TimeSpan TemplateCacheTimeout; - private readonly MinioClient Client; - private readonly S3Config S3Config; - - public SendEndpoint(PluginBase plugin, IReadOnlyDictionary<string, JsonElement> config) - { - string? path = config["path"].GetString(); - FromAddress = config["from_address"].GetString() ?? throw new KeyNotFoundException("Missing required key 'from_address' in 'transaction_endpoint'"); - TemplateCacheTimeout = config["cache_valid_sec"].GetTimeSpan(TimeParseType.Seconds); - BaseObjectPath = config["base_object_path"].GetString(); - - InitPathAndLog(path, plugin.Log); - - //Smtp setup - { - IReadOnlyDictionary<string, JsonElement> smtp = plugin.GetConfig("smtp"); - Uri serverUri = new(smtp["server_address"].GetString()!); - string username = smtp["username"].GetString() ?? throw new KeyNotFoundException("Missing required key 'usename' in 'smtp' config"); - string password = plugin.TryGetSecretAsync("smtp_password").Result ?? throw new KeyNotFoundException("Missing required 'smtp_password' in secrets"); - TimeSpan timeout = smtp["timeout_sec"].GetTimeSpan(TimeParseType.Seconds); - NetworkCredential cred = new(username, password); - //Init email service - EmailService = new(serverUri, cred, timeout); - } - //S3 minio setup - { - //Init minio s3 client - S3Config = plugin.TryGetS3Config() ?? throw new KeyNotFoundException("Missing required 's3_config' configuration variable"); - //Init minio from config - Client = new(); - Client.WithEndpoint(S3Config.ServerAddress) - .WithCredentials(S3Config.ClientId, S3Config.ClientSecret); - - if (S3Config.UseSsl == true) - { - Client.WithSSL(); - } - //Accept optional region - if (!string.IsNullOrWhiteSpace(S3Config.Region)) - { - Client.WithRegion(S3Config.Region); - } - //Build client - Client.Build(); - //If the plugin is in debug mode, log requests to logger - if (plugin.IsDebug()) - { - Client.SetTraceOn(new ReqLogger(Log)); - } - } - - //Load transactions - Transactions = new(plugin.GetContextOptions()); - - TemplateCache = new(20, StringComparer.OrdinalIgnoreCase); - } - - protected override async ValueTask<VfReturnType> PostAsync(HttpEntity entity) - { - //Make sure the user has the required scope to send an email - if (!entity.Session.HasScope(OAUTH2_USER_SCOPE_PERMISSION)) - { - entity.CloseResponseError(HttpStatusCode.Forbidden, ErrorType.InvalidScope, "Your account does not have the required permissions scope"); - return VfReturnType.VirtualSkip; - } - - //Get the transaction request from the client - EmailTransaction? transaction = await entity.GetJsonFromFileAsync<EmailTransaction>(); - if(transaction == null) - { - entity.CloseResponseError(HttpStatusCode.BadRequest, ErrorType.InvalidRequest, "No request body was received"); - return VfReturnType.VirtualSkip; - } - - TransactionResult webm = new() - { - Success = false - }; - //Set a default from name/address if not set by user - transaction.From ??= FromAddress; - transaction.FromName ??= FromAddress; - //Specify user-id - transaction.UserId = entity.Session.UserID; - //validate the form - if (!Validator.Validate(transaction, webm)) - { - //return errors - entity.CloseResponseJson(HttpStatusCode.UnprocessableEntity, webm); - return VfReturnType.VirtualSkip; - } - - IFluidTemplate fTemp; - - //See if the template is in cache - if (TemplateCache.TryGetOrEvictRecord(transaction.TemplateId!, out FluidCache? cache) == 1) - { - fTemp = cache.Template; - } - //Record was evicted or not found - else - { - string? templateData = null; - try - { - //Combine base obj path - string objPath = string.Concat(BaseObjectPath, transaction.TemplateId); - //Recover the template from the store - GetObjectArgs args = new(); - args.WithBucket(S3Config.BaseBucket) - .WithObject(objPath) - .WithCallbackStream((stream) => - { - //Read template from stream - using StreamReader reader = new(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true); - templateData = reader.ReadToEnd(); - }); - //get the template object - ObjectStat status = await Client.GetObjectAsync(args, entity.EventCancellation); - - - } - catch(ObjectNotFoundException) - { - entity.CloseResponseError(HttpStatusCode.NotFound, ErrorType.InvalidRequest, "The requested template does not exist"); - return VfReturnType.VirtualSkip; - } - catch(MinioException me) - { - Log.Error(me); - return VfReturnType.Error; - } - - //Make sure template data was found - if (string.IsNullOrWhiteSpace(templateData)) - { - entity.CloseResponseError(HttpStatusCode.NotFound, ErrorType.InvalidRequest, "The requested template does not exist"); - return VfReturnType.VirtualSkip; - } - - //Try to parse the template - if (!Parser.TryParse(templateData, out fTemp, out string error)) - { - Log.Error(error, "Liquid template parsing error"); - return VfReturnType.Error; - } - - //Cache the new template - TemplateCache.StoreRecord(transaction.TemplateId!, new FluidCache(fTemp), TemplateCacheTimeout); - } - - //Allways add the template name to the model - transaction.Variables!["template_name"] = transaction.TemplateId!; - - //Create a template model - TemplateContext ctx = new(transaction.Variables); - //render the template - string rendered = fTemp.Render(ctx); - try - { - //Send the template - _ = await EmailService.SendAsync(transaction, rendered, TextFormat.Html, entity.EventCancellation); - //Set success flag - webm.Success = true; - } - catch (Exception ex) - { - Log.Error(ex); - //Write an error status message to the transaction store - transaction.Result = ex.Message; - } - //Write transaction to db (we need to return the transaction id) - _ = await Transactions.AddOrUpdateAsync(transaction); - //Store the results object - webm.SmtpStatus = transaction.Result; - webm.TransactionId = transaction.Id; - //Return the response object - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - } -} diff --git a/Transactional Emails/EmailDbCtx.cs b/Transactional Emails/EmailDbCtx.cs deleted file mode 100644 index cd865d8..0000000 --- a/Transactional Emails/EmailDbCtx.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: EmailDbCtx.cs -* -* EmailDbCtx.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -using System; - -using Microsoft.EntityFrameworkCore; - -using VNLib.Plugins.Extensions.Data; - -namespace Emails.Transactional -{ - internal class EmailDbCtx : TransactionalDbContext - { - public DbSet<EmailTransaction> EmailTransactions { get; set; } - - public EmailDbCtx(DbContextOptions options) : base(options) - {} - } -} diff --git a/Transactional Emails/EmailTransaction.cs b/Transactional Emails/EmailTransaction.cs deleted file mode 100644 index bb7b4a8..0000000 --- a/Transactional Emails/EmailTransaction.cs +++ /dev/null @@ -1,162 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: EmailTransaction.cs -* -* EmailTransaction.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -using VNLib.Plugins.Essentials; -using VNLib.Plugins.Extensions.Data; -using VNLib.Plugins.Extensions.Data.Abstractions; - -#nullable enable - -namespace Emails.Transactional -{ - /// <summary> - /// Represents an email transaction request and its status reflected - /// in the database - /// </summary> - internal class EmailTransaction : DbModelBase, IUserEntity - { - ///<inheritdoc/> - [Key] - [JsonPropertyName("id")] - public override string Id { get; set; } - ///<inheritdoc/> - [JsonIgnore] - public override DateTime Created { get; set; } - ///<inheritdoc/> - [JsonIgnore] - public override DateTime LastModified { get; set; } - - /// <summary> - /// The sever side user-id that send the email - /// </summary> - [JsonIgnore] - public string? UserId { get; set; } - - //To address - [JsonIgnore] - public string? To - { - //Use json to serialize/deserialze the to addresses - get => JsonSerializer.Serialize(ToAddresses, Statics.SR_OPTIONS); - set => ToAddresses = JsonSerializer.Deserialize<Dictionary<string, string>>(value!, Statics.SR_OPTIONS); - } - - /// <summary> - /// A dictionary of to email address and name pairs - /// </summary> - [NotMapped] - [JsonPropertyName("to")] - public Dictionary<string, string>? ToAddresses { get; set; } - - //From - /// <summary> - /// The from email address - /// </summary> - [JsonPropertyName("from")] - public string? From { get; set; } - - /// <summary> - /// The optional from name (not mapped in db) - /// </summary> - [NotMapped] - [JsonPropertyName("from_name")] - public string? FromName { get; set; } - /// <summary> - /// The email subject - /// </summary> - [JsonPropertyName("subject")] - public string? Subject { get; set; } - - //CC names - //ccs are stored in the db as a json serialized string - [JsonIgnore] - public string Ccs - { - //Use json to serialize/deserialze the to addresses - get => JsonSerializer.Serialize(CcAddresses, Statics.SR_OPTIONS); - set => CcAddresses = JsonSerializer.Deserialize<Dictionary<string, string>>(value, Statics.SR_OPTIONS); - } - - [JsonPropertyName("cc")] - [NotMapped] - public Dictionary<string, string>? CcAddresses { get; set; } - - //BCC Names - - //bccs are stored in the db as a json serialized string - [JsonIgnore] - public string Bccs - { - //Store bccs as a comma separated list of addresses - get => JsonSerializer.Serialize(BccAddresses, Statics.SR_OPTIONS); - set => BccAddresses = JsonSerializer.Deserialize<Dictionary<string, string>>(value, Statics.SR_OPTIONS); - } - - /// <summary> - /// A dictionary of bcc addresses and names - /// </summary> - [JsonPropertyName("bcc")] - [NotMapped] - public Dictionary<string, string>? BccAddresses { get; set; } - - /// <summary> - /// The replyto email address - /// </summary> - [JsonPropertyName("reply_to")] - public string? ReplyTo { get; set; } - /// <summary> - /// Optional reply-to name for the address (not stored in db) - /// </summary> - [NotMapped] - [JsonPropertyName("reply_to_name")] - public string? ReplyToName { get; set; } - - /// <summary> - /// The object id of the template to send - /// </summary> - [JsonPropertyName("template_id")] - public string? TemplateId { get; set; } - - /// <summary> - /// The result of the STMP transaction - /// </summary> - [JsonIgnore] - public string? Result { get; set; } - - /// <summary> - /// Variables requested from the client to embed in the template - /// during processing. These are not stored in the database - /// </summary> - [NotMapped] - [JsonPropertyName("variables")] - public Dictionary<string, string>? Variables { get; set; } - } -} diff --git a/Transactional Emails/SmtpProvider.cs b/Transactional Emails/SmtpProvider.cs deleted file mode 100644 index e864a9d..0000000 --- a/Transactional Emails/SmtpProvider.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: SmtpProvider.cs -* -* SmtpProvider.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using System.Collections.Generic; - -using MailKit.Net.Smtp; - -using MimeKit; -using MimeKit.Text; - -namespace Emails.Transactional -{ - internal class SmtpProvider - { - private readonly Uri ServerAddress; - private readonly ICredentials ServerCreds; - private readonly TimeSpan Timeout; - - public SmtpProvider(Uri ServerAddress, ICredentials ServerCreds, TimeSpan Timeout) - { - this.ServerCreds = ServerCreds; - this.ServerAddress = ServerAddress; - this.Timeout = Timeout; - } - - /// <summary> - /// Opens a connection to the configured SMTP server and sends the specified email - /// request transaction on the server. When the operation completes, the transaction's - /// result property is populated with the result of the operation. - /// </summary> - /// <param name="transaction">The transaction data</param> - /// <param name="messageBody">The content of the message to send</param> - /// <param name="dataFromat">The format of the body content</param> - /// <returns>A task that resolves the status of the operation</returns> - public async Task<string> SendAsync(EmailTransaction transaction, string messageBody, TextFormat dataFromat, CancellationToken cancellation) - { - //Configured a new message - using MimeMessage message = new() - { - Date = DateTime.UtcNow, - Subject = transaction.Subject - }; - //From address is the stored from address - message.From.Add(new MailboxAddress(transaction.FromName, transaction.From)); - - //Add to email addresses - foreach (KeyValuePair<string, string> tos in transaction.ToAddresses) - { - message.To.Add(new MailboxAddress(tos.Value, tos.Key)); - } - //Add ccs - if (transaction.CcAddresses != null) - { - foreach (KeyValuePair<string, string> ccs in transaction.CcAddresses) - { - message.Cc.Add(new MailboxAddress(ccs.Value, ccs.Key)); - } - } - //Add bccs - if (transaction.BccAddresses != null) - { - foreach (KeyValuePair<string, string> bccs in transaction.BccAddresses) - { - message.Bcc.Add(new MailboxAddress(bccs.Value, bccs.Key)); - } - } - - //Use html format since we expect to be reading html templates - using TextPart body = new(dataFromat) - { - IsAttachment = false, - Text = messageBody - }; - //Set message body - message.Body = body; - //Open a new mail client - using SmtpClient client = new(); - //Set timeout for senting messages - client.Timeout = (int)Timeout.TotalMilliseconds; - //Connect to server - await client.ConnectAsync(ServerAddress, cancellation); - //Aithenticate - await client.AuthenticateAsync(ServerCreds, cancellation); - //Send the email - string result = await client.SendAsync(message, cancellation); - //Disconnect from the server - await client.DisconnectAsync(true, CancellationToken.None); - //Update the transaction - transaction.Result = result; - return result; - } - } -} diff --git a/Transactional Emails/TEmailEntryPoint.cs b/Transactional Emails/TEmailEntryPoint.cs deleted file mode 100644 index c95ca08..0000000 --- a/Transactional Emails/TEmailEntryPoint.cs +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: TEmailEntryPoint.cs -* -* TEmailEntryPoint.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Threading.Tasks; -using System.Collections.Generic; - -using Emails.Transactional.Endpoints; - -using Minio; -using Minio.DataModel.Tracing; - -using VNLib.Utils.Logging; -using VNLib.Plugins; -using VNLib.Plugins.Extensions.Loading.Routing; - -namespace Emails.Transactional -{ - public class TEmailEntryPoint : PluginBase - { - public override string PluginName => "Emails.Transactional"; - - internal class ReqLogger : IRequestLogger - { - private readonly ILogProvider logProvider; - - public ReqLogger(ILogProvider log) - { - logProvider = log; - } - - public void LogRequest(RequestToLog requestToLog, ResponseToLog responseToLog, double durationMs) - { - logProvider.Debug("S3 result\n{method} {uri} HTTP {ms}ms\nHTTP {status} {message}\n{content}", - requestToLog.method, requestToLog.resource, durationMs, - responseToLog.statusCode, responseToLog.errorMessage, responseToLog.content - ); - } - } - - protected override void OnLoad() - { - try - { - //Route send oauth endpoint - this.Route<SendEndpoint>(); - - Log.Information("Plugin loaded"); - } - catch (KeyNotFoundException kne) - { - Log.Warn("Missing required configuration keys {err}", kne.Message); - } - } - - - protected override void OnUnLoad() - { - Log.Information("Plugin unloaded"); - } - - protected override void ProcessHostCommand(string cmd) - { - throw new NotImplementedException(); - } - } -} diff --git a/Transactional Emails/Transactional Emails.csproj b/Transactional Emails/Transactional Emails.csproj deleted file mode 100644 index 4c1a745..0000000 --- a/Transactional Emails/Transactional Emails.csproj +++ /dev/null @@ -1,62 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <TargetFramework>net6.0</TargetFramework> - <RootNamespace>Emails.Transactional</RootNamespace> - <AssemblyName>TransactionalEmails</AssemblyName> - - <Nullable>enable</Nullable> - <Authors>Vaughn Nugent</Authors> - <Copyright>Copyright © 2022 Vaughn Nugent</Copyright> - <Version>1.0.0.1</Version> - <PackageProjectUrl>https://www.vaughnnugent.com/resources</PackageProjectUrl> - </PropertyGroup> - - <!-- Resolve nuget dll files and store them in the output dir --> - <PropertyGroup> - <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> - </PropertyGroup> - - <ItemGroup> - <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> - <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> - <PackageReference Include="FluentValidation" Version="11.3.0" /> - <PackageReference Include="Fluid.Core" Version="2.2.16" /> - <PackageReference Include="MailKit" Version="3.4.2" /> - <PackageReference Include="Minio" Version="4.0.6" /> - </ItemGroup> - - <ItemGroup> - <None Update="TransactionalEmails.json"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </None> - </ItemGroup> - - <ItemGroup> - <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" /> - </ItemGroup> - - <ItemGroup> - <Folder Include="Endpoints\" /> - <Folder Include="Meta\" /> - </ItemGroup> - - <ItemGroup> - <ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Data\VNLib.Plugins.Extensions.Data.csproj" /> - <ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Loading.Sql\VNLib.Plugins.Extensions.Loading.Sql.csproj" /> - <ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Loading\VNLib.Plugins.Extensions.Loading.csproj" /> - <ProjectReference Include="..\..\Extensions\VNLib.Plugins.Extensions.Validation\VNLib.Plugins.Extensions.Validation.csproj" /> - <ProjectReference Include="..\..\PluginBase\VNLib.Plugins.PluginBase.csproj" /> - </ItemGroup> - - <Target Name="PostBuild" AfterTargets="PostBuildEvent"> - <Exec Command="start xcopy "$(TargetDir)" "F:\Programming\Web Plugins\DevPlugins\$(TargetName)" /E /Y /R" /> - </Target> - -</Project> diff --git a/Transactional Emails/Transactions/EmailTransactionValidator.cs b/Transactional Emails/Transactions/EmailTransactionValidator.cs deleted file mode 100644 index 5786efb..0000000 --- a/Transactional Emails/Transactions/EmailTransactionValidator.cs +++ /dev/null @@ -1,133 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: EmailTransactionValidator.cs -* -* EmailTransactionValidator.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -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 deleted file mode 100644 index 8506a56..0000000 --- a/Transactional Emails/Transactions/TransactionResult.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: TransactionResult.cs -* -* TransactionResult.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -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 deleted file mode 100644 index a6bd4b9..0000000 --- a/Transactional Emails/Transactions/TransactionStore.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: Transactional Emails -* File: TransactionStore.cs -* -* TransactionStore.cs is part of Transactional Emails which is part of the larger -* VNLib collection of libraries and utilities. -* -* Transactional Emails is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published -* by the Free Software Foundation, either version 2 of the License, -* or (at your option) any later version. -* -* Transactional Emails is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Transactional Emails. If not, see http://www.gnu.org/licenses/. -*/ - -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; - } - } -} |