tstat_be/app/Controllers/UserController.php

941 lines
31 KiB
PHP

<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use App\Models\UserModel;
use App\Models\MailTemplateModel;
use App\Models\UserFrequentFlierInformationModel;
use App\Models\UserHotelMembershipModel;
use App\Models\UserVisaDetailsModel;
use PhpOffice\PhpSpreadsheet\IOFactory;
class UserController extends ResourceController
{
protected $format = 'json';
protected $myLogger;
protected $userModel;
protected $mailTemplateModel;
protected $userFrequentFlierInformationModel;
protected $userHotelMembershipModel;
protected $userVisaDetailsModel;
public function __construct()
{
$this->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','Fourth 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);
$maxColumns = 12;
$trimmedData = array_map(function ($row) use ($maxColumns) {
return array_slice($row, 0, $maxColumns);
}, $sheetData);
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
$rawHeaders = array_values($trimmedData[1]);
$headers = array_map(function ($header) {
return strtolower(preg_replace('/[^a-zA-Z0-9]/', '', trim($header)));
}, $rawHeaders);
$predefinedHeaders = array_map(function ($header) {
return strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $header));
}, $predefinedHeaders);
unset($trimmedData[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','fourth_approver_email'];
$rolesList = $this->userModel->getRolesList();
$groupsList = $this->userModel->getgroupsList();
foreach ($trimmedData 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['fourth_approver_email']) && !filter_var($user['fourth_approver_email'], FILTER_VALIDATE_EMAIL)) {
$fail++;
$failedUsers[] = ['data' => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid fourth_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['fourth_approver_email'] = filter_var($user['fourth_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('fourth', $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);
}
}