diff --git a/services/nginx/app/objects/department_daily_reports_o.php b/services/nginx/app/objects/department_daily_reports_o.php index 6dc29fc9..305a79e2 100644 --- a/services/nginx/app/objects/department_daily_reports_o.php +++ b/services/nginx/app/objects/department_daily_reports_o.php @@ -298,19 +298,23 @@ class department_daily_reports_o extends db /** * Check if a department daily report exists for today * @param int $department_id The id of the department + * @param string $date The date to check for (YYYY-MM-DD) * @return bool True if the report exists, false otherwise */ - public function doesDepartmentDailyReportExist(int $department_id): bool + public function doesDepartmentDailyReportExist(int $department_id, string $date = 'today'): bool { global $db; + if ($date === 'today') { + $date = date('Y-m-d'); + } $conn = $db->conn(); $stmt = $conn->prepare( 'SELECT COUNT(*) as amount FROM department_daily_reports o - WHERE o.department_id = ? AND DATE(o.created_at) = CURDATE()' + WHERE o.department_id = ? AND DATE(o.created_at) = ?' ); if ($stmt) { - $stmt->bind_param('i', $department_id); // Bind parameters (i = integer, s = string) + $stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string) $stmt->execute(); $result = $stmt->get_result(); // Get the result set from the statement $data = $result->fetch_assoc(); // Fetch the result as an associative array @@ -393,4 +397,60 @@ class department_daily_reports_o extends db } return (int)$amount; } + + /** + * Check if a department daily report exists for today + * @param int $department_id The id of the department + * @return bool True if the report exists, false otherwise + */ + public function hasReportForToday(int $department_id): bool + { + return $this->doesDepartmentDailyReportExist($department_id); + } + + /** + * Select the department daily report for a given date + * @param int $department_id The id of the department + * @param string $date The date to get the report for (YYYY-MM-DD) + * @return department_daily_reports_o The department daily report + * @throws Exception If a department daily report does not exist for today + * @throws Exception If the object was not selected + */ + public function selectDepartmentReportByDate(int $department_id, string $date): department_daily_reports_o + { + global $db; + if (!$this->doesDepartmentDailyReportExist($department_id, $date)) { + throw new Exception('Department daily report does not exist'); + } + $conn = $db->conn(); + $stmt = $conn->prepare( + 'SELECT id FROM department_daily_reports o + WHERE o.department_id = ? AND DATE(o.created_at) = ?' + ); + // Check if the statement was prepared successfully + if ($stmt) { + $stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string) + $stmt->execute(); + $result = $stmt->get_result(); // Get the result set from the statement + $data = $result->fetch_assoc(); // Fetch the result as an associative array + + // Access the "amount" field + if (!$data) { + throw new Exception('Department daily report does not exist'); + } + $id = $data['id']; + + $stmt->close(); // Close the statement + } else { + // Handle query preparation error + die('Query preparation failed: ' . $conn->error); + } + $this->select($id); + return $this; + } + + public function hasReport(int $department_id, string $date): bool + { + return $this->doesDepartmentDailyReportExist($department_id, $date); + } } \ No newline at end of file diff --git a/services/nginx/app/routes/departmentDailyReportsRoute.php b/services/nginx/app/routes/departmentDailyReportsRoute.php index 39c80cef..cd5d5174 100644 --- a/services/nginx/app/routes/departmentDailyReportsRoute.php +++ b/services/nginx/app/routes/departmentDailyReportsRoute.php @@ -31,9 +31,11 @@ class departmentDailyReportsRoute // The fields that can be searched. This would otherwise make it possible to get secret information from the database, simply by searching for it and getting the result count back 'id', 'water_usage', + 'water_usage_morning', 'notes', 'filled_by', - 'created_at' + 'created_at', + 'department_id', ]) ->listObjectsWithPaginationIfSet( function ($department_report) use ($user) { @@ -41,6 +43,7 @@ class departmentDailyReportsRoute 'id' => (int)$department_report['id'], 'department_id' => (int)$department_report['department_id'], 'water_usage' => (int)$department_report['water_usage'], + 'water_usage_morning' => (int)$department_report['water_usage_morning'], 'notes' => (string)$department_report['notes'], 'filled_by' => (int)$department_report['filled_by'], 'created_at' => (string)$department_report['created_at'], @@ -68,7 +71,7 @@ class departmentDailyReportsRoute ] ); - $this->get('/departments/daily-reports/latest', function () { + $this->get('/departments/daily-reports/get', function () { // Require the user to be logged in global $response; $this->requirePermission('list_department_daily_reports'); @@ -79,7 +82,8 @@ class departmentDailyReportsRoute // Check if the required fields are set self::requireParameters( [ - 'id' + 'id', + 'date' ] ); // Validate the department_id @@ -92,6 +96,16 @@ class departmentDailyReportsRoute (int)self::getParameter('id'), 1 ); + // Require the date to be at least 0 characters long + self::requireMinLength( + 'date', + 0 + ); + // Validate the date + self::requireDateFormat( + (string)self::getParameter('date'), + self::FORMAT_DATE() + ); // Determine if the user has access to the department self::requireDepartmentAccess((int)self::getParameter('id')); // Log the incident @@ -99,7 +113,10 @@ class departmentDailyReportsRoute // Return the list of departments $department_daily_reports_o = new department_daily_reports_o(); try { - $department_daily_report_latest = $department_daily_reports_o->selectLastDepartmentDailyReport((int)self::getParameter('id')); + $department_daily_report_latest = $department_daily_reports_o->selectDepartmentReportByDate( + (int)self::getParameter('id'), + (string)self::getParameter('date') + ); } catch (\Exception $e) { $response->error('No department daily report found', 404); } @@ -141,7 +158,8 @@ class departmentDailyReportsRoute 'department_id', 'water_usage', 'water_usage_morning', - 'notes' + 'notes', + 'date' ] ); // Validate the department_id @@ -189,8 +207,32 @@ class departmentDailyReportsRoute 'notes', 4000 ); + // Validate the date + self::requireType( + (string)self::getParameter('date'), + self::type_string() + ); + // Require the date to be at least 0 characters long + self::requireMinLength( + 'date', + 0 + ); + // Require the date to be at most 10 characters long + self::requireMaxLength( + 'date', + 10 + ); + // Validate the date format (YYYY-MM-DD) + self::requireDateFormat( + (string)self::getParameter('date'), + self::FORMAT_DATE() + ); // Determine if the user has access to the department self::requireDepartmentAccess((int)self::getParameter('department_id')); + // Check if there is already a report for today + if ((new department_daily_reports_o())->hasReport((int)self::getParameter('department_id'), (string)self::getParameter('date'))) { + $response->error('There is already a report for today', 400); + } // Log the incident (new logs_o())->add('departments', 'global', 1, $user->id, 'CREATE_DEPARTMENT_DAILY_REPORTS', 'Successfully created department daily report'); // Return the list of departments diff --git a/services/nginx/app/traits/route_t.php b/services/nginx/app/traits/route_t.php index c5ef773d..ee5fa632 100644 --- a/services/nginx/app/traits/route_t.php +++ b/services/nginx/app/traits/route_t.php @@ -39,6 +39,16 @@ trait route_t return true; } + /** + * The default date format (Y-m-d) Example: 2023-01-01 + * @note This is used to format dates in the API + * @return string + */ + public function FORMAT_DATE(): string + { + return 'Y-m-d'; + } + public function requireDateFormat(string $date, string $format): void { global $response;