1 Commits

Author SHA1 Message Date
MrFastwind
4f4575f86e feat(Lactose): Change UserRepository to Async version 2025-07-02 21:31:54 +02:00
6 changed files with 60 additions and 59 deletions

View File

@@ -43,7 +43,7 @@ public class RefreshTokenTransformation(
) : IClaimsTransformation
{
public const string ClaimType = "LoginValid";
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity();
if (principal.HasClaim(claim => claim.Type == ClaimType)) {
@@ -54,12 +54,12 @@ public class RefreshTokenTransformation(
}
}
var userData = authService.GetUserData(principal);
if (userData == null) return Task.FromResult(principal);
var user = userRepository.Find(userData.Id);
if (user == null) return Task.FromResult(principal);
if (string.IsNullOrEmpty(user.RefreshToken) || user.RefreshTokenExpires == null || user.RefreshTokenExpires < DateTime.Now) return Task.FromResult(principal);
if (userData == null) return principal;
var user = await userRepository.FindAsync(userData.Id);
if (user == null) return principal;
if (string.IsNullOrEmpty(user.RefreshToken) || user.RefreshTokenExpires == null || user.RefreshTokenExpires < DateTime.Now) return principal;
claimsIdentity.AddClaim(new Claim(ClaimType, "true", ClaimValueTypes.Boolean));
principal.AddIdentity(claimsIdentity);
return Task.FromResult(principal);
return principal;
}
}

View File

