Adding crud operations for users

This commit is contained in:
2025-06-17 23:08:21 +02:00
parent 8986e3d77e
commit e1a249c07a
9 changed files with 493 additions and 28 deletions

View File

@@ -206,7 +206,7 @@ namespace BasicDotnetTemplate.MainProject.Controllers
return NotFound();
}
await this._roleService.DeleteRoleAsync(role);
await this._roleService.DeleteRoleAsync(role);
return Success(String.Empty);
}

View File

@@ -128,7 +128,187 @@ namespace BasicDotnetTemplate.MainProject.Controllers
}
[JwtAuthorization()]
[HttpPut("update/{guid}")]
[ProducesResponseType<GetUserResponse>(StatusCodes.Status201Created)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateUserAsync([FromBody] UpdateUserRequest request, string guid)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(_requestNotWellFormed);
}
if (request == null || request.Data == null ||
String.IsNullOrEmpty(request.Data.FirstName) ||
String.IsNullOrEmpty(request.Data.LastName)
)
{
return BadRequest(_requestNotWellFormed);
}
var user = await this._userService.GetUserByGuidAsync(guid);
if(user == null)
{
return NotFound();
}
user = await this._userService.UpdateUserAsync(request.Data, user);
var userDto = _mapper?.Map<UserDto>(user);
return Success(String.Empty, userDto);
}
catch (Exception exception)
{
var message = this._somethingWentWrong;
if (!String.IsNullOrEmpty(exception.Message))
{
message += $". {exception.Message}";
}
return InternalServerError(message);
}
}
[JwtAuthorization()]
[HttpPut("update/{guid}/password")]
[ProducesResponseType<GetUserResponse>(StatusCodes.Status201Created)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateUserPasswordAsync(string guid, string newPassword)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(_requestNotWellFormed);
}
if (String.IsNullOrEmpty(newPassword))
{
return BadRequest(_requestNotWellFormed);
}
var user = await this._userService.GetUserByGuidAsync(guid);
if(user == null)
{
return NotFound();
}
user = await this._userService.UpdateUserPasswordAsync(user, newPassword);
var userDto = _mapper?.Map<UserDto>(user);
return Success(String.Empty, userDto);
}
catch (Exception exception)
{
var message = this._somethingWentWrong;
if (!String.IsNullOrEmpty(exception.Message))
{
message += $". {exception.Message}";
}
return InternalServerError(message);
}
}
[JwtAuthorization()]
[HttpPut("update/{guid}/role")]
[ProducesResponseType<GetUserResponse>(StatusCodes.Status201Created)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> UpdateUserRoleAsync(string guid, string roleGuid)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(_requestNotWellFormed);
}
if (String.IsNullOrEmpty(roleGuid))
{
return BadRequest(_requestNotWellFormed);
}
var role = await this._roleService.GetRoleForUser(roleGuid);
if (role == null)
{
return BadRequest("Role not found");
}
var user = await this._userService.GetUserByGuidAsync(guid);
if(user == null)
{
return NotFound();
}
user = await this._userService.UpdateUserRoleAsync(user, role);
var userDto = _mapper?.Map<UserDto>(user);
return Success(String.Empty, userDto);
}
catch (Exception exception)
{
var message = this._somethingWentWrong;
if (!String.IsNullOrEmpty(exception.Message))
{
message += $". {exception.Message}";
}
return InternalServerError(message);
}
}
[JwtAuthorization()]
[HttpDelete("{guid}")]
[ProducesResponseType<GetUserResponse>(StatusCodes.Status200OK)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status404NotFound)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status400BadRequest)]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> DeleteUserByGuidAsync(string guid)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(_requestNotWellFormed);
}
if (String.IsNullOrEmpty(guid))
{
return BadRequest(_requestNotWellFormed);
}
var user = await this._userService.GetUserByGuidAsync(guid);
if (user == null || String.IsNullOrEmpty(user.Guid))
{
return NotFound();
}
await this._userService.DeleteUserAsync(user);
return Success(String.Empty);
}
catch (Exception exception)
{
var message = this._somethingWentWrong;
if (!String.IsNullOrEmpty(exception.Message))
{
message += $". {exception.Message}";
}
return InternalServerError(message);
}
}
}
}

View File

@@ -15,21 +15,21 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.16" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.17" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.17" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.5">
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
<PackageReference Include="Microsoft.Identity.Web" Version="3.9.3" />
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="9.0.0" />
@@ -37,14 +37,14 @@
<PackageReference Include="NLog" Version="5.5.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.5.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters.Abstractions" Version="8.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters.Abstractions" Version="9.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.1" />
</ItemGroup>
</Project>

