myLogger = \Config\Services::mylogger(); $this->userModel = new UserModel(); $this->mailTemplateModel = new MailTemplateModel(); $this->userFrequentFlierInformationModel = new UserFrequentFlierInformationModel(); $this->userHotelMembershipModel = new UserHotelMembershipModel(); $this->userVisaDetailsModel = new UserVisaDetailsModel(); } public function index() { $orgId = $this->request->getGet('org_id'); $for = $this->request->getGet('for'); if(isset($for)){ $active = [0,1]; }else{ $active = [1]; } $users = $this->userModel->getUsers($orgId,$active,[1,2,3,4]); if (!$users) { return $this->failNotFound('No users found'); } return $this->respond([ 'status' => 200, 'message' => 'Users retrieved successfully', 'data' => $users ]); } public function agentList() { $orgId = $this->request->getGet('org_id'); $for = $this->request->getGet('for'); if(isset($for)){ $active = [0,1]; }else{ $active = [1]; } $users = $this->userModel->getUsers($orgId,$active,[5]); if (!$users) { return $this->failNotFound('No users found'); } return $this->respond([ 'status' => 200, 'message' => 'Users retrieved successfully', 'data' => $users ]); } public function create() { $rules = [ 'first_name' => 'required', 'email' => 'required|valid_email|is_unique[m_users.email]', ]; $postData = $this->request->getPost(); //mailcontent data $mailData = [ 'first_name' => $postData['first_name'], 'last_name' => $postData['last_name'], 'email' => $postData['email'], 'password' => $postData['password'], 'org_id' => env('ORG_id'), 'site_url' => env('FE_URL'), 'template' => 'user_creation_notification', ]; if (!$this->validate($rules)) { return $this->failValidationErrors($this->validator->getErrors()); } // $postData = $this->request->getJSON(true); $data = $this->formatUserData($postData); // Hash password before inserting into the database if (isset($data['password'])) { $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT); } $data['org_id'] = env('ORG_id'); // Handle file upload $file = $this->request->getFile('passport_document'); if ($file && $file->isValid() && !$file->hasMoved()) { $newName = $file->getRandomName(); // Generate a unique name $uploadPath = FCPATH.'assets/images/passport'; // Move file to the specified directory $file->move($uploadPath, $newName); // Save file path in database $data['passport_document'] = $uploadPath . '/' . $newName; } else { // return $this->failValidationErrors(['passport_document' => 'Invalid file upload']); } try { $insert_id = $this->userModel->insert($data); //insert other user data ( hotal membership, visa details, frequent filler ) $this->createOrUpdateUserOtherDetails($insert_id, $data); //trigger Mail sendUserCreationMail($mailData); return $this->respondCreated([ 'status' => 201, 'message' => 'User created successfully', 'data' => $postData ]); } catch (\Exception $e) { return $this->failServerError('Failed to create user: ' . $e->getMessage()); } } public function find($id = null) { if (!$id) { return $this->failNotFound('User ID is required'); } // Fetch user by ID $user = $this->userModel->find($id); if (!$user) { return $this->failNotFound('User not found'); } $user = $this->formatUserDataForEdit($user); $frequentFlierInformation = $this->userFrequentFlierInformationModel->where('user_id', $id)->findAll() ?? []; $hotelMembership = $this->userHotelMembershipModel->where('user_id', $id)->findAll() ?? []; $visaDetails = $this->userVisaDetailsModel->where('user_id', $id)->findAll() ?? []; $user['travel_details']['frequent_flier_information'] = $frequentFlierInformation; $user['travel_details']['hotel_membership'] = $hotelMembership; $user['travel_details']['visa_details'] = $visaDetails; //formate the date to the indian date format $user = $this->convertDateToDBFormat($user, 'd-m-Y'); return $this->respond([ 'status' => 200, 'message' => 'User retrieved successfully', 'data' => $user ]); } public function update($id = null) { if (!$id) { return $this->failNotFound('User ID is required'); } $postData = $this->request->getPost(); // $postData = $this->request->getJSON(true); $data = $this->formatUserData($postData); if (empty($data)) { return $this->failValidationErrors('No data provided for update'); } // Check if user exists $user = $this->userModel->find($id); if (!$user) { return $this->failNotFound('User not found'); } // Handle file upload $file = $this->request->getFile('passport_document'); if ($file && $file->isValid() && !$file->hasMoved()) { $newName = $file->getRandomName(); // Generate a unique file name $uploadPath = FCPATH.'assets/images/passport'; // Move file to the directory $file->move($uploadPath, $newName); // Delete the old file if it exists if (!empty($user['passport_document']) && file_exists($user['passport_document'])) { unlink($user['passport_document']); // Remove old file } // Save the new file path $data['passport_document'] = $uploadPath . '/' . $newName; } // Update user details try { unset($data['password']); $this->userModel->update($id, $data); //update other user data ( hotal membership, visa details, frequent filler ) $this->createOrUpdateUserOtherDetails($id, $data); return $this->respond([ 'status' => 200, 'message' => 'User updated successfully', 'data' => $postData ]); } catch (\Exception $e) { return $this->failServerError('Failed to update user: ' . $e->getMessage()); } } public function changePassword($id = null) { if (!$id) { return $this->failNotFound('User ID is required'); } $data = $this->request->getJSON(true); // Fetch user details $user = $this->userModel->find($id); if (!$user) { return $this->failNotFound('User not found'); } // Hash new password $newPasswordHash = password_hash($data['password'], PASSWORD_DEFAULT); // Update password try { $this->userModel->update($id, ['password' => $newPasswordHash]); return $this->respond([ 'status' => 200, 'message' => 'Password changed successfully' ]); } catch (\Exception $e) { return $this->failServerError('Failed to change password: ' . $e->getMessage()); } } public function updateUserStatus($id) { // Fetch user by ID $user = $this->userModel->find($id); if (!$user) { return $this->failNotFound('User not found'); } // Toggle the is_active status $newStatus = $user['is_active'] == 1 ? 0 : 1; // Update user status $this->userModel->update($id, ['is_active' => $newStatus]); return $this->respond([ 'status' => 200, 'message' => $newStatus ? 'User activated successfully' : 'User deactivated successfully', 'is_active' => $newStatus ]); } public function roleList() { // Fetch all roles $roles = db_connect()->table('m_role')->orderBy('id', 'asc')->get()->getResultArray(); // Check roles exist if (!$roles) { log_message('error', 'No roles found in roleList()'); return $this->failNotFound('No roles found'); } log_message('error', 'Roles retrieved successfully in roleList()'); return $this->respond([ 'status' => 200, 'message' => 'Roles retrieved successfully', 'data' => $roles ]); } public function verifyUser() { $data = $this->request->getJSON(true); if (empty($data)) { log_message('error', "No data provided for user verification"); return $this->failValidationErrors('No data provided for verification'); } if (!isset($data['email']) || empty($data['email'])) { log_message('error', "Email is missing or empty for user verification"); return $this->failValidationErrors('Email is required for user verification'); } //featch user data for the give email $userData = $this->userModel->where('email', $data['email'])->first(); if(empty($userData)){ log_message('error', "User not found"); return $this->failNotFound('User not found'); } if ($userData['is_active'] == 0) { log_message('error', "User found but not active"); return $this->failNotFound('User found but not active, no further action to be made'); } //generate random number for OTP $temp_password = random_int(100000, 999999); $userData['otp'] = $temp_password; log_message('error', "Generated temp password : ".$temp_password ?? "-"); //update otp to the given email user $return_value = $this->userModel->where('email', $data['email'])->set('temp_password', $temp_password)->update(); log_message('error', "Temp password updated successfully aginst the user email"); //mail send function $mail_response = send_email($userData['org_id'], $data['email'], 'forgot_password_otp', $userData); // print_r($mail_response); $data = [ "request_data" => $data, "mail_response" => $mail_response, ]; return $this->respond([ 'status' => 200, 'message' => 'User verified successfully. Mail send to the given mail-id', 'data' => $data, ]); } public function forgotChangePassword() { $data = $this->request->getJSON(true); if (empty($data)) { log_message('error', "No data provided for forgot change password"); return $this->failValidationErrors('No data provided for change password'); } if (!isset($data['email']) || empty($data['email'])) { log_message('error', "email is missing or empty for forgot change password"); return $this->failValidationErrors('Email id is required for change password'); } if (!isset($data['otp']) || empty($data['otp'])) { log_message('error', "Temp password is missing or empty for forgot change password"); return $this->failValidationErrors('OTP is required for change password'); } if (!isset($data['new_password']) || empty($data['new_password'])) { log_message('error', "New password is missing or empty for forgot change password"); return $this->failValidationErrors('New password is required for change password'); } if (!isset($data['confirm_password']) || empty($data['confirm_password'])) { log_message('error', "Confirm password is missing or empty for forgot change password"); return $this->failValidationErrors('Confirm password is required for change password'); } if (!isset($data['confirm_password']) || empty($data['confirm_password'])) { log_message('error', "Confirm password is missing or empty for forgot change password"); return $this->failValidationErrors('Confirm password is required for change password'); } //featch user data for the give email $userData = $this->userModel->where('email', $data['email'])->first(); if(empty($userData)){ log_message('error', "User not found"); return $this->failNotFound('User not found'); } if ($userData['is_active'] == 0) { log_message('error', "User found but not active"); return $this->failNotFound('User found but not active, no further action to be made'); } if($userData['temp_password'] !== $data['otp']){ log_message('error', "Invalid OTP"); return $this->failValidationErrors('Invalid OTP'); } if($data['new_password'] !== $data['confirm_password']){ log_message('error', "New password as not same as the confirm password"); return $this->failValidationErrors('New password as not same as the confirm password'); } //construct the updated data $update_data = [ 'password' => password_hash($data['new_password'], PASSWORD_DEFAULT), 'temp_password' => null ]; $return_value = $this->userModel->where('user_id', $userData['user_id'])->set($update_data)->update(); log_message('error', "Password changed successfully and Temp password reseted successfully aginst the user id"); return $this->respond([ 'status' => 200, 'message' => 'Password changed successfully.', ]); } public function createOrUpdateUserOtherDetails($user_id, $data) { //insert or update frequent flier information if(!empty($data) && isset($data['frequent_flier_information']) && !empty($data['frequent_flier_information'])){ foreach ($data['frequent_flier_information'] as $key => $value) { $value['user_id'] = $user_id; if(isset($value['id']) && !empty($value['id'])){ $this->userFrequentFlierInformationModel->update($value['id'], $value); }else{ $this->userFrequentFlierInformationModel->insert($value); } } } //insert or update hotel membership if(!empty($data) && isset($data['hotel_membership']) && !empty($data['hotel_membership'])){ foreach ($data['hotel_membership'] as $key => $value) { $value['user_id'] = $user_id; if(isset($value['id']) && !empty($value['id'])){ $this->userHotelMembershipModel->update($value['id'], $value); }else{ $this->userHotelMembershipModel->insert($value); } } } //insert or update visa details if(!empty($data) && isset($data['visa_details']) && !empty($data['visa_details'])){ foreach ($data['visa_details'] as $key => $value) { $value['user_id'] = $user_id; if(isset($value['id']) && !empty($value['id'])){ $this->userVisaDetailsModel->update($value['id'], $value); }else{ $this->userVisaDetailsModel->insert($value); } } } return true; } public function formatUserData($data) { if (empty($data)) { return $data; } if (isset($data['travel_details'])) { if (!is_array($data['travel_details'])) { $decoded = json_decode($data['travel_details'], true); if (json_last_error() === JSON_ERROR_NONE) { $data['travel_details'] = $decoded; //format the date to the database format $data = $this->convertDateToDBFormat($data); } else { return $data; } } $data = array_merge($data, $data['travel_details']); unset($data['travel_details']); } return $data; } public function formatUserDataForEdit($data) { if (!empty($data)) { $travelKeys = [ 'passport_firstname', 'passport_middlename', 'passport_lastname', 'nationality', 'passport_number', 'place_of_issue', 'passport_document', 'date_of_expiry', 'd_meal_preference', 'd_seat_preference', 'd_additonalInfo', 'i_meal_preference', 'i_seat_preference', 'i_additonalInfo', 'emergency_contact_number', 'date_of_issue', 'forex_pre_paid_card_number', 'forex_expiry_date', ]; $data['travel_details'] = []; foreach ($travelKeys as $key) { if (array_key_exists($key, $data)) { $data['travel_details'][$key] = $data[$key]; unset($data[$key]); } else { $data['travel_details'][$key] = null; } } } return $data; } //Function for date conversion public function convertDateToDBFormat($data, $format = 'Y-m-d') { if (!empty($data)) { // Handle date_of_birth if (isset($data['date_of_birth'])) { $dob = trim($data['date_of_birth']); $timestamp = ($dob && $dob !== '0000-00-00' && $dob !== '0000-00-00 00:00:00') ? strtotime($dob) : false; $data['date_of_birth'] = ($timestamp) ? date($format, $timestamp) : null; } // Handle delegation_start_date if (isset($data['delegation_start_date'])) { $dob = trim($data['delegation_start_date']); $timestamp = ($dob && $dob !== '0000-00-00' && $dob !== '0000-00-00 00:00:00') ? strtotime($dob) : false; $data['delegation_start_date'] = ($timestamp) ? date($format, $timestamp) : null; } // Handle delegation_end_date if (isset($data['delegation_end_date'])) { $dob = trim($data['delegation_end_date']); $timestamp = ($dob && $dob !== '0000-00-00' && $dob !== '0000-00-00 00:00:00') ? strtotime($dob) : false; $data['delegation_end_date'] = ($timestamp) ? date($format, $timestamp) : null; } if (!empty($data['travel_details']) && is_array($data['travel_details'])) { // Handle date_of_issue if (isset($data['travel_details']['date_of_issue'])) { $doi = trim($data['travel_details']['date_of_issue']); $timestamp = ($doi && $doi !== '0000-00-00' && $doi !== '0000-00-00 00:00:00') ? strtotime($doi) : false; $data['travel_details']['date_of_issue'] = ($timestamp) ? date($format, $timestamp) : null; } // Handle date_of_expiry if (isset($data['travel_details']['date_of_expiry'])) { $doe = trim($data['travel_details']['date_of_expiry']); $timestamp = ($doe && $doe !== '0000-00-00' && $doe !== '0000-00-00 00:00:00') ? strtotime($doe) : false; $data['travel_details']['date_of_expiry'] = ($timestamp) ? date($format, $timestamp) : null; } // Handle forex_expiry_date if (isset($data['travel_details']['forex_expiry_date'])) { $fed = trim($data['travel_details']['forex_expiry_date']); $timestamp = ($fed && $fed !== '0000-00-00' && $fed !== '0000-00-00 00:00:00') ? strtotime($fed) : false; $data['travel_details']['forex_expiry_date'] = ($timestamp) ? date($format, $timestamp) : null; } // Handle visa_details if (!empty($data['travel_details']['visa_details']) && is_array($data['travel_details']['visa_details'])) { foreach ($data['travel_details']['visa_details'] as $key => &$value) { // valid_from $from = trim($value['valid_from'] ?? ''); $timestamp1 = ($from && $from !== '0000-00-00' && $from !== '0000-00-00 00:00:00') ? strtotime($from) : false; $value['valid_from'] = ($timestamp1) ? date($format, $timestamp1) : null; // valid_upto $upto = trim($value['valid_upto'] ?? ''); $timestamp2 = ($upto && $upto !== '0000-00-00' && $upto !== '0000-00-00 00:00:00') ? strtotime($upto) : false; $value['valid_upto'] = ($timestamp2) ? date($format, $timestamp2) : null; } unset($value); } } } return $data; } public function checkDuplicate() { $request = $this->request->getGet(); // Define supported fields $validFields = ['email', 'mobile_no', 'forex_pre_paid_card_number', 'employee_code', 'passport_number']; $conditions = []; $fieldName = null; // Determine which field is provided foreach ($validFields as $field) { if (!empty($request[$field])) { $conditions[$field] = $request[$field]; $fieldName = $field; break; // only one field allowed at a time } } if (!$fieldName) { return $this->response->setJSON([ 'status' => 'error', 'message' => 'One of the following is required: email, mobile_no, forex_pre_paid_card_number, employee_code' ])->setStatusCode(400); } $builder = $this->userModel->where($fieldName, $conditions[$fieldName]); // Optional: exclude user_id if (!empty($request['user_id'])) { $builder->where('user_id !=', $request['user_id']); } $user = $builder->first(); if ($user) { return $this->response->setJSON(['status' => 'exists', 'field' => $fieldName]); } else { return $this->response->setJSON(['status' => 'not', 'field' => $fieldName]); } } public function userUpload() { $predefinedHeaders = ['First Name', 'Last Name', 'Email', 'Mobile Number', 'Password' , 'Role' ,'Employee Code','Group Name', 'First Approver Email','Second Approver Email','Third Approver Email','Exceptional Approver Email']; $uploadDir = WRITEPATH . 'uploads/userUploadFiles/'; // Create folder if not exists createDirectoryWith0777Permission($uploadDir); $file = $this->request->getFile('user_file'); if (!isValidUploadedFile($file)) { return $this->response->setJSON([ 'status' => 'failed', 'message' => "Invalid file or file not uploaded.", 'data' => ['successfulUsers' => [],'failedUsers' => [] ] ]); } if (!isAllowedExtension($file, ['xlsx', 'xls'])) { return $this->response->setJSON([ 'status' => 'failed', 'message' => "Only Excel files are allowed.", 'data' => ['successfulUsers' => [],'failedUsers' => [] ] ]); } // Move file temporarily $randomName = $file->getRandomName(); $file->move($uploadDir, $randomName); $filePath = $uploadDir . $randomName; // Load Excel $spreadsheet = IOFactory::load($filePath); $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); if (!isExcelNotEmpty($sheetData)) { // before return remove the empty file return $this->response->setJSON([ 'status' => 'failed', 'message' => "Excel sheet is empty or has no data.", 'data' => ['successfulUsers' => [],'failedUsers' => [] ] ]); } // Validate headers // Sanitize headers: remove spaces/special characters and convert to lowercase $headers = array_map(function ($header) { return strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $header)); }, array_values($sheetData[1])); $predefinedHeaders = array_map(function ($header) { return strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $header)); }, $predefinedHeaders); if ($headers != $predefinedHeaders) { //before return remove the empty file return $this->response->setJSON([ 'status' => 'failed', 'message' => "Invalid headers in Excel file.", 'data' => ['successfulUsers' => [],'failedUsers' => [] ] ]); } unset($sheetData[1]); // Remove header row $success = 0 ; $fail = 0 ; $successfulUsers = []; $failedUsers = []; $insertUsers = []; $dbHeaders = ['first_name','last_name','email','mobile_no','password','role_id','employee_code','group_id', 'first_approver_email','second_approver_email','third_approver_email','exceptional_approver_email']; $rolesList = $this->userModel->getRolesList(); $groupsList = $this->userModel->getgroupsList(); // foreach ($sheetData as $row) { // $user = array_combine($dbHeaders, array_values($row)); // if (!isset($user['email']) || empty($user['email']) || !filter_var($user['email'], FILTER_VALIDATE_EMAIL)) { // $fail++; // $failedUsers [] = $user['email'] ; // continue ; // } // $userExists = $this->userModel->userExists($user['email']); // if ( !$userExists) { // //insert // $user['password_string'] = $user['password']; // $user['password'] = password_hash($user['password'], PASSWORD_DEFAULT); // $user['email'] = filter_var($user['email'], FILTER_SANITIZE_EMAIL); // $user['first_approver_email'] = filter_var($user['first_approver_email'], FILTER_SANITIZE_EMAIL); // $role = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $user['role_id'])); // $group = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $user['group_id'])); // $user['role_id'] = $rolesList[$role] ?? '4' ; // $user['group_id'] = $groupsList[$group] ?? Null ; // $user['org_id'] = env('ORG_id'); // $insertUsers [] = $user ; // $success++; // $successfulUsers [] = $user['email'] ; // } // } foreach ($sheetData as $row) { $user = array_combine($dbHeaders, array_values($row)); $email = $user['email'] ?? 'N/A'; // Email validation if (!isset($user['email']) || empty($user['email'])) { $fail++; $failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Email is missing']; continue; } if (!filter_var($user['email'], FILTER_VALIDATE_EMAIL)) { $fail++; $failedUsers[] = ['data' => $email, 'reason' => 'Invalid email format']; continue; } // Check duplicate $userExists = $this->userModel->userExists($user['email']); if ($userExists) { $fail++; $failedUsers[] = ['data' => $email, 'reason' => 'User already exists']; continue; } // Check approver mail valid if (!empty($user['first_approver_email']) && !filter_var($user['first_approver_email'], FILTER_VALIDATE_EMAIL)) { $fail++; $failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid first approver email format' ]; continue; } if (!empty($user['second_approver_email']) && !filter_var($user['second_approver_email'], FILTER_VALIDATE_EMAIL)) { $fail++; $failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid second_approver_email format' ]; continue; } if (!empty($user['third_approver_email']) && !filter_var($user['third_approver_email'], FILTER_VALIDATE_EMAIL)) { $fail++; $failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid third_approver_email format' ]; continue; } if (!empty($user['exceptional_approver_email']) && !filter_var($user['exceptional_approver_email'], FILTER_VALIDATE_EMAIL)) { $fail++; $failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid exceptional_approver_email format' ]; continue; } $role = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $user['role_id'])); $group = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $user['group_id'])); // Sanitize and prepare for insert $user['password_string'] = $user['password']; $user['password'] = password_hash($user['password'], PASSWORD_DEFAULT); $user['email'] = filter_var($user['email'], FILTER_SANITIZE_EMAIL); $user['first_approver_email'] = filter_var($user['first_approver_email'], FILTER_SANITIZE_EMAIL); $user['second_approver_email'] = filter_var($user['second_approver_email'], FILTER_SANITIZE_EMAIL); $user['third_approver_email'] = filter_var($user['third_approver_email'], FILTER_SANITIZE_EMAIL); $user['exceptional_approver_email'] = filter_var($user['exceptional_approver_email'], FILTER_SANITIZE_EMAIL); $user['role_id'] = $rolesList[$role] ?? 4; $user['group_id'] = $groupsList[$group] ?? null; $user['org_id'] = env('ORG_id'); $insertUsers[] = $user; $success++; $successfulUsers[] = $user['email']; } $insertedIds = []; foreach ($insertUsers as $user) { $insertSuccess = $this->userModel->insert($user); if ($insertSuccess) { $insertedIds[] = $this->userModel->getInsertID(); // Prepare mail content $mailData = [ 'first_name' => $user['first_name'], 'last_name' => $user['last_name'], 'email' => $user['email'], 'password' => $user['password_string'], 'org_id' => env('ORG_id'), 'site_url' => env('FE_URL'), 'template' => 'user_creation_notification', ]; // Trigger mail sendUserCreationMail($mailData); } } //since email id directly stored in first_approver_email need to update in first_approver with id $this->userModel->updateApprover('first', $insertedIds); $this->userModel->updateApprover('second', $insertedIds); $this->userModel->updateApprover('third', $insertedIds); $this->userModel->updateApprover('exceptional', $insertedIds); return $this->response->setJSON([ 'status' => 'success', 'message' => "$success users processed successfully, $fail failed.", 'data' => [ 'successfulUsers' => $successfulUsers, 'failedUsers' => $failedUsers ] ]); } public function userUploadTemplate() { $uploadDir = WRITEPATH . 'uploads/template'; createDirectoryWith0777Permission($uploadDir); $filePath = WRITEPATH . 'uploads/template/user_file.xlsx'; if (!file_exists($filePath)) { return $this->response->setStatusCode(404)->setJSON(['error' => 'Template file not found.']); } return $this->response->download($filePath, null); } }