using System.IdentityModel.Tokens.Jwt; using Application.Classes; using Application.DataTransferObjects.Authentication; using Application.Errors; using Application.Interfaces; using AutoMapper; using Database; using Database.Entities; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Utilities.Constants; namespace Application.Repositories; public class AuthenticationRepository(UserManager userManager, ApplicationContext context, IMapper mapper, IJwtService jwtService, ILogger logger) : IAuthenticationRepository { public async Task> LoginAsync(LoginRequestDto loginRequestDto, CancellationToken cancellationToken) { var userToLogin = await userManager.FindByEmailAsync(loginRequestDto.Email); if (userToLogin is null || !await userManager.CheckPasswordAsync(userToLogin, loginRequestDto.Password)) { return Result.Failure(AuthenticationErrors.LoginFailed); } var loginResponse = new LoginResponseDto() { Token = await CreateJwtToken(userToLogin) }; return Result.Success(loginResponse); } public async Task> RegisterToApplicationAsync(RegisterRequestDto registerRequestDto, CancellationToken cancellationToken) { var newUser = mapper.Map(registerRequestDto); var userAlliance = mapper.Map(registerRequestDto); var checkAllianceExists = await AllianceAlreadyExists(userAlliance.Server, userAlliance.Abbreviation, cancellationToken); if (checkAllianceExists) return Result.Failure(AuthenticationErrors.AllianceAlreadyExists); var createAllianceResult = await CreateAlliance(userAlliance, cancellationToken); if (createAllianceResult.IsFailure) return Result.Failure(createAllianceResult.Error); newUser.AllianceId = createAllianceResult.Value.Id; var userCreateResult = await userManager.CreateAsync(newUser, registerRequestDto.Password); if (!userCreateResult.Succeeded) { var rollBackResult = await RollbackAlliance(createAllianceResult.Value, cancellationToken); return Result.Failure(rollBackResult.IsFailure ? rollBackResult.Error : AuthenticationErrors.RegisterFailed); } var addRoleResult = await userManager.AddToRoleAsync(newUser, ApplicationRoles.Administrator); if (!addRoleResult.Succeeded) { await userManager.DeleteAsync(newUser); await RollbackAlliance(createAllianceResult.Value, cancellationToken); return Result.Failure(AuthenticationErrors.RegisterFailed); } var response = new LoginResponseDto() { Token = await CreateJwtToken(newUser) }; return Result.Success(response); } private async Task> CreateAlliance(Alliance alliance, CancellationToken cancellationToken) { await context.Alliances.AddAsync(alliance, cancellationToken); try { await context.SaveChangesAsync(cancellationToken); return alliance; } catch (Exception e) { logger.LogError(e, e.Message); return Result.Failure(GeneralErrors.DatabaseError); } } private async Task> RollbackAlliance(Alliance alliance, CancellationToken cancellationToken) { context.Alliances.Remove(alliance); try { await context.SaveChangesAsync(cancellationToken); return Result.Success(true); } catch (Exception e) { logger.LogError(e, e.Message); return Result.Failure(GeneralErrors.DatabaseError); } } private async Task CreateJwtToken(User user) { var signingCredentials = jwtService.GetSigningCredentials(); var claims = await jwtService.GetClaimsAsync(user); var tokenOptions = jwtService.GenerateTokenOptions(signingCredentials, claims); return new JwtSecurityTokenHandler().WriteToken(tokenOptions); } private async Task AllianceAlreadyExists(int server, string allianceAbbreviation, CancellationToken cancellationToken) { var allianceToCheck = await context.Alliances .FirstOrDefaultAsync(alliance => alliance.Server == server && alliance.Abbreviation == allianceAbbreviation, cancellationToken); return allianceToCheck is not null; } }