danylokhodus's picture
feat: include daily AI generation count in user response DTO
67d4c53
Raw
History Blame Contribute Delete
5.41 kB
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
};
}
}