Skip to content
Snippets Groups Projects
Commit 15019ebd authored by Adiv Asif's avatar Adiv Asif
Browse files

Merged PR 41: fixed emails

fixed emails
parents 4b769c7b 42b70597
No related branches found
No related tags found
No related merge requests found
Showing
with 221 additions and 7 deletions
appsettings.Development.json AuthenticationMicroservice/appsettings.Development.json
# Created by https://www.toptal.com/developers/gitignore/api/aspnetcore # Created by https://www.toptal.com/developers/gitignore/api/aspnetcore
# Edit at https://www.toptal.com/developers/gitignore?templates=aspnetcore # Edit at https://www.toptal.com/developers/gitignore?templates=aspnetcore
......
namespace AuthenticationMicroservice.Tests;
using AutoMapper;
using Helpers;
using Microsoft.Extensions.Options;
using Models.DTOs;
using Models.Entities;
using Moq;
using Repositories;
using Services;
using Settings;
public class AuthServiceTests
{
private readonly IMapper _mapper;
public AuthServiceTests()
{
_mapper = AutoMapperHelper.CreateTestMapper();
}
[Fact]
public async Task TestRegisterUser()
{
var registerRequest = new UserRegisterRequestDTO
{
EmailAddress = "aa03980@surrey.ac.uk",
Password = "Testtest1.",
ConfirmPassword = "Testtest1.",
FirstName = "Adiv",
Surname = "Asif"
};
await using var context = DbContextHelper.CreateInMemoryDbContext();
var userRepo = new BaseRepository<User>(context);
var userService = new UserService(_mapper, userRepo);
var createdUser = await userService.CreateUser(registerRequest);
Assert.True(createdUser.EmailAddress == "aa03980@surrey.ac.uk");
}
[Fact]
public async Task TestRegisterAndLoginUser()
{
var registerRequest = new UserRegisterRequestDTO
{
EmailAddress = "aa03980@surrey.ac.uk",
Password = "Testtest1.",
ConfirmPassword = "Testtest1.",
FirstName = "Adiv",
Surname = "Asif"
};
var loginRequest = new UserLoginRequestDTO
{
EmailAddress = "aa03980@surrey.ac.uk",
Password = "Testtest1."
};
await using var context = DbContextHelper.CreateInMemoryDbContext();
var userRepo = new BaseRepository<User>(context);
var userService = new UserService(_mapper, userRepo);
var createdUser = await userService.CreateUser(registerRequest);
var mockEmailService = new Mock<IEmailService>();
var mockRefreshTokenService = new Mock<IRefreshTokenService>();
mockRefreshTokenService.Setup(r => r.CreateNewTokenForUser(It.IsAny<int>())).ReturnsAsync(new AccessToken{Token = "test"});
mockRefreshTokenService.Setup(r => r.CreateNewTokenForUser(It.IsAny<User>())).Returns(new AccessToken{Token = "test"});
mockRefreshTokenService.Setup(r => r.GenerateRefreshToken(It.IsAny<int>())).ReturnsAsync(new RefreshToken{Token = "test"});
var frontendString = new FrontendStrings {BaseUrl = "test"};
var mockOptions = new Mock<IOptions<FrontendStrings>>();
mockOptions.Setup(s => s.Value).Returns(frontendString);
var authService = new AuthService(context, mockEmailService.Object, mockRefreshTokenService.Object, mockOptions.Object);
var login = await authService.Authenticate(loginRequest);
Assert.True(login.UserId == createdUser.Id);
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AuthenticationMicroservice\AuthenticationMicroservice.csproj"/>
</ItemGroup>
</Project>
namespace AuthenticationMicroservice.Tests.Helpers;
using AutoMapper;
public class AutoMapperHelper
{
public static IMapper CreateTestMapper()
{
var configuration = new MapperConfiguration(cfg => { cfg.AddProfile<AutoMapperProfile>(); });
return configuration.CreateMapper();
}
}
\ No newline at end of file
namespace AuthenticationMicroservice.Tests.Helpers;
using Microsoft.EntityFrameworkCore;
using Models;
public class DbContextHelper
{
public static AuthenticationDbContext CreateInMemoryDbContext()
{
var options = new DbContextOptionsBuilder<AuthenticationDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var context = new AuthenticationDbContext(options);
return context;
}
}
\ No newline at end of file
global using Xunit;
\ No newline at end of file
...@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 ...@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.6.33513.286 VisualStudioVersion = 17.6.33513.286
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticationMicroservice", "AuthenticationMicroservice.csproj", "{EFB5174F-F711-4272-A765-8147AF59AF34}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticationMicroservice", "AuthenticationMicroservice\AuthenticationMicroservice.csproj", "{EFB5174F-F711-4272-A765-8147AF59AF34}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticationMicroservice.Tests", "AuthenticationMicroservice.Tests\AuthenticationMicroservice.Tests.csproj", "{93DC4F65-3B37-466A-BFE0-B96ABCD6CCBD}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
...@@ -15,6 +17,10 @@ Global ...@@ -15,6 +17,10 @@ Global
{EFB5174F-F711-4272-A765-8147AF59AF34}.Debug|Any CPU.Build.0 = Debug|Any CPU {EFB5174F-F711-4272-A765-8147AF59AF34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFB5174F-F711-4272-A765-8147AF59AF34}.Release|Any CPU.ActiveCfg = Release|Any CPU {EFB5174F-F711-4272-A765-8147AF59AF34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFB5174F-F711-4272-A765-8147AF59AF34}.Release|Any CPU.Build.0 = Release|Any CPU {EFB5174F-F711-4272-A765-8147AF59AF34}.Release|Any CPU.Build.0 = Release|Any CPU
{93DC4F65-3B37-466A-BFE0-B96ABCD6CCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{93DC4F65-3B37-466A-BFE0-B96ABCD6CCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{93DC4F65-3B37-466A-BFE0-B96ABCD6CCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{93DC4F65-3B37-466A-BFE0-B96ABCD6CCBD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
......
File moved
...@@ -11,10 +11,14 @@ ...@@ -11,10 +11,14 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1"/> <PackageReference Include="AutoMapper" Version="12.0.1"/>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0"/> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1"/>
<PackageReference Include="Azure.Storage.Blobs" Version="12.16.0-beta.1"/> <PackageReference Include="Azure.Storage.Blobs" Version="12.16.0-beta.1"/>
<PackageReference Include="Azure.Storage.Common" Version="12.15.0-beta.1"/> <PackageReference Include="Azure.Storage.Common" Version="12.15.0-beta.1"/>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5"/> <PackageReference Include="BenchmarkDotNet" Version="0.13.5"/>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="LazyCache" Version="2.4.0"/> <PackageReference Include="LazyCache" Version="2.4.0"/>
<PackageReference Include="LazyCache.AspNetCore" Version="2.4.0"/> <PackageReference Include="LazyCache.AspNetCore" Version="2.4.0"/>
<PackageReference Include="MailKit" Version="3.6.0"/> <PackageReference Include="MailKit" Version="3.6.0"/>
...@@ -33,6 +37,7 @@ ...@@ -33,6 +37,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1"/> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1"/>
<PackageReference Include="Moq" Version="4.18.4"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/> <PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="Polly" Version="7.2.3"/> <PackageReference Include="Polly" Version="7.2.3"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1"/> <PackageReference Include="SixLabors.ImageSharp" Version="3.0.1"/>
......
File moved
...@@ -2,16 +2,19 @@ namespace AuthenticationMicroservice.Controllers; ...@@ -2,16 +2,19 @@ namespace AuthenticationMicroservice.Controllers;
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using Exceptions; using Exceptions;
using Helpers; using Helpers;
using LazyCache; using LazyCache;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Middleware; using Middleware;
using Models.DTOs; using Models.DTOs;
using Models.Entities; using Models.Entities;
using Services; using Services;
using Settings;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
[Route("api/[controller]")] [Route("api/[controller]")]
...@@ -20,17 +23,19 @@ public class AuthController : BaseAuthController ...@@ -20,17 +23,19 @@ public class AuthController : BaseAuthController
{ {
private readonly IAuthService _authService; private readonly IAuthService _authService;
private readonly IEmailService _emailService; private readonly IEmailService _emailService;
private readonly FrontendStrings _frontendStrings;
private readonly IAppCache _memoryCache; private readonly IAppCache _memoryCache;
private readonly IRefreshTokenService _refreshTokenService; private readonly IRefreshTokenService _refreshTokenService;
private readonly IUserService _userService; private readonly IUserService _userService;
public AuthController(IAppCache memoryCache, IAuthService authService, IRefreshTokenService refreshTokenService, public AuthController(IAppCache memoryCache, IAuthService authService, IRefreshTokenService refreshTokenService,
IUserService userService, IEmailService emailService) IUserService userService, IEmailService emailService, IOptions<FrontendStrings> frontendStrings)
{ {
_authService = authService; _authService = authService;
_memoryCache = memoryCache; _memoryCache = memoryCache;
_userService = userService; _userService = userService;
_emailService = emailService; _emailService = emailService;
_frontendStrings = frontendStrings.Value;
_refreshTokenService = refreshTokenService; _refreshTokenService = refreshTokenService;
} }
...@@ -211,7 +216,8 @@ public class AuthController : BaseAuthController ...@@ -211,7 +216,8 @@ public class AuthController : BaseAuthController
if (request.EmailAddress != null) if (request.EmailAddress != null)
_emailService.SendEmail(new EmailDTO _emailService.SendEmail(new EmailDTO
{ {
Subject = "Successfully Registered", Body = "Test", Receiver = request.EmailAddress, Subject = "Successfully Registered", Body = GetRegisteredUserTableEmail(createdUser),
Receiver = request.EmailAddress,
To = request.Username To = request.Username
}).FireAndForget(); }).FireAndForget();
return Ok(authenticatedUser); return Ok(authenticatedUser);
...@@ -226,11 +232,11 @@ public class AuthController : BaseAuthController ...@@ -226,11 +232,11 @@ public class AuthController : BaseAuthController
[HttpPost("ResendConfirmEmail")] [HttpPost("ResendConfirmEmail")]
[SwaggerResponse(204)] [SwaggerResponse(204)]
[SwaggerResponse(400, Type = typeof(ResponseEnvelope<BadRequestObjectResult>))] [SwaggerResponse(400, Type = typeof(ResponseEnvelope<BadRequestObjectResult>))]
public async Task<ActionResult> ResendConfirmEmail(string callbackUrl) public async Task<ActionResult> ResendConfirmEmail()
{ {
try try
{ {
await _authService.ResendConfirmEmail(UserId, callbackUrl); await _authService.ResendConfirmEmail(UserId);
} }
catch (Exception ex) catch (Exception ex)
{ {
...@@ -305,4 +311,34 @@ public class AuthController : BaseAuthController ...@@ -305,4 +311,34 @@ public class AuthController : BaseAuthController
return BadRequest(ex.Message); return BadRequest(ex.Message);
} }
} }
private string GetRegisteredUserTableEmail(User user)
{
var s = new StringBuilder();
s.Append($"<table {EmailHelper.TableProperties(TableSize.Small)}>");
s.Append("<thead>");
s.Append("<tr>");
s.Append($"<th {EmailHelper.TableHeader(2)}>New User Registration</th>");
s.Append("</tr>");
s.Append("<tr>");
s.Append($"<th {EmailHelper.TableCell}>First Name</th>");
s.Append($"<td {EmailHelper.TableCell}>{user.FirstName}</td>");
s.Append("</tr>");
s.Append("<tr>");
s.Append($"<th {EmailHelper.TableCell}>Surname</th>");
s.Append($"<td {EmailHelper.TableCell}>{user.Surname}</td>");
s.Append("</tr>");
s.Append("<tr>");
s.Append($"<th {EmailHelper.TableCell}>Username</th>");
s.Append($"<td {EmailHelper.TableCell}>{user.Username}</td>");
s.Append("</tr>");
s.Append("<tr>");
s.Append($"<td {EmailHelper.TableFooter(2)}></td>");
s.Append("</tr>");
s.Append("</thead>");
s.Append("</table>");
s.Append(
$"<p style='font-family: sans-serif'>Please click here to <a href='{_frontendStrings.BaseUrl}/ConfirmEmail?{user.EmailConfirmationToken}'>confirm your email.</a></p>");
return s.ToString();
}
} }
\ No newline at end of file
File moved
namespace AuthenticationMicroservice.Helpers;
public enum TableSize
{
Small = 500,
Medium = 800,
Large = 1000
}
public static class EmailHelper
{
public const string TableCell =
" style='color:#000; padding-bottom:1%; vertical-align: middle; border-bottom: 1px solid #8D8AD8; border-left: 1px solid #8D8AD8; border-right: 1px solid #8D8AD8;'";
public static string TableProperties(TableSize width)
{
return
$"width={width} cellpadding=0 cellspacing=0 border=0 style='text-align: center; font-family: sans-serif'";
}
public static string TableHeader(int colspan)
{
return
$"colspan='{colspan}' style='color:#000; background:#8D8AD8; text-align: center; border-bottom: 1px solid #414447; font-weight: 100; padding:8px; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); border-top-left-radius:10px; border-top-right-radius:10px;'";
}
public static string TableFooter(int colspan)
{
return
$"colspan='{colspan}' style='color:#000; background:#8D8AD8; text-align: center; font-weight: 100; padding:8px; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); border-bottom-left-radius:10px; border-bottom-right-radius:10px;'";
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment