using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using FirebaseAdmin.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using OnlineAssessment.Common; using OnlineAssessment.Data.EFCore; using OnlineAssessment.Domain.Models; using OnlineAssessment.Domain.ViewModels; namespace OnlineAssessment.V1.Controllers { [Route("v{version:apiVersion}/[controller]")] [ApiController] [ApiVersion("1.0")] public class UsersController : BaseController { private readonly IConfiguration _config; EfCoreUserRepository _repository; string responseMessage; public UsersController(EfCoreUserRepository repository, IConfiguration config) : base(repository) { _repository = repository; _config = config; } /* /// /// Create a new user /// /// /// [HttpPost] [AllowAnonymous] public IActionResult SignUp([FromBody] UserAddModel user) { int returnCode = 0; string returnMessage = string.Empty; IActionResult returnResponse; UserViewModel newUser = _repository.SignUp(user, out returnCode, out returnMessage); if (newUser != null) returnResponse = Ok(ReturnResponse.GetSuccessStatus(newUser as dynamic)); else { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage + " " + returnMessage)); } return returnResponse; } /// /// User Log in /// /// [HttpPost] [Route("[Action]")] [Authorize] public async System.Threading.Tasks.Task SignIn() { string returnMessage = string.Empty; IActionResult returnResponse; ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity; string uuid = Security.GetValueFromToken("user_id", identity); LoginViewModel login = _repository.SignUpStudent(identity, out returnMessage); if(login != null) { string token = await Security.GetFirebaseTokenAsync(uuid, login.id, login.role_id); returnResponse = Ok(ReturnResponse.GetSuccessStatus(login)); } else { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage + " " + returnMessage)); } return returnResponse; } */ /// /// Admin/ Teacher Log in /// /// [HttpPost] [Route("[Action]")] [Authorize] public async System.Threading.Tasks.Task SignIn() { string returnMessage = string.Empty; IActionResult returnResponse; ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity; string uuid = Security.GetValueFromToken("user_id", identity); dynamic login = _repository.SignInAdminTeacher(identity, out returnMessage); if (login is LoginViewModel) { string token = await Security.GetFirebaseTokenAsync(uuid, login.id, login.role_id, 1); returnResponse = Ok(ReturnResponse.GetSuccessStatus(login)); } else if (login is int && login == (int)UserMessage.InvalidUser) { responseMessage = _repository.GetMessageByCode(UserMessage.InvalidUser.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.InvalidUser, responseMessage)); } else if (login is int && login == (int)Message.NotAllowedToResource) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.NotAllowedToResource, responseMessage)); } else { responseMessage = _repository.GetMessageByCode(Message.FailedToSignIn.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.FailedToAdd, responseMessage)); } return returnResponse; } /// /// Add Admin/Teacher /// /// [HttpPost] [Route("[Action]")] [Authorize(Roles = "Admin")] public IActionResult AddAdminTeacher([FromBody] AddAdminTeacherModel userDetails) { string returnMessage = string.Empty; IActionResult returnResponse; if (userDetails == null || (userDetails.roleId != 2 && userDetails.roleId != 3)) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString()); returnResponse = BadRequest(ReturnResponse.GetFailureStatus(responseMessage)); } dynamic login = _repository.AddAdminTeacher(InstituteId, userDetails.emailId, userDetails.roleId, out returnMessage); if (login is LoginViewModel) { returnResponse = Ok(ReturnResponse.GetSuccessStatus(login.email_id)); } else if(login is int && login == (int)UserMessage.InvalidUser) { responseMessage = _repository.GetMessageByCode(UserMessage.InvalidUser.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.InvalidUser, responseMessage)); } else if(login is int && login == (int)Message.NotAllowedToResource) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.NotAllowedToResource, responseMessage)); } else if (login is int && login == (int)UserMessage.UserAlreadyExists) { responseMessage = _repository.GetMessageByCode(UserMessage.UserAlreadyExists.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.UserAlreadyExists, responseMessage)); } else { responseMessage = _repository.GetMessageByCode(Message.FailedToAdd.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)Message.FailedToAdd, responseMessage)); } return returnResponse; } /* /// /// User Log in /// /// /// [AllowAnonymous] [HttpPost] [Route("[Action]")] public IActionResult SignIn([FromBody] UserLogin loginCredentials) { int returnCode = 0; IActionResult returnResponse; LoginViewModel loggedOnUser = _repository.SignIn(loginCredentials, out returnCode); if (loggedOnUser != null && returnCode > 0) { //Generate and set the access token var secretKey = _config["Jwt:Key"].ToString(); var issuer = _config["Jwt:Issuer"].ToString(); var audience = _config["Jwt:Issuer"].ToString(); //----------------------------------------------------------------------------------------------- loggedOnUser.JwtToken = Security.GetJwtToken(loggedOnUser, secretKey, issuer, audience); //----------------------------------------------------------------------------------------------- returnResponse = Ok(ReturnResponse.GetSuccessStatus(loggedOnUser as dynamic)); } else { responseMessage = _repository.GetMessageByCode(Message.FailedToSignIn.ToString()); switch (returnCode) { case (int)UserMessage.InvalidUser: responseMessage = string.Concat(responseMessage, ". Reason: ", _repository.GetMessageByCode(UserMessage.InvalidUser.ToString())); break; case (int)UserMessage.InvalidPasword: responseMessage = string.Concat(responseMessage, ". Reason: ", _repository.GetMessageByCode(UserMessage.InvalidPasword.ToString())); break; case (int)UserMessage.UserNotActive: responseMessage = string.Concat(responseMessage, ". Reason:", _repository.GetMessageByCode(UserMessage.UserNotActive.ToString())); break; } returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } return returnResponse; } */ /// /// Get All Users (accessible to SuperAdmin only) /// /// All Users of all the institutes [HttpGet] [Authorize(Roles = "SuperAdmin")] public override IActionResult GetAll() { IActionResult returnResponse; dynamic userList = _repository.GetUsersList(); if (userList == null) { responseMessage = _repository.GetMessageByCode(Message.NoData.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { returnResponse = Ok(ReturnResponse.GetSuccessStatus(userList)); } return returnResponse; } /// /// Get details of an user (accessible to SuperAdmin only) /// /// Id of the user /// The user's information [HttpGet("{id}")] [Authorize(Roles = "SuperAdmin")] public override IActionResult Get(int id) { IActionResult returnResponse; dynamic entity = _repository.GetUserById(id); if (entity == null) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotFound.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { returnResponse = Ok(ReturnResponse.GetSuccessStatus(entity)); } return returnResponse; } /// /// Edit an user (accessible to SuperAdmin only) /// /// The id of the user to edit /// User's data to edit /// [HttpPut("{id}")] [Authorize(Roles = "SuperAdmin")] public IActionResult Put(int id, [FromBody] UserEditModel userEdit) { IActionResult returnResponse = null; if (id != userEdit.Id) { responseMessage = _repository.GetMessageByCode(Message.IdMismatchBetweenBodyAndQueryString.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } else { string returnMessage = string.Empty; UserViewModel uvm = _repository.UpdateUser(id, userEdit, out returnMessage); if (uvm != null) { returnResponse = Ok(ReturnResponse.GetSuccessStatus(uvm)); } else { responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, returnMessage })); } } return returnResponse; } /// /// Delete a record (accessible to SuperAdmin only) /// /// /// [HttpDelete("{id}")] [Authorize(Roles = "SuperAdmin")] public IActionResult Delete(int id) { IActionResult returnResponse = null; try { bool isSuccess = _repository.Delete(id); if (isSuccess) { responseMessage = _repository.GetMessageByCode(Message.SucessfullyDeleted.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage)); } else { responseMessage = _repository.GetMessageByCode(Message.ObjectNotDeleted.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } } catch (Exception ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotDeleted.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() })); } return returnResponse; } [HttpPost] [AllowAnonymous] [Route("RegUser")] public IActionResult RegisterUser(StudentAddModel data) { int returnCode = -1; string returnMessage = string.Empty; IActionResult returnResponse = null; int userID = -1; try { userID = _repository.RegisterUser(data, out returnCode, out returnMessage); if(userID > 0) { responseMessage = _repository.GetMessageByCode(Message.SucessfullyAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage)); } else if(userID == (int)UserMessage.UserAlreadyExists) { responseMessage = _repository.GetMessageByCode(UserMessage.UserAlreadyExists.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } } catch (ApplicationException ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() })); } return returnResponse; } [HttpGet] [AllowAnonymous] [Route("VerifyAccount/{code}")] public IActionResult ActivateUser(string code) { string returnMessage = string.Empty; IActionResult returnResponse = null; int userID = -1; try { userID = _repository.VerifyAccount(code, out returnMessage); if (userID > 0) { responseMessage = _repository.GetMessageByCode(Message.Success.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetSuccessStatus(responseMessage)); } else { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } } catch (ApplicationException ex) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() })); } return returnResponse; } [ HttpPost] [AllowAnonymous] [Route("SignUpNew")] public async System.Threading.Tasks.Task SignUpNew([FromBody] SignupRequestModel request) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { // Create a new user var userRecordArgs = new UserRecordArgs { Email = request.Email, Password = request.Password, DisplayName = request.DisplayName, }; UserRecord record = await FirebaseAuth.DefaultInstance.CreateUserAsync(userRecordArgs); if (record == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } int userID = _repository.SignUpDB(record); // Assign custom claims //await Security.GetFirebaseTokenAsync(record.Uid, userID, 2, 1); var claims = new Dictionary() { {ClaimTypes.Role, "Admin"}, { "RoleId", 2}, { "InstituteId", 1 }, { "UserId", userID}, }; await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(record.Uid, claims); var link = await FirebaseAuth.DefaultInstance.GenerateEmailVerificationLinkAsync(record.Email); string sent = _repository.SendEmailLink(record.Email, link); Console.WriteLine($"Verification Link: {link}"); // Use email service here /* var claims2 = new Dictionary { { "email_verified", record.EmailVerified } }; await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(record.Uid, claims2); */ returnResponse = Ok(ReturnResponse.GetSuccessStatus(link));; } catch (ApplicationException ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message.ToString(), ex.InnerException.Message.ToString() })); } return returnResponse; } [HttpPost] [Authorize] [Route("SendEmailVerification")] public async Task SendOrResendVerification([FromQuery] bool isResend) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { // Extract the user's UID from the Firebase token ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity; string uid = Security.GetValueFromToken("user_id", identity); var userRecord = await FirebaseAuth.DefaultInstance.GetUserAsync(uid); if (userRecord.EmailVerified && isResend) { return BadRequest(new { Message = "Email is already verified" }); } var link = await FirebaseAuth.DefaultInstance.GenerateEmailVerificationLinkAsync(userRecord.Email); _repository.SendEmailLink(userRecord.Email, link); Console.WriteLine($"Verification Link: {link}"); // Use email service here return Ok(new { Message = isResend ? "Verification email resent!" : "Verification email sent!" }); } catch (Exception ex) { return BadRequest(new { Message = "Error processing request", Error = ex.Message }); } } /* [HttpPost] [AllowAnonymous] [Route("SignInAdmin")] public async Task SignInAdmin([FromBody] SignInRequest request) { if (string.IsNullOrEmpty(request.Email) || string.IsNullOrEmpty(request.Password)) { return BadRequest(new { Message = "Email and Password are required" }); } try { // Sign in with Firebase using email and password var auth = FirebaseAuth.DefaultInstance; var userCredential = await auth.SignInWithEmailAndPasswordAsync(request.Email, request.Password); // Get the user information var user = userCredential.User; string uid = user.Uid; // Check if the email is verified if (user.EmailVerified) { // If email is verified, return Firebase ID token string idToken = await user.GetIdTokenAsync(); return Ok(new { Message = "Sign-in successful", IdToken = idToken }); } else { // If the email is not verified, send verification email await SendVerificationEmailAsync(user.Email); return Ok(new { Message = "Email not verified. A verification email has been sent." }); } } catch (Exception ex) { // Handle sign-in error return Unauthorized(new { Message = "Sign-in failed", Error = ex.Message }); } } */ /// /// Update language /// /// /// [HttpPut("{language}/UpdatePreference")] [Authorize(Roles = "Student")] public IActionResult UpdatePreference(string language) { IActionResult returnResponse = null; string return_message = string.Empty; int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity); int language_id = _repository.GetLanguageIdByCode(language); if (language_id <= 0) { responseMessage = _repository.GetMessageByCode(Message.NoData.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } //TODO: check if works fine int langId = _repository.UpdateMyLanguage(user_id, language_id, out return_message); if (langId < 0) { responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { returnResponse = Ok(ReturnResponse.GetSuccessStatus(return_message)); } return returnResponse; } /// /// Attch me to usergroup /// /// /// /// [HttpPost("{user_group_id}/AttachBatch")] [Authorize(Roles = "Student")] public IActionResult AttachMeToUserGroup(int user_group_id, [FromBody] DefaultGroup defaultGroup) { IActionResult returnResponse = null; string return_message = string.Empty; int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity); //TODO: check if works fine ClassStructureViewModel csvm = _repository.AttachMeToUserGroup(base.InstituteId, user_group_id, user_id, defaultGroup.isDefault, out return_message); if (csvm == null) { responseMessage = _repository.GetMessageByCode(Message.FailedToAttach.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { returnResponse = Ok(ReturnResponse.GetSuccessStatus(csvm)); } return returnResponse; } /// /// Detach user group of a user /// /// /// [HttpPost("{user_group_id}/Detach")] [Authorize(Roles = "Admin,Teacher,Student")] public IActionResult DetachUserGroup(int user_group_id) { IActionResult returnResponse = null; string return_message = string.Empty; int user_id = Security.GetIdFromJwtToken(UserClaim.UserId, HttpContext.User.Identity as ClaimsIdentity); int recordsEffected = _repository.DetachUserGroup(base.InstituteId, user_id, user_group_id, out return_message); if (recordsEffected < 0) { responseMessage = _repository.GetMessageByCode(Message.FailedToDetach.ToString()); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } else { returnResponse = Ok(ReturnResponse.GetSuccessStatus(return_message)); } return returnResponse; } } }