From 7b0b1c34154836a3b9b7a57ca3caec27c2838d09 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Fri, 28 Aug 2026 18:45:53 +0530 Subject: [PATCH] feat(auth): add Nurse PIN Security Authentication, App QR Codes, and Lock Screen for NursingCare PWA --- app/Config/Routes.php | 2 + app/Controllers/Api/v1/NursingApi.php | 90 +++++++ app/Controllers/Setting/Nurse.php | 6 + app/Models/NurseModel.php | 3 + app/Views/Setting/Nurse/Nurse_Search_V.php | 56 +++- public/App/Nursing/index.html | 294 ++++++++++++++++++--- 6 files changed, 416 insertions(+), 35 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 44c9be2..5e8630a 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -1571,6 +1571,8 @@ $routes->group('api/v1', ['namespace' => 'App\Controllers\Api\v1'], static funct // Nursing PWA APIs $routes->get('nursing/beds', 'NursingApi::beds'); $routes->get('nursing/nurses', 'NursingApi::nurses'); + $routes->post('nursing/auth/verify-pin', 'NursingApi::verifyPin'); + $routes->post('nursing/auth/set-pin', 'NursingApi::setPin'); $routes->get('nursing/workspace/(:num)', 'NursingApi::workspace/$1'); $routes->post('nursing/entry/save/(:num)', 'NursingApi::saveEntry/$1'); }); diff --git a/app/Controllers/Api/v1/NursingApi.php b/app/Controllers/Api/v1/NursingApi.php index 3439a9e..085d393 100644 --- a/app/Controllers/Api/v1/NursingApi.php +++ b/app/Controllers/Api/v1/NursingApi.php @@ -78,6 +78,96 @@ class NursingApi extends BaseController ]); } + /** + * POST api/v1/nursing/auth/verify-pin + */ + public function verifyPin() + { + $post = $this->request->getPost() ?: ($this->request->getJSON(true) ?? []); + $nurseId = (int) ($post['nurse_id'] ?? 0); + $nurseCode = trim((string) ($post['nurse_code'] ?? '')); + $pin = trim((string) ($post['pin'] ?? '')); + + if ($nurseId <= 0 && $nurseCode !== '') { + $nurseRow = db_connect()->table('nurse_master')->where('nurse_code', $nurseCode)->get()->getRowArray(); + } else { + $nurseRow = $this->nurseModel->getNurseById($nurseId); + } + + if (! $nurseRow) { + return $this->response->setStatusCode(404)->setJSON(['status' => 0, 'message' => 'Nurse profile not found']); + } + + $hashedPin = (string) ($nurseRow['app_pin'] ?? ''); + + if ($hashedPin === '') { + return $this->response->setJSON([ + 'status' => 2, + 'message' => 'PIN not set yet. Please set a 4-6 digit PIN.', + 'nurse' => [ + 'id' => (int) $nurseRow['id'], + 'nurse_code' => $nurseRow['nurse_code'], + 'name' => $nurseRow['name'], + 'designation' => $nurseRow['designation'] ?? 'Staff Nurse', + ], + ]); + } + + $isValid = password_verify($pin, $hashedPin) || ($pin === $hashedPin); + + if (! $isValid) { + return $this->response->setStatusCode(401)->setJSON(['status' => 0, 'message' => 'Incorrect Security PIN']); + } + + return $this->response->setJSON([ + 'status' => 1, + 'message' => 'Authentication successful', + 'nurse' => [ + 'id' => (int) $nurseRow['id'], + 'nurse_code' => $nurseRow['nurse_code'], + 'name' => $nurseRow['name'], + 'designation' => $nurseRow['designation'] ?? 'Staff Nurse', + ], + ]); + } + + /** + * POST api/v1/nursing/auth/set-pin + */ + public function setPin() + { + $post = $this->request->getPost() ?: ($this->request->getJSON(true) ?? []); + $nurseId = (int) ($post['nurse_id'] ?? 0); + $newPin = trim((string) ($post['new_pin'] ?? '')); + $oldPin = trim((string) ($post['old_pin'] ?? '')); + + if ($nurseId <= 0 || strlen($newPin) < 4) { + return $this->response->setStatusCode(422)->setJSON(['status' => 0, 'message' => 'Valid Nurse ID and 4-6 digit PIN are required']); + } + + $nurseRow = $this->nurseModel->getNurseById($nurseId); + if (! $nurseRow) { + return $this->response->setStatusCode(404)->setJSON(['status' => 0, 'message' => 'Nurse profile not found']); + } + + $hashedPin = (string) ($nurseRow['app_pin'] ?? ''); + if ($hashedPin !== '' && $oldPin !== '') { + $isValid = password_verify($oldPin, $hashedPin) || ($oldPin === $hashedPin); + if (! $isValid) { + return $this->response->setStatusCode(401)->setJSON(['status' => 0, 'message' => 'Current PIN is incorrect']); + } + } + + $this->nurseModel->updateNurse($nurseId, [ + 'app_pin' => password_hash($newPin, PASSWORD_DEFAULT), + ]); + + return $this->response->setJSON([ + 'status' => 1, + 'message' => 'Security PIN updated successfully', + ]); + } + /** * GET api/v1/nursing/workspace/(:num) */ diff --git a/app/Controllers/Setting/Nurse.php b/app/Controllers/Setting/Nurse.php index 54ba2e8..d250c75 100644 --- a/app/Controllers/Setting/Nurse.php +++ b/app/Controllers/Setting/Nurse.php @@ -53,6 +53,8 @@ class Nurse extends BaseController $nurseCode = 'NUR-' . str_pad((string) (rand(100, 999)), 3, '0', STR_PAD_LEFT); } + $appPin = trim((string) ($this->request->getPost('app_pin') ?? '')); + $payload = [ 'nurse_code' => $nurseCode, 'name' => $name, @@ -67,6 +69,10 @@ class Nurse extends BaseController 'is_active' => $isActive, ]; + if ($appPin !== '') { + $payload['app_pin'] = password_hash($appPin, PASSWORD_DEFAULT); + } + if ($id > 0) { $this->nurseModel->updateNurse($id, $payload); $savedId = $id; diff --git a/app/Models/NurseModel.php b/app/Models/NurseModel.php index 096a050..819ecd3 100644 --- a/app/Models/NurseModel.php +++ b/app/Models/NurseModel.php @@ -52,6 +52,9 @@ class NurseModel if (! in_array('designation', $fields, true)) { $this->db->query("ALTER TABLE nurse_master ADD COLUMN designation VARCHAR(100) NULL AFTER gender"); } + if (! in_array('app_pin', $fields, true)) { + $this->db->query("ALTER TABLE nurse_master ADD COLUMN app_pin VARCHAR(255) NULL AFTER email"); + } return true; } diff --git a/app/Views/Setting/Nurse/Nurse_Search_V.php b/app/Views/Setting/Nurse/Nurse_Search_V.php index d5fa4e5..273a0d9 100644 --- a/app/Views/Setting/Nurse/Nurse_Search_V.php +++ b/app/Views/Setting/Nurse/Nurse_Search_V.php @@ -83,6 +83,9 @@ + @@ -185,6 +188,15 @@ + + +
+
+ + + Used by nurse to login to NursingCare PWA App +
+
+ + +