diff --git a/BedBrigade.Client/Components/Pages/Administration/Admin/Email.razor.cs b/BedBrigade.Client/Components/Pages/Administration/Admin/Email.razor.cs index 0aeb083a..d2d1dedb 100644 --- a/BedBrigade.Client/Components/Pages/Administration/Admin/Email.razor.cs +++ b/BedBrigade.Client/Components/Pages/Administration/Admin/Email.razor.cs @@ -43,8 +43,8 @@ protected override async Task OnInitializedAsync() Model.EmailRecipientOptions = EnumHelper.GetEnumNameValues().Where(x => x.Value != EmailRecipientOption.Everyone).ToList(); } - Model.CurrentEmailRecipientOption = EmailRecipientOption.BedBrigadeLeadersForLocation; - Model.ShowLocationDropdown = isNationalAdmin; + Model.CurrentEmailRecipientOption = EmailRecipientOption.Myself; + Model.ShowLocationDropdown = false; Model.ShowEventDropdown = false; await BuildPlan(); } diff --git a/BedBrigade.Client/Program.cs b/BedBrigade.Client/Program.cs index 0ef60872..38689a21 100644 --- a/BedBrigade.Client/Program.cs +++ b/BedBrigade.Client/Program.cs @@ -8,5 +8,5 @@ await StartupLogic.SetupDatabase(app); await StartupLogic.SetupCaching(app); //TODO: Renable later -//StartupLogic.SetupEmailQueueProcessing(app); +StartupLogic.SetupEmailQueueProcessing(app); app.Run(); diff --git a/BedBrigade.Client/appsettings.Development.json b/BedBrigade.Client/appsettings.Development.json index 9a143e5c..b9bc8e97 100644 --- a/BedBrigade.Client/appsettings.Development.json +++ b/BedBrigade.Client/appsettings.Development.json @@ -35,15 +35,5 @@ } } ] - }, - "EmailConfiguration": { - "From": "noreply@bedbrigade.org", - "SmtpServer": "localhost", - "Port": 25, - "UserName": "national.admin@bedbrigade.org", - "Password": "Password", - "EnableSsl": false, - "UseFileMock": true, - "FileMockPath": "..\\logs\\EmailFileMock.txt" } } diff --git a/BedBrigade.Client/appsettings.Local.json b/BedBrigade.Client/appsettings.Local.json index e85e739d..fc7f4f6c 100644 --- a/BedBrigade.Client/appsettings.Local.json +++ b/BedBrigade.Client/appsettings.Local.json @@ -35,15 +35,5 @@ } } ] - }, - "EmailConfiguration": { - "From": "noreply@bedbrigade.org", - "SmtpServer": "localhost", - "Port": 25, - "UserName": "national.admin@bedbrigade.org", - "Password": "Password", - "EnableSsl": false, - "UseFileMock": true, - "FileMockPath": "..\\logs\\EmailFileMock.txt" } } diff --git a/BedBrigade.Client/appsettings.Production.json b/BedBrigade.Client/appsettings.Production.json index 9a143e5c..b9bc8e97 100644 --- a/BedBrigade.Client/appsettings.Production.json +++ b/BedBrigade.Client/appsettings.Production.json @@ -35,15 +35,5 @@ } } ] - }, - "EmailConfiguration": { - "From": "noreply@bedbrigade.org", - "SmtpServer": "localhost", - "Port": 25, - "UserName": "national.admin@bedbrigade.org", - "Password": "Password", - "EnableSsl": false, - "UseFileMock": true, - "FileMockPath": "..\\logs\\EmailFileMock.txt" } } diff --git a/BedBrigade.Client/appsettings.json b/BedBrigade.Client/appsettings.json index 5a003c2d..582094bf 100644 --- a/BedBrigade.Client/appsettings.json +++ b/BedBrigade.Client/appsettings.json @@ -35,15 +35,5 @@ } } ] - }, - "EmailConfiguration": { - "From": "noreply@bedbrigade.org", - "SmtpServer": "localhost", - "Port": 25, - "UserName": "national.admin@bedbrigade.org", - "Password": "Password", - "EnableSsl": false, - "UseFileMock": true, - "FileMockPath": "../logs/EmailFileMock.txt" } } diff --git a/BedBrigade.Common/Constants/ConfigNames.cs b/BedBrigade.Common/Constants/ConfigNames.cs index d3fcc52f..6f793a6b 100644 --- a/BedBrigade.Common/Constants/ConfigNames.cs +++ b/BedBrigade.Common/Constants/ConfigNames.cs @@ -2,6 +2,23 @@ { public static class ConfigNames { + //System + public const string TokenExpiration = "TokenExpiration"; + public const string ReCaptchaSecret = "ReCaptchaSecret"; + public const string ReCaptchaSiteKey = "ReCaptchaSiteKey"; + public const string IsCachingEnabled = "IsCachingEnabled"; + public const string BedBrigadeNearMeMaxMiles = "BedBrigadeNearMeMaxMiles"; + public const string DisplayIdFields = "DisplayIdFields"; + public const string EmptyGridText = "EmptyGridText"; + + //Media + public const string AllowedFileExtensions = "AllowedFileExtensions"; + public const string AllowedVideoExtensions = "AllowedVideoExtensions"; + public const string MediaFolder = "MediaFolder"; + public const string MainMediaSubFolder = "MainMediaSubFolder"; + public const string MaxFileSize = "MaxFileSize"; + public const string MaxVideoSize = "MaxVideoSize"; + //Email Section public const string FromEmailAddress = "FromEmailAddress"; public const string FromEmailDisplayName = "FromEmailDisplayName"; @@ -16,20 +33,11 @@ public static class ConfigNames public const string EmailKeepDays = "EmailKeepDays"; public const string EmailMaxPerChunk = "EmailMaxPerChunk"; public const string EmailUseFileMock = "EmailUseFileMock"; + public const string EmailHost = "EmailHost"; + public const string EmailPort = "EmailPort"; + public const string EmailUserName = "EmailUserName"; + public const string EmailPassword = "EmailPassword"; - //Other - public const string TokenExpiration = "TokenExpiration"; - public const string AllowedFileExtensions = "AllowedFileExtensions"; - public const string AllowedVideoExtensions = "AllowedVideoExtensions"; - public const string MediaFolder = "MediaFolder"; - public const string MainMediaSubFolder = "MainMediaSubFolder"; - public const string MaxFileSize = "MaxFileSize"; - public const string MaxVideoSize = "MaxVideoSize"; - public const string IsCachingEnabled = "IsCachingEnabled"; - public const string BedBrigadeNearMeMaxMiles = "BedBrigadeNearMeMaxMiles"; - public const string ReCaptchaSecret = "ReCaptchaSecret"; - public const string ReCaptchaSiteKey = "ReCaptchaSiteKey"; - public const string DisplayIdFields = "DisplayIdFields"; - public const string EmptyGridText = "EmptyGridText"; + } } diff --git a/BedBrigade.Common/Enums/EmailRecipientOption.cs b/BedBrigade.Common/Enums/EmailRecipientOption.cs index 0363dc02..1fb81ad1 100644 --- a/BedBrigade.Common/Enums/EmailRecipientOption.cs +++ b/BedBrigade.Common/Enums/EmailRecipientOption.cs @@ -9,6 +9,8 @@ namespace BedBrigade.Common.Enums { public enum EmailRecipientOption { + [Description("Myself (used for testing)")] + Myself, [Description("Bed Brigade Leaders Nationwide")] BedBrigadeLeadersNationwide, [Description("Bed Brigade Leaders for Location")] diff --git a/BedBrigade.Common/Models/EmailQueue.cs b/BedBrigade.Common/Models/EmailQueue.cs index ee55564b..f4215f73 100644 --- a/BedBrigade.Common/Models/EmailQueue.cs +++ b/BedBrigade.Common/Models/EmailQueue.cs @@ -16,9 +16,15 @@ public class EmailQueue : BaseEntity [Required, MaxLength(100)] public string FromAddress { get; set; } = string.Empty; + [MaxLength(100)] + public string? ReplyToAddress { get; set; } + [Required, MaxLength(100)] public string ToAddress { get; set; } = string.Empty; + [MaxLength(100)] + public string? ToDisplayName { get; set; } + [Required, MaxLength(100)] public string Subject { get; set; } = string.Empty; diff --git a/BedBrigade.Data/BedBrigade.Data.csproj b/BedBrigade.Data/BedBrigade.Data.csproj index e20048fb..7cfa3133 100644 --- a/BedBrigade.Data/BedBrigade.Data.csproj +++ b/BedBrigade.Data/BedBrigade.Data.csproj @@ -49,7 +49,6 @@ - diff --git a/BedBrigade.Data/Data/Seeding/Seed.cs b/BedBrigade.Data/Data/Seeding/Seed.cs index c67e9b89..7d23def4 100644 --- a/BedBrigade.Data/Data/Seeding/Seed.cs +++ b/BedBrigade.Data/Data/Seeding/Seed.cs @@ -216,12 +216,6 @@ private static async Task SeedConfigurations(IDbContextFactory cont Log.Logger.Information("No configurations found, adding"); var configurations = new List { - new() - { - ConfigurationKey = ConfigNames.FromEmailAddress, - ConfigurationValue = "DoNotReply@89a27aba-71cb-4968-863a-b1e5203187d5.azurecomm.net", - Section = ConfigSection.Email - }, new() { ConfigurationKey = ConfigNames.TokenExpiration, @@ -289,6 +283,12 @@ private static async Task SeedConfigurations(IDbContextFactory cont Section = ConfigSection.System }, new() + { + ConfigurationKey = ConfigNames.FromEmailAddress, + ConfigurationValue = "devtest@bedbrigadecolumbus.org", + Section = ConfigSection.Email + }, + new() { ConfigurationKey = ConfigNames.EmailBeginHour, ConfigurationValue = "0", @@ -361,6 +361,30 @@ private static async Task SeedConfigurations(IDbContextFactory cont Section = ConfigSection.Email }, new() + { + ConfigurationKey = ConfigNames.EmailHost, + ConfigurationValue = "mail5019.site4now.net", + Section = ConfigSection.Email + }, + new() + { + ConfigurationKey = ConfigNames.EmailPort, + ConfigurationValue = "8889", + Section = ConfigSection.Email + }, + new() + { + ConfigurationKey = ConfigNames.EmailUserName, + ConfigurationValue = "devtest@bedbrigadecolumbus.org", + Section = ConfigSection.Email + }, + new() + { + ConfigurationKey = ConfigNames.EmailPassword, + ConfigurationValue = "AskGregForPassword", + Section = ConfigSection.Email + }, + new() { ConfigurationKey = ConfigNames.DisplayIdFields, ConfigurationValue = "No", diff --git a/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.Designer.cs b/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.Designer.cs new file mode 100644 index 00000000..cca25d1a --- /dev/null +++ b/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.Designer.cs @@ -0,0 +1,1087 @@ +// +using System; +using BedBrigade.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BedBrigade.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20240816133434_EmailQueueReplyTo")] + partial class EmailQueueReplyTo + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("BedBrigade.Data.Models.BedRequest", b => + { + b.Property("BedRequestId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("BedRequestId")); + + b.Property("AgesGender") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("City") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("DeliveryDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(25) + .HasColumnType("nvarchar(25)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Notes") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("NumberOfBeds") + .HasColumnType("int"); + + b.Property("Phone") + .IsRequired() + .HasMaxLength(14) + .HasColumnType("nvarchar(14)"); + + b.Property("PostalCode") + .IsRequired() + .HasMaxLength(5) + .HasColumnType("nvarchar(5)"); + + b.Property("ScheduleId") + .HasColumnType("int"); + + b.Property("SpecialInstructions") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("State") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Street") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("TeamNumber") + .HasColumnType("int"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("BedRequestId"); + + b.HasIndex("LocationId"); + + b.HasIndex("ScheduleId"); + + b.ToTable("BedRequests"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Configuration", b => + { + b.Property("ConfigurationKey") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ConfigurationValue") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Section") + .HasColumnType("int"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("ConfigurationKey"); + + b.ToTable("Configurations"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.ContactUs", b => + { + b.Property("ContactUsId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ContactUsId")); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(25) + .HasColumnType("nvarchar(25)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Phone") + .IsRequired() + .HasMaxLength(14) + .HasColumnType("nvarchar(14)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("ContactUsId"); + + b.HasIndex("LocationId"); + + b.HasIndex("Status"); + + b.ToTable("ContactUs"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Content", b => + { + b.Property("ContentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ContentId")); + + b.Property("ContentHtml") + .HasColumnType("nvarchar(max)"); + + b.Property("ContentType") + .HasColumnType("int"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("ContentId"); + + b.HasIndex("ContentType"); + + b.HasIndex("LocationId"); + + b.ToTable("Content"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Donation", b => + { + b.Property("DonationId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("DonationId")); + + b.Property("Amount") + .HasColumnType("decimal(18,4)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FirstName") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("LastName") + .HasMaxLength(25) + .HasColumnType("nvarchar(25)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TaxFormSent") + .HasColumnType("bit"); + + b.Property("TransactionId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("DonationId"); + + b.HasIndex("LocationId"); + + b.ToTable("Donations"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.EmailQueue", b => + { + b.Property("EmailQueueId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("EmailQueueId")); + + b.Property("Body") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FailureMessage") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("FirstName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FromAddress") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FromDisplayName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("HtmlBody") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LockDate") + .HasColumnType("datetime2"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("QueueDate") + .HasColumnType("datetime2"); + + b.Property("ReplyToAddress") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SentDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ToAddress") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ToDisplayName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("EmailQueueId"); + + b.ToTable("EmailQueue"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Location", b => + { + b.Property("LocationId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("LocationId")); + + b.Property("Address1") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Address2") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("City") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Latitude") + .HasColumnType("decimal(18,10)"); + + b.Property("Longitude") + .HasColumnType("decimal(18,10)"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("PostalCode") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Route") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("State") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("LocationId"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Media", b => + { + b.Property("MediaId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("MediaId")); + + b.Property("AltText") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FileName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FilePath") + .HasMaxLength(260) + .HasColumnType("nvarchar(260)"); + + b.Property("FileSize") + .HasColumnType("int"); + + b.Property("FileStatus") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("FileUse") + .HasColumnType("int"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MediaType") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("MediaId"); + + b.HasIndex("LocationId"); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Role", b => + { + b.Property("RoleId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RoleId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("RoleId"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Schedule", b => + { + b.Property("ScheduleId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ScheduleId")); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("EventDateScheduled") + .HasColumnType("datetime2"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("EventNote") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("EventStatus") + .HasColumnType("int"); + + b.Property("EventType") + .HasColumnType("int"); + + b.Property("GroupName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VehiclesDeliveryMax") + .HasColumnType("int"); + + b.Property("VehiclesDeliveryRegistered") + .HasColumnType("int"); + + b.Property("VehiclesNormalMax") + .HasColumnType("int"); + + b.Property("VolunteersMax") + .HasColumnType("int"); + + b.Property("VolunteersRegistered") + .HasColumnType("int"); + + b.HasKey("ScheduleId"); + + b.HasIndex("EventType"); + + b.HasIndex("LocationId"); + + b.ToTable("Schedules"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Template", b => + { + b.Property("TemplateId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TemplateId")); + + b.Property("ContentHtml") + .HasColumnType("nvarchar(max)"); + + b.Property("ContentType") + .HasColumnType("int"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("TemplateId"); + + b.ToTable("Templates"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.User", b => + { + b.Property("UserName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("FkRole") + .HasColumnType("int"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(25) + .HasColumnType("nvarchar(25)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("PasswordHash") + .HasMaxLength(255) + .HasColumnType("varbinary(255)"); + + b.Property("PasswordSalt") + .HasMaxLength(255) + .HasColumnType("varbinary(255)"); + + b.Property("PersistBedRequest") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistConfig") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistDonation") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistLocation") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistMedia") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistPages") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistUser") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("PersistVolunteers") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Phone") + .IsRequired() + .HasMaxLength(14) + .HasColumnType("nvarchar(14)"); + + b.Property("Role") + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("UserName"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Volunteer", b => + { + b.Property("VolunteerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("VolunteerId")); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("IHaveAMinivan") + .HasColumnType("bit"); + + b.Property("IHaveAPickupTruck") + .HasColumnType("bit"); + + b.Property("IHaveAnSUV") + .HasColumnType("bit"); + + b.Property("IHaveVolunteeredBefore") + .HasColumnType("bit"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(25) + .HasColumnType("nvarchar(25)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Message") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("OrganizationOrGroup") + .HasMaxLength(80) + .HasColumnType("nvarchar(80)"); + + b.Property("Phone") + .IsRequired() + .HasMaxLength(14) + .HasColumnType("nvarchar(14)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VehicleType") + .HasColumnType("int"); + + b.Property("VolunteeringForDate") + .HasColumnType("datetime2"); + + b.Property("VolunteeringForId") + .HasColumnType("int"); + + b.HasKey("VolunteerId"); + + b.HasIndex("LocationId"); + + b.HasIndex("VolunteeringForId"); + + b.ToTable("Volunteers"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.VolunteerEvent", b => + { + b.Property("RegistrationId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RegistrationId")); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ScheduleId") + .HasColumnType("int"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VolunteerEventNote") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("VolunteerId") + .HasColumnType("int"); + + b.HasKey("RegistrationId"); + + b.HasIndex("VolunteerId"); + + b.ToTable("VolunteerEvents"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.VolunteerFor", b => + { + b.Property("VolunteerForId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("VolunteerForId")); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("CreateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MachineName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("UpdateDate") + .HasColumnType("datetime2"); + + b.Property("UpdateUser") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("VolunteerForId"); + + b.ToTable("VolunteersFor"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.BedRequest", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("BedRequests") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.ContactUs", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("ContactUs") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Content", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Contents") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Donation", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Donations") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Media", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Media") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Schedule", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Schedules") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.User", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Users") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Volunteer", b => + { + b.HasOne("BedBrigade.Data.Models.Location", null) + .WithMany("Volunteers") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.VolunteerEvent", b => + { + b.HasOne("BedBrigade.Data.Models.Volunteer", "Volunteer") + .WithMany() + .HasForeignKey("VolunteerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volunteer"); + }); + + modelBuilder.Entity("BedBrigade.Data.Models.Location", b => + { + b.Navigation("BedRequests"); + + b.Navigation("ContactUs"); + + b.Navigation("Contents"); + + b.Navigation("Donations"); + + b.Navigation("Media"); + + b.Navigation("Schedules"); + + b.Navigation("Users"); + + b.Navigation("Volunteers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.cs b/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.cs new file mode 100644 index 00000000..56cd67f8 --- /dev/null +++ b/BedBrigade.Data/Migrations/20240816133434_EmailQueueReplyTo.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BedBrigade.Data.Migrations +{ + /// + public partial class EmailQueueReplyTo : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ReplyToAddress", + table: "EmailQueue", + type: "nvarchar(100)", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "ToDisplayName", + table: "EmailQueue", + type: "nvarchar(100)", + maxLength: 100, + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ReplyToAddress", + table: "EmailQueue"); + + migrationBuilder.DropColumn( + name: "ToDisplayName", + table: "EmailQueue"); + } + } +} diff --git a/BedBrigade.Data/Migrations/DataContextModelSnapshot.cs b/BedBrigade.Data/Migrations/DataContextModelSnapshot.cs index cd5281eb..2ac93800 100644 --- a/BedBrigade.Data/Migrations/DataContextModelSnapshot.cs +++ b/BedBrigade.Data/Migrations/DataContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.2") + .HasAnnotation("ProductVersion", "8.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -397,6 +397,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("QueueDate") .HasColumnType("datetime2"); + b.Property("ReplyToAddress") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + b.Property("SentDate") .HasColumnType("datetime2"); @@ -415,6 +419,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(100) .HasColumnType("nvarchar(100)"); + b.Property("ToDisplayName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + b.Property("UpdateDate") .HasColumnType("datetime2"); diff --git a/BedBrigade.Data/Services/ConfigurationDataService.cs b/BedBrigade.Data/Services/ConfigurationDataService.cs index ab733dd9..35bb09a4 100644 --- a/BedBrigade.Data/Services/ConfigurationDataService.cs +++ b/BedBrigade.Data/Services/ConfigurationDataService.cs @@ -40,6 +40,90 @@ public async Task>> GetAllAsync(ConfigSectio return new ServiceResponse>(result.Count + " records found", true, result); } } + + public override async Task> GetByIdAsync(object? id) + { + if (id == null) + { + return new ServiceResponse("Configuration.GetByIdAsync id is null", false); + } + var response = await base.GetAllAsync(); + + if (!response.Success || response.Data == null) + return new ServiceResponse(response.Message, false); + + Configuration result = response.Data.FirstOrDefault(o => o.ConfigurationKey == id.ToString()); + + if (result == null) + { + return new ServiceResponse("Configuration.GetByIdAsync not found: " + id); + } + + return new ServiceResponse("Configuration.GetByIdAsyncFound: " + id, true, result); + } + + public async Task GetConfigValueAsIntAsync(ConfigSection section, string key) + { + List configs = (await GetAllAsync(section)).Data; + + var config = configs.FirstOrDefault(c => c.ConfigurationKey == key); + + if (config == null) + ThrowKeyNotFound(section, key); + + if (!int.TryParse(config.ConfigurationValue, out int result)) + { + throw new FormatException($"Configuration value is not an integer for {section} - {key}"); + } + + return result; + } + + public void ThrowKeyNotFound(ConfigSection section, string key) + { + throw new KeyNotFoundException($"Configuration not found for {section} - {key}"); + } + + public async Task GetConfigValueAsync(ConfigSection section, string key) + { + List configs = (await GetAllAsync(section)).Data; + + var config = configs.FirstOrDefault(c => c.ConfigurationKey == key); + + if (config == null) + ThrowKeyNotFound(section, key); + + return config.ConfigurationValue; + } + + public async Task GetConfigValueAsDecimalAsync(ConfigSection section, string key) + { + List configs = (await GetAllAsync(section)).Data; + + var config = configs.FirstOrDefault(c => c.ConfigurationKey == key); + + if (config == null) + ThrowKeyNotFound(section, key); + + if (!decimal.TryParse(config.ConfigurationValue, out decimal result)) + { + throw new FormatException($"Configuration value is not an decimal for {section} - {key}"); + } + + return result; + } + + public async Task GetConfigValueAsBoolAsync(ConfigSection section, string key) + { + List configs = (await GetAllAsync(section)).Data; + + var config = configs.FirstOrDefault(c => c.ConfigurationKey == key); + + if (config == null) + ThrowKeyNotFound(section, key); + + return config.ConfigurationValue.ToLower() == "true"; + } } diff --git a/BedBrigade.Data/Services/EmailQueueDataService.cs b/BedBrigade.Data/Services/EmailQueueDataService.cs index 5a897429..4b06a1de 100644 --- a/BedBrigade.Data/Services/EmailQueueDataService.cs +++ b/BedBrigade.Data/Services/EmailQueueDataService.cs @@ -277,6 +277,8 @@ public async Task>> GetEmailsToSend(int locationId, const string message = "Built Email List"; switch (option) { + case EmailRecipientOption.Myself: + return new ServiceResponse>(message, true, (await GetMyself())); case EmailRecipientOption.Everyone: return new ServiceResponse>(message, true, (await GetEveryone())); case EmailRecipientOption.VolunteersForLocation: @@ -325,7 +327,11 @@ public async Task GetEstimatedTime(int queueCount, int emailCount) return DateUtil.MillisecondsToTimeLapse(milliseconds); } - + private async Task> GetMyself() + { + var user = await GetUserEmail(); + return new List { user }; + } private async Task> GetEveryone() { diff --git a/BedBrigade.Data/Services/EmailQueueLogic.cs b/BedBrigade.Data/Services/EmailQueueLogic.cs index 6614c053..bae0ce46 100644 --- a/BedBrigade.Data/Services/EmailQueueLogic.cs +++ b/BedBrigade.Data/Services/EmailQueueLogic.cs @@ -1,10 +1,7 @@ #region Includes - -using System.Data.Common; -using System.Drawing; +using System.Net.Mail; using System.Text; using Azure; -using Azure.Communication.Email; using BedBrigade.Common.Constants; using BedBrigade.Common.Enums; using BedBrigade.Data.Models; @@ -34,10 +31,12 @@ public static class EmailQueueLogic private static bool _emailUseFileMock; private static string _fromEmailAddress; private static string _fromEmailDisplayName; + private static string _host; + private static int _port; + private static string _userName; + private static string _password; #endregion - - #region Public Methods public static void Start(IEmailQueueDataService emailQueueDataService, IConfigurationDataService configurationDataService) @@ -140,13 +139,26 @@ private static async Task SendQueuedEmails() if (emailsToProcess.Count == 0) return; + if (!_emailUseFileMock) + { + Log.Debug("EmailQueueLogic: Sending LIVE emails"); + } + Log.Debug("EmailQueueLogic: Locking Emails"); await _emailQueueDataService.LockEmailsToProcess(emailsToProcess); foreach (var emailQueue in emailsToProcess) { - emailQueue.FromAddress = _fromEmailAddress; - emailQueue.FromDisplayName = _fromEmailDisplayName; + if (string.IsNullOrEmpty(emailQueue.FromAddress)) + { + emailQueue.FromAddress = _fromEmailAddress; + } + + if (string.IsNullOrEmpty(emailQueue.FromDisplayName)) + { + emailQueue.FromDisplayName = _fromEmailDisplayName; + } + if (_emailUseFileMock) { @@ -169,7 +181,7 @@ private static async Task SendQueuedEmails() private static async Task LogEmail(EmailQueue email) { StringBuilder sb = new StringBuilder(); - sb.AppendLine("Send Email"); + sb.AppendLine("Send Email (nothing actually sent see Configuration.EmailUseFileMock"); sb.AppendLine($"From: {email.FromAddress}"); sb.AppendLine($"From Display Name: {email.FromDisplayName}"); sb.AppendLine($"To: {email.ToAddress}"); @@ -178,6 +190,7 @@ private static async Task LogEmail(EmailQueue email) sb.AppendLine("=".PadRight(40,'=')); Log.Information(sb.ToString()); + email.LockDate = null; email.SentDate = DateTime.UtcNow; email.Status = EmailQueueStatus.Sent.ToString(); await _emailQueueDataService.UpdateAsync(email); @@ -185,49 +198,52 @@ private static async Task LogEmail(EmailQueue email) private static async Task SendLiveEmail(EmailQueue email) { - // This code retrieves your connection string from an environment variable. - string connectionString = Environment.GetEnvironmentVariable("COMMUNICATION_SERVICES_CONNECTION_STRING"); + // Create the email message + MailMessage mailMessage = new MailMessage(); - if (String.IsNullOrEmpty(connectionString)) + if (!string.IsNullOrEmpty(email.FromDisplayName)) { - string errorMessage = - "EmailQueueLogic: COMMUNICATION_SERVICES_CONNECTION_STRING is not set as an environment variable"; - Log.Error(errorMessage); - email.SentDate = DateTime.UtcNow; - email.FailureMessage = errorMessage; - email.Status = EmailQueueStatus.Failed.ToString(); - await _emailQueueDataService.UpdateAsync(email); - return; + mailMessage.From = new MailAddress(email.FromAddress, email.FromDisplayName); } - - var emailClient = new EmailClient(connectionString); - - EmailContent emailContent = new EmailContent(email.Subject); - emailContent.PlainText = email.Body; - EmailMessage emailMessage = new EmailMessage(email.FromAddress, email.ToAddress, emailContent); - EmailAddress sender = new EmailAddress(email.FromAddress,email.FromDisplayName ?? email.FromAddress); - emailMessage.ReplyTo.Add(sender); - - try + else { - EmailSendOperation emailSendOperation = await emailClient.SendAsync(WaitUntil.Completed, emailMessage); - - - if (!emailSendOperation.HasValue) - { - return; - } + mailMessage.From = new MailAddress(email.FromAddress); + } - if (emailSendOperation.Value.Status == EmailSendStatus.Succeeded) + if (!string.IsNullOrEmpty(email.ReplyToAddress)) + { + if (!string.IsNullOrEmpty(email.FromDisplayName)) { - email.Status = EmailQueueStatus.Sent.ToString(); + mailMessage.ReplyToList.Add(new MailAddress(email.ReplyToAddress, email.FromDisplayName)); } else { - email.FailureMessage = emailSendOperation.GetRawResponse().ToString(); - email.Status = EmailQueueStatus.Failed.ToString(); + mailMessage.ReplyToList.Add(new MailAddress(email.ReplyToAddress)); } } + + if (!string.IsNullOrEmpty(email.ToDisplayName)) + { + mailMessage.To.Add(new MailAddress(email.ToAddress, email.ToDisplayName)); + } + else + { + mailMessage.To.Add(new MailAddress(email.ToAddress)); + } + + mailMessage.Subject = email.Subject; + mailMessage.Body = email.Body; + + // Send the email + SmtpClient smtpClient = new SmtpClient(_host, _port); + + + try + { + smtpClient.Credentials = new System.Net.NetworkCredential(_userName, _password); + smtpClient.Send(mailMessage); + email.Status = EmailQueueStatus.Sent.ToString(); + } catch (RequestFailedException ex) { email.FailureMessage = @@ -235,6 +251,7 @@ private static async Task SendLiveEmail(EmailQueue email) email.Status = EmailQueueStatus.Failed.ToString(); } + email.LockDate = null; email.SentDate = DateTime.UtcNow; await _emailQueueDataService.UpdateAsync(email); } @@ -328,9 +345,15 @@ private static async Task LoadConfiguration() _emailLockWaitMinutes = await LoadEmailConfigValue( ConfigNames.EmailLockWaitMinutes); _emailKeepDays = await LoadEmailConfigValue( ConfigNames.EmailKeepDays); _emailMaxPerChunk = await LoadEmailConfigValue( ConfigNames.EmailMaxPerChunk); - _emailUseFileMock = await LoadEmailConfigValue( ConfigNames.EmailUseFileMock) == 1; + _emailUseFileMock = + await _configurationDataService.GetConfigValueAsBoolAsync(ConfigSection.Email, + ConfigNames.EmailUseFileMock); _fromEmailAddress = await LoadEmailConfigString( ConfigNames.FromEmailAddress); _fromEmailDisplayName = await LoadEmailConfigString( ConfigNames.FromEmailDisplayName); + _host = await LoadEmailConfigString(ConfigNames.EmailHost); + _port = await LoadEmailConfigValue(ConfigNames.EmailPort); + _userName = await LoadEmailConfigString(ConfigNames.EmailUserName); + _password = await LoadEmailConfigString(ConfigNames.EmailPassword); } private static async Task LoadEmailConfigString(string id) diff --git a/BedBrigade.Data/Services/IConfigurationDataService.cs b/BedBrigade.Data/Services/IConfigurationDataService.cs index 573eda03..31d0ed31 100644 --- a/BedBrigade.Data/Services/IConfigurationDataService.cs +++ b/BedBrigade.Data/Services/IConfigurationDataService.cs @@ -7,5 +7,9 @@ namespace BedBrigade.Data.Services public interface IConfigurationDataService : IRepository { Task>> GetAllAsync(ConfigSection section); + Task GetConfigValueAsIntAsync(ConfigSection section, string key); + Task GetConfigValueAsync(ConfigSection section, string key); + Task GetConfigValueAsDecimalAsync(ConfigSection section, string key); + Task GetConfigValueAsBoolAsync(ConfigSection section, string key); } } \ No newline at end of file