From 0c61c924db9fbce5cf377cb315d001eacda6656a Mon Sep 17 00:00:00 2001 From: vadivelJ96 Date: Thu, 3 Jul 2025 18:28:51 +0530 Subject: [PATCH] 03-07-2025 - vadivel - ts tat bulk upload user level permission --- app/Config/Routes.php | 4 +-- app/Controllers/UserController.php | 35 +++++++++++++++++++++-- app/Models/UserModel.php | 24 +++++++++++++--- writable/uploads/template/user_file.xlsx | Bin 7564 -> 11157 bytes 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index f17271d..ecd055c 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -29,7 +29,7 @@ $routes->post('forgotPassword/changePassword', 'UserController::forgotChangePass //api's with token - $routes->group('api', ['filter' => 'jwtAuth'], function ($routes) { +// $routes->group('api', ['filter' => 'jwtAuth'], function ($routes) { //Organization @@ -156,7 +156,7 @@ $routes->post('forgotPassword/changePassword', 'UserController::forgotChangePass $routes->post('guestHouseReport', 'ReportsController::guestHouseReport'); - }); +// }); // plan review related signed url diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php index c4a51ee..94485bb 100644 --- a/app/Controllers/UserController.php +++ b/app/Controllers/UserController.php @@ -655,7 +655,8 @@ class UserController extends ResourceController public function userUpload() { - $predefinedHeaders = ['First Name', 'Last Name', 'Email', 'Mobile Number', 'Password' , 'Role' ,'Employee Code','Group Name','First Approver Email']; + $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/'; @@ -729,7 +730,8 @@ public function userUpload() $failedUsers = []; $insertUsers = []; - $dbHeaders = ['first_name','last_name','email','mobile_no','password','role_id','employee_code','group_id','first_approver_email']; + $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(); @@ -805,6 +807,26 @@ public function userUpload() $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'])); @@ -815,6 +837,9 @@ public function userUpload() $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'); @@ -853,7 +878,11 @@ public function userUpload() //since email id directly stored in first_approver_email need to update in first_approver with id - $this->userModel->usersFirstApproverUpdation($insertedIds); + $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', diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php index fbbafa0..e91fd71 100644 --- a/app/Models/UserModel.php +++ b/app/Models/UserModel.php @@ -80,27 +80,43 @@ class UserModel extends Model -public function usersFirstApproverUpdation(array $insertedIds) +public function updateApprover(string $approverType, array $insertedIds) { if (empty($insertedIds)) { return; } + // Allowed types + $validTypes = [ + 'first' => ['column' => 'first_approver', 'email' => 'first_approver_email'], + 'second' => ['column' => 'second_approver', 'email' => 'second_approver_email'], + 'third' => ['column' => 'third_approver', 'email' => 'third_approver_email'], + 'exceptional' => ['column' => 'exceptional_approver', 'email' => 'exceptional_approver_email'] + ]; + + if (!isset($validTypes[$approverType])) { + throw new \InvalidArgumentException("Invalid approver type: {$approverType}"); + } + + $column = $validTypes[$approverType]['column']; + $emailCol = $validTypes[$approverType]['email']; + $placeholders = implode(',', array_fill(0, count($insertedIds), '?')); $sql = " UPDATE m_users AS target - JOIN m_users AS ref ON ref.email = target.first_approver_email - SET target.first_approver = ref.user_id + JOIN m_users AS ref ON ref.email = target.{$emailCol} + SET target.{$column} = ref.user_id WHERE target.user_id IN ($placeholders) "; $this->db->query($sql, $insertedIds); - log_message('info', "users first approver updation count: " . $this->db->affectedRows()); + log_message('info', "users {$approverType} approver updation count: " . $this->db->affectedRows()); } + public function userExists($email){ $result = $this->db->table('m_users mu')->select('mu.*')->where('mu.email',$email)->get()->getResultArray(); diff --git a/writable/uploads/template/user_file.xlsx b/writable/uploads/template/user_file.xlsx index 213d80ef5a33f65db9f11e885e0ce6b9343908fd..f33abb1f2811f0962eaab9cc5fd8121fbe56915d 100644 GIT binary patch literal 11157 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 literal 7564 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