diff --git a/services/nginx/app/objects/order_bookings_o.php b/services/nginx/app/objects/order_bookings_o.php new file mode 100644 index 00000000..21bad150 --- /dev/null +++ b/services/nginx/app/objects/order_bookings_o.php @@ -0,0 +1,96 @@ +setTable('order_bookings'); + } + + /** + * Add an object + * @param array $data The additional data of the object (e.g. ["key" => "value"]) + * @return void + * @throws Exception If the object was not created successfully + */ + public function add( + array $data, + ): void + { + global /** @var db $db */ + $db; + // Add the object to the database + $new_id = self::add_object($data); + self::select($new_id); + } + + public function getObjectProperties(): void + { + $this->customer_number = new object_property($this->table, $this->id, 'customer_number', 'int', false); + $this->department = new object_property($this->table, $this->id, 'department', 'int', false); + $this->reg_1 = new object_property($this->table, $this->id, 'reg_1', 'string', false); + $this->reg_2 = new object_property($this->table, $this->id, 'reg_2', 'string', false); + $this->reg_3 = new object_property($this->table, $this->id, 'reg_3', 'string', false); + $this->datetime = new object_property($this->table, $this->id, 'datetime', 'timestamp', false); + $this->note = new object_property($this->table, $this->id, 'note', 'string', false); + $this->reference = new object_property($this->table, $this->id, 'reference', 'string', false); + $this->po = new object_property($this->table, $this->id, 'po', 'string', false); + $this->pickup = new object_property($this->table, $this->id, 'pickup', 'bool', false); + $this->items = new object_property($this->table, $this->id, 'items', 'json', false); + $this->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false); + $this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'timestamp', false); + $this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false); + } + + public function objectChanged(): void + { + //TODO: Add cache invalidation + } + + + public function asArray(): array + { + return [ + 'id' => (int)$this->id, + 'customer_number' => (int)$this->customer_number->value(), + 'department' => (int)$this->department->value(), + 'reg_1' => $this->reg_1->value(), + 'reg_2' => $this->reg_2->value(), + 'reg_3' => $this->reg_3->value(), + 'datetime' => $this->datetime->value(), + 'note' => $this->note->value(), + 'reference' => $this->reference->value(), + 'po' => $this->po->value(), + 'pickup' => (bool)$this->pickup->value(), + 'items' => $this->items->value(), + 'created_at' => $this->created_at->value(), + 'updated_at' => $this->updated_at->value(), + ]; + } + +} \ No newline at end of file diff --git a/services/nginx/app/routes/orderBookingRoute.php b/services/nginx/app/routes/orderBookingRoute.php index 3d35d426..20ab7a36 100644 --- a/services/nginx/app/routes/orderBookingRoute.php +++ b/services/nginx/app/routes/orderBookingRoute.php @@ -6,6 +6,7 @@ use classes\authentication; use Exception; use objects\departments_o; use objects\logs_o; +use objects\order_bookings_o; use objects\order_items_o; use objects\users_o; use traits\route_t; @@ -34,10 +35,10 @@ class orderBookingRoute $pickup = self::getTargetPickup(); // Bool | Null $items = self::getTargetItems(); // Array of order_items_o objects /** - * Debug input + * Input data */ - $response->success([ - 'customer_number' => $customer_number->customer_number, + $data = [ + 'customer_number' => (int)$customer_number->customer_number->value(), 'department' => $department->id, 'reg_1' => $reg_1, 'reg_2' => $reg_2, @@ -48,46 +49,98 @@ class orderBookingRoute 'po' => $po, 'pickup' => $pickup, 'items' => $items, - 'items_count' => count($items), - ]); - exit; - - //self::requirePermission('user_security_change_email'); - $user = (new authentication())->get_user(); - if (!$user) { - (new logs_o())->add('user_security', 'global', 0, 0, 'USER_SECURITY_CHANGE_EMAIL', 'User not logged in'); - $response->error('Invalid session', 400); - } - // Require the email, and password parameters - self::requireParameters(['email', 'password']); - // Check if the email is valid - $email = (string)self::getParameter('email'); - self::requireMinLength('email', 5); - self::requireMaxLength('email', 255); - self::requireType($email, self::type_string()); - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { - (new logs_o())->add('user_security', 'global', 0, $user->id, 'USER_SECURITY_CHANGE_EMAIL', 'Invalid email'); - $response->error('Invalid email', 400); - } - // Validate the password - $password = (string)self::getParameter('password'); - self::requireMinLength('password', 5); - self::requireMaxLength('password', 255); - self::requireType($password, self::type_string()); - if (!$user->passwordMatches($password)) { - (new logs_o())->add('user_security', 'global', 0, $user->id, 'USER_SECURITY_CHANGE_EMAIL', 'Invalid password'); - $response->error('Invalid password', 400); - } else { - // Change the email - $user->setEmail($email); - (new logs_o())->add('user_security', 'global', 0, $user->id, 'USER_SECURITY_CHANGE_EMAIL', 'Email changed'); - $response->success(['message' => 'Email changed']); - } + ]; + /** + * Create the object + */ + $order_bookings_o = new order_bookings_o(); + $order_bookings_o->add($data); + $response->success($order_bookings_o->asArray()); }, [ - 'user_security_change_email' => 'Change the email address of the user', + // No Permissions required. ] ); + + $this->get('/order-bookings', function () { + // Require the user to be logged in + global $response; + /** + * Parameters + */ + $object = self::getTargetObject(); + /** + * Authentication + */ + $user = (new authentication())->get_user(); + /** + * Permissions + */ + $permission_own = 'list_own_bookings'; // Only permits access to bookings with the user's customer number + $permission_other = 'list_bookings'; // Requires access to the department as an admin to view other users' bookings + $has_permission_own = self::hasPermission($permission_own); + $has_permission_other = self::hasPermission($permission_other); + $has_permission = false; // Updated below + // Check if the user has permission to view their own bookings + if ($has_permission_own && (!$object || (int)$object->customer_number->value() === (int)$user->customer_number->value())) { + $has_permission = true; + } + // Check if the user has permission to view other users' bookings + if (!$has_permission && $has_permission_other) { + if (!empty($object)) self::requireDepartmentAccess((int)$object->department->value()); + // Check if the user has access to the department + $has_permission = true; + } + // If the user does not have permission, return an error + if (!$has_permission) { + $response->error('You do not have permission to view this order booking.', 403); + } + /** + * Return the object + */ + if (!empty($object)) $response->success($object->asArray()); + /** + * Return the filtered list of objects + */ + $object = new order_bookings_o(); // New object for listing + $response->success($object->listObjectsWithPaginationIfSet( + function ($booking) { return (new order_bookings_o())->select((int)$booking['id'])->asArray(); }, + $object->forceRestrictFilters([ + ...($has_permission_other ? [ + 'department' => $user->getGroup()->getDepartments() + ] : []), + ...(!$has_permission_other ? [ + 'customer_number' => (int)$user->customer_number->value() + ] : []) + ]) + )); + }, + [ + 'list_own_bookings' => 'Permission to list own order bookings.', + 'list_bookings' => 'Permission to list department order bookings.', + ] + ); + } + + /** + * @throws Exception + */ + private function getTargetObject(): order_bookings_o|null + { + global $response; + $parameter = 'id'; + $error = 'Invalid ' . $parameter; + if (!$this->isParametersSet([$parameter])) return null; + self::requireParameters(['id']); + self::requireType(self::getParameter($parameter), self::type_int()); + self::requireMinLength($parameter, 1); + self::requireMaxLength($parameter, 9); + $value = (int)self::getParameter($parameter); + self::requireMinValue($value, 1); + self::requireMaxValue($value, 999999999); + $object = (new order_bookings_o())->select($value); + if (!$object->exists()) $response->error($error, 400); + return $object; } private function getTargetCustomer(): users_o @@ -103,9 +156,7 @@ class orderBookingRoute self::requireMinValue($value, 1); self::requireMaxValue($value, 999999999); $object = (new users_o())->getUserByCustomerNumber($value); - if (!$object->exists()) { - $response->error($error, 400); - } + if (!$object->exists()) $response->error($error, 400); return $object; } @@ -125,9 +176,7 @@ class orderBookingRoute self::requireMinValue($value, 1); self::requireMaxValue($value, 999999999); $object = (new departments_o())->select($value); - if (!$object->exists()) { - $response->error($error, 400); - } + if (!$object->exists()) $response->error($error, 400); return $object; } diff --git a/services/nginx/app/traits/route_t.php b/services/nginx/app/traits/route_t.php index a648685c..5d5c68c9 100644 --- a/services/nginx/app/traits/route_t.php +++ b/services/nginx/app/traits/route_t.php @@ -217,6 +217,18 @@ trait route_t self::requirePermission('department_access_' . $department . ($permission ? '_' . $permission : '')); } + /** + * Has department access? + * @note This checks if the user has access to the department by checking if the user has the permission department_access_{department} (_{permission} if provided) + * @param string $department + * @param string|null $permission + * @return bool + */ + public function hasDepartmentAccess(string $department, string|null $permission = null): bool + { + return self::hasPermission('department_access_' . $department . ($permission ? '_' . $permission : '')); + } + /** * Require permission * @param string $permission