diff --git a/Surge365.MassEmailReact.API/Controllers/AuthenticationController.cs b/Surge365.MassEmailReact.API/Controllers/AuthenticationController.cs deleted file mode 100644 index 697b3ff..0000000 --- a/Surge365.MassEmailReact.API/Controllers/AuthenticationController.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Surge365.MassEmailReact.API.Controllers; -using Surge365.MassEmailReact.Application.DTOs; -using Surge365.MassEmailReact.Application.Interfaces; -using Surge365.MassEmailReact.Domain.Entities; - -namespace Surge365.MassEmailReact.API.Controllers -{ - [AllowAnonymous] - public class AuthenticationController : BaseController - { - private readonly IAuthService _authService; - - public AuthenticationController(IAuthService authService) - { - _authService = authService; - } - - [HttpPost("logout")] - public IActionResult Logout() - { - Response.Cookies.Append("refreshToken", "", new CookieOptions - { - HttpOnly = true, - Secure = true, - SameSite = SameSiteMode.Strict, - Expires = DateTimeOffset.UtcNow.AddDays(-1) // Expire immediately - }); - Response.Cookies.Append("accessToken", "", new CookieOptions - { - HttpOnly = true, - Secure = true, - SameSite = SameSiteMode.Strict, - Expires = DateTimeOffset.UtcNow.AddDays(-1) // Expire immediately - }); - - return Ok(new { message = "Logged out successfully" }); - } - - [HttpPost("authenticate")] - public async Task Authenticate([FromBody] LoginRequest request) - { - var authResponse = await _authService.Authenticate(request.Username, request.Password); - if (!authResponse.authenticated) - return Unauthorized(new { message = authResponse.errorMessage }); - else if(authResponse.data == null) - return Unauthorized(new { message = "Invalid credentials" }); - - //TODO: Store refresh token in DB - var cookieOptions = new CookieOptions - { - HttpOnly = true, // Prevents JavaScript access (mitigates XSS) - Secure = true, // Ensures cookie is only sent over HTTPS - SameSite = SameSiteMode.Strict, // Mitigates CSRF by restricting cross-site usage - Expires = DateTimeOffset.UtcNow.AddDays(7) - }; - Response.Cookies.Append("refreshToken", authResponse.data.Value.refreshToken, cookieOptions); - Response.Cookies.Append("accessToken", authResponse.data.Value.accessToken, cookieOptions); - - //TODO: Store user in session - return Ok(new { success = true, authResponse.data.Value.accessToken, authResponse.data.Value.user }); - } - [HttpPost("refreshtoken")] - public async Task RefreshToken() - { - var refreshToken = Request.Cookies["refreshToken"]; - - if (string.IsNullOrWhiteSpace(refreshToken)) - return Unauthorized("Invalid refresh token"); - - var authResponse = await _authService.Authenticate(refreshToken); - if (!authResponse.authenticated) - return Unauthorized(new { message = authResponse.errorMessage }); - else if (authResponse.data == null) - return Unauthorized(new { message = "Invalid credentials" }); - - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = true, - SameSite = SameSiteMode.Strict, - Expires = DateTimeOffset.UtcNow.AddDays(7) - }; - Response.Cookies.Append("refreshToken", authResponse.data.Value.refreshToken, cookieOptions); - Response.Cookies.Append("accessToken", authResponse.data.Value.accessToken, cookieOptions); - - return Ok(new { accessToken = authResponse.data.Value.accessToken }); - } - [HttpPost("generatepasswordrecovery")] - public IActionResult GeneratePasswordRecovery([FromBody] GeneratePasswordRecoveryRequest request) - { - return Ok(new { }); - } - } -} \ No newline at end of file diff --git a/Surge365.MassEmailReact.API/Controllers/BaseController.cs b/Surge365.MassEmailReact.API/Controllers/BaseController.cs deleted file mode 100644 index 1c518a2..0000000 --- a/Surge365.MassEmailReact.API/Controllers/BaseController.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Surge365.MassEmailReact.API.Controllers -{ - [Route("[controller]")] - [Route("api/[controller]")] - [ApiController] - [Authorize] - public class BaseController : ControllerBase - { - } -} diff --git a/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs b/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs index c075565..15b01ee 100644 --- a/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs +++ b/Surge365.MassEmailReact.API/Controllers/BouncedEmailsController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; using System.Net.Mail; diff --git a/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs b/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs index d67f8cb..96496cd 100644 --- a/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs +++ b/Surge365.MassEmailReact.API/Controllers/EmailDomainsController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; using System.Threading.Tasks; diff --git a/Surge365.MassEmailReact.API/Controllers/MailingsController.cs b/Surge365.MassEmailReact.API/Controllers/MailingsController.cs index 26eafdf..fe6c61e 100644 --- a/Surge365.MassEmailReact.API/Controllers/MailingsController.cs +++ b/Surge365.MassEmailReact.API/Controllers/MailingsController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Data.SqlClient; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; using Surge365.MassEmailReact.Domain.Enums; diff --git a/Surge365.MassEmailReact.API/Controllers/ServersController.cs b/Surge365.MassEmailReact.API/Controllers/ServersController.cs index 7fdb53a..d8eb8a4 100644 --- a/Surge365.MassEmailReact.API/Controllers/ServersController.cs +++ b/Surge365.MassEmailReact.API/Controllers/ServersController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.DTOs; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; diff --git a/Surge365.MassEmailReact.API/Controllers/TargetsController.cs b/Surge365.MassEmailReact.API/Controllers/TargetsController.cs index 5d7f987..f8ceaec 100644 --- a/Surge365.MassEmailReact.API/Controllers/TargetsController.cs +++ b/Surge365.MassEmailReact.API/Controllers/TargetsController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.DTOs; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; diff --git a/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs b/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs index 598af35..2bb8a27 100644 --- a/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs +++ b/Surge365.MassEmailReact.API/Controllers/TemplatesController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; diff --git a/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs b/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs index 297e75b..4fdfcf3 100644 --- a/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs +++ b/Surge365.MassEmailReact.API/Controllers/TestEmailListsController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; diff --git a/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs b/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs index 4d6b8ee..0f9fa10 100644 --- a/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs +++ b/Surge365.MassEmailReact.API/Controllers/UnsubscribeUrlController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Surge365.Core.Controllers; using Surge365.MassEmailReact.Application.DTOs; using Surge365.MassEmailReact.Application.Interfaces; using Surge365.MassEmailReact.Domain.Entities; diff --git a/Surge365.MassEmailReact.API/Program.cs b/Surge365.MassEmailReact.API/Program.cs index 9bddea7..628a7d6 100644 --- a/Surge365.MassEmailReact.API/Program.cs +++ b/Surge365.MassEmailReact.API/Program.cs @@ -1,21 +1,24 @@ using Azure.Identity; -using Microsoft.AspNetCore.Identity; -using Surge365.MassEmailReact.Application.Interfaces; -using Surge365.MassEmailReact.Domain.Entities; -using Surge365.MassEmailReact.Infrastructure; -using Surge365.MassEmailReact.Infrastructure.DapperMaps; -using Surge365.MassEmailReact.Infrastructure.Repositories; -using Surge365.MassEmailReact.Infrastructure.Services; -using Surge365.MassEmailReact.Infrastructure.Middleware; -using System.Net; -using System.Security.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; +using Surge365.Core.Authentication; +using Surge365.Core.Extensions; +using Surge365.Core.Services; +using Surge365.Core.Middleware; +using Surge365.MassEmailReact.Application.Interfaces; +using Surge365.MassEmailReact.Infrastructure.Repositories; +using Surge365.MassEmailReact.Infrastructure.Services; +using System.Security.Authentication; +using System.Security.Claims; using System.Text; - +using Surge365.Core.Interfaces; +using Surge365.MassEmailReact.Infrastructure.EntityMaps; var builder = WebApplication.CreateBuilder(args); + +builder.AddCustomConfigurationSources(); + WebApplication? app = null; try { @@ -50,21 +53,41 @@ try IssuerSigningKey = new SymmetricSecurityKey(jwtKey), ClockSkew = TimeSpan.Zero // Optional: no grace period for expiration }; - // Read JWT from accessToken cookie - options.Events = new JwtBearerEvents - { - OnMessageReceived = context => - { - var token = context.Request.Cookies["accessToken"]; - if (!string.IsNullOrEmpty(token)) - { - context.Token = token; - } - return Task.CompletedTask; - } - }; }); + builder.Services.AddHttpContextAccessor(); + + + Factory.RegisterDefaultServices(builder.Services, + adminContextProvider: provider => + { + var httpContextAccessor = provider.GetRequiredService(); + var httpContext = httpContextAccessor.HttpContext; + + if (httpContext == null) + return new AdminContext(); + + string? adminId = null; + string? ipAddress = httpContext?.Connection?.RemoteIpAddress?.ToString(); + string? appVersion = httpContext?.Request.Headers["app-version"].ToString(); + string? deviceInfo = httpContext?.Request.Headers["User-Agent"].ToString(); + + if (httpContext?.User?.Identity?.IsAuthenticated == true) + { + adminId = httpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? httpContext.User.FindFirst("sub")?.Value; + } + + return new AdminContext + { + LoggedIn = !string.IsNullOrWhiteSpace(adminId), + AdminId = adminId, + IpAddress = ipAddress, + AppVersion = appVersion, + DeviceInfo = deviceInfo + }; + } + ); + builder.Services.AddHttpClient("SendGridClient", client => { client.BaseAddress = new Uri("https://api.sendgrid.com/"); // Optional, for clarity @@ -74,10 +97,10 @@ try }); // Add services to the container. - builder.Services.AddControllers(); + builder.Services.AddControllers().AddApplicationPart(typeof(Surge365.Core.Controllers.AuthenticationController).Assembly); + // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); - builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -95,10 +118,12 @@ try builder.Services.AddScoped(); builder.Services.AddScoped(); + EntityMapperConfiguration.ConfigureCustomMaps(); + app = builder.Build(); - app.UseCustomExceptionHandler(); + app.UseDefaultFiles(); app.MapStaticAssets(); @@ -109,17 +134,17 @@ try } app.UseHttpsRedirection(); - + app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); - DapperConfiguration.ConfigureMappings(); } catch (Exception ex) { - LoggingService appLoggingService = new LoggingService(builder.Configuration); + Console.WriteLine($"Error during application startup: {ex.Message}"); + LoggingService appLoggingService = new LoggingService(builder.Configuration, new DataAccessFactory(builder.Configuration)); appLoggingService.LogError(ex).Wait(); return; } diff --git a/Surge365.MassEmailReact.API/Surge365.MassEmailReact.API.csproj b/Surge365.MassEmailReact.API/Surge365.MassEmailReact.API.csproj index 21eff41..b4723ae 100644 --- a/Surge365.MassEmailReact.API/Surge365.MassEmailReact.API.csproj +++ b/Surge365.MassEmailReact.API/Surge365.MassEmailReact.API.csproj @@ -18,6 +18,7 @@ + diff --git a/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthResponse.cs b/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthResponse.cs deleted file mode 100644 index 7958a12..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthResponse.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs.AuthApi -{ - public class AuthResponse - { - public string accessToken { get; set; } = ""; - public string refreshToken { get; set; } = ""; - public User? user { get; set; } - public string message { get; set; } = ""; - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthenticateApiRequest.cs b/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthenticateApiRequest.cs deleted file mode 100644 index 2b457ac..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/AuthApi/AuthenticateApiRequest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs.AuthApi -{ - public class AuthenticateApiRequest - { - public required string appCode { get; set; } - public required string username { get; set; } - public required string password { get; set; } - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/AuthApi/RefreshTokenApiRequest.cs b/Surge365.MassEmailReact.Application/DTOs/AuthApi/RefreshTokenApiRequest.cs deleted file mode 100644 index 5f21cdd..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/AuthApi/RefreshTokenApiRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs.AuthApi -{ - public class RefreshTokenApiRequest - { - public string appCode { get; set; } = ""; - public string refreshToken { get; set; } = ""; - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/AuthApi/User.cs b/Surge365.MassEmailReact.Application/DTOs/AuthApi/User.cs deleted file mode 100644 index 12dcf57..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/AuthApi/User.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs.AuthApi -{ - public class User - { - public int? UserKey { get; set; } - public Guid UserId { get; set; } - public string Username { get; set; } = ""; - public string FirstName { get; set; } = ""; - public string MiddleInitial { get; set; } = ""; - public string LastName { get; set; } = ""; - public bool IsActive { get; set; } - public List Roles { get; set; } = new List(); - - public User() { } - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/GeneratePasswordRecoveryRequest.cs b/Surge365.MassEmailReact.Application/DTOs/GeneratePasswordRecoveryRequest.cs deleted file mode 100644 index 4471073..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/GeneratePasswordRecoveryRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs -{ - public class GeneratePasswordRecoveryRequest - { - public required string Username { get; set; } - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/LoginRequest.cs b/Surge365.MassEmailReact.Application/DTOs/LoginRequest.cs deleted file mode 100644 index 2b99c20..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/LoginRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs -{ - public class LoginRequest - { - public required string Username { get; set; } - public required string Password { get; set; } - } -} diff --git a/Surge365.MassEmailReact.Application/DTOs/RefreshTokenRequest.cs b/Surge365.MassEmailReact.Application/DTOs/RefreshTokenRequest.cs deleted file mode 100644 index 8348f1a..0000000 --- a/Surge365.MassEmailReact.Application/DTOs/RefreshTokenRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Application.DTOs -{ - public class RefreshTokenRequest - { - public required string RefreshToken { get; set; } - } - -} diff --git a/Surge365.MassEmailReact.Application/Interfaces/IAuthService.cs b/Surge365.MassEmailReact.Application/Interfaces/IAuthService.cs deleted file mode 100644 index 1339cb2..0000000 --- a/Surge365.MassEmailReact.Application/Interfaces/IAuthService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Surge365.MassEmailReact.Application.DTOs.AuthApi; - -namespace Surge365.MassEmailReact.Application.Interfaces -{ - public interface IAuthService - { - Task<(bool authenticated, (User user, string accessToken, string refreshToken)? data, string errorMessage)> Authenticate(string username, string password); - Task<(bool authenticated, (User user, string accessToken, string refreshToken)? data, string errorMessage)> Authenticate(string refreshToken); - } -} diff --git a/Surge365.MassEmailReact.Application/Interfaces/ILogginService.cs b/Surge365.MassEmailReact.Application/Interfaces/ILogginService.cs deleted file mode 100644 index f0d7a10..0000000 --- a/Surge365.MassEmailReact.Application/Interfaces/ILogginService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Surge365.MassEmailReact.Application.DTOs.AuthApi; - -namespace Surge365.MassEmailReact.Application.Interfaces -{ - public enum LogLevels //TODO: Move all this to Surge365.Core (new project) - { - Fatal = 1, - Error, - Warn, - Info, - Debug - } - public interface ILoggingService - { - Task InsertLog(LogLevels level, string logger, int? userKey, string task, string message, - string exceptionStack, string exceptionMessage, string exceptionInnerMessage, - string customMessage1, string customMessage2, string customMessage3, - string customMessage4, string customMessage5); - Task LogError(Exception ex); - } -} diff --git a/Surge365.MassEmailReact.Domain/Enums/AuthResult.cs b/Surge365.MassEmailReact.Domain/Enums/AuthResult.cs deleted file mode 100644 index c7100d9..0000000 --- a/Surge365.MassEmailReact.Domain/Enums/AuthResult.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Domain.Enums -{ - public enum AuthResult - { - Success = 0, - LoginNotFound = 1, - LoginLocked = 2, - InvalidPassword = 3, - UnexpectedError = 4, - NotAllowed = 5 - } -} diff --git a/Surge365.MassEmailReact.Domain/Enums/Extensions/AuthenticationResponseExtensions.cs b/Surge365.MassEmailReact.Domain/Enums/Extensions/AuthenticationResponseExtensions.cs deleted file mode 100644 index 71396f4..0000000 --- a/Surge365.MassEmailReact.Domain/Enums/Extensions/AuthenticationResponseExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Domain.Enums.Extensions -{ - public static class AuthResultExtensions - { - public static string GetMessage(this AuthResult response) - { - return response switch - { - AuthResult.Success => "Login successful.", - AuthResult.InvalidPassword or AuthResult.LoginNotFound => "Invalid username and/or password.", - AuthResult.LoginLocked => "User has been locked out.", - AuthResult.NotAllowed => "User has not been granted access to this application.", - AuthResult.UnexpectedError or _ => "Unexpected error." - }; - } - } -} diff --git a/Surge365.MassEmailReact.Domain/Surge365.MassEmailReact.Domain.csproj b/Surge365.MassEmailReact.Domain/Surge365.MassEmailReact.Domain.csproj index 125f4c9..95d00e4 100644 --- a/Surge365.MassEmailReact.Domain/Surge365.MassEmailReact.Domain.csproj +++ b/Surge365.MassEmailReact.Domain/Surge365.MassEmailReact.Domain.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs deleted file mode 100644 index 69ac3e6..0000000 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/DapperConfiguration.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Dapper; -using Dapper.FluentMap; -using Surge365.MassEmailReact.Domain.Entities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps -{ - public class DapperConfiguration - { - public static void ConfigureMappings() - { - SqlMapper.AddTypeHandler(new JsonListStringTypeHandler()); - - FluentMapper.Initialize(config => - { - config.AddMap(new TargetMap()); - config.AddMap(new TargetColumnMap()); - config.AddMap(new ServerMap()); - config.AddMap(new TestEmailListMap()); - config.AddMap(new BouncedEmailMap()); - config.AddMap(new UnsubscribeUrlMap()); - config.AddMap(new TemplateMap()); - config.AddMap(new EmailDomainMap()); - config.AddMap(new MailingMap()); - config.AddMap(new MailingEmailMap()); - config.AddMap(new MailingTemplateMap()); - config.AddMap(new MailingTargetMap()); - config.AddMap(new MailingStatisticMap()); - }); - } - } -} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/JsonListStringTypeHandler.cs b/Surge365.MassEmailReact.Infrastructure/DapperMaps/JsonListStringTypeHandler.cs deleted file mode 100644 index de6f86a..0000000 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/JsonListStringTypeHandler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Dapper; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps -{ - public class JsonListStringTypeHandler : SqlMapper.TypeHandler> - { - public override List Parse(object value) - { - if (value == null || value == DBNull.Value) - return new List(); - - string json = value.ToString() ?? ""; - return string.IsNullOrEmpty(json) - ? new List() - : JsonSerializer.Deserialize>(json) ?? new List(); - } - - public override void SetValue(IDbDataParameter parameter, List value) - { - parameter.Value = value != null ? JsonSerializer.Serialize(value) : DBNull.Value; - } - } -} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Infrastructure/DataAccess.cs b/Surge365.MassEmailReact.Infrastructure/DataAccess.cs deleted file mode 100644 index f9947c1..0000000 --- a/Surge365.MassEmailReact.Infrastructure/DataAccess.cs +++ /dev/null @@ -1,437 +0,0 @@ -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection.PortableExecutable; -using System.Text; -using System.Threading.Tasks; - - -namespace Surge365.MassEmailReact.Infrastructure -{ - public class DataAccess - { - private string GetConnectionString(string connectionStringName) - { - if (_configuration == null) - return ""; - return _configuration[$"ConnectionStrings:{connectionStringName}"] ?? ""; - } - public DataAccess(IConfiguration configuration, string connectionStringName) - { - _configuration = configuration; - _connectionString = GetConnectionString(connectionStringName).Replace("##application_code##", Utilities.GetAppCode(configuration)); - } - - internal IConfiguration? _configuration; - internal Guid _sessionID = Guid.NewGuid(); - internal string _connectionString; - internal int _timeout = 30; - internal SqlTransaction? _transaction; - internal SqlConnection? _connection; - internal bool _transactionStarted; - internal Object? _transactionStarter; - - public string ConnectionString - { - get { return _connectionString; } - set { _connectionString = value; } - } - public int Timeout - { - get { return _timeout; } - set { _timeout = value; } - } - public bool TransactionStarted - { - get { return _transactionStarted; } - internal set { _transactionStarted = value; } - } - public Object? TransactionStarter - { - get { return _transactionStarter; } - internal set { _transactionStarter = value; } - } - - #region Non-Async - internal void OpenConnection() - { - _connection = new SqlConnection(_connectionString); - _connection.Open(); - } - internal void CloseConnection() - { - if (_connection == null) - return; - - _connection.Close(); - _connection.Dispose(); - _connection = null; - } - public SqlTransaction BeginTransaction(Object sender) - { - if (_transaction != null) - return _transaction; - - OpenConnection(); - - ArgumentNullException.ThrowIfNull(_connection); - - _transaction = _connection.BeginTransaction(); - _transactionStarted = true; - _transactionStarter = sender; - return _transaction; - } - public void RollbackTransaction(Object sender) - { - if (_transaction != null && sender == _transactionStarter) - { - _transaction.Rollback(); - _transaction = null; - CloseConnection(); - _transactionStarter = null; - _transactionStarted = false; - } - } - public void CommitTransaction(Object sender) - { - if (_transaction != null && sender == _transactionStarter) - { - _transaction.Commit(); - _transaction = null; - CloseConnection(); - _transactionStarter = null; - _transactionStarted = false; - } - } - - public DataSet CallRetrievalProcedure(List parameters, string proc, int timeoutSeconds = 0) - { - DataSet ds = new DataSet(); - bool createdConnection = false; - if (timeoutSeconds == 0) - timeoutSeconds = _timeout; - try - { - if (_connection == null) - { - createdConnection = true; - OpenConnection(); - } - - using SqlCommand cmd = new SqlCommand(proc, _connection); - cmd.Transaction = _transaction; - if (parameters != null) - { - foreach (SqlParameter p in parameters) - { - if (p != null) - cmd.Parameters.Add(p); - } - } - cmd.CommandType = CommandType.StoredProcedure; - cmd.CommandTimeout = timeoutSeconds; - using SqlDataAdapter da = new SqlDataAdapter(cmd); - try - { - da.Fill(ds); - } - catch (Exception ex) - { - string message = String.Format("Unable to retrieve data from proc: {0}", proc); - LogError(ex, message, "CallRetrievalProcedure"); - throw; - } - if (createdConnection) - { - CloseConnection(); - } - } - catch (Exception) - { - if (createdConnection) - { - CloseConnection(); - } - throw; - } - - return ds; - } - public int CallActionProcedure(List parameters, string proc, int timeoutSeconds = 0) - { - int iReturnVal = -1; - if (timeoutSeconds == 0) - timeoutSeconds = _timeout; - bool createdConnection = false; - try - { - if (_connection == null) - { - createdConnection = true; - OpenConnection(); - } - using SqlCommand cmd = new SqlCommand(proc, _connection); - cmd.Transaction = _transaction; - if (parameters != null) - { - foreach (SqlParameter p in parameters) - { - if (p != null) - cmd.Parameters.Add(p); - } - } - cmd.CommandType = CommandType.StoredProcedure; - cmd.CommandTimeout = timeoutSeconds; - try - { - iReturnVal = cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - string message = String.Format("Unable to execute proc: {0}", proc); - LogError(ex, message, "CallActionProcedure"); - throw; - } - } - catch (Exception) - { - if (createdConnection) - { - CloseConnection(); - } - throw; - } - - if (createdConnection) - { - CloseConnection(); - } - return iReturnVal; - } - private static void LogError(Exception ex, string message, string task) - { - Exception ex1 = ex; - if (ex == null) - ex1 = new Exception(message); - else if (!string.IsNullOrEmpty(message)) - ex1 = new Exception(message, ex); - - //Log - } - #endregion - - #region Async - internal async Task OpenConnectionAsync() - { - //_connection = new SqlConnection(_connectionString); - //await _connection.OpenAsync(); - await Task.Run(() => OpenConnectionWithRetry()); - } - internal void OpenConnectionWithRetry(short maxRetries = 3, int totalTimeoutMs = 1000) - { - int attempt = 0; - while (attempt < maxRetries) - { - using (var cts = new CancellationTokenSource(totalTimeoutMs)) // Total cap, e.g., 3 seconds - { - try - { - Console.WriteLine($"Attempt {attempt + 1}..."); - _connection = new SqlConnection(_connectionString); - _connection.OpenAsync(cts.Token).Wait(); // Use async with cancellation - return; - } - catch (Exception ex) - { - attempt++; - if (attempt == maxRetries) - { - Console.WriteLine($"Failed after {attempt} attempts: {ex.Message}"); - throw; - } - Console.WriteLine($"Retrying after failure: {ex.Message}"); - Thread.Sleep(1000); // Delay between retries - } - } - } - } - internal async Task CloseConnectionAsync() - { - if (_connection == null) - return; - - await _connection.CloseAsync(); - _connection.Dispose(); - _connection = null; - } - public async Task BeginTransactionAsync(Object sender) - { - if (_transaction != null) - return _transaction; - - await OpenConnectionAsync(); - - ArgumentNullException.ThrowIfNull(_connection); - - _transaction = _connection.BeginTransaction(); - _transactionStarted = true; - _transactionStarter = sender; - return _transaction; - } - public async Task RollbackTransactionAsync(Object sender) - { - if (_transaction != null && sender == _transactionStarter) - { - await _transaction.RollbackAsync(); - _transaction = null; - await CloseConnectionAsync(); - _transactionStarter = null; - _transactionStarted = false; - } - } - public async Task CommitTransactionAsync(Object sender) - { - if (_transaction != null && sender == _transactionStarter) - { - await _transaction.CommitAsync(); - _transaction = null; - await CloseConnectionAsync(); - _transactionStarter = null; - _transactionStarted = false; - } - } - public async Task CallRetrievalProcedureAsync(List parameters, string proc, int timeoutSeconds = 0) - { - DataSet ds = new DataSet(); - bool createdConnection = false; - if (timeoutSeconds == 0) - timeoutSeconds = _timeout; - try - { - if (_connection == null) - { - createdConnection = true; - await OpenConnectionAsync(); - } - - using SqlCommand cmd = new SqlCommand(proc, _connection); - - cmd.Transaction = _transaction; - if (parameters != null) - { - foreach (SqlParameter p in parameters) - { - if (p != null) - cmd.Parameters.Add(p); - } - } - cmd.CommandType = CommandType.StoredProcedure; - cmd.CommandTimeout = timeoutSeconds; - - try - { - //using var reader = await cmd.ExecuteReaderAsync(); - using var adapter = new SqlDataAdapter(cmd); - await Task.Run(() => adapter.Fill(ds)); - } - catch (Exception ex) - { - string message = String.Format("Unable to retrieve data from proc: {0}", proc); - await LogErrorAsync(ex, message, "CallRetrievalProcedure"); - throw; - } - if (createdConnection) - { - await CloseConnectionAsync(); - } - } - catch (Exception) - { - if (createdConnection) - { - await CloseConnectionAsync(); - } - throw; - } - - return ds; - } - public async Task CallActionProcedureAsync(List parameters, string proc, int timeoutSeconds = 0) - { - int iReturnVal = -1; - if (timeoutSeconds == 0) - timeoutSeconds = _timeout; - bool createdConnection = false; - try - { - if (_connection == null) - { - createdConnection = true; - await OpenConnectionAsync(); - } - using SqlCommand cmd = new SqlCommand(proc, _connection); - - cmd.Transaction = _transaction; - if (parameters != null) - { - foreach (SqlParameter p in parameters) - { - if (p != null) - cmd.Parameters.Add(p); - } - } - cmd.CommandType = CommandType.StoredProcedure; - cmd.CommandTimeout = timeoutSeconds; - try - { - iReturnVal = await cmd.ExecuteNonQueryAsync(); - } - catch (Exception ex) - { - string message = String.Format("Unable to execute proc: {0}", proc); - await LogErrorAsync(ex, message, "CallActionProcedure"); - throw; - } - } - catch (Exception) - { - if (createdConnection) - { - await CloseConnectionAsync(); - } - throw; - } - - if (createdConnection) - { - await CloseConnectionAsync(); - } - return iReturnVal; - } - private static async Task LogErrorAsync(Exception ex, string message, string task) - { - Exception ex1 = ex; - if (ex == null) - ex1 = new Exception(message); - else if (!string.IsNullOrEmpty(message)) - ex1 = new Exception(message, ex); - - try - { - using SqlConnection c = new SqlConnection(); - await c.OpenAsync(); - using SqlCommand cmd = new SqlCommand("lg_log_error", c); - await cmd.ExecuteNonQueryAsync(); - } - catch (Exception iex) //Trap all errors, don't do any - { - Console.WriteLine($"Unhandled Exception occurred logging exception: exception={iex}; trying to log exception={ex}"); - } - } - #endregion - } -} diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/BouncedEmailMap.cs similarity index 85% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/BouncedEmailMap.cs index 88b904a..40c5fce 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/BouncedEmailMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/BouncedEmailMap.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class BouncedEmailMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/EmailDomainMap.cs similarity index 85% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/EmailDomainMap.cs index 369ab10..844875b 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/EmailDomainMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/EmailDomainMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class EmailDomainMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/EntityMaps/EntityMapperConfiguration.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/EntityMapperConfiguration.cs new file mode 100644 index 0000000..4026416 --- /dev/null +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/EntityMapperConfiguration.cs @@ -0,0 +1,24 @@ +using Surge365.Core.Mapping; + +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps +{ + public static class EntityMapperConfiguration + { + public static void ConfigureCustomMaps() + { + QueryMapper.AddMap(new TargetMap()); + QueryMapper.AddMap(new TargetColumnMap()); + QueryMapper.AddMap(new ServerMap()); + QueryMapper.AddMap(new TestEmailListMap()); + QueryMapper.AddMap(new BouncedEmailMap()); + QueryMapper .AddMap(new UnsubscribeUrlMap()); + QueryMapper.AddMap(new TemplateMap()); + QueryMapper.AddMap(new EmailDomainMap()); + QueryMapper .AddMap(new MailingMap()); + QueryMapper.AddMap(new MailingEmailMap()); + QueryMapper.AddMap(new MailingTemplateMap()); + QueryMapper.AddMap(new MailingTargetMap()); + QueryMapper.AddMap(new MailingStatisticMap()); + } + } +} \ No newline at end of file diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingEmailMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingEmailMap.cs similarity index 87% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingEmailMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingEmailMap.cs index 4eff038..7c5aaa9 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingEmailMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingEmailMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class MailingEmailMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingMap.cs similarity index 90% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingMap.cs index f9fc6f2..a1915f1 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class MailingMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingStatisticMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingStatisticMap.cs similarity index 92% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingStatisticMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingStatisticMap.cs index 1fb2174..b013618 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingStatisticMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingStatisticMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class MailingStatisticMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTargetMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTargetMap.cs similarity index 89% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTargetMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTargetMap.cs index 09cb2a5..daad13f 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTargetMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTargetMap.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class MailingTargetMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTemplateMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTemplateMap.cs similarity index 91% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTemplateMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTemplateMap.cs index 4537baa..87bf360 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/MailingTemplateMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/MailingTemplateMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class MailingTemplateMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/ServerMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/ServerMap.cs similarity index 85% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/ServerMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/ServerMap.cs index 90cd373..88709ae 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/ServerMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/ServerMap.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class ServerMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetColumnMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetColumnMap.cs similarity index 88% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetColumnMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetColumnMap.cs index 8a538a7..7394087 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetColumnMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetColumnMap.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class TargetColumnMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetMap.cs similarity index 88% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetMap.cs index ccd36bb..5907bf2 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TargetMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TargetMap.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class TargetMap : EntityMap { diff --git a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TemplateMap.cs similarity index 91% rename from Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs rename to Surge365.MassEmailReact.Infrastructure/EntityMaps/TemplateMap.cs index 56d4663..1348853 100644 --- a/Surge365.MassEmailReact.Infrastructure/DapperMaps/TemplateMap.cs +++ b/Surge365.MassEmailReact.Infrastructure/EntityMaps/TemplateMap.cs @@ -1,7 +1,7 @@ -using Dapper.FluentMap.Mapping; +using Surge365.Core.Mapping; using Surge365.MassEmailReact.Domain.Entities; -namespace Surge365.MassEmailReact.Infrastructure.DapperMaps +namespace Surge365.MassEmailReact.Infrastructure.EntityMaps { public class TemplateMap : EntityMap