using qtc_api.Services.BucketService; using qtc_api.Services.EmailService; namespace qtc_api.Services.UserService { public class UserService : IUserService { private readonly IConfiguration _configuration; private readonly IBucketService _bucketService; private readonly DataContext _dataContext; private long idMax = 900000000000000000; public UserService(IConfiguration configuration, IBucketService bucketService, DataContext dataContext) { _configuration = configuration; _dataContext = dataContext; _bucketService = bucketService; } public async Task> AddUser(UserDto userReq) { var serviceResponse = new ServiceResponse(); var userList = await _dataContext.Users.ToListAsync(); var user = new User(); Random rnd = new Random(); var id = LongRandom(1, idMax, rnd); user.Id = id.ToString(); user.Username = userReq.Username; user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(userReq.Password); user.Email = userReq.Email; user.DateOfBirth = userReq.DateOfBirth; user.Role = _configuration["Jwt:DefaultUserRole"]!; user.CreatedAt = DateTime.UtcNow; try { var cUser = userList.FirstOrDefault(x => x.Email == user.Email); if (cUser != null) { serviceResponse.Success = false; serviceResponse.Message = "User with that email already exists."; return serviceResponse; } else { await _dataContext.Users.AddAsync(user); await _dataContext.SaveChangesAsync(); userList = await _dataContext.Users.ToListAsync(); if (userList.Contains(user)) { var createdUser = await _dataContext.Users.FindAsync(user.Id); serviceResponse.Success = true; serviceResponse.Data = createdUser; return serviceResponse; } else { serviceResponse.Success = false; serviceResponse.Message = "User not created."; return serviceResponse; } } } catch (Exception ex) { serviceResponse.Success = false; serviceResponse.Message = ex.Message; return serviceResponse; } } public async Task> DeleteUser(string id) { var serviceResponse = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(x => x.Id == id)!; if(user != null) { _dataContext.Users.Remove(user); await _dataContext.SaveChangesAsync(); serviceResponse.Success = true; serviceResponse.Data = user; } else { serviceResponse.Success = false; serviceResponse.Message = "User not found."; } return serviceResponse; } public async Task>> GetAllUsers() { var serviceResponse = new ServiceResponse>(); var userList = await _dataContext.Users.ToListAsync(); var userInfoList = new List(); foreach(var user in userList) { var x = new UserInformationDto(); x.Id = user.Id; x.Username = user.Username; x.ProfilePicture = user.ProfilePicture; x.Role = user.Role; x.Bio = user.Bio; x.DateOfBirth = user.DateOfBirth; x.CurrencyAmount = user.CurrencyAmount; x.Status = user.Status; x.CreatedAt = user.CreatedAt; x.ProfileCosmeticId = user.ActiveProfileCosmetic; x.LastLogin = user.LastLogin; userInfoList.Add(x); } serviceResponse.Success = true; serviceResponse.Data = userInfoList; return serviceResponse; } public async Task>> GetAllOnlineUsers() { var serviceResponse = new ServiceResponse>(); var onlineUsers = new List(); await _dataContext.Users.ForEachAsync(user => { if (user.Status == 1 || user.Status == 2 || user.Status == 3) { var x = new UserInformationDto(); x.Id = user.Id; x.Username = user.Username; x.ProfilePicture = user.ProfilePicture; x.Role = user.Role; x.Bio = user.Bio; x.Status = user.Status; x.DateOfBirth = user.DateOfBirth; x.CreatedAt = user.CreatedAt; x.CurrencyAmount = user.CurrencyAmount; x.CreatedAt = user.CreatedAt; x.ProfileCosmeticId = user.ActiveProfileCosmetic; x.LastLogin = user.LastLogin; onlineUsers.Add(x); } }); serviceResponse.Success = true; serviceResponse.Data = onlineUsers; return serviceResponse; } public async Task> GetUserById(string id) { var serviceResponse = new ServiceResponse(); var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == id); serviceResponse.Success = true; serviceResponse.Data = user; return serviceResponse; } public async Task> GetUserInformationById(string id) { var serviceResponse = new ServiceResponse(); var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == id); if(user != null) { var dto = new UserInformationDto(); dto.Id = user.Id; dto.Username = user.Username; dto.ProfilePicture = user.ProfilePicture; dto.Role = user.Role; dto.Bio = user.Bio; dto.DateOfBirth = user.DateOfBirth; dto.CreatedAt = user.CreatedAt; dto.Status = user.Status; dto.CurrencyAmount = user.CurrencyAmount; dto.ProfileCosmeticId = user.ActiveProfileCosmetic; dto.LastLogin = user.LastLogin; serviceResponse.Success = true; serviceResponse.Data = dto; return serviceResponse; } else { serviceResponse.Success = false; serviceResponse.Message = "User not found."; return serviceResponse; } } public async Task> GetUserByEmail(string email) { var serviceResponse = new ServiceResponse(); var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Email == email); serviceResponse.Success = true; serviceResponse.Data = user; return serviceResponse; } public async Task> UpdateUserInfo(UserUpdateInformationDto request) { var serviceResponse = new ServiceResponse(); var dbUser = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == request.Id); if(dbUser != null) { dbUser.Username = request.Username; dbUser.Bio = request.Bio; dbUser.DateOfBirth = request.DateOfBirth; dbUser.ActiveProfileCosmetic = request.ProfileCosmeticId; await _dataContext.SaveChangesAsync(); var infoDto = new UserInformationDto(); infoDto.Id = dbUser.Id; infoDto.Username = request.Username; infoDto.ProfilePicture = dbUser.ProfilePicture; infoDto.Bio = request.Bio; infoDto.Role = dbUser.Role; infoDto.DateOfBirth = request.DateOfBirth; infoDto.CreatedAt = dbUser.CreatedAt; infoDto.Status = dbUser.Status; infoDto.CurrencyAmount = dbUser.CurrencyAmount; infoDto.ProfileCosmeticId = request.ProfileCosmeticId; serviceResponse.Success = true; serviceResponse.Data = infoDto; } else { serviceResponse.Success = false; serviceResponse.Message = "User not found."; } return serviceResponse; } public async Task> UpdateUserPic(string userId, IFormFile file) { var serviceResponse = new ServiceResponse(); var userToUpdate = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == userId); var cdnPath = _configuration["GeneralConfig:CDNPath"]; if (userToUpdate == null) { serviceResponse.Success = false; serviceResponse.Message = "User Not Found."; return serviceResponse; } if (file != null && file.Length > 0) { if (!Directory.Exists(cdnPath)) Directory.CreateDirectory(cdnPath!); if (!Directory.Exists($"{cdnPath}/{userId}")) Directory.CreateDirectory($"{cdnPath}/{userId}"); if (userToUpdate.ProfilePicture != null) await _bucketService.DeleteProfileImage(userToUpdate.Id, userToUpdate.ProfilePicture); var fileName = $"{Guid.NewGuid()}.{file.FileName.Split('.')[1]}"; using var ms = new MemoryStream(); file.CopyTo(ms); var result = await _bucketService.PutProfileImage(userId, fileName, ms.ToArray()); if (result) { userToUpdate.ProfilePicture = fileName; await _dataContext.SaveChangesAsync(); serviceResponse.Success = true; serviceResponse.Data = fileName; } else { // fallback to using local cdn var filePath = Path.Combine(cdnPath ?? "./user-content", userId, fileName); using (var stream = File.Create(filePath)) { await file.CopyToAsync(stream); } userToUpdate.ProfilePicture = fileName; await _dataContext.SaveChangesAsync(); serviceResponse.Success = true; serviceResponse.Data = fileName; } } else { serviceResponse.Success = false; serviceResponse.Message = "Empty File."; } return serviceResponse; } public async Task> GetUserPic(string userId) { var serviceResponse = new ServiceResponse(); var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == userId); var cdnPath = _configuration["GeneralConfig:CDNPath"]; if (user != null) { if (user.ProfilePicture != null) { var response = await _bucketService.GetProfileImageBytes(user.Id, user.ProfilePicture); if (response != null) { serviceResponse.Success = true; serviceResponse.Message = user.ProfilePicture; serviceResponse.Data = new FileContentResult(response, "image/jpeg"); } else { // try local cdn if (!Directory.Exists(cdnPath)) { serviceResponse.Success = false; serviceResponse.Message = "User Content Folder Does Not Exist Yet."; return serviceResponse; } var pic = Path.Combine(cdnPath, userId, user.ProfilePicture); if (!File.Exists(pic)) { serviceResponse.Success = false; serviceResponse.Message = "User Does Not Have A Profile Picture."; return serviceResponse; } serviceResponse.Success = true; serviceResponse.Message = user.ProfilePicture; serviceResponse.Data = new FileContentResult(File.ReadAllBytes(pic), "image/jpeg"); } } else { serviceResponse.Success = false; serviceResponse.Message = "User Does Not Have A Profile Picture."; } } else { serviceResponse.Success = false; serviceResponse.Message = "User Not Found."; } return serviceResponse; } public async Task> UpdateStatus(UserStatusDto request) { var serviceResponse = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(x => x.Id == request.Id)!; user.Status = request.Status; await _dataContext.SaveChangesAsync(); serviceResponse.Success = true; serviceResponse.Data = request; return serviceResponse; } public async Task> AddCurrencyToUser(string id, int amount, bool isSpinClaim) { var response = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(e => e.Id == id); if (user != null) { user.CurrencyAmount += amount; if (isSpinClaim) user.LastCurrencySpin = DateTime.UtcNow; await _dataContext.SaveChangesAsync(); response.Success = true; response.Data = user.CurrencyAmount; return response; } else { response.Success = false; response.Message = "User Not Found"; return response; } } public async Task> RemoveCurrencyFromUser(string id, int amount) { var response = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(e => e.Id == id); if (user != null) { user.CurrencyAmount -= amount; await _dataContext.SaveChangesAsync(); response.Success = true; response.Data = user.CurrencyAmount; return response; } else { response.Success = false; response.Message = "User Not Found"; return response; } } public async Task> AddStockToUser(string id, int amount) { var response = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(e => e.Id == id); if (user != null) { user.StockAmount += amount; await _dataContext.SaveChangesAsync(); response.Success = true; response.Data = user.StockAmount; return response; } else { response.Success = false; response.Message = "User Not Found"; return response; } } public async Task> RemoveStockFromUser(string id, int amount) { var response = new ServiceResponse(); var user = _dataContext.Users.FirstOrDefault(e => e.Id == id); if (user != null) { user.StockAmount -= amount; await _dataContext.SaveChangesAsync(); response.Success = true; response.Data = user.StockAmount; return response; } else { response.Success = false; response.Message = "User Not Found"; return response; } } private long LongRandom(long min, long max, Random rnd) { long result = rnd.Next((int)(min >> 32), (int)(max >> 32)); result = result << 32; result = result | (long)rnd.Next((int)min, (int)max); return result; } } }