@@ -143,7 +143,7 @@ public class AssetController(
[HttpPost("{id}")]
[Authorize(Roles = "Curator,Admin")]
public IStatusCodeActionResult Update([FromRoute] Guid id, [FromBody] AssetUpdateDto dto) {
public async Task<IStatusCodeActionResult> Update([FromRoute] Guid id, [FromBody] AssetUpdateDto dto) {
var uid = authService.GetUserData(User)?.Id;
var accesslevel = authService.GetUserData(User)!.AccessLevel;
var asset = assetRepository.Find(id);
@@ -166,7 +166,7 @@ public class AssetController(
asset.DeletedAt = dto.DeletedAt ?? asset.DeletedAt;
log += $"DeletedAt: {asset.DeletedAt} -> {dto.DeletedAt ?? asset.DeletedAt}\n";
asset.Owner = dto.Owner != null ? userRepository.Find(dto.Owner.Value) : asset.Owner;
asset.Owner = dto.Owner != null ? await userRepository.FindAsync(dto.Owner.Value) : asset.Owner;
log += $"Owner: {asset.Owner?.Id} -> {dto.Owner ?? asset.Owner?.Id}\n";
logger.LogTrace($"Updating asset {id}\n{log}");
@@ -179,7 +179,7 @@ public class AssetController(
[HttpPost]
[Authorize(Roles = "Curator,Admin")]
public IStatusCodeActionResult BulkUpdate([FromBody] BulkDto<AssetUpdateDto> bulkDto) {
public async Task<IStatusCodeActionResult> BulkUpdate([FromBody] BulkDto<AssetUpdateDto> bulkDto) {
var uid = authService.GetUserData(User)?.Id;
var accesslevel = authService.GetUserData(User)!.AccessLevel;
var assets = assetRepository.FindBulk(bulkDto.Ids);
@@ -199,13 +199,12 @@ public class AssetController(
//If the user is not an admin, they can only update their own assets
if (accesslevel != EAccessLevel.Admin) enumerable = enumerable.Where(x => x.OwnerId == uid).ToList();
enumerable.ForEach(
x => {
x.IsPubliclyShared = bulkDto.Data.IsPublic ?? x.IsPubliclyShared;
x.DeletedAt = bulkDto.Data.DeletedAt ?? x.DeletedAt;
x.Owner = bulkDto.Data.Owner != null ? userRepository.Find(bulkDto.Data.Owner.Value) : x.Owner;
}
);
foreach (var x in enumerable) {
x.IsPubliclyShared = bulkDto.Data.IsPublic ?? x.IsPubliclyShared;
x.DeletedAt = bulkDto.Data.DeletedAt ?? x.DeletedAt;
x.Owner = x.Owner;
if (bulkDto.Data.Owner != null) x.Owner = await userRepository.FindAsync(bulkDto.Data.Owner.Value);
}
assetRepository.UpdateBulk(enumerable);
return Ok();
@@ -270,7 +269,7 @@ public class AssetController(
var uid = authService.GetUserData(User)?.Id;
var accesslevel = authService.GetUserData(User)!.AccessLevel;
if (userRepository.Find(dto.Owner) == null) {
if (userRepository.FindAsync(dto.Owner) == null) {
logger.LogWarning($"User {dto.Owner} does not exist in the database");
return BadRequest();
}

View File

@@ -21,15 +21,15 @@ public class AuthController(
[HttpPost("login")]
public ActionResult<AuthResultDto> Login([FromBody] CredentialsDto userDto) {
public async Task<ActionResult<AuthResultDto>> Login([FromBody] CredentialsDto userDto) {
User? user;
if (userDto.Identifier.Contains('@')) {
//search for user in database (by email)
user = userRepository.FindByEmail(userDto.Identifier);
user = await userRepository.FindByEmailAsync(userDto.Identifier);
} else {
//search for user in database (by username)
user = userRepository.FindByUsername(userDto.Identifier);
user = await userRepository.FindByUsernameAsync(userDto.Identifier);
}
if (user == null) {
return NotFound(new AuthResultDto() {
@@ -59,7 +59,7 @@ public class AuthController(
case PasswordVerificationResult.Failed: return NotFound(new AuthResultDto() { Success = false, ErrorMessage = "User or Password was wrong"});
case PasswordVerificationResult.SuccessRehashNeeded:
user.Password = passwordHasher.HashPassword(user, userDto.Password);
userRepository.Save();
userRepository.SaveAsync();
break;
case PasswordVerificationResult.Success: break;
}
@@ -68,7 +68,7 @@ public class AuthController(
var token = authService.GenerateAccessToken(user);
var refreshToken = authService.GenerateRefreshToken(user);
userRepository.Save();
userRepository.SaveAsync();
return new AuthResultDto() {
UserId = user.Id,
Token = token,
@@ -88,7 +88,7 @@ public class AuthController(
"""
);
if (userRepository.FindByEmail(dto.Email) != null || userRepository.FindByUsername(dto.Username) != null) {
if (userRepository.FindByEmailAsync(dto.Email) != null || userRepository.FindByUsernameAsync(dto.Username) != null) {
return Conflict("User already exists");
}
@@ -102,8 +102,8 @@ public class AuthController(
user.Password = passwordHasher.HashPassword(user, dto.Password);
userRepository.Insert(user);
userRepository.Save();
userRepository.InsertAsync(user);
userRepository.SaveAsync();
return Ok(user.Id);
}
@@ -118,17 +118,17 @@ public class AuthController(
[Authorize]
[HttpPost("logout")]
public ActionResult Logout() {
public async Task<ActionResult> Logout() {
LactoseAuthenticatedUser? identity = authService.GetUserData(User);
if (identity == null) { return Unauthorized(); }
//Reset token from the database
User? user = userRepository.Find(identity.Id);
User? user = await userRepository.FindAsync(identity.Id);
if (user == null) { return Unauthorized(); }
user.RefreshToken = string.Empty;
user.RefreshTokenExpires = null;
userRepository.Save();
userRepository.SaveAsync();
return Ok();
}
@@ -139,8 +139,8 @@ public class AuthController(
*/
[HttpPost("refresh")]
public ActionResult<AuthResultDto> RefreshToken([FromBody] RefreshDto token) {
User? user = userRepository.Find(token.UserId);
public async Task<ActionResult<AuthResultDto>> RefreshToken([FromBody] RefreshDto token) {
User? user = await userRepository.FindAsync(token.UserId);
if (user == null) {
return NotFound(
@@ -188,7 +188,7 @@ public class AuthController(
// TODO: Decide if we want to change or extend refresh token
if (user.RefreshTokenExpires > DateTime.Now - TimeSpan.FromMinutes(LactoseAuthService.BaseExpirationTime)) {
user.RefreshTokenExpires = DateTime.Now.AddMinutes(LactoseAuthService.LongExpirationTime);
userRepository.Save();
userRepository.SaveAsync();
}
return authDto;

View File

@@ -20,7 +20,7 @@ namespace Lactose.Controllers {
) : ControllerBase {
[Authorize(Roles = "Admin")]
[HttpPut]
public ActionResult<UserInfoDto> Create([FromBody] UserCreateDto userCreateDto) {
public async Task<ActionResult<UserInfoDto>> Create([FromBody] UserCreateDto userCreateDto) {
LactoseAuthenticatedUser? authenticatedUser = authService.GetUserData(User);
if (authenticatedUser != null) {
@@ -45,18 +45,18 @@ namespace Lactose.Controllers {
AccessLevel = userCreateDto.AccessLevel ?? EAccessLevel.User
};
if (userRepository.GetAll().Any(x => x.Email == user.Email)) return Conflict("Email already exists");
if (userRepository.GetAll().Any(x => x.Username == user.Username)) return Conflict("Username already exists");
if (await userRepository.FindByEmailAsync(user.Email) != null) return Conflict("Email already exists");
if (await userRepository.FindByUsernameAsync(user.Username)!= null) return Conflict("Username already exists");
userRepository.Insert(user);
userRepository.Save();
userRepository.InsertAsync(user);
userRepository.SaveAsync();
return Ok(user.Id);
}
[HttpGet("{id}")]
public ActionResult<UserInfoDto> Get(Guid id) {
public async Task<ActionResult<UserInfoDto>> Get(Guid id) {
LactoseAuthenticatedUser? authenticatedUser = authService.GetUserData(User);
if (authenticatedUser == null) {
@@ -67,7 +67,7 @@ namespace Lactose.Controllers {
//TODO: Lower level of access should fill less information of users
logger.LogDebug($"Sending user with id {id}");
User? user = userRepository.Find(id);
User? user = await userRepository.FindAsync(id);
if (user is null) return NotFound();
@@ -75,7 +75,7 @@ namespace Lactose.Controllers {
}
[HttpGet]
public ActionResult<List<UserInfoDto>> GetAll() {
public async Task<ActionResult<List<UserInfoDto>>> GetAll() {
logger.LogDebug("Sending Users list");
LactoseAuthenticatedUser? authenticatedUser = authService.GetUserData(User);
@@ -87,12 +87,12 @@ namespace Lactose.Controllers {
//TODO: Lower level of access should fill less information of users
//if (false) return Unauthorized();
return Ok(userRepository.GetAll().Select(u => u.ToGetUsersDto()).ToList());
return Ok((await userRepository.GetAllAsync()).Select(u => u.ToGetUsersDto()).ToList());
}
[HttpPost("update")]
public ActionResult<UserInfoDto> Update([FromBody] UserUpdateDto dto) {
public async Task<ActionResult<UserInfoDto>> Update([FromBody] UserUpdateDto dto) {
LactoseAuthenticatedUser? authenticatedUser = authService.GetUserData(User);
if (authenticatedUser == null) {
@@ -114,7 +114,7 @@ namespace Lactose.Controllers {
if (authenticatedUser.AccessLevel != EAccessLevel.Admin && authenticatedUser.Id != dto.Id) return Forbid();
User? user = userRepository.Find(dto.Id);
User? user = await userRepository.FindAsync(dto.Id);
if (user == null) return NotFound();
if (dto.Username != null) { user.Username = dto.Username; }
@@ -133,13 +133,13 @@ namespace Lactose.Controllers {
if (dto.AccessLevel != null) { user.AccessLevel = dto.AccessLevel.Value; }
}
userRepository.Save();
userRepository.SaveAsync();
return Ok(user.ToGetUsersDto());
}
[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public ActionResult<Guid> Delete([FromRoute] Guid id) {
public async Task<ActionResult<Guid>> Delete([FromRoute] Guid id) {
LactoseAuthenticatedUser? authenticatedUser = authService.GetUserData(User);
if (authenticatedUser == null) {
@@ -149,14 +149,14 @@ namespace Lactose.Controllers {
logger.LogDebug($"Deleting user: {id}");
User? user = userRepository.Find(id);
User? user = await userRepository.FindAsync(id);
if (user == null) return NotFound();
userRepository.Delete(user);
//TODO: eventually remove/hide all of the user content if required
userRepository.Save();
userRepository.SaveAsync();
return Ok(id);
}
}

View File

@@ -1,4 +1,5 @@
using Lactose.Models;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Lactose.Repositories;
@@ -7,39 +8,39 @@ public interface IUserRepository : IDisposable {
/// Return the list of all users
/// </summary>
/// <returns></returns>
IEnumerable<User> GetAll();
Task<IEnumerable<User>> GetAllAsync();
/// <summary>
/// Insert a new uer
/// </summary>
/// <param name="user"></param>
void Insert(User user);
void InsertAsync(User user);
/// <summary>
/// Saves all the changes to the Model
/// </summary>
void Save();
void SaveAsync();
/// <summary>
/// Get the user from the database.
/// </summary>
/// <param name="id"></param>
/// <returns>Returns the user if exist</returns>
User? Find(Guid id);
Task<User?> FindAsync(Guid id);
/// <summary>
/// Find a user by email, expects that the email is unique
/// </summary>
/// <param name="email"></param>
/// <returns>Returns the user if found </returns>
User? FindByEmail(string email);
Task<User?> FindByEmailAsync(string email);
/// <summary>
/// Find a user by username, expects that the username is unique
/// </summary>
/// <param name="username"></param>
/// <returns>Returns the user if found </returns>
User? FindByUsername(string username);
Task<User?> FindByUsernameAsync(string username);
/// <summary>
/// Delete a user from the database.

View File

@@ -1,22 +1,23 @@
using Lactose.Context;
using Lactose.Models;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Lactose.Repositories;
public class UserRepository(LactoseDbContext context) : IUserRepository {
public void Dispose() => context.Dispose();
public void Dispose() => context.DisposeAsync();
public IEnumerable<User> GetAll() => context.Users.AsEnumerable();
public async Task<IEnumerable<User>> GetAllAsync() => await context.Users.ToListAsync();
public void Insert(User user) => context.Users.Add(user);
public async void InsertAsync(User user) => await context.Users.AddAsync(user);
public void Save() => context.SaveChanges();
public async void SaveAsync() => await context.SaveChangesAsync();
public User? Find(Guid id) => context.Users.Find(id);
public async Task<User?> FindAsync(Guid id) => await context.Users.FindAsync(id);
public User? FindByEmail(string email) => context.Users.FirstOrDefault(u => u.Email == email);
public async Task<User?> FindByEmailAsync(string email) => await context.Users.FirstOrDefaultAsync(u => u.Email == email);
public User? FindByUsername(string username) => context.Users.FirstOrDefault(u => u.Username == username);
public async Task<User?> FindByUsernameAsync(string username) => await context.Users.FirstOrDefaultAsync(u => u.Username == username);
public void Delete(User user) => context.Users.Remove(user);
}