mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Refactor user registration process to use UserRegistrationDto;
implement user registration in seed app
This commit is contained in:
@@ -8,29 +8,29 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="idunno.Password.Generator" Version="1.0.1"/>
|
<PackageReference Include="idunno.Password.Generator" Version="2.0.0" />
|
||||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1"/>
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.2" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.2"/>
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.0" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.9"/>
|
|
||||||
<PackageReference Include="dbup" Version="5.0.41"/>
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
remove this override once microsoft ships official fix to vulnerability
|
remove this override once microsoft ships official fix to vulnerability
|
||||||
https:
|
https:
|
||||||
-->
|
-->
|
||||||
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="3.50.3"/>
|
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="3.50.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Domain\Domain.Entities\Domain.Entities.csproj"/>
|
<ProjectReference Include="..\..\Domain\Domain.Entities\Domain.Entities.csproj" />
|
||||||
<ProjectReference Include="..\..\Infrastructure\Infrastructure.Sql\Infrastructure.Sql.csproj"/>
|
<ProjectReference
|
||||||
<ProjectReference Include="..\..\Features\Features.Breweries\Features.Breweries.csproj"/>
|
Include="..\..\Infrastructure\Infrastructure.Sql\Infrastructure.Sql.csproj" />
|
||||||
<ProjectReference Include="..\..\Features\Features.Auth\Features.Auth.csproj"/>
|
<ProjectReference Include="..\..\Features\Features.Breweries\Features.Breweries.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Features\Features.Auth\Features.Auth.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- Pipeline-generated seed data, copied to the output directory so it can be opened via
|
<!-- Pipeline-generated seed data, copied to the output directory so it can be opened via
|
||||||
ConnectionStrings.SqliteConnectionString at runtime. -->
|
ConnectionStrings.SqliteConnectionString at runtime. -->
|
||||||
<None CopyToOutputDirectory="PreserveNewest" Include="SeedData\seed.sqlite"/>
|
<None CopyToOutputDirectory="PreserveNewest"
|
||||||
|
Include="SeedData\biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Database.Seed.DatabaseHelpers;
|
|||||||
public class ConnectionStrings
|
public class ConnectionStrings
|
||||||
{
|
{
|
||||||
public static string SqlServerConnectionString => GetSqlServerConnectionString();
|
public static string SqlServerConnectionString => GetSqlServerConnectionString();
|
||||||
public static string SqliteConnectionString => "Data Source=SeedData/seed.sqlite";
|
public static string SqliteConnectionString => "Data Source=SeedData/biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite";
|
||||||
|
|
||||||
private static string GetSqlServerConnectionString()
|
private static string GetSqlServerConnectionString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Database.Seed.DatabaseHelpers;
|
|||||||
using Database.Seed.PipelineData;
|
using Database.Seed.PipelineData;
|
||||||
using Database.Seed.Sqlite;
|
using Database.Seed.Sqlite;
|
||||||
using Features.Auth.DependencyInjection;
|
using Features.Auth.DependencyInjection;
|
||||||
|
using Features.Auth.Dtos;
|
||||||
using Features.Auth.Repository;
|
using Features.Auth.Repository;
|
||||||
using Features.Breweries.DependencyInjection;
|
using Features.Breweries.DependencyInjection;
|
||||||
using Features.Breweries.Repository;
|
using Features.Breweries.Repository;
|
||||||
@@ -11,68 +12,109 @@ using Infrastructure.Sql;
|
|||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using idunno.Password;
|
||||||
|
using Infrastructure.PasswordHashing;
|
||||||
|
using Domain.Entities;
|
||||||
|
|
||||||
|
|
||||||
IReadOnlyList<BreweryRecord> breweries;
|
async static Task<int> main()
|
||||||
IReadOnlyList<UserRecord> users;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
PipelineSeedDataReader reader = new(ConnectionStrings.SqliteConnectionString);
|
IReadOnlyList<BreweryRecord> breweries;
|
||||||
breweries = reader.ReadBreweryRecords();
|
IReadOnlyList<UserRecord> users;
|
||||||
users = reader.ReadUserRecords();
|
try
|
||||||
}
|
{
|
||||||
catch (SqliteException ex)
|
PipelineSeedDataReader reader = new(ConnectionStrings.SqliteConnectionString);
|
||||||
{
|
breweries = reader.ReadBreweryRecords();
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
users = reader.ReadUserRecords();
|
||||||
Console.WriteLine($"Error opening database connection: {ex.Message}");
|
}
|
||||||
Console.ResetColor();
|
catch (SqliteException ex)
|
||||||
return 1;
|
{
|
||||||
}
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Error opening database connection: {ex.Message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
ServiceCollection services = [];
|
ServiceCollection services = [];
|
||||||
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||||
services.AddSingleton<ISqlConnectionFactory, DefaultSqlConnectionFactory>();
|
services.AddSingleton<ISqlConnectionFactory, DefaultSqlConnectionFactory>();
|
||||||
services.AddFeaturesBreweries();
|
services.AddFeaturesBreweries();
|
||||||
services.AddFeaturesAuth();
|
services.AddFeaturesAuth();
|
||||||
|
|
||||||
using ServiceProvider provider = services.BuildServiceProvider();
|
using ServiceProvider provider = services.BuildServiceProvider();
|
||||||
|
|
||||||
IBreweryRepository breweryRepository;
|
IBreweryRepository breweryRepository;
|
||||||
IAuthRepository authRepository;
|
IAuthRepository authRepository;
|
||||||
try
|
IPasswordInfrastructure passwordInfrastructure;
|
||||||
{
|
try
|
||||||
breweryRepository = provider.GetRequiredService<IBreweryRepository>();
|
{
|
||||||
authRepository = provider.GetRequiredService<IAuthRepository>();
|
breweryRepository = provider.GetRequiredService<IBreweryRepository>();
|
||||||
}
|
authRepository = provider.GetRequiredService<IAuthRepository>();
|
||||||
catch (InvalidOperationException ex)
|
passwordInfrastructure = provider.GetRequiredService<IPasswordInfrastructure>();
|
||||||
{
|
}
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
catch (InvalidOperationException ex)
|
||||||
Console.WriteLine($"Error configuring database connection: {ex.Message}");
|
{
|
||||||
Console.ResetColor();
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
return 1;
|
Console.WriteLine($"Error configuring database connection: {ex.Message}");
|
||||||
}
|
Console.ResetColor();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
Console.WriteLine(
|
|
||||||
$"Loaded {breweries.Count} breweries."
|
|
||||||
);
|
|
||||||
Console.ResetColor();
|
|
||||||
|
|
||||||
for (int i = 0; i < breweries.Count; i++)
|
|
||||||
{
|
|
||||||
BreweryRecord brewery = breweries[i];
|
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"{i + 1}:\t{brewery.Brewery.NameEn}\t({brewery.Address.City.CityName}, {brewery.Address.City.Country})");
|
$"Loaded {breweries.Count} breweries."
|
||||||
|
);
|
||||||
|
Console.ResetColor();
|
||||||
|
|
||||||
|
for (int i = 0; i < breweries.Count; i++)
|
||||||
|
{
|
||||||
|
BreweryRecord brewery = breweries[i];
|
||||||
|
Console.WriteLine(
|
||||||
|
$"{i + 1}:\t{brewery.Brewery.NameEn}\t({brewery.Address.City.CityName}, {brewery.Address.City.Country})");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine($"Loaded {users.Count} users.");
|
||||||
|
Console.ResetColor();
|
||||||
|
|
||||||
|
foreach (UserRecord user in users)
|
||||||
|
{
|
||||||
|
string username = user.User.Username;
|
||||||
|
string firstName = user.User.FirstName;
|
||||||
|
string lastName = user.User.LastName;
|
||||||
|
string email = user.Email;
|
||||||
|
DateTime dateOfBirth = DateTime.Parse(user.DateOfBirth);
|
||||||
|
|
||||||
|
// Generate a password that is 64 characters long with 10 digits, 10 symbols,
|
||||||
|
// allowing upper and lower case letters, disallowing repeat characters.
|
||||||
|
string generatedPassword = PasswordGenerator.Generate(length: 64, numberOfDigits: 10, numberOfSymbols: 10);
|
||||||
|
string hashedPassword = passwordInfrastructure.Hash(generatedPassword);
|
||||||
|
|
||||||
|
UserRegistrationDto registrationDto = new(
|
||||||
|
username,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
email,
|
||||||
|
dateOfBirth,
|
||||||
|
hashedPassword
|
||||||
|
);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
UserAccount createdUser = await authRepository.RegisterUserAsync(registrationDto);
|
||||||
|
Console.WriteLine($"Created user: {createdUser.Username} ({createdUser.UserAccountId})");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Error creating user {username}: {ex.Message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
|
||||||
Console.WriteLine($"Loaded {users.Count} users.");
|
|
||||||
Console.ResetColor();
|
|
||||||
|
|
||||||
for (int i = 0; i < users.Count; i++)
|
return await main();
|
||||||
{
|
|
||||||
UserRecord user = users[i];
|
|
||||||
Console.WriteLine($"{i + 1}:\t{user.User.FirstName} {user.User.LastName}\t ({user.Email})");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|||||||
@@ -105,9 +105,16 @@ public sealed class PipelineSeedDataReader
|
|||||||
private static IReadOnlyDictionary<long, City> ReadCities(SqliteConnection connection)
|
private static IReadOnlyDictionary<long, City> ReadCities(SqliteConnection connection)
|
||||||
{
|
{
|
||||||
const string sql = """
|
const string sql = """
|
||||||
SELECT id, city, state_province, iso3166_2, country, iso3166_1,
|
SELECT
|
||||||
local_languages_json, postal_code_country_format_regex,
|
id,
|
||||||
postal_code_city_regex_json
|
city,
|
||||||
|
state_province,
|
||||||
|
iso3166_2,
|
||||||
|
country,
|
||||||
|
iso3166_1,
|
||||||
|
local_languages_json,
|
||||||
|
postal_code_country_format_regex,
|
||||||
|
postal_code_city_regex_json
|
||||||
FROM cities;
|
FROM cities;
|
||||||
""";
|
""";
|
||||||
|
|
||||||
@@ -115,25 +122,36 @@ public sealed class PipelineSeedDataReader
|
|||||||
using SqliteDataReader reader = command.ExecuteReader();
|
using SqliteDataReader reader = command.ExecuteReader();
|
||||||
|
|
||||||
Dictionary<long, City> cities = [];
|
Dictionary<long, City> cities = [];
|
||||||
|
|
||||||
|
const int cityNameBindIndex = 1;
|
||||||
|
const int stateProvinceBindIndex = 2;
|
||||||
|
const int iso31662BindIndex = 3;
|
||||||
|
const int countryBindIndex = 4;
|
||||||
|
const int iso31661BindIndex = 5;
|
||||||
|
const int localLanguagesBindIndex = 6;
|
||||||
|
const int countryFormatRegexBindIndex = 7;
|
||||||
|
const int cityRegexesBindIndex = 8;
|
||||||
|
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
cities[reader.GetInt64(0)] = new City
|
cities[reader.GetInt64(0)] = new City
|
||||||
{
|
{
|
||||||
CityName = reader.GetString(1),
|
CityName = reader.GetString(cityNameBindIndex),
|
||||||
StateProvince = reader.GetString(2),
|
StateProvince = reader.GetString(stateProvinceBindIndex),
|
||||||
Iso31662 = reader.GetString(3),
|
Iso31662 = reader.GetString(iso31662BindIndex),
|
||||||
Country = reader.GetString(4),
|
Country = reader.GetString(countryBindIndex),
|
||||||
Iso31661 = reader.GetString(5),
|
Iso31661 = reader.GetString(iso31661BindIndex),
|
||||||
LocalLanguages = DeserializeStringArray(reader.GetString(6)),
|
LocalLanguages = DeserializeStringArray(reader.GetString(localLanguagesBindIndex)),
|
||||||
PostalCode = new PostalCodeSpec
|
PostalCode = new PostalCodeSpec
|
||||||
{
|
{
|
||||||
CountryFormatRegex = reader.GetString(7),
|
CountryFormatRegex = reader.GetString(countryFormatRegexBindIndex),
|
||||||
CityRegexes = DeserializeStringArray(reader.GetString(8))
|
CityRegexes = DeserializeStringArray(reader.GetString(cityRegexesBindIndex))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return cities;
|
return cities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static IReadOnlyList<string> DeserializeStringArray(string json)
|
private static IReadOnlyList<string> DeserializeStringArray(string json)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<string>>(json) ?? [];
|
return JsonSerializer.Deserialize<List<string>>(json) ?? [];
|
||||||
|
|||||||
@@ -68,12 +68,14 @@ public class RegisterUserHandlerTests
|
|||||||
_authRepoMock
|
_authRepoMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
x.RegisterUserAsync(
|
x.RegisterUserAsync(
|
||||||
command.Username,
|
new UserRegistrationDto(
|
||||||
command.FirstName,
|
command.Username,
|
||||||
command.LastName,
|
command.FirstName,
|
||||||
command.Email,
|
command.LastName,
|
||||||
command.DateOfBirth,
|
command.Email,
|
||||||
hashedPassword
|
command.DateOfBirth,
|
||||||
|
hashedPassword
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.ReturnsAsync(
|
.ReturnsAsync(
|
||||||
@@ -139,15 +141,7 @@ public class RegisterUserHandlerTests
|
|||||||
.WithMessage("Username or email already exists");
|
.WithMessage("Username or email already exists");
|
||||||
|
|
||||||
_authRepoMock.Verify(
|
_authRepoMock.Verify(
|
||||||
x =>
|
x => x.RegisterUserAsync(It.IsAny<UserRegistrationDto>()),
|
||||||
x.RegisterUserAsync(
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<DateTime>(),
|
|
||||||
It.IsAny<string>()
|
|
||||||
),
|
|
||||||
Times.Never
|
Times.Never
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -192,12 +186,7 @@ public class RegisterUserHandlerTests
|
|||||||
_authRepoMock
|
_authRepoMock
|
||||||
.Setup(x =>
|
.Setup(x =>
|
||||||
x.RegisterUserAsync(
|
x.RegisterUserAsync(
|
||||||
It.IsAny<string>(),
|
It.Is<UserRegistrationDto>(dto => dto.PasswordHash == hashedPassword)
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<DateTime>(),
|
|
||||||
hashedPassword
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.ReturnsAsync(new UserAccount { UserAccountId = Guid.NewGuid() });
|
.ReturnsAsync(new UserAccount { UserAccountId = Guid.NewGuid() });
|
||||||
@@ -215,12 +204,14 @@ public class RegisterUserHandlerTests
|
|||||||
_authRepoMock.Verify(
|
_authRepoMock.Verify(
|
||||||
x =>
|
x =>
|
||||||
x.RegisterUserAsync(
|
x.RegisterUserAsync(
|
||||||
command.Username,
|
new UserRegistrationDto(
|
||||||
command.FirstName,
|
command.Username,
|
||||||
command.LastName,
|
command.FirstName,
|
||||||
command.Email,
|
command.LastName,
|
||||||
command.DateOfBirth,
|
command.Email,
|
||||||
hashedPassword
|
command.DateOfBirth,
|
||||||
|
hashedPassword
|
||||||
|
)
|
||||||
),
|
),
|
||||||
Times.Once
|
Times.Once
|
||||||
);
|
);
|
||||||
@@ -239,16 +230,7 @@ public class RegisterUserHandlerTests
|
|||||||
.ReturnsAsync((UserAccount?)null);
|
.ReturnsAsync((UserAccount?)null);
|
||||||
_passwordInfraMock.Setup(x => x.Hash(It.IsAny<string>())).Returns("hashed");
|
_passwordInfraMock.Setup(x => x.Hash(It.IsAny<string>())).Returns("hashed");
|
||||||
_authRepoMock
|
_authRepoMock
|
||||||
.Setup(x =>
|
.Setup(x => x.RegisterUserAsync(It.IsAny<UserRegistrationDto>()))
|
||||||
x.RegisterUserAsync(
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<string>(),
|
|
||||||
It.IsAny<DateTime>(),
|
|
||||||
It.IsAny<string>()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.ReturnsAsync(
|
.ReturnsAsync(
|
||||||
new UserAccount
|
new UserAccount
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Apps72.Dev.Data.DbMocker;
|
using Apps72.Dev.Data.DbMocker;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Features.Auth.Dtos;
|
||||||
using Features.Auth.Repository;
|
using Features.Auth.Repository;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
|
||||||
@@ -50,12 +51,14 @@ public class AuthRepositoryTests
|
|||||||
|
|
||||||
AuthRepository repo = CreateRepo(conn);
|
AuthRepository repo = CreateRepo(conn);
|
||||||
UserAccount result = await repo.RegisterUserAsync(
|
UserAccount result = await repo.RegisterUserAsync(
|
||||||
"testuser",
|
new UserRegistrationDto(
|
||||||
"Test",
|
"testuser",
|
||||||
"User",
|
"Test",
|
||||||
"test@example.com",
|
"User",
|
||||||
new DateTime(1990, 1, 1),
|
"test@example.com",
|
||||||
"hashedpassword123"
|
new DateTime(1990, 1, 1),
|
||||||
|
"hashedpassword123"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
result.Should().NotBeNull();
|
result.Should().NotBeNull();
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ public class RegisterUserHandler(
|
|||||||
string hashed = passwordInfrastructure.Hash(request.Password);
|
string hashed = passwordInfrastructure.Hash(request.Password);
|
||||||
|
|
||||||
UserAccount createdUser = await authRepo.RegisterUserAsync(
|
UserAccount createdUser = await authRepo.RegisterUserAsync(
|
||||||
request.Username,
|
new UserRegistrationDto(request.Username,
|
||||||
request.FirstName,
|
request.FirstName,
|
||||||
request.LastName,
|
request.LastName,
|
||||||
request.Email,
|
request.Email,
|
||||||
request.DateOfBirth,
|
request.DateOfBirth,
|
||||||
hashed
|
hashed)
|
||||||
);
|
);
|
||||||
|
|
||||||
string accessToken = tokenService.GenerateAccessToken(createdUser);
|
string accessToken = tokenService.GenerateAccessToken(createdUser);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Features.Auth.Dtos;
|
||||||
|
|
||||||
|
public record UserRegistrationDto(
|
||||||
|
string Username,
|
||||||
|
string FirstName,
|
||||||
|
string LastName,
|
||||||
|
string Email,
|
||||||
|
DateTime DateOfBirth,
|
||||||
|
string PasswordHash
|
||||||
|
);
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Features.Auth.Dtos;
|
||||||
using Infrastructure.Sql;
|
using Infrastructure.Sql;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
@@ -35,12 +36,7 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
/// <exception cref="Exception">Thrown when the newly registered user cannot be retrieved after registration.</exception>
|
/// <exception cref="Exception">Thrown when the newly registered user cannot be retrieved after registration.</exception>
|
||||||
/// <exception cref="Microsoft.Data.SqlClient.SqlException">Thrown when the database command fails.</exception>
|
/// <exception cref="Microsoft.Data.SqlClient.SqlException">Thrown when the database command fails.</exception>
|
||||||
public async Task<UserAccount> RegisterUserAsync(
|
public async Task<UserAccount> RegisterUserAsync(
|
||||||
string username,
|
UserRegistrationDto userRegistrationDto
|
||||||
string firstName,
|
|
||||||
string lastName,
|
|
||||||
string email,
|
|
||||||
DateTime dateOfBirth,
|
|
||||||
string passwordHash
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
await using DbConnection connection = await CreateConnection();
|
await using DbConnection connection = await CreateConnection();
|
||||||
@@ -49,6 +45,9 @@ public class AuthRepository(ISqlConnectionFactory connectionFactory)
|
|||||||
command.CommandText = "USP_RegisterUser";
|
command.CommandText = "USP_RegisterUser";
|
||||||
command.CommandType = CommandType.StoredProcedure;
|
command.CommandType = CommandType.StoredProcedure;
|
||||||
|
|
||||||
|
var (username, firstName, lastName, email, dateOfBirth, passwordHash) =
|
||||||
|
userRegistrationDto;
|
||||||
|
|
||||||
AddParameter(command, "@Username", username);
|
AddParameter(command, "@Username", username);
|
||||||
AddParameter(command, "@FirstName", firstName);
|
AddParameter(command, "@FirstName", firstName);
|
||||||
AddParameter(command, "@LastName", lastName);
|
AddParameter(command, "@LastName", lastName);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Features.Auth.Dtos;
|
||||||
|
|
||||||
namespace Features.Auth.Repository;
|
namespace Features.Auth.Repository;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Repository for authentication-related database operations including user registration and credential management.
|
/// Repository for authentication-related database operations including user registration and credential management.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -11,20 +11,8 @@ public interface IAuthRepository
|
|||||||
/// Registers a new user with account details and initial credential.
|
/// Registers a new user with account details and initial credential.
|
||||||
/// Uses stored procedure: USP_RegisterUser
|
/// Uses stored procedure: USP_RegisterUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="username">Unique username for the user</param>
|
|
||||||
/// <param name="firstName">User's first name</param>
|
|
||||||
/// <param name="lastName">User's last name</param>
|
|
||||||
/// <param name="email">User's email address</param>
|
|
||||||
/// <param name="dateOfBirth">User's date of birth</param>
|
|
||||||
/// <param name="passwordHash">Hashed password</param>
|
|
||||||
/// <returns>The newly created UserAccount with generated ID</returns>
|
|
||||||
Task<UserAccount> RegisterUserAsync(
|
Task<UserAccount> RegisterUserAsync(
|
||||||
string username,
|
UserRegistrationDto userRegistrationDto
|
||||||
string firstName,
|
|
||||||
string lastName,
|
|
||||||
string email,
|
|
||||||
DateTime dateOfBirth,
|
|
||||||
string passwordHash
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user