using System; using System.Collections.Generic; using System.Configuration; using System.Diagnostics.Eventing.Reader; using System.Linq; using System.Security.Claims; using System.Text.Json; using System.Threading.Tasks; using Azure.Core; 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, OdooService odooService) : base(repository, odooService) // Pass OdooService to the base class { _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, base.InstituteId); 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 /// [HttpPost("{id}/Update")] [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) /// /// /// [HttpPost("{id}/Delete")] [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; } [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; string slugDomain = _repository.ConvertToSlug(request.DomainName); try { //Check if the domain name exists if(_repository.isUniqueSlug(slugDomain) == false || _repository.isUniqueEmail(request.Email) == false) { responseMessage = _repository.GetMessageByCode(Message.AlreadyExist.ToString(), slugDomain); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Create a new user var userRecordArgs = new UserRecordArgs { Email = request.Email, Password = request.Password, DisplayName = "Admin", }; UserRecord record = await FirebaseAuth.DefaultInstance.CreateUserAsync(userRecordArgs); if (record == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Create Institute and Admin in my DB Users user = _repository.SignUpDB(record, slugDomain); if (user == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Create company in Odoo var companyFields = new { name = slugDomain, barcode = user.InstituteId, is_company = true, // Indicates this is a company }; var odooCompanyId = await _odooService.CreateCompanyAsync("res.partner", companyFields); if (odooCompanyId <= 0) { responseMessage = "Failed to create company in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Create an employee in Odoo var contactFields = new Dictionary { { "name", "Admin" }, { "email", request.Email }, { "marital", "single" }, { "employee_type", "employee" }, { "barcode", user.Id } //{ "type", "contact" } //{ "company_id", odooCompanyId } // Optionally, link to the institute }; int odooEmployeeId = await _odooService.CreateEmployeeAsync("hr.employee", contactFields); if (odooEmployeeId <= 0) { responseMessage = "Failed to create employee in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Assign custom claims var claims = new Dictionary() { { ClaimTypes.Role, "Admin"}, { "RoleId", user.RoleId}, { "InstituteId", user.InstituteId }, { "UserId", user.Id}, }; 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 // Return success response with Firebase and Odoo details 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] [AllowAnonymous] [Route("SignUpAdmin")] public async System.Threading.Tasks.Task SignUpAdmin([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.Name, }; UserRecord record = await FirebaseAuth.DefaultInstance.CreateUserAsync(userRecordArgs); if (record == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Assign custom claims var claims = new Dictionary() { { ClaimTypes.Role, "Admin"}, { "RoleId", 2}, { "UserId", record.Uid}, }; 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 // Return success response with Firebase and Odoo details 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; } /// /// Admin adds institute details /// /// [HttpPost] [Route("AddInstitute")] [Authorize(Roles = "Admin")] public async System.Threading.Tasks.Task AddInstitute([FromBody] DisplayName domainName) { string returnMessage = string.Empty; IActionResult returnResponse; int institute_id = -1; ClaimsIdentity identity = HttpContext.User.Identity as ClaimsIdentity; //Check if the inssititute is already set string InstituteId = Security.GetValueFromToken("InstituteId", identity); if (InstituteId != null) { institute_id = int.Parse(InstituteId); returnResponse = Ok(ReturnResponse.GetSuccessStatus(institute_id)); return returnResponse; } string slugDomain = _repository.ConvertToSlug(domainName.Name); //Check if the domain name is already picked if (_repository.isUniqueSlug(slugDomain) == false) { responseMessage = _repository.GetMessageByCode(Message.AlreadyExist.ToString(), slugDomain); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } string uuid = Security.GetValueFromToken("user_id", identity); // Get the user record by UID UserRecord userRecord = await FirebaseAuth.DefaultInstance.GetUserAsync(uuid); if(userRecord == null || userRecord.EmailVerified == false) { responseMessage = _repository.GetMessageByCode(UserMessage.InvalidUser.ToString(), Constant.User); returnResponse = BadRequest(ReturnResponse.GetFailureStatus((int)UserMessage.InvalidUser, responseMessage)); return returnResponse; } //Create Institute and Admin in my DB Users user = _repository.SignUpDB(userRecord, slugDomain); if (user == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } /* //Odoo code supress //Create company in Odoo var odooCompanyId = await companyService.CreateCompanyAsync(new { name = domainName.Name, barcode = user.InstituteId, is_company = true }); if (odooCompanyId <= 0) { responseMessage = "Failed to create company in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Create an employee in Odoo var odooEmployeeId = await employeeService.CreateEmployeeAsync(new { name = userRecord.DisplayName, work_email = userRecord.Email, employee_type = "employee", barcode = user.Id }); if (odooEmployeeId <= 0) { responseMessage = "Failed to create employee in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Update odoo employee ID and company ID _repository.updateOdooUser(user.Id, odooEmployeeId); _repository.updateOdooCompany(user.InstituteId, odooCompanyId); */ // Assign custom claims var claims = new Dictionary() { { ClaimTypes.Role, "Admin"}, { "RoleId", user.RoleId}, { "InstituteId", user.InstituteId }, { "UserId", user.Id}, }; await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(userRecord.Uid, claims); returnResponse = Ok(ReturnResponse.GetSuccessStatus(user.InstituteId)); return returnResponse; } [HttpPost] [Authorize(Roles = "Admin")] [Route("AddStudent")] public async System.Threading.Tasks.Task AddStudent([FromBody] SignupUserModel userModel) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { // Create a new user in firebase var userRecordArgs = new UserRecordArgs { DisplayName = userModel.FirstName + userModel.LastName, Email = userModel.Email, EmailVerified = false, // Mark email as not verified initially Disabled = false, }; UserRecord record = await FirebaseAuth.DefaultInstance.CreateUserAsync(userRecordArgs); if (record == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Create student in my DB Users user = _repository.CreateUser(record, base.InstituteId, 4); if (user == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Assign custom claims var claims = new Dictionary() { {ClaimTypes.Role, "Student"}, { "RoleId", user.RoleId}, { "InstituteId", user.InstituteId }, { "UserId", user.Id}, }; await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(record.Uid, claims); var link = await FirebaseAuth.DefaultInstance.GeneratePasswordResetLinkAsync(record.Email); string sent = _repository.SendEmailLink(record.Email, link); Console.WriteLine($"Verification Link: {link}"); // Use email service here /* //Odoo code supress // Step 5: Create an employee in Odoo var odooEmployeeId = await employeeService.CreateEmployeeAsync(new { name = $"{userModel.FirstName} {userModel.LastName}", work_email = userModel.Email, employee_type = "student", barcode = user.Id }); if (odooEmployeeId <= 0) { responseMessage = "Failed to create employee in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Update odoo employee ID and company ID _repository.updateOdooUser(user.Id, odooEmployeeId); */ // Return success response with Firebase and Odoo details returnResponse = Ok(new { Status = "Success", FirebaseLink = 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() })); } catch (Exception ex) { responseMessage = "An unexpected error occurred."; returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message })); } return returnResponse; } /* //Odoo code supress [HttpPost] [Authorize(Roles = "Admin")] [Route("UpdateStudentDetails")] public async System.Threading.Tasks.Task UpdateStudentDetails([FromBody] UpdateUserModel userModel) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { var empId = _repository.getOdooEmpID(userModel.user_id); if (empId == null || empId <= 0) { responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString(), Constant.User); return Ok(ReturnResponse.GetFailureStatus(responseMessage)); } // Step 2: Build update dictionary only with non-null values var updateData = new Dictionary(); if (!string.IsNullOrEmpty(userModel.FirstName) || !string.IsNullOrEmpty(userModel.LastName)) { var fullName = $"{userModel.FirstName ?? ""} {userModel.LastName ?? ""}".Trim(); updateData["name"] = fullName; } if (userModel.gender == 1 || userModel.gender == 2) { // Assuming: 1 = male, 2 = female updateData["gender"] = userModel.gender == 1 ? "male" : "female"; } if (userModel.DateOfBirth != null) { updateData["birthday"] = userModel.DateOfBirth?.ToString("yyyy-MM-dd"); } if (!string.IsNullOrEmpty(userModel.GuardianName) || !string.IsNullOrEmpty(userModel.GuardianContact)) { // Update guardian updateData["emergency_contact"] = userModel.GuardianName; updateData["emergency_phone"] = userModel.GuardianContact; if (userModel.Guardian_relation != null) { updateData["l10n_in_relationship"] = userModel.Guardian_relation; } } // Step 3: Call service to update employee var bResult = await employeeService.UpdateEmployeeAsync(empId, updateData); if (bResult == false) { responseMessage = _repository.GetMessageByCode(Message.FailedToUpdate.ToString(), Constant.User); return Ok(ReturnResponse.GetFailureStatus(responseMessage)); } // Step 3: Get address_home_id (partner id) from employee var partnerId = await employeeService.GetAddressHomeIdByEmployeeIdAsync(empId); if (partnerId > 0) { var partnerUpdateData = new Dictionary(); if (!string.IsNullOrEmpty(userModel.Street)) partnerUpdateData["street"] = userModel.Street; if (!string.IsNullOrEmpty(userModel.City)) partnerUpdateData["city"] = userModel.City; if (!string.IsNullOrEmpty(userModel.Zip)) partnerUpdateData["zip"] = userModel.Zip; if (userModel.StateId.HasValue) partnerUpdateData["state_id"] = userModel.StateId.Value; if (userModel.CountryId.HasValue) partnerUpdateData["country_id"] = userModel.CountryId.Value; await employeeService.UpdatePartnerAsync((int)partnerId, partnerUpdateData); } return Ok(ReturnResponse.GetSuccessStatus("Student details updated successfully.")); } catch (Exception ex) { responseMessage = "An unexpected error occurred."; return Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message, ex.InnerException?.Message })); } } */ [HttpPost] [Authorize(Roles = "Admin")] [Route("AddTeacher")] public async System.Threading.Tasks.Task AddTeacher([FromBody] SignupUserModel userModel) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { // Create a new user var userRecordArgs = new UserRecordArgs { DisplayName = userModel.FirstName + userModel.LastName, Email = userModel.Email, EmailVerified = false, // Mark email as not verified initially Disabled = false, }; UserRecord record = await FirebaseAuth.DefaultInstance.CreateUserAsync(userRecordArgs); if (record == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } Users user = _repository.CreateUser(record, base.InstituteId, 3); if (user == null) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } // Assign custom claims var claims = new Dictionary() { {ClaimTypes.Role, "Teacher"}, { "RoleId", user.RoleId}, { "InstituteId", user.InstituteId }, { "UserId", user.Id}, }; await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(record.Uid, claims); var link = await FirebaseAuth.DefaultInstance.GeneratePasswordResetLinkAsync(record.Email); string sent = _repository.SendEmailLink(record.Email, link); Console.WriteLine($"Verification Link: {link}"); // Use email service here /* //Odoo code supress // Step 5: Create an employee in Odoo var odooEmployeeId = await employeeService.CreateEmployeeAsync(new { name = $"{userModel.FirstName} {userModel.LastName}", work_email = userModel.Email, employee_type = "employee", barcode = user.Id }); if (odooEmployeeId <= 0) { responseMessage = "Failed to create employee in Odoo."; returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //Update odoo employee ID and company ID _repository.updateOdooUser(user.Id, odooEmployeeId); */ // Return success response with Firebase and Odoo details 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(Roles = "Admin, Teacher")] [Authorize(Policy = "SubscriptionRequired")] [Route("MarkAttendance")] public async Task MarkAttendance([FromBody] AttendanceRequest request) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { bool isValidUser = _repository.isValidUser(base.InstituteId, request.userId); if(isValidUser == false) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } int employeeId = _repository.getOdooEmpID(request.userId); string currentTime = DateTime.UtcNow.ToString("HH:mm:ss"); string checkInTime = $"{request.date:yyyy-MM-dd} {currentTime}"; string checkOutTime = $"{request.date:yyyy-MM-dd} {DateTime.UtcNow.AddMinutes(1):HH:mm:ss}"; // Record attendance var attendanceId = await attendanceService.RecordAttendanceAsync(new { employee_id = employeeId, check_in = checkInTime, // Current UTC time check_out = checkOutTime // 1 minute later }); returnResponse = Ok(ReturnResponse.GetSuccessStatus(attendanceId)); } catch (Exception 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(Roles = "Admin, Teacher")] [Authorize(Policy = "SubscriptionRequired")] [Route("MarkAbsent")] public async Task MarkAbsent([FromBody] AttendanceRequest request) { string returnMessage = string.Empty; IActionResult returnResponse = null; try { bool isValidUser = _repository.isValidUser(base.InstituteId, request.userId); if (!isValidUser) { responseMessage = _repository.GetMessageByCode(Message.NotAllowedToResource.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } int employeeId = _repository.getOdooEmpID(request.userId); // Call DeleteAttendanceAsync to delete the attendance record for the employee and date bool isDeleted = await attendanceService.DeleteAttendanceAsync(employeeId, request.date); if (isDeleted) { returnResponse = Ok(ReturnResponse.GetSuccessStatus("Attendance marked as absent successfully.")); } else { responseMessage = _repository.GetMessageByCode(Message.FailedToDelete.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } } catch (Exception 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] [Route("GetAttendanceByDate")] [Authorize(Roles = "Admin, Teacher")] public async Task GetAttendanceByDate([FromBody] AttendanceRequestList request) { IActionResult returnResponse = null; try { if (request.EmployeeIds == null || request.EmployeeIds.Count == 0) { responseMessage = _repository.GetMessageByCode(Message.MustNotEmpty.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } if (request.FromDate >= request.ToDate) { responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } List odooEmployeeIds = _repository.getOdooEmpIDList(request.EmployeeIds); var filterData = new { domain = new List { new object[] { "employee_id", "in", odooEmployeeIds }, new object[] { "check_in", ">=", request.FromDate.ToString("yyyy-MM-dd HH:mm:ss") }, new object[] { "check_in", "<=", request.ToDate.ToString("yyyy-MM-dd HH:mm:ss") } } }; var attendanceRecords = await attendanceService.GetAttendanceAsync(filterData); var attendanceLookup = attendanceRecords .Select(record => ((JsonElement)record).GetProperty("employee_id").EnumerateArray().FirstOrDefault().GetInt32()) .ToHashSet(); var result = request.EmployeeIds .Select((userId, index) => new { EmployeeId = userId, // Database User ID Present = attendanceLookup.Contains(odooEmployeeIds[index]) // Fast lookup }) .ToList(); returnResponse = Ok(ReturnResponse.GetSuccessStatus(result)); } catch (Exception 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] [Route("CreateTimetable")] [Authorize(Roles = "Admin, Teacher")] public async Task CreateTimetable([FromBody] CalendarRequest request) { IActionResult returnResponse = null; try { if (request == null || string.IsNullOrWhiteSpace(request.Title) || request.StartTime >= request.EndTime) { responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } var eventData = new { name = request.Title, start = request.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), stop = request.EndTime.ToString("yyyy-MM-dd HH:mm:ss"), location = request.Location, description = request.Description }; var eventId = await calendarService.CreateEventAsync(eventData); returnResponse = Ok(ReturnResponse.GetSuccessStatus(new { EventId = eventId })); } catch (Exception ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message, ex.InnerException?.Message })); } return returnResponse; } [HttpPost] [Route("GetTimetableByDate")] [Authorize(Roles = "Admin, Teacher")] public async Task GetTimetableByDate([FromBody] CalendarRequestList request) { IActionResult returnResponse = null; try { /* if (request.EmployeeIds == null || request.EmployeeIds.Count == 0) { responseMessage = _repository.GetMessageByCode(Message.MustNotEmpty.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; }*/ if (request.FromDate >= request.ToDate) { responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } //List odooEmployeeIds = _repository.getOdooEmpIDList(request.EmployeeIds); var filterData = new { domain = new List { //new object[] { "employee_id", "in", odooEmployeeIds }, new object[] { "start", ">=", request.FromDate.ToString("yyyy-MM-dd HH:mm:ss") }, new object[] { "stop", "<=", request.ToDate.ToString("yyyy-MM-dd HH:mm:ss") } } }; var calenderRecords = await calendarService.GetEventsAsync(filterData); var eventRecords = calenderRecords .Select(record => { var jsonElement = (JsonElement)record; return new { Id = jsonElement.GetProperty("id").GetInt32(), Name = jsonElement.GetProperty("name").GetString(), Start = jsonElement.GetProperty("start").GetString(), Stop = jsonElement.GetProperty("stop").GetString(), UserId = jsonElement.GetProperty("user_id").EnumerateArray().FirstOrDefault().GetInt32(), PartnerIds = jsonElement.GetProperty("partner_ids").EnumerateArray().Select(p => p.GetInt32()).ToList() }; }) .Select(eventObj => new CalendarRecordList { Id = eventObj.Id, Name = eventObj.Name, Start = eventObj.Start, Stop = eventObj.Stop, UserId = eventObj.UserId, PartnerIds = eventObj.PartnerIds }) .ToList(); returnResponse = Ok(ReturnResponse.GetSuccessStatus(eventRecords)); } catch (Exception ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotAdded.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message, ex.InnerException?.Message })); } return returnResponse; } [HttpPost] [Route("UpdateTimetable")] [Authorize(Roles = "Admin, Teacher")] public async Task UpdateTimetable([FromBody] UpdateMeetingRequest request) { IActionResult returnResponse = null; try { if (request.MeetingId <= 0) { responseMessage = _repository.GetMessageByCode(Message.InvalidInput.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } var updateData = new Dictionary(); if (!string.IsNullOrWhiteSpace(request.Title)) updateData["name"] = request.Title; if (request.StartTime != default) updateData["start"] = request.StartTime.ToString("yyyy-MM-dd HH:mm:ss"); if (request.EndTime != default) updateData["stop"] = request.EndTime.ToString("yyyy-MM-dd HH:mm:ss"); if (!string.IsNullOrWhiteSpace(request.Location)) updateData["location"] = request.Location; if (!string.IsNullOrWhiteSpace(request.Description)) updateData["description"] = request.Description; if (updateData.Count == 0) { responseMessage = _repository.GetMessageByCode(Message.MustNotEmpty.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); return returnResponse; } var success = await calendarService.UpdateMeetingAsync(request.MeetingId, updateData); if (success) { returnResponse = Ok(ReturnResponse.GetSuccessStatus("Meeting updated successfully")); } else { responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(responseMessage)); } } catch (Exception ex) { responseMessage = _repository.GetMessageByCode(Message.ObjectNotUpdated.ToString(), Constant.User); returnResponse = Ok(ReturnResponse.GetFailureStatus(new List { responseMessage, ex.Message, ex.InnerException?.Message })); } 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 /// /// /// [HttpPost("{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; } } }