Spaces:
Running
Running
| using System.Security.Cryptography; | |
| using System.Text; | |
| using FlowAPI.Application.DTOs.User; | |
| using FlowAPI.Application.Interfaces; | |
| using FlowAPI.Domain.Entities; | |
| using Microsoft.Extensions.Configuration; | |
| namespace FlowAPI.Application.Services | |
| { | |
| public class UserService : IUserService | |
| { | |
| private readonly IUserRepository _repo; | |
| private readonly ITokenService _tokenService; | |
| private readonly IConfiguration _config; | |
| private readonly IAchievementService _achievementService; | |
| public UserService(IUserRepository repo, ITokenService tokenService, IConfiguration config, IAchievementService achievementService) | |
| { | |
| _repo = repo; | |
| _tokenService = tokenService; | |
| _config = config; | |
| _achievementService = achievementService; | |
| } | |
| public async Task<IEnumerable<UserResponseDto>> GetAllAsync() | |
| { | |
| var users = await _repo.GetAllAsync(); | |
| return users.Select(MapToDto); | |
| } | |
| public async Task<UserResponseDto?> GetByIdAsync(Guid id) | |
| { | |
| var user = await _repo.GetByIdAsync(id); | |
| return user is null ? null : MapToDto(user); | |
| } | |
| public async Task<AuthResponseDto> RegisterAsync(CreateUserDto dto) | |
| { | |
| var existing = await _repo.GetByEmailAsync(dto.Email); | |
| if (existing is not null) | |
| throw new InvalidOperationException("User with this email already exists."); | |
| var user = new User | |
| { | |
| Id = Guid.NewGuid(), | |
| Email = dto.Email, | |
| PasswordHash = HashPassword(dto.Password), | |
| DisplayName = dto.DisplayName, | |
| CreatedAt = DateTime.UtcNow | |
| }; | |
| var created = await _repo.CreateAsync(user); | |
| return new AuthResponseDto | |
| { | |
| User = MapToDto(created), | |
| Token = _tokenService.CreateToken(created) | |
| }; | |
| } | |
| public async Task<AuthResponseDto?> LoginAsync(LoginDto dto) | |
| { | |
| var user = await _repo.GetByEmailAsync(dto.Email); | |
| if (user is null || string.IsNullOrEmpty(user.PasswordHash) || user.PasswordHash != HashPassword(dto.Password)) | |
| return null; | |
| return new AuthResponseDto | |
| { | |
| User = MapToDto(user), | |
| Token = _tokenService.CreateToken(user) | |
| }; | |
| } | |
| public async Task<AuthResponseDto> GoogleLoginAsync(GoogleLoginDto dto) | |
| { | |
| var settings = new Google.Apis.Auth.GoogleJsonWebSignature.ValidationSettings | |
| { | |
| Audience = new List<string> { _config["Google:ClientId"]! } | |
| }; | |
| var payload = await Google.Apis.Auth.GoogleJsonWebSignature.ValidateAsync(dto.IdToken, settings); | |
| var user = await _repo.GetByEmailAsync(payload.Email); | |
| if (user == null) | |
| { | |
| user = new User | |
| { | |
| Id = Guid.NewGuid(), | |
| Email = payload.Email, | |
| DisplayName = payload.Name, | |
| CreatedAt = DateTime.UtcNow, | |
| PasswordHash = "" // No password for Google users | |
| }; | |
| user = await _repo.CreateAsync(user); | |
| } | |
| return new AuthResponseDto | |
| { | |
| User = MapToDto(user), | |
| Token = _tokenService.CreateToken(user) | |
| }; | |
| } | |
| public async Task<UserResponseDto?> UpdateAsync(Guid id, UpdateUserDto dto) | |
| { | |
| var user = await _repo.GetByIdAsync(id); | |
| if (user is null) return null; | |
| bool isAvatarUpdated = dto.AvatarUrl is not null && user.AvatarUrl != dto.AvatarUrl; | |
| if (dto.DisplayName is not null) user.DisplayName = dto.DisplayName; | |
| if (dto.IsPremium.HasValue) user.IsPremium = dto.IsPremium.Value; | |
| if (dto.AvatarUrl is not null) user.AvatarUrl = dto.AvatarUrl; | |
| if (dto.SubscriptionTier is not null) | |
| { | |
| user.SubscriptionTier = dto.SubscriptionTier; | |
| user.IsPremium = dto.SubscriptionTier != "Free"; | |
| } | |
| if (!string.IsNullOrEmpty(dto.Password)) user.PasswordHash = HashPassword(dto.Password); | |
| var updated = await _repo.UpdateAsync(user); | |
| if (isAvatarUpdated) | |
| { | |
| await _achievementService.ProcessEventAsync(id, "AvatarUploaded"); | |
| } | |
| return MapToDto(updated); | |
| } | |
| public async Task<bool> DeleteAsync(Guid id) | |
| { | |
| return await _repo.DeleteAsync(id); | |
| } | |
| private static string HashPassword(string password) | |
| { | |
| var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(password)); | |
| return Convert.ToBase64String(bytes); | |
| } | |
| private static UserResponseDto MapToDto(User user) => new() | |
| { | |
| Id = user.Id, | |
| Email = user.Email, | |
| DisplayName = user.DisplayName, | |
| IsPremium = user.IsPremium, | |
| AvatarUrl = user.AvatarUrl, | |
| CreatedAt = user.CreatedAt, | |
| SubscriptionTier = user.SubscriptionTier, | |
| DailyAiGenerationsCount = user.DailyAiGenerationsCount | |
| }; | |
| } | |
| } | |