diff --git a/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs b/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs new file mode 100644 index 0000000..02a0975 --- /dev/null +++ b/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs @@ -0,0 +1,74 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Domain.Entities; +using System.Net.Mail; + +namespace Surge365.MassEmailReact.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class BouncedEmailsController : ControllerBase + { + private readonly IBouncedEmailService _bouncedEmailService; + + public BouncedEmailsController(IBouncedEmailService bouncedEmailService) + { + _bouncedEmailService = bouncedEmailService; + } + + [HttpGet("GetAll")] + public async Task GetAll() + { + var bouncedEmails = await _bouncedEmailService.GetAllAsync(); + return Ok(bouncedEmails); + } + + [HttpGet("{emailAddress}")] + public async Task GetByEmail(string emailAddress) + { + var bouncedEmail = await _bouncedEmailService.GetByEmailAsync(emailAddress); + return bouncedEmail is not null ? Ok(bouncedEmail) : NotFound($"Bounced email with emailAddress '{emailAddress}' not found."); + } + + [HttpPost()] + public async Task CreateBouncedEmail([FromBody] BouncedEmailUpdateDto bouncedEmailUpdateDto) + { + var success = await _bouncedEmailService.CreateAsync(bouncedEmailUpdateDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to create bounced email."); + + var updatedBouncedEmail = await _bouncedEmailService.GetByEmailAsync(bouncedEmailUpdateDto.EmailAddress); + + return Ok(updatedBouncedEmail); + } + + [HttpPut("{emailAddress}")] + public async Task UpdateBouncedEmail(string emailAddress, [FromBody] BouncedEmailUpdateDto bouncedEmailUpdateDto) + { + var existingBouncedEmail = await _bouncedEmailService.GetByEmailAsync(emailAddress); + if (existingBouncedEmail == null) + return NotFound($"Bounced email with emailAddress {emailAddress} not found"); + + var success = await _bouncedEmailService.UpdateAsync(emailAddress, bouncedEmailUpdateDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to update bounced email."); + + var updatedBouncedEmail = await _bouncedEmailService.GetByEmailAsync(bouncedEmailUpdateDto.EmailAddress); + + return Ok(updatedBouncedEmail); + } + + [HttpDelete("{emailAddress}")] + public async Task DeleteBouncedEmail(string emailAddress) + { + ArgumentNullException.ThrowIfNullOrWhiteSpace(emailAddress); + + var success = await _bouncedEmailService.DeleteAsync(emailAddress); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to delete bounced email."); + + return Ok(); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs b/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs new file mode 100644 index 0000000..13951ae --- /dev/null +++ b/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Mvc; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Domain.Entities; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class EmailDomainsController : ControllerBase + { + private readonly IEmailDomainService _emailDomainService; + + public EmailDomainsController(IEmailDomainService emailDomainService) + { + _emailDomainService = emailDomainService; + } + + [HttpGet("GetAll")] + public async Task GetAll([FromQuery] bool? activeOnly) + { + var emailDomains = await _emailDomainService.GetAllAsync(activeOnly == null || activeOnly.Value ? true : false); + return Ok(emailDomains); + } + + [HttpGet("{id}")] + public async Task GetByKey(int id) + { + var emailDomain = await _emailDomainService.GetByIdAsync(id); + return emailDomain is not null ? Ok(emailDomain) : NotFound($"EmailDomain with key '{id}' not found."); + } + + [HttpPost()] + public async Task CreateTarget(int id, [FromBody] EmailDomainUpdateDto emailDomainUpdateDto) + { + if (emailDomainUpdateDto.Id != null && emailDomainUpdateDto.Id > 0) + return BadRequest("Id must be null or 0"); + + var emailDomainId = await _emailDomainService.CreateAsync(emailDomainUpdateDto); + if (emailDomainId == null) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to create email domain."); + + var createdEmailDomain = await _emailDomainService.GetByIdAsync(emailDomainId.Value); + return Ok(createdEmailDomain); + } + + [HttpPut("{id}")] + public async Task UpdateTarget(int id, [FromBody] EmailDomainUpdateDto emailDomainUpdateDto) + { + if (id != emailDomainUpdateDto.Id) + return BadRequest("Id in URL does not match Id in request body"); + + var existingEmailDomain = await _emailDomainService.GetByIdAsync(id); + if (existingEmailDomain == null) + return NotFound($"EmailDomain with Id {id} not found"); + + var success = await _emailDomainService.UpdateAsync(emailDomainUpdateDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to update email domain."); + + var updatedEmailDomain = await _emailDomainService.GetByIdAsync(id); + return Ok(updatedEmailDomain); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Controllers/ServersController.cs b/Surge365.MassEmailReact.API/Controllers/ServersController.cs index b03440a..318bd14 100644 --- a/Surge365.MassEmailReact.API/Controllers/ServersController.cs +++ b/Surge365.MassEmailReact.API/Controllers/ServersController.cs @@ -28,7 +28,7 @@ namespace Surge365.MassEmailReact.Server.Controllers return Ok(servers); } - [HttpGet("{key}")] + [HttpGet("{id}")] public async Task GetByKey(int id, bool? returnPassword = null) { bool returnPasswordValue = returnPassword == null || returnPassword.Value ? true : false; diff --git a/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs b/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs new file mode 100644 index 0000000..4956017 --- /dev/null +++ b/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TemplatesController : ControllerBase + { + private readonly ITemplateService _templateService; + + public TemplatesController(ITemplateService templateService) + { + _templateService = templateService; + } + + [HttpGet("GetAll")] + public async Task GetAll([FromQuery] bool? activeOnly) + { + var templates = await _templateService.GetAllAsync(activeOnly == null || activeOnly.Value ? true : false); + return Ok(templates); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + var template = await _templateService.GetByIdAsync(id); + return template is not null ? Ok(template) : NotFound($"Template with id '{id}' not found."); + } + + [HttpPost] + public async Task CreateTemplate([FromBody] TemplateUpdateDto templateUpdateDto) + { + if (templateUpdateDto.Id != null && templateUpdateDto.Id > 0) + return BadRequest("Id must be null or 0"); + + var templateId = await _templateService.CreateAsync(templateUpdateDto); + if (templateId == null) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to create template."); + + var createdTemplate = await _templateService.GetByIdAsync(templateId.Value); + return Ok(createdTemplate); + } + + [HttpPut("{id}")] + public async Task UpdateTemplate(int id, [FromBody] TemplateUpdateDto templateUpdateDto) + { + if (id != templateUpdateDto.Id) + return BadRequest("Id in URL does not match Id in request body"); + + var existingTemplate = await _templateService.GetByIdAsync(id); + if (existingTemplate == null) + return NotFound($"Template with Id {id} not found"); + + var success = await _templateService.UpdateAsync(templateUpdateDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to update template."); + + var updatedTemplate = await _templateService.GetByIdAsync(id); + return Ok(updatedTemplate); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs b/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs new file mode 100644 index 0000000..45a97e0 --- /dev/null +++ b/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TestEmailListsController : ControllerBase + { + private readonly ITestEmailListService _testEmailListService; + + public TestEmailListsController(ITestEmailListService testEmailListService) + { + _testEmailListService = testEmailListService; + } + + [HttpGet("GetAll")] + public async Task GetAll() + { + var testEmailLists = await _testEmailListService.GetAllAsync(); + return Ok(testEmailLists); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + var testEmailList = await _testEmailListService.GetByIdAsync(id); + return testEmailList is not null ? Ok(testEmailList) : NotFound($"Test email list with id '{id}' not found."); + } + + [HttpPost] + public async Task Create([FromBody] TestEmailListUpdateDto testEmailListDto) + { + if (testEmailListDto.Id != null && testEmailListDto.Id > 0) + return BadRequest("Id must be null or 0"); + + var testEmailListId = await _testEmailListService.CreateAsync(testEmailListDto); + if (testEmailListId == null) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to create test email list."); + + var createdTestEmailList = await _testEmailListService.GetByIdAsync(testEmailListId.Value); + return Ok(createdTestEmailList); + } + + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] TestEmailListUpdateDto testEmailListDto) + { + if (id != testEmailListDto.Id) + return BadRequest("Id in URL does not match Id in request body"); + + var existingTestEmailList = await _testEmailListService.GetByIdAsync(id); + if (existingTestEmailList == null) + return NotFound($"Test email list with Id {id} not found"); + + var success = await _testEmailListService.UpdateAsync(testEmailListDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to update test email list."); + + var updatedTestEmailList = await _testEmailListService.GetByIdAsync(id); + return Ok(updatedTestEmailList); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs b/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs new file mode 100644 index 0000000..3366617 --- /dev/null +++ b/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Surge365.MassEmailReact.Application.DTOs; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Server.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class UnsubscribeUrlsController : ControllerBase + { + private readonly IUnsubscribeUrlService _unsubscribeUrlService; + + public UnsubscribeUrlsController(IUnsubscribeUrlService unsubscribeUrlService) + { + _unsubscribeUrlService = unsubscribeUrlService; + } + + [HttpGet("GetAll")] + public async Task GetAll([FromQuery] bool? activeOnly) + { + var unsubscribeUrls = await _unsubscribeUrlService.GetAllAsync(activeOnly == null || activeOnly.Value ? true : false); + return Ok(unsubscribeUrls); + } + + [HttpGet("{id}")] + public async Task GetByKey(int id) + { + var unsubscribeUrl = await _unsubscribeUrlService.GetByIdAsync(id); + return unsubscribeUrl is not null ? Ok(unsubscribeUrl) : NotFound($"UnsubscribeUrl with key '{id}' not found."); + } + [HttpPost()] + public async Task Create(int id, [FromBody] UnsubscribeUrlUpdateDto unsubscribeUrlUpdateDto) + { + if (unsubscribeUrlUpdateDto.Id != null && unsubscribeUrlUpdateDto.Id > 0) + return BadRequest("Id must be null or 0"); + + var unsubscribeUrlId = await _unsubscribeUrlService.CreateAsync(unsubscribeUrlUpdateDto); + if (unsubscribeUrlId == null) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to create unsubscribe url."); + + var createdUnsubscribeUrl = await _unsubscribeUrlService.GetByIdAsync(unsubscribeUrlId.Value); + + return Ok(createdUnsubscribeUrl); + } + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] UnsubscribeUrlUpdateDto unsubscribeUrlUpdateDto) + { + if (id != unsubscribeUrlUpdateDto.Id) + return BadRequest("Id in URL does not match Id in request body"); + + var existingUnsubscribeUrl = await _unsubscribeUrlService.GetByIdAsync(id); + if (existingUnsubscribeUrl == null) + return NotFound($"UnsubscribeUrl with Id {id} not found"); + + var success = await _unsubscribeUrlService.UpdateAsync(unsubscribeUrlUpdateDto); + if (!success) + return StatusCode(StatusCodes.Status500InternalServerError, "Failed to update unsubscribe url."); + + var updatedUnsubscribeUrl = await _unsubscribeUrlService.GetByIdAsync(id); + + return Ok(updatedUnsubscribeUrl); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Program.cs b/Surge365.MassEmailReact.API/Program.cs index b6298ac..cec99e9 100644 --- a/Surge365.MassEmailReact.API/Program.cs +++ b/Surge365.MassEmailReact.API/Program.cs @@ -18,6 +18,17 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + var app = builder.Build(); app.UseDefaultFiles(); diff --git a/Surge365.MassEmailReact.Application/DTOs/BouncedEmailUpdateDto.cs b/Surge365.MassEmailReact.Application/DTOs/BouncedEmailUpdateDto.cs new file mode 100644 index 0000000..8b26ba6 --- /dev/null +++ b/Surge365.MassEmailReact.Application/DTOs/BouncedEmailUpdateDto.cs @@ -0,0 +1,10 @@ +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class BouncedEmailUpdateDto + { + public int? Id { get; set; } + public string EmailAddress { get; set; } = ""; + public bool Spam { get; set; } = false; + public bool Unsubscribe { get; set; } = false; + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/DTOs/EmailDomainUpdateDto.cs b/Surge365.MassEmailReact.Application/DTOs/EmailDomainUpdateDto.cs new file mode 100644 index 0000000..98c2aa3 --- /dev/null +++ b/Surge365.MassEmailReact.Application/DTOs/EmailDomainUpdateDto.cs @@ -0,0 +1,15 @@ +using System; + +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class EmailDomainUpdateDto + { + public int? Id { get; set; } + public string Name { get; set; } = ""; + public string EmailAddress { get; set; } = ""; + public string Username { get; set; } = ""; + public string Password { get; set; } = ""; + public bool IsActive { get; set; } = true; + public int DisplayOrder { get; set; } = 0; + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/DTOs/TemplateUpdateDto.cs b/Surge365.MassEmailReact.Application/DTOs/TemplateUpdateDto.cs new file mode 100644 index 0000000..2b3710d --- /dev/null +++ b/Surge365.MassEmailReact.Application/DTOs/TemplateUpdateDto.cs @@ -0,0 +1,20 @@ +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class TemplateUpdateDto + { + public int? Id { get; set; } + public string Name { get; set; } = ""; + public int DomainId { get; set; } + public string Description { get; set; } = ""; + public string HtmlBody { get; set; } = ""; + public string Subject { get; set; } = ""; + public string ToName { get; set; } = ""; + public string FromName { get; set; } = ""; + public string FromEmail { get; set; } = ""; + public string ReplyToEmail { get; set; } = ""; + public bool ClickTracking { get; set; } = false; + public bool OpenTracking { get; set; } = false; + public string CategoryXml { get; set; } = ""; + public bool IsActive { get; set; } = true; + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/DTOs/TestEmailListUpdateDto.cs b/Surge365.MassEmailReact.Application/DTOs/TestEmailListUpdateDto.cs new file mode 100644 index 0000000..4672fea --- /dev/null +++ b/Surge365.MassEmailReact.Application/DTOs/TestEmailListUpdateDto.cs @@ -0,0 +1,9 @@ +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class TestEmailListUpdateDto + { + public int? Id { get; set; } + public string Name { get; set; } = ""; + public List Emails { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/DTOs/UnsubscribeUrlUpdateDto.cs b/Surge365.MassEmailReact.Application/DTOs/UnsubscribeUrlUpdateDto.cs new file mode 100644 index 0000000..d6918a2 --- /dev/null +++ b/Surge365.MassEmailReact.Application/DTOs/UnsubscribeUrlUpdateDto.cs @@ -0,0 +1,11 @@ +using System; + +namespace Surge365.MassEmailReact.Application.DTOs +{ + public class UnsubscribeUrlUpdateDto + { + public int? Id { get; set; } + public string Name { get; set; } = ""; + public string Url { get; set; } = ""; + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailRepository.cs b/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailRepository.cs new file mode 100644 index 0000000..ae4a0d4 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailRepository.cs @@ -0,0 +1,16 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IBouncedEmailRepository + { + Task GetByEmailAsync(string emailAddress); + Task> GetAllAsync(); + Task CreateAsync(BouncedEmail bouncedEmail); + Task UpdateAsync(string originalEmailAddress, BouncedEmail bouncedEmail); + Task DeleteAsync(string emailAddress); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailService.cs b/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailService.cs new file mode 100644 index 0000000..ff3c4a3 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IBouncedEmailService.cs @@ -0,0 +1,13 @@ +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IBouncedEmailService + { + Task GetByEmailAsync(string emailAddress); + Task> GetAllAsync(); + Task CreateAsync(BouncedEmailUpdateDto bouncedEmailDto); + Task UpdateAsync(string originalEmailAddress, BouncedEmailUpdateDto bouncedEmailDto); + Task DeleteAsync(string emailAddress); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainRepository.cs b/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainRepository.cs new file mode 100644 index 0000000..987bf39 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainRepository.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IEmailDomainRepository + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(EmailDomain emailDomain); + Task UpdateAsync(EmailDomain emailDomain); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainService.cs b/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainService.cs new file mode 100644 index 0000000..6bffa51 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IEmailDomainService.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IEmailDomainService + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(EmailDomainUpdateDto emailDomainDto); + Task UpdateAsync(EmailDomainUpdateDto emailDomainDto); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/ITemplateRepository.cs b/Surge365.MassEmailReact.Application/Interfaces/ITemplateRepository.cs new file mode 100644 index 0000000..f2f4ee2 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/ITemplateRepository.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface ITemplateRepository + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(Template template); + Task UpdateAsync(Template template); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/ITemplateService.cs b/Surge365.MassEmailReact.Application/Interfaces/ITemplateService.cs new file mode 100644 index 0000000..6d8d034 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/ITemplateService.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface ITemplateService + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(TemplateUpdateDto templateDto); + Task UpdateAsync(TemplateUpdateDto templateDto); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListRepository.cs b/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListRepository.cs new file mode 100644 index 0000000..05bfbab --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListRepository.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface ITestEmailListRepository + { + Task GetByIdAsync(int id); + Task> GetAllAsync(); + Task CreateAsync(TestEmailList testEmailList); + Task UpdateAsync(TestEmailList testEmailList); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListService.cs b/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListService.cs new file mode 100644 index 0000000..449e169 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/ITestEmailListService.cs @@ -0,0 +1,14 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface ITestEmailListService + { + Task GetByIdAsync(int id); + Task> GetAllAsync(); + Task CreateAsync(TestEmailListUpdateDto testEmailListDto); + Task UpdateAsync(TestEmailListUpdateDto testEmailListDto); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlRepository.cs b/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlRepository.cs new file mode 100644 index 0000000..5d7152c --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlRepository.cs @@ -0,0 +1,15 @@ +using Surge365.MassEmailReact.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IUnsubscribeUrlRepository + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(UnsubscribeUrl unsubscribeUrl); + Task UpdateAsync(UnsubscribeUrl unsubscribeUrl); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlService.cs b/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlService.cs new file mode 100644 index 0000000..17ebd36 --- /dev/null +++ b/Surge365.MassEmailReact.Application/Interfaces/IUnsubscribeUrlService.cs @@ -0,0 +1,16 @@ +using Surge365.MassEmailReact.Application.DTOs; +using Surge365.MassEmailReact.Domain.Entities; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Surge365.MassEmailReact.Application.Interfaces +{ + public interface IUnsubscribeUrlService + { + Task GetByIdAsync(int id); + Task> GetAllAsync(bool activeOnly = true); + Task CreateAsync(UnsubscribeUrlUpdateDto unsubscribeUrlDto); + Task UpdateAsync(UnsubscribeUrlUpdateDto unsubscribeUrlDto); + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Domain/Entities/BouncedEmail.cs b/Surge365.MassEmailReact.Domain/Entities/BouncedEmail.cs new file mode 100644 index 0000000..ae5d4b4 --- /dev/null +++ b/Surge365.MassEmailReact.Domain/Entities/BouncedEmail.cs @@ -0,0 +1,23 @@ +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class BouncedEmail + { + public string EmailAddress { get; set; } = ""; + public bool Spam { get; set; } + public bool Unsubscribe { get; set; } + public bool EnteredByAdmin { get; set; } + + public BouncedEmail() { } + private BouncedEmail(string emailAddress, bool spam, bool unsubscribe, bool enteredByAdmin) + { + EmailAddress = emailAddress; + Spam = spam; + Unsubscribe = unsubscribe; + EnteredByAdmin = enteredByAdmin; + } + public static BouncedEmail Create(string emailAddress, bool spam, bool unsubscribe, bool enteredByAdmin) + { + return new BouncedEmail(emailAddress, spam, unsubscribe, enteredByAdmin); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Domain/Entities/EmailDomain.cs b/Surge365.MassEmailReact.Domain/Entities/EmailDomain.cs new file mode 100644 index 0000000..f6cf520 --- /dev/null +++ b/Surge365.MassEmailReact.Domain/Entities/EmailDomain.cs @@ -0,0 +1,33 @@ +using System; + +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class EmailDomain + { + public int? Id { get; private set; } + public string Name { get; set; } = ""; + public string EmailAddress { get; set; } = ""; + public string Username { get; set; } = ""; + public string Password { get; set; } = ""; + public bool IsActive { get; set; } + public int DisplayOrder { get; set; } + + public EmailDomain() { } + + private EmailDomain(int id, string name, string emailAddress, string username, string password, bool isActive, int displayOrder) + { + Id = id; + Name = name; + EmailAddress = emailAddress; + Username = username; + Password = password; + IsActive = isActive; + DisplayOrder = displayOrder; + } + + public static EmailDomain Create(int id, string name, string emailAddress, string username, string password, bool isActive, int displayOrder) + { + return new EmailDomain(id, name, emailAddress, username, password, isActive, displayOrder); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Domain/Entities/Template.cs b/Surge365.MassEmailReact.Domain/Entities/Template.cs new file mode 100644 index 0000000..f61f3aa --- /dev/null +++ b/Surge365.MassEmailReact.Domain/Entities/Template.cs @@ -0,0 +1,53 @@ +using System; + +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class Template + { + public int? Id { get; private set; } + public string Name { get; set; } = ""; + public int DomainId { get; set; } + public string Description { get; set; } = ""; + public string HtmlBody { get; set; } = ""; + public string Subject { get; set; } = ""; + public string ToName { get; set; } = ""; + public string FromName { get; set; } = ""; + public string FromEmail { get; set; } = ""; + public string ReplyToEmail { get; set; } = ""; + public bool ClickTracking { get; set; } + public bool OpenTracking { get; set; } + public string CategoryXml { get; set; } = ""; + public bool IsActive { get; set; } + + public Template() { } + + private Template(int id, string name, int domainId, string description, string htmlBody, string subject, + string toName, string fromName, string fromEmail, string replyToEmail, + bool clickTracking, bool openTracking, string categoryXml, bool isActive) + { + Id = id; + Name = name; + DomainId = domainId; + Description = description; + HtmlBody = htmlBody; + Subject = subject; + ToName = toName; + FromName = fromName; + FromEmail = fromEmail; + ReplyToEmail = replyToEmail; + ClickTracking = clickTracking; + OpenTracking = openTracking; + CategoryXml = categoryXml; + IsActive = isActive; + } + + public static Template Create(int id, string name, int domainId, string description, string htmlBody, + string subject, string toName, string fromName, string fromEmail, + string replyToEmail, bool clickTracking, bool openTracking, + string categoryXml, bool isActive) + { + return new Template(id, name, domainId, description, htmlBody, subject, toName, fromName, + fromEmail, replyToEmail, clickTracking, openTracking, categoryXml, isActive); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Domain/Entities/TestEmailList.cs b/Surge365.MassEmailReact.Domain/Entities/TestEmailList.cs new file mode 100644 index 0000000..de185d3 --- /dev/null +++ b/Surge365.MassEmailReact.Domain/Entities/TestEmailList.cs @@ -0,0 +1,48 @@ +using System.Data.SqlTypes; +using System.Xml.Linq; + +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class TestEmailList + { + public int? Id { get; private set; } + public string Name { get; set; } = ""; + public string List { get; set; } = ""; + public List Emails + { + get + { + return ParseListXml(List); + } + } + public TestEmailList() { } + + public static List ParseListXml(string xml) + { + return XDocument.Parse(xml).Descendants("Email").Select(e => e.Value).ToList(); + } + public string GetListXml() + { + return GetListXml(Emails); + } + public static string GetListXml(List emails) + { + if (emails.Count == 0) + return ""; + + string xmlString = new XDocument(new XElement("Emails",emails.Select(email => new XElement("Email", email)))).ToString(); + return xmlString; + } + private TestEmailList(int id, string name, string list) + { + Id = id; + Name = name; + List = list; + } + + public static TestEmailList Create(int id, string name, string list) + { + return new TestEmailList(id, name, list); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Domain/Entities/UnsubscribeUrl.cs b/Surge365.MassEmailReact.Domain/Entities/UnsubscribeUrl.cs new file mode 100644 index 0000000..a28fde8 --- /dev/null +++ b/Surge365.MassEmailReact.Domain/Entities/UnsubscribeUrl.cs @@ -0,0 +1,23 @@ +using System; + +namespace Surge365.MassEmailReact.Domain.Entities +{ + public class UnsubscribeUrl + { + public int? Id { get; private set; } + public string Name { get; set; } = ""; + public string Url { get; set; } = ""; + + public UnsubscribeUrl() { } + private UnsubscribeUrl(int id, string name, string url) + { + Id = id; + Name = name; + Url = url; + } + public static UnsubscribeUrl Create(int id, string name, string url) + { + return new UnsubscribeUrl(id, name, url); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs new file mode 100644 index 0000000..88b904a --- /dev/null +++ b/Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper.FluentMap.Mapping; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +{ + public class BouncedEmailMap : EntityMap + { + public BouncedEmailMap() + { + Map(p => p.EmailAddress).ToColumn("email_address"); + Map(p => p.Spam).ToColumn("spam"); + Map(p => p.Unsubscribe).ToColumn("unsubscribe"); + Map(p => p.EnteredByAdmin).ToColumn("entered_by_admin"); + } + } +} diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs index 53d32a7..36e1a21 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs +++ b/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs @@ -1,4 +1,5 @@ using Dapper.FluentMap; +using Surge365.MassEmailReact.Domain.Entities; using System; using System.Collections.Generic; using System.Linq; @@ -15,6 +16,11 @@ namespace Surge365.MassEmailReact.Infrastructure.DapperMaps { config.AddMap(new TargetMap()); config.AddMap(new ServerMap()); + config.AddMap(new TestEmailListMap()); + config.AddMap(new BouncedEmailMap()); + config.AddMap(new UnsubscribeUrlMap()); + config.AddMap(new TemplateMap()); + config.AddMap(new EmailDomainMap()); }); } } diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs new file mode 100644 index 0000000..369ab10 --- /dev/null +++ b/Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs @@ -0,0 +1,19 @@ +using Dapper.FluentMap.Mapping; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +{ + public class EmailDomainMap : EntityMap + { + public EmailDomainMap() + { + Map(p => p.Id).ToColumn("domain_key"); + Map(p => p.Name).ToColumn("name"); + Map(p => p.EmailAddress).ToColumn("email_address"); + Map(p => p.Username).ToColumn("username"); + Map(p => p.Password).ToColumn("password"); + Map(p => p.IsActive).ToColumn("is_active"); + Map(p => p.DisplayOrder).ToColumn("display_order"); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs new file mode 100644 index 0000000..56d4663 --- /dev/null +++ b/Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs @@ -0,0 +1,26 @@ +using Dapper.FluentMap.Mapping; +using Surge365.MassEmailReact.Domain.Entities; + +namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +{ + public class TemplateMap : EntityMap