using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using System.Security.Claims; using System.Text.Json; using AyCode.Core.Consts; using AyCode.Core.Extensions; using TIAMWebApp.Shared.Application.Models; using TIAMWebApp.Shared.Application.Models.PageModels; using TIAMWebApp.Server.Models; using AyCode.Core.Loggers; using TIAM.Database.DataLayers.Users; using TIAM.Entities.Users; using TIAM.Models.Dtos.Users; using AyCode.Core.Helpers; using AyCode.Services.SignalRs; using TIAM.Services; using TIAM.Services.Interfaces; using TIAM.Database.DataLayers.Admins; using TIAM.Entities.Emails; using TIAMWebApp.Shared.Application.Models.ClientSide.Messages; using TIAMWebApp.Shared.Application.Models.ClientSide; using System.Net; using TIAM.Services.Server; using TIAM.Services.Server.Logins; using TIAMWebApp.Server.Services; using AyCode.Core.Enums; using AyCode.Models.Enums; using TIAM.Models; namespace TIAMWebApp.Server.Controllers { [Authorize] [ApiController] [Route("api/v1/[controller]")] public class UserAPIController(IConfiguration configuration, AdminDal adminDal, UserDal userDal, IMessageSenderService messageSenderService, SessionService sessionService, IEnumerable logWriters) : ControllerBase, IUserApiControllerCommon { private readonly TIAM.Core.Loggers.Logger _logger = new(logWriters.ToArray()); private readonly LoginService _loginService = new(userDal, configuration); //private readonly IWebHostEnvironment _webHostEnvironment; //readonly PasswordHasher _hasher = new(); //private readonly ILogger _logger; /*private UserModel[] users = new UserModel[] { new UserModel(new Guid("540271f6-c604-4c16-8160-d5a7cafedf00"), "test@tiam.hu", "+36701234567", "Asdasd123456"), new UserModel(new Guid("4cbaed43-2465-4d99-84f1-c8bc6b7025f7"), "adam@tiam.hu", "+36701234567", "Asdasd987654") };*/ //[AllowAnonymous] //[HttpPost] //[Route(APIUrls.LoggerRouteName)] //public async Task AddLogItem(AcLogItem? logItem) //{ // if (logItem == null) // { // _logger.Error("AddLogItem; LogItem == null"); // //_logger.Writer().Detail(""); // return; // } // //logItem.LogHeaderId = ??? // logItem.TimeStampUtc = DateTime.UtcNow; // _logger.Write(logItem); // //_logger.Writer()?.Write(logItem.AppType, logItem.LogLevel, logItem.Text, logItem.CallerName, logItem.CategoryName, logItem.ErrorType, logItem.Exception); // //_logger.Writer().WriteLogItemAsync(logItem); //} [AllowAnonymous] [HttpPost] [Route(APIUrls.LogoutUserRouteName)] public async Task LogoutUser([FromBody] string refreshToken) { _logger.Info(@"LogoutUser called"); _logger.Info($"refreshtoken: {refreshToken}"); _loginService.Logout(); //TODO: Implementálni a Logout-ot kliens és szerver oldalon is! - J. return Ok("OK"); } [AllowAnonymous] [HttpPost] [Route(APIUrls.AuthenticateUserRouteName)] public async Task AuthenticateUser([FromBody] JsonElement serializedLoginModel) { _logger.Info(@"AuthenticateUser called"); var authenticateUser = JObject.Parse(serializedLoginModel.GetRawText()).ToObject(); if (authenticateUser == null) throw new NullReferenceException("authenticateUser == null"); _logger.Info(authenticateUser.Email); var loggedInModel = _loginService.Login(authenticateUser.Email, authenticateUser.Password); if (loggedInModel.IsLoggedIn) { var response = new MainResponse { Content = new AuthenticationResponse { RefreshToken = loggedInModel.LoggedInUser.RefreshToken, AccessToken = loggedInModel.AccessToken }, IsSuccess = true, ErrorMessage = "" }; return Ok(response); } _logger.Warning(@"User not valid! errorCode: " + loggedInModel.LoginErrorCode); return Unauthorized(); } [AllowAnonymous] [HttpPost] [Route(APIUrls.RefreshTokenRouteName)] public async Task RefreshToken(RefreshTokenRequest? refreshTokenRequest) { _logger.Info(@"RefreshToken called"); var response = new MainResponse(); if (refreshTokenRequest is null) { _logger.Info(@"RefreshTokenRequest is null"); response.ErrorMessage = "Invalid request"; return BadRequest(response); } var principal = _loginService.GetPrincipalFromExpiredToken(refreshTokenRequest.AccessToken); if (principal != null) { _logger.Info(@"Principal is not null"); var email = principal.Claims.FirstOrDefault(f => f.Type == ClaimTypes.Email); //var userModel = await _userManager.FindByEmailAsync(email?.Value); //UserModel? user = users.FirstOrDefault(x => x.Email == email?.Value); User? dbUser = null; if (email != null) { //get user from db dbUser = await userDal.GetUserByEmailAsync(email.Value, true); _logger.Info($@"DbUser email: {dbUser?.EmailAddress}"); } //mocking - update userModel with new refreshToken so it returns true after the check below //dbUser.RefreshToken = refreshTokenRequest.RefreshToken; if (dbUser is null || dbUser.RefreshToken != refreshTokenRequest.RefreshToken) { response.ErrorMessage = "Invalid Request"; _logger.Info($@"{dbUser?.RefreshToken}, {refreshTokenRequest.RefreshToken}"); return BadRequest(response); } var newAccessToken = _loginService.GenerateAccessToken(dbUser); var refreshToken = _loginService.GenerateRefreshToken(); //mocking - update userModel with new refreshToken dbUser.RefreshToken = refreshToken; //TODO await _userManager.UpdateAsync(userModel); await userDal.UpdateJwtRefreshTokenAsync(dbUser.EmailAddress, dbUser.RefreshToken); response.IsSuccess = true; response.Content = new AuthenticationResponse { RefreshToken = refreshToken, AccessToken = newAccessToken }; return Ok(response); } _logger.Info(@"Principal is null"); return NotFound("Invalid Token Found"); } [AllowAnonymous] [HttpPost] [Route("CreateUser")] public async Task CreateUser([FromBody] JsonElement serializedRegistrationModel) { _logger.Info(@"CreateUser called"); if (string.IsNullOrEmpty(serializedRegistrationModel.GetRawText())) { return BadRequest("SerializedLoginModel is required"); } else { var user = JObject.Parse(serializedRegistrationModel.GetRawText()).ToObject(); bool result = false; if (user != null) { //add userModel to users array //Array.Resize(ref users, users.Length + 1); //users[users.Length - 1] = new UserModel(user.Email, user.PhoneNumber, user.Password); var userId = Guid.NewGuid(); var email = user?.Email; var phoneNumber = user?.PhoneNumber; var password = user?.Password; if (email is null || phoneNumber is null || password is null) { return BadRequest("Invalid request"); } else { _logger.Info($@"User to be created: {userId}"); _logger.Info($@"User to be created: {email}"); _logger.Info($@"User to be created: {phoneNumber}"); _logger.Info($@"User to be created: {password}"); //var hashedPassword = PasswordHasher.HashPassword(user.Password, PasswordHasher.GenerateDynamicSalt(userId)); //await _userDal.CreateUserAsync(new User(userId, email, phoneNumber, hashedPassword)); var createResult = await _loginService.RegistrationAsync(userId, email, password, phoneNumber); if (createResult != AyCode.Core.Consts.AcErrorCode.Unset) { _logger.Error("Error:" + createResult.ToString()); result = false; } else { result = true; } } } return Ok(result.ToString()); } } [AllowAnonymous] [HttpPost] [Route(APIUrls.CreateGuestUserRouteName)] public async Task CreateGuestUser([FromBody] JsonElement serializedRegistrationModel) { _logger.Info(@"CreateGuestUser called"); UserModelDtoDetail? guestUser = null; if (string.IsNullOrEmpty(serializedRegistrationModel.GetRawText())) { return BadRequest("SerializedLoginModel is required"); } var user = JObject.Parse(serializedRegistrationModel.GetRawText()).ToObject(); if (user != null) { //var random = new Random(); //var chars = "1234567890"; //var nameExtension = new string(Enumerable.Repeat(chars, 10) // .Select(s => s[random.Next(s.Length)]).ToArray()); var userId = Guid.NewGuid(); var email = user.Email?.ToLower(); var phoneNumber = user.PhoneNumber; var password = user.Password; var referralId = user.ReferralId.IsNullOrEmpty() ? null : user.ReferralId; if (email is null || phoneNumber is null || password is null) { return BadRequest("Invalid request"); } _logger.Info($@"User to be created: {userId}"); _logger.Info($@"User to be created: {email}"); _logger.Info($@"User to be created: {phoneNumber}"); _logger.Info($@"User to be created: {password}"); var createResult = await _loginService.RegistrationAsync(userId, email, password, phoneNumber, referralId); if (createResult != AyCode.Core.Consts.AcErrorCode.Unset) { _logger.Error("Error:" + createResult.ToString()); } else { } } return Ok(guestUser); } [AllowAnonymous] [HttpGet] [Route("GetUsers")] public async Task> GetUsers() { //var users = await _userDal.Ctx.Users.ToListAsync();//.GetUsersAsync(); //return users; return await userDal.GetAllUserModelDtoAsync(); } [AllowAnonymous] [HttpGet] [Route(APIUrls.GetUsersWithDetailsRouteName)] [SignalR(SignalRTags.GetAllUserModelDtoDetails)] public async Task> GetUsersWithDetails() { _logger.Info("GetUsersWithDetails called"); var users = await userDal.GetAllUserModelDtoAsync(); return users; } [NonAction] [SignalR(SignalRTags.GetAllUsers)] public async Task> GetAllUsers() { _logger.Info("GetAllUsers called"); return await userDal.GetUsersAsync(); } [NonAction] [SignalR(SignalRTags.GetAllUserModelDtoEmails)] public async Task> GetUserModelDtoEmails() { _logger.Info("GetUserModelDtoEmails called"); return await userDal.GetUserModelDtoEmailsAsync(); } [AllowAnonymous] [HttpPost] [Route(APIUrls.UpdateUser)] [SignalR(SignalRTags.UpdateUser)] public async Task UpdateUser([FromBody] User user) { _logger.Info("UpdateUser called"); return await userDal.UpdateUserAsync(user); } [NonAction] [SignalR(SignalRTags.UserChangePassword)] public async Task UserChangePassword([FromBody] ChangePasswordDto changePasswordDto) { _logger.Info("ChangeUserPassword called"); var errorCode = await _loginService.ChangePasswordAsync(changePasswordDto.UserId, changePasswordDto.OldPassword, changePasswordDto.NewPassword); if (errorCode != AcErrorCode.Unset) _logger.Error($"ErrorCode: {errorCode}; userId: {changePasswordDto.UserId}"); return errorCode; } [NonAction] [SignalR(SignalRTags.UserForgotPassword)] public async Task UserForgotPassword([FromBody] ForgotPasswordDto forgotPasswordDto) { _logger.Info("UserForgotPassword called"); var errorCode = await _loginService.ForgotPasswordAsync(forgotPasswordDto.Email, forgotPasswordDto.NewPassword); if (errorCode != AcErrorCode.Unset) _logger.Error($"ErrorCode: {errorCode}; email: {forgotPasswordDto.Email}"); return errorCode; } [NonAction] [SignalR(SignalRTags.UpdateUserModelDtoDetail)] public async Task UpdateUserModelDtoDetail(UserModelDtoDetail userModelDtoDetail) { _logger.Info($"UpdateUserModelDtoDetail called; Id: {userModelDtoDetail.UserDto.Id}"); var result = await userDal.UpdateUserModelDtoDetailAsync(userModelDtoDetail); return result; } [NonAction] [SignalR(SignalRTags.AddUser)] public async Task AddUser(User user) { throw new NotImplementedException("Profile, Address, etc..."); if (user.Id.IsNullOrEmpty()) user.Id = Guid.NewGuid(); _logger.Info($"AddUser called; Id: {user.Id}"); return await userDal.AddUserAsync(user) ? user : null; } [NonAction] [SignalR(SignalRTags.AddUserModelDtoDetail)] public async Task AddUserModelDtoDetail(UserModelDtoDetail userModelDtoDetail) { throw new NotImplementedException("Profile, Address, etc..."); if (userModelDtoDetail.UserDto.Id.IsNullOrEmpty()) userModelDtoDetail.UserDto.Id = Guid.NewGuid(); _logger.Info($"AddUserModelDtoDetail called; Id: {userModelDtoDetail.UserDto.Id}"); var result = await userDal.AddUserModelDtoDetailAsync(userModelDtoDetail); return result; } [AllowAnonymous] [HttpGet] [Route(APIUrls.GetUserByEmailRouteName + "/{email}")] public async Task? GetUserByEmail(string email) { _logger.Info($"GetUserByEmail called with email: {email}"); var result = await userDal.GetUserModelDtoByEmailAsync(email, false); if (result == null) { UserModelDto resultDto = new UserModelDto(); return resultDto; } else { return result; } } [AllowAnonymous] [HttpPost] [Route(APIUrls.GetUserByIdRouteName)] public async Task GetUserById([FromBody] Guid id) { _logger.Info($"GetUserById called with id: {id}"); return await userDal.GetUserModelDtoByIdAsync(id, true); } [AllowAnonymous] [HttpPost] [Route(APIUrls.GetUserDetailByIdRouteName)] public async Task GetUserDetailById([FromBody] Guid id) { _logger.Info($"GetUserDetailById called with id: {id}"); var result = await userDal.GetUserModelDtoByIdAsync(id, false); return result; } [AllowAnonymous] [HttpPost] [Route(APIUrls.SendForgottenPasswordMailRouteName)] public async Task SendForgottenPasswordMail([FromBody] string email) { _logger.Info($"SendForgottenPasswordMail called with id: {email}"); var user = await userDal.GetUserByEmailAsync(email, false); if (user == null) { return false; } else { //create new token for the user //user.ConfirmToken = Guid.NewGuid().ToString("N"); user.ConfirmToken = AcCharsGenerator.NewToken(); _logger.Debug($"Generated token for user: {user.ConfirmToken}"); var result = await adminDal.UpdateUserAsync(user); _logger.Debug($"Saved token for user: {result.ConfirmToken}"); //send email _logger.Info($"Created transfer, send emailMessage!!!"); var message = new MessageSenderModel(); message.Message = new EmailMessage(); message.Message.EmailAddress = email; message.Message.Id = Guid.NewGuid(); message.MessageType = MessageTypesEnum.email; message.Message.Subject = "[Tour I Am] New transfer in Budapest"; message.Message.ContextId = user.Id; message.Message.ContextType = MessageContextType.System; message.Message.SenderId = Guid.Empty; message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, message.Message.Id, email)); message.Message.Text = EmailTemplateHelper.GenerateForgotPasswordEmail( user.FullName, Setting.BaseUrl, user.Id.ToString(), user.ConfirmToken); _logger.Info(message.Message.Text); var messageElement = message.Message; Console.WriteLine(message.Message); var mailResult = await messageSenderService.SendMessageAsync(messageElement, (int)message.MessageType); await adminDal.AddEmailMessageAsync(messageElement); _logger.Info("SendEmail result: " + mailResult); //----------------- if (mailResult == HttpStatusCode.OK.ToString()) { await adminDal.AddEmailMessageAsync(messageElement); return true; } else { return false; } } } [AllowAnonymous] [HttpPost] [Route(APIUrls.ValidateForgottenPasswordTokenRouteName)] public async Task ValidateForgottenPasswordToken([FromBody] string[] parameters) { User? user; _logger.Info($"ValidateForgottenPasswordToken called with id: {parameters[0]}"); if (parameters != null && parameters[0] != null && parameters[1] != null) { user = await userDal.GetUserByIdAsync(Guid.Parse(parameters[0]), false); if (user == null) { return "User not found"; } else { if (parameters[1] == user.ConfirmToken) { _logger.Debug($"Generated token for user: {user.ConfirmToken}"); //if user is not email validated, set email valid if (!user.EmailConfirmed) await SetEmailConfirmedMethod(user); return "Success"; } else { _logger.Debug($"Generated token for user: {user.ConfirmToken}"); return "Invalid token"; } } } else { return "Invalid request"; } } [AllowAnonymous] [HttpPost] [Route(APIUrls.SetEmailConfirmedRouteName)] public async Task SetEmailConfirmed([FromBody] Guid userId) { _logger.Info($"SetEmailConfirmed called with id: {userId}"); if(User!= null) { var user = await userDal.GetUserByIdAsync(userId, false); return await SetEmailConfirmedMethod(user); } return false; } [NonAction] private async Task SetEmailConfirmedMethod(User? user) { user.EmailConfirmed = true; var result = await adminDal.UpdateUserAsync(user); if (result != null) { return true; } return false; } [AllowAnonymous] [HttpPost] [Route(APIUrls.SendWelcomeMailRouteName)] public async Task SendWelcomeMail([FromBody] string email) { _logger.Info($"SendWelcomeMail called with id: {email}"); var user = await userDal.GetUserByEmailAsync(email, false); if (user == null) { return false; } else { //create new token for the user //user.ConfirmToken = Guid.NewGuid().ToString("N"); user.ConfirmToken = AcCharsGenerator.NewToken(); _logger.Debug($"Generated token for user: {user.ConfirmToken}"); var result = await adminDal.UpdateUserAsync(user); _logger.Debug($"Saved token for user: {result.ConfirmToken}"); //send email var message = new MessageSenderModel(); message.Message = new EmailMessage(); message.Message.EmailAddress = email; message.Message.Id = Guid.NewGuid(); message.MessageType = MessageTypesEnum.email; message.Message.Subject = "[Tour I Am] Validate your email"; message.Message.ContextId = user.Id; message.Message.ContextType = MessageContextType.System; message.Message.SenderId = Guid.Empty; message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, message.Message.Id, email)); message.Message.Text = EmailTemplateHelper.GenerateWelcomeEmail( user.FullName, Setting.BaseUrl, user.Id.ToString(), user.ConfirmToken); _logger.Info(message.Message.Text); var messageElement = message.Message; Console.WriteLine(message.Message); var mailResult = await messageSenderService.SendMessageAsync(messageElement, (int)message.MessageType); await adminDal.AddEmailMessageAsync(messageElement); _logger.Info("SendEmail result: " + mailResult); //----------------- if (mailResult == HttpStatusCode.OK.ToString()) { await adminDal.AddEmailMessageAsync(messageElement); return true; } else { return false; } } } } }