using System.Diagnostics; using Google.Apis.Oauth2.v2.Data; using System.Security.Claims; using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Models; using Hutopy.Application.Users.Models; using Hutopy.Infrastructure.Identity.OwnedEntities; using Hutopy.Infrastructure.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; namespace Hutopy.Infrastructure.Identity; public class IdentityService( UserManager userManager, SignInManager signInManager, IUserClaimsPrincipalFactory userClaimsPrincipalFactory, IAuthorizationService authorizationService, IHttpContextAccessor contextAccessor, IConfiguration configuration ) : IIdentityService { public async Task GetUserNameAsync(string userId) { var user = await userManager.FindByIdAsync(userId); return user?.UserName; } public async Task GetUserByUserNameAsync(string userName) { var response = await userManager.FindByNameAsync(userName); if (response == null) return null; var userModel = new UserModel() { Id = response.Id, UserName = response.UserName, FirstName = response.FirstName, LastName = response.LastName, Email = response.Email, }; return userModel; } public async Task> CreateUserAsync(Userinfo userInfo) { var applicationUser = new ApplicationUser { UserName = userInfo.Name, Email = userInfo.Email, FirstName = userInfo.GivenName, LastName = userInfo.FamilyName }; var password = Guid.NewGuid().ToString("N")[..32]; var identityResult = await userManager.CreateAsync(applicationUser, password); var applicationResult = identityResult.ToApplicationResult(); var result = new Result(applicationResult.Succeeded, applicationResult.Errors); result.Value = applicationUser.Id; return result; } public async Task> CreateUserAsync(string email, string userName, string firstName, string lastName, string password) { var applicationUser = new ApplicationUser { UserName = userName, Email = email, FirstName = firstName, LastName = lastName }; var response = await userManager.CreateAsync(applicationUser, password); var result = new Result(response.Succeeded, response.ToApplicationResult().Errors); result.Value = applicationUser.Id; return result; } public async Task> UpdateCurrentUserAsync(string id, string firstName, string lastName, string occupation, string phoneNumber, string birthDate, string country, string city, string address, string about, string description, SocialNetworksModel socialNetworks) { var applicationUser = await userManager.FindByIdAsync(id); if (applicationUser is null) return Result.Failure(new[] { "User not found." }); applicationUser.FirstName = firstName; applicationUser.LastName = lastName; applicationUser.Occupation = occupation; applicationUser.PhoneNumber = phoneNumber; applicationUser.BirthDate = birthDate; applicationUser.Country = country; applicationUser.City = city; applicationUser.Address = address; applicationUser.About = about; applicationUser.Description = description; applicationUser.SocialNetworks = new SocialNetworks() { FacebookUrl = socialNetworks.FacebookUrl, InstagramUrl = socialNetworks.InstagramUrl, XUrl = socialNetworks.XUrl, LinkedInUrl = socialNetworks.LinkedInUrl, TikTokUrl = socialNetworks.TikTokUrl, YoutubeUrl = socialNetworks.YoutubeUrl, RedditUrl = socialNetworks.RedditUrl, YourWebsiteUrl = socialNetworks.YourWebsiteUrl }; var response = await userManager.UpdateAsync(applicationUser); var applicationResult = response.ToApplicationResult(); var result = new Result(applicationResult.Succeeded, applicationResult.Errors); result.Value = id; return result; } public async Task FindUserByIdAsync(string id) { var response = await userManager.FindByIdAsync(id); if (response == null) return null; var userModel = new UserModel { Id = response.Id, UserName = response.UserName, FirstName = response.FirstName, LastName = response.LastName, Email = response.Email, Occupation = response.Occupation, Phone = response.PhoneNumber, BirthDate = response.BirthDate, Country = response.Country, City = response.City, Address = response.Address, About = response.About, Description = response.Description, SocialNetworks = new SocialNetworksModel { FacebookUrl = response.SocialNetworks.FacebookUrl, InstagramUrl = response.SocialNetworks.InstagramUrl, XUrl = response.SocialNetworks.XUrl, LinkedInUrl = response.SocialNetworks.LinkedInUrl, TikTokUrl = response.SocialNetworks.TikTokUrl, YoutubeUrl = response.SocialNetworks.YoutubeUrl, RedditUrl = response.SocialNetworks.RedditUrl, YourWebsiteUrl = response.SocialNetworks.YourWebsiteUrl, } }; return userModel; } public async Task GetCurrentUserAsync() { var currentUserId = contextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(currentUserId)) { return null; } return await FindUserByIdAsync(currentUserId); } public async Task FindUserByEmailAsync(string email) { var response = await userManager.FindByEmailAsync(email); if (response == null) return null; var userModel = new UserModel { Id = response.Id, UserName = response.UserName, FirstName = response.FirstName, LastName = response.LastName, Email = response.Email }; return userModel; } public async Task IsInRoleAsync(string userId, string role) { var user = await userManager.FindByIdAsync(userId); return user != null && await userManager.IsInRoleAsync(user, role); } public async Task CurrentUserIsInRoleAsync(string role) { var currentUserModel = await GetCurrentUserAsync(); var currentUser = await userManager.FindByIdAsync(currentUserModel?.Id ?? ""); return currentUser != null && await userManager.IsInRoleAsync(currentUser, role); } public async Task AuthorizeAsync(string userId, string policyName) { var user = await userManager.FindByIdAsync(userId); if (user == null) { return false; } var principal = await userClaimsPrincipalFactory.CreateAsync(user); var result = await authorizationService.AuthorizeAsync(principal, policyName); return result.Succeeded; } public async Task DeleteUserAsync(string userId) { var user = await userManager.FindByIdAsync(userId); return user != null ? await DeleteUserAsync(user) : Result.Success(); } public async Task DeleteUserAsync(ApplicationUser user) { var result = await userManager.DeleteAsync(user); return result.ToApplicationResult(); } public async Task AddRoleAsync(string userId, string role) { var hasAdminAccess = await CurrentUserIsInRoleAsync("Administrator"); if (!hasAdminAccess) return Result.Failure(new []{"Only administrator can assign new roles to a user."}); var user = await userManager.FindByIdAsync(userId); if (user is null) return Result.Failure(new []{"User not found."}); var result = await userManager.AddToRoleAsync(user, role); return result.ToApplicationResult(); } public async Task> GetCurrentUserRolesAsync() { var currentUserModel = await GetCurrentUserAsync(); var currentUser = await userManager.FindByIdAsync(currentUserModel?.Id ?? ""); if (currentUser is null) return []; var userRoles = await userManager.GetRolesAsync(currentUser); return userRoles; } public async Task LoginAsync(string userName, string password) { var result = await signInManager.PasswordSignInAsync(userName, password, isPersistent: false, lockoutOnFailure: false); if (!result.Succeeded) { return null; } var user = await GetUserByUserNameAsync(userName); if (user is null) throw new InvalidOperationException(); var jwtSection = configuration.GetRequiredSection("Authentication:Jwt"); var token = JwtTokenHelper.GenerateJwtToken( issuer: jwtSection["Issuer"] ?? "", audience: jwtSection["Audience"] ?? "", key: jwtSection["Key"] ?? "", userId: user.Id, email: user.Email, firstname: user.FirstName, lastname: user.LastName, portraitUrl: user.PortraitUrl); return token; } }