View File

@@ -1,9 +1,7 @@
namespace BasicDotnetTemplate.MainProject.Models.Api.Data.User;
public class CreateUserRequestData
public class CreateUserRequestData : UpdateUserRequestData
{
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string Email { get; set; } = String.Empty;
public string Password { get; set; } = String.Empty;
public string? RoleGuid { get; set; }

View File

@@ -0,0 +1,12 @@
namespace BasicDotnetTemplate.MainProject.Models.Api.Data.User;
public class UpdateUserRequestData
{
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
}

View File

@@ -0,0 +1,14 @@
using BasicDotnetTemplate.MainProject.Models.Api.Data.User;
namespace BasicDotnetTemplate.MainProject.Models.Api.Request.User;
public class UpdateUserRequest
{
#nullable enable
public UpdateUserRequestData? Data { get; set; }
#nullable disable
}

View File

@@ -16,7 +16,10 @@ public interface IUserService
Task<User?> GetUserByUsernameAndPassword(string email, string password);
Task<bool> CheckIfEmailIsValid(string email, string? guid = "");
Task<User?> CreateUserAsync(CreateUserRequestData data, Role role);
Task<User?> UpdateUserAsync(UpdateUserRequestData data, User user);
Task<bool?> DeleteUserAsync(User user);
Task<User?> UpdateUserPasswordAsync(User user, string newPassword);
Task<User?> UpdateUserRoleAsync(User user, Role newRole);
}
public class UserService : BaseService, IUserService
@@ -134,6 +137,31 @@ public class UserService : BaseService, IUserService
return user;
}
public async Task<User?> UpdateUserAsync(UpdateUserRequestData data, User user)
{
using var transaction = await _sqlServerContext.Database.BeginTransactionAsync();
try
{
user.FirstName = data.FirstName ?? user.FirstName;
user.LastName = data.LastName ?? user.LastName;
user.UpdateTime = DateTime.UtcNow;
user.UpdateUserId = this.GetCurrentUserId();
_sqlServerContext.Users.Update(user);
await _sqlServerContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception exception)
{
Logger.Error(exception, $"[UserService][UpdateUserAsync] | {transaction.TransactionId}");
await transaction.RollbackAsync();
throw new UpdateException($"An error occurred while updating the user for transaction ID {transaction.TransactionId}.", exception);
}
return user;
}
public async Task<bool?> DeleteUserAsync(User user)
{
bool? deleted = false;
@@ -151,6 +179,59 @@ public class UserService : BaseService, IUserService
return deleted;
}
public async Task<User?> UpdateUserPasswordAsync(User user, string newPassword)
{
using var transaction = await _sqlServerContext.Database.BeginTransactionAsync();
try
{
var salt = _appSettings.EncryptionSettings?.Salt ?? String.Empty;
var pepper = CryptUtils.GeneratePepper();
var iterations = _appSettings.EncryptionSettings?.Iterations ?? 10;
user.PasswordSalt = salt;
user.PasswordPepper = pepper;
user.PasswordIterations = iterations;
user.Password = CryptUtils.GeneratePassword(newPassword, salt, iterations, pepper);
user.UpdateTime = DateTime.UtcNow;
user.UpdateUserId = this.GetCurrentUserId();
_sqlServerContext.Users.Update(user);
await _sqlServerContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception exception)
{
Logger.Error(exception, $"[UserService][UpdateUserPasswordAsync] | {transaction.TransactionId}");
await transaction.RollbackAsync();
throw new UpdateException($"An error occurred while updating the user for transaction ID {transaction.TransactionId}.", exception);
}
return user;
}
public async Task<User?> UpdateUserRoleAsync(User user, Role newRole)
{
using var transaction = await _sqlServerContext.Database.BeginTransactionAsync();
try
{
user.Role = newRole;
user.UpdateTime = DateTime.UtcNow;
user.UpdateUserId = this.GetCurrentUserId();
_sqlServerContext.Users.Update(user);
await _sqlServerContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception exception)
{
Logger.Error(exception, $"[UserService][UpdateUserRoleAsync] | {transaction.TransactionId}");
await transaction.RollbackAsync();
throw new UpdateException($"An error occurred while updating the user for transaction ID {transaction.TransactionId}.", exception);
}
return user;
}
}