From 914f5ba1b014308c8e4b5ddfb45deb963cd59d13 Mon Sep 17 00:00:00 2001 From: Jepp9350 <2jepp9350@gmail.com> Date: Mon, 16 Dec 2024 08:54:03 +0100 Subject: [PATCH] Added the files from MVP --- classes/authentication.php | 109 ++++++ classes/db.php | 106 ++++++ classes/encrypt.php | 49 +++ classes/object_property.php | 58 +++ classes/ratelimit.php | 29 ++ classes/request.php | 8 + classes/response.php | 133 +++++++ classes/router.php | 108 ++++++ classes/session.php | 10 + config.example.php | 23 ++ index.php | 94 +++++ interfaces/authentication_i.php | 11 + interfaces/encrypt_i.php | 9 + interfaces/ratelimit_i.php | 8 + interfaces/response_i.php | 16 + .../economic/customers/economicCustomers.php | 27 ++ .../customers/economic_customer_mo.php | 65 ++++ modules/economic/economic_m.php | 67 ++++ .../invoices/draft/economicInvoicesDrafts.php | 21 ++ .../draft/economic_invoice_draft_mo.php | 115 ++++++ objects/cron_o.php | 78 ++++ objects/customer_notes_o.php | 93 +++++ objects/customer_vehicles_o.php | 124 ++++++ objects/departments_o.php | 73 ++++ objects/economic_module_orders.php | 68 ++++ objects/logs_o.php | 52 +++ objects/order_items_o.php | 146 +++++++ objects/orders_o.php | 192 ++++++++++ objects/plate_scanners_o.php | 99 +++++ objects/plate_scans_o.php | 84 +++++ objects/products_o.php | 114 ++++++ objects/ratelimit_o.php | 111 ++++++ objects/tokens_o.php | 74 ++++ objects/users_o.php | 357 ++++++++++++++++++ routes/authRoute.php | 78 ++++ routes/customerAttributes.php | 115 ++++++ routes/customerNotes.php | 105 ++++++ routes/customerSearchRoute.php | 53 +++ routes/departmentsRoute.php | 94 +++++ routes/economicInvoiceRoute.php | 202 ++++++++++ routes/exampleRoute.php | 18 + routes/intimidateRoute.php | 42 +++ routes/optionsRoute.php | 22 ++ routes/orderItemsRoute.php | 99 +++++ routes/orderRoute.php | 45 +++ routes/ordersRoute.php | 140 +++++++ routes/plateScannersRoute.php | 96 +++++ routes/plateScansRoute.php | 73 ++++ routes/productsRoute.php | 111 ++++++ routes/sessionRoute.php | 35 ++ routes/userOrdersRoute.php | 44 +++ routes/usersRoute.php | 133 +++++++ routes/vehiclesRoute.php | 121 ++++++ traits/db_object_t.php | 172 +++++++++ traits/route_t.php | 160 ++++++++ traits/session_t.php | 8 + 56 files changed, 4697 insertions(+) create mode 100644 classes/authentication.php create mode 100644 classes/db.php create mode 100644 classes/encrypt.php create mode 100644 classes/object_property.php create mode 100644 classes/ratelimit.php create mode 100644 classes/request.php create mode 100644 classes/response.php create mode 100644 classes/router.php create mode 100644 classes/session.php create mode 100644 config.example.php create mode 100644 index.php create mode 100644 interfaces/authentication_i.php create mode 100644 interfaces/encrypt_i.php create mode 100644 interfaces/ratelimit_i.php create mode 100644 interfaces/response_i.php create mode 100644 modules/economic/customers/economicCustomers.php create mode 100644 modules/economic/customers/economic_customer_mo.php create mode 100644 modules/economic/economic_m.php create mode 100644 modules/economic/invoices/draft/economicInvoicesDrafts.php create mode 100644 modules/economic/invoices/draft/economic_invoice_draft_mo.php create mode 100644 objects/cron_o.php create mode 100644 objects/customer_notes_o.php create mode 100644 objects/customer_vehicles_o.php create mode 100644 objects/departments_o.php create mode 100644 objects/economic_module_orders.php create mode 100644 objects/logs_o.php create mode 100644 objects/order_items_o.php create mode 100644 objects/orders_o.php create mode 100644 objects/plate_scanners_o.php create mode 100644 objects/plate_scans_o.php create mode 100644 objects/products_o.php create mode 100644 objects/ratelimit_o.php create mode 100644 objects/tokens_o.php create mode 100644 objects/users_o.php create mode 100644 routes/authRoute.php create mode 100644 routes/customerAttributes.php create mode 100644 routes/customerNotes.php create mode 100644 routes/customerSearchRoute.php create mode 100644 routes/departmentsRoute.php create mode 100644 routes/economicInvoiceRoute.php create mode 100644 routes/exampleRoute.php create mode 100644 routes/intimidateRoute.php create mode 100644 routes/optionsRoute.php create mode 100644 routes/orderItemsRoute.php create mode 100644 routes/orderRoute.php create mode 100644 routes/ordersRoute.php create mode 100644 routes/plateScannersRoute.php create mode 100644 routes/plateScansRoute.php create mode 100644 routes/productsRoute.php create mode 100644 routes/sessionRoute.php create mode 100644 routes/userOrdersRoute.php create mode 100644 routes/usersRoute.php create mode 100644 routes/vehiclesRoute.php create mode 100644 traits/db_object_t.php create mode 100644 traits/route_t.php create mode 100644 traits/session_t.php diff --git a/classes/authentication.php b/classes/authentication.php new file mode 100644 index 00000000..27d1eb85 --- /dev/null +++ b/classes/authentication.php @@ -0,0 +1,109 @@ +getUserByCustomerNumber( $customer_number ); + // Check if the customer exists + if (!$customer->password->value()) { + return false; + } + // Check if the password is correct + if (!$this->match_passwords($password, $customer->password->value())) { + return false; + } + return true; + } + + public function create_token(int $customer_number): string + { + // Create a token + $token = bin2hex(random_bytes(32)); + // Get the user id + $user_id = (new users_o())->getUserByCustomerNumber($customer_number)->id; + // Save the token in the database + (new tokens_o())->create($user_id, $token, 'AUTH_TOKEN'); + return $token; + } + + public function validate_token(string $token): bool + { + // Get the token from the database + $token = (new tokens_o())->getToken($token); + // Check if the token exists + if (!$token->id) { + return false; + } + return true; + } + + /** + * @throws Exception + */ + public function get_user(): users_o|false + { + /** + * Get the user from the token + */ + // Get the token from the headers + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + return false; + } + $token = $headers['Authorization']; + // Strip the Bearer prefix + $token = str_replace('Bearer ', '', $token); + // Get the token from the database + $token = (new tokens_o())->getToken($token); + // Check if the token exists + if (!$token->id) { + return false; + } + // Get the user from the database + return (new users_o())->getUserById($token->user_id->value()); + } + + public function get_plate_scanner(): plate_scanners_o|false + { + // Get the token from the headers + $headers = getallheaders(); + if (!isset($headers['Authorization'])) { + return false; + } + $token = $headers['Authorization']; + // Strip the Bearer prefix + $token = str_replace('Bearer ', '', $token); + // Get the token from the database + $token = (new plate_scanners_o())->getPlateScannerByApiKey($token); + // Check if the token exists + if (!isset($token->id)) { + return false; + } + // Get the plate scanner from the database + return $token; + } + + + public function hash_password($password): string + { + // Hash the password + return password_hash($password, PASSWORD_DEFAULT); + } + + public function match_passwords($password, $hash): bool + { + // Compare the password with the hash + return password_verify($password, $hash); + } +} \ No newline at end of file diff --git a/classes/db.php b/classes/db.php new file mode 100644 index 00000000..e0018d85 --- /dev/null +++ b/classes/db.php @@ -0,0 +1,106 @@ +host = $config['host']; + $this->user = $config['user']; + $this->password = $config['password']; + $this->database = $config['database']; + } + + public function connect(): void + { + global $response; + try { + $this->conn = new mysqli($this->host, $this->user, $this->password, $this->database); + } catch (Exception $e) { + $response->internal_server_error($e->getMessage()); + } + } + + public function query(string $sql): \mysqli_result|bool + { + // If the connection is not established, connect + return $this->conn->query($sql); + } + + public function fetch_assoc($result) + { + return $result->fetch_assoc(); + } + + public function fetch_all($result) + { + return $result->fetch_all(MYSQLI_ASSOC); + } + + public function escape_string(string $string): string + { + return $this->conn->real_escape_string($string); + } + + public function close(): void + { + $this->conn->close(); + } + + public function get(string $table, int $id) + { + $sql = "SELECT * FROM $table WHERE id = $id"; + $result = $this->query($sql); + return $this->fetch_assoc($result); + } + + public function list_objects(string $table): array + { + $sql = "SELECT * FROM $table"; + $result = $this->query($sql); + return $this->fetch_all($result); + } + + public function list_objects_paginated(string $table, int $page, int $limit): array + { + $offset = ($page - 1) * $limit; + $sql = "SELECT * FROM $table LIMIT $limit OFFSET $offset"; + $result = $this->query($sql); + return $this->fetch_all($result); + } + + public function count_objects(string $table): int + { + $sql = "SELECT COUNT(*) FROM $table"; + $result = $this->query($sql); + return $result->fetch_row()[0]; + } + + public function add_object(string $table, array $data): void + { + $columns = implode(', ', array_keys($data)); + $values = implode("', '", array_values($data)); + $sql = "INSERT INTO $table ($columns) VALUES ('$values')"; + $this->query($sql); + } + + public function insert_id(): int + { + return $this->conn->insert_id; + } + + public function conn(): mysqli + { + return $this->conn; + } +} \ No newline at end of file diff --git a/classes/encrypt.php b/classes/encrypt.php new file mode 100644 index 00000000..6954c5aa --- /dev/null +++ b/classes/encrypt.php @@ -0,0 +1,49 @@ +table = $table; + $this->id = $id; + $this->column = $column; + $this->type = $type; + $this->required = $required; + $this->default = $default; + } + + /** + * Get the value of the field in the database table + * @return mixed The value of the field in the database table + */ + public function value(): mixed + { + // Get the value of the field in the database table + global $db; + $sql = "SELECT $this->column FROM $this->table WHERE id = $this->id"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + return $row[$this->column]; + } + + /** + * Set the value of the field in the database table + * @param mixed $value The value of the field in the database table + */ + public function set(mixed $value): void + { + // Set the value of the field in the database table + global /** @var db $db */ + $db; + // If the value is null, set it to null + if ($value === null) { + $sql = "UPDATE $this->table SET $this->column = NULL WHERE id = $this->id"; + } + // If the value is a string, escape it + else { + $value = $db->escape_string($value); + $sql = "UPDATE $this->table SET $this->column = '$value' WHERE id = $this->id"; + } + $db->query($sql); + } +} \ No newline at end of file diff --git a/classes/ratelimit.php b/classes/ratelimit.php new file mode 100644 index 00000000..0e8b2d6a --- /dev/null +++ b/classes/ratelimit.php @@ -0,0 +1,29 @@ +limit = $defaultLimit; + $this->time = $defaultTime; + } + + public function enforceIP(string $ip): bool + { + global $response; + $ratelimit = (new ratelimit_o())->getOrCreateRateLimitByIp($ip); + if ($ratelimit->count->value() >= $this->limit) { + $response->rate_limit_exceeded(); + } + $ratelimit->increment($ratelimit->id, 1); + return true; + } +} \ No newline at end of file diff --git a/classes/request.php b/classes/request.php new file mode 100644 index 00000000..65abd224 --- /dev/null +++ b/classes/request.php @@ -0,0 +1,8 @@ + $data]; + } + echo json_encode([ + 'success' => $success, + 'data' => $data, + 'meta' => $this->meta, + 'includes' => $this->includes + ]); + exit; + } + + #[NoReturn] public function success(mixed $data, int $status = null): void + { + $this->response(true, $data, $status); + } + + #[NoReturn] public function error(mixed $data, int $status = null): void + { + $this->response(false, $data, $status); + } + + #[NoReturn] public function not_found(): void + { + $this->error('Not found', 404); + } + + #[NoReturn] public function rate_limit_exceeded(): void + { + $this->error('Rate limit exceeded', 429); + } + + public function add_data(string $key, mixed $value): void + { + $this->data[$key] = $value; + } + + public function add_meta(string $key, mixed $value): void + { + $this->meta[$key] = $value; + } + + public function add_included(string $key, mixed $value): void + { + $this->includes[$key] = $value; + } + + public function matching_route_found(): void + { + $this->matching_route_found = true; + } + + #[NoReturn] public function method_not_allowed(): void + { + $this->error('Method not allowed', 405); + } + + #[NoReturn] public function internal_server_error($error): void + { + $this->error('Internal server error' . ($error ? ': ' . $error : ''), 500); + } + + public function paginate(int $page, int $per_page, int $total, string $search = null, array $filters = null): void + { + // If the total is 0, return 1 page, 0 total + if ($total === 0) { + $total = 1; + } + $this->add_meta('pagination', [ + 'page' => $page, + 'per_page' => $per_page, + 'total' => $total, + 'search' => $search, + 'filters' => $filters + ]); + } + + public function get_data(): array + { + return $this->data; + } + + public function is_matching_route_found(): bool + { + return $this->matching_route_found; + } + + public function add_debug(mixed $data): void + { + $this->add_data('debug', $data); + } + + public function getRequestParameter(string $key): string|null + { + // Get the request data if the method is POST, PUT or PATCH + if ($_SERVER['REQUEST_METHOD'] === 'POST' || $_SERVER['REQUEST_METHOD'] === 'PUT' || $_SERVER['REQUEST_METHOD'] === 'PATCH') { + $data = json_decode(file_get_contents('php://input'), true); + } + // Get the request data if the method is GET, DELETE or OPTIONS + if ($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'DELETE' || $_SERVER['REQUEST_METHOD'] === 'OPTIONS') { + $data = $_GET; + } + // Return the data + return $data[$key] ?? null; + } + + public function add_include(string $string, array $dataArray): void + { + $this->add_included($string, $dataArray); + } +} \ No newline at end of file diff --git a/classes/router.php b/classes/router.php new file mode 100644 index 00000000..d74617e7 --- /dev/null +++ b/classes/router.php @@ -0,0 +1,108 @@ +url = $_SERVER['REQUEST_URI']; + $this->method = $_SERVER['REQUEST_METHOD']; + $this->routes = []; + $this->routeClasses = []; + } + + public function add($route, $method, $function): void + { + $this->routes[] = ['route' => $route, 'method' => $method, 'function' => $function]; + } + + public function run(): void + { + foreach ($this->routeClasses as $class) { + $route = new $class(); + // Add the routes to the router + $route->run(); + } + + $this->routeRequest(); + } + + public function auto_load_routes(string $path): void + { + global $response; + $files = scandir($path); + foreach ($files as $file) { + if ($file == '.' || $file == '..') { + continue; + } + require_once $path . '/' . $file; + } + + // Get all the classes in the files with the route_t trait + $classes = get_declared_classes(); + foreach ($classes as $class) { + if (in_array('traits\route_t', class_uses($class))) { + $this->routeClasses[] = $class; + } + } + + // Try to run the routes, if there is an error, catch it and send an internal server error response + try { + $this->run(); + } catch (\Exception $e) { + $response->internal_server_error($e->getMessage()); + } + } + + public function ERROR_HANDLER($callback): void + { + try { + $callback(); + } catch (\Exception $e) { + global $response; + $response->internal_server_error($e->getMessage()); + } + } + + private function routeRequest(): void + { + global $response; + $matching_route_found = false; + foreach ($this->routes as $route) { + if ($this->doesRouteMatchCurrent($route['route']) && $route['method'] == $this->method) { + $route['function'](); + $matching_route_found = true; + } + } + + if ($matching_route_found) { + $response->matching_route_found(); + } else { + $response->not_found(); + } + } + + private function doesRouteMatchCurrent($route): bool + { + // Check if the route matches the current URL or if it matches the regex pattern + // Remove the query string + $this->url = explode('?', $this->url)[0]; + // Exact match + if ($route == $this->url) { + return true; + } + // Regex + $route = str_replace('/', '\/', $route); + $route = preg_replace('/{[a-zA-Z0-9]+}/', '([a-zA-Z0-9]+)', $route); + if (preg_match('/^' . $route . '$/', $this->url)) { + return true; + } + // None of the matches were found + return false; + } +} \ No newline at end of file diff --git a/classes/session.php b/classes/session.php new file mode 100644 index 00000000..80fbd542 --- /dev/null +++ b/classes/session.php @@ -0,0 +1,10 @@ + '', // IP address of the database server e.g. 127.0.0.1 + 'user' => '', // Username of the database server e.g. root + 'password' => '', // Password of the database server e.g. password123 + 'database' => '' // Name of the database e.g. my_database + ]; +$DEBUG = true; // Set to true to enable debugging (Error messages will be shown, and this should never be used in production) +$USE_PROD_ECONOMIC_IN_DEBUG = true; // Set to true to use the production economic API in debug mode +$ENCRYPTION_KEY = ''; // 44 Characters long encryption key +$CORS = '*'; // Set to the domain that should be allowed to access the API e.g. https://example.com +$ECONOMIC_API = [ + 'app_access_grant' => '', // Economic API access grant token (1) + 'app_access_grant2' => '', // Economic API access grant token (2) + 'app_secret_token' => '' // Economic API secret token + ]; +if ($DEBUG && !$USE_PROD_ECONOMIC_IN_DEBUG) { + $ECONOMIC_API = [ + 'app_access_grant' => '', // Development Economic API access grant token (1) + 'app_access_grant2' => '', // Development Economic API access grant token (2) + 'app_secret_token' => '' // Development Economic API secret token + ]; +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 00000000..51895b55 --- /dev/null +++ b/index.php @@ -0,0 +1,94 @@ +connect(); +} catch (Exception $e) { + $response->error($e->getMessage(), 500); +} +// Load all the traits +foreach (glob(WD . '/traits/*.php') as $trait) { + require_once $trait; +} + +// Load all the routes +foreach (glob(WD . '/routes/*.php') as $route) { + require_once $route; +} + +/** Load all Objects */ +foreach (glob(WD . '/objects/*.php') as $object) { + try { + require_once $object; + } catch (Exception $e) { + $response->error($e->getMessage(), 500); + } +} + +// Autoload all the routes +$router->auto_load_routes(WD . '/routes'); + +/** If no matching route is found, return a 404 */ +if (!$response->is_matching_route_found()) { + // Debug + $response->add_debug(['message' => 'No matching route found']); + $response->not_found(); +} \ No newline at end of file diff --git a/interfaces/authentication_i.php b/interfaces/authentication_i.php new file mode 100644 index 00000000..585e4bdd --- /dev/null +++ b/interfaces/authentication_i.php @@ -0,0 +1,11 @@ +send_request($url, 'GET', ''); + $response = json_decode($response); + return $response->collection; + } + + public function searchCustomers(string|int $search, string $filter, int $limit = 10, int $page = 1): object + { + // Make sure the search string is ready for the API + $search = urlencode($search); + // Search for customers + $url = '/customers?filter=' . $filter . '$like:' . $search . '&pagesize=' . $limit . '&skippages=' . $page - 1; + $response = $this->send_request($url, 'GET', ''); + return json_decode($response); + } +} \ No newline at end of file diff --git a/modules/economic/customers/economic_customer_mo.php b/modules/economic/customers/economic_customer_mo.php new file mode 100644 index 00000000..bd4ea1f8 --- /dev/null +++ b/modules/economic/customers/economic_customer_mo.php @@ -0,0 +1,65 @@ +getCustomerId($customer_number); + // Check if the customer exists + if (count($customer) > 0) { + return $this->parseCustomer($customer[0]); + } + return $this; + + } + + public function parseCustomer($customer): static + { + $this->customer_number = $customer->customerNumber; + $this->name = ($customer->name ?? null); + $this->address = ($customer->address ?? null); + $this->city = ($customer->city ?? null); + $this->zip = ($customer->zip ?? null); + $this->corporateIdentificationNumber = ($customer->corporateIdentificationNumber ?? null); + $this->email = ($customer->email ?? null); + $this->mobilePhone = ($customer->mobilePhone ?? null); + $this->currency = ($customer->currency ?? null); + $this->country = ($customer->country ?? null); + return $this; + } + + public function asArray(): array + { + // If the customer does not exist, return an empty array + if (!isset($this->customer_number)) { + return []; + } + return [ + 'customerNumber' => $this->customer_number, + 'name' => $this->name, + 'address' => $this->address, + 'city' => $this->city, + 'zip' => $this->zip, + 'corporateIdentificationNumber' => $this->corporateIdentificationNumber, + 'email' => $this->email, + 'mobilePhone' => $this->mobilePhone, + 'currency' => $this->currency, + 'country' => $this->country, + ]; + } +} \ No newline at end of file diff --git a/modules/economic/economic_m.php b/modules/economic/economic_m.php new file mode 100644 index 00000000..89b1a391 --- /dev/null +++ b/modules/economic/economic_m.php @@ -0,0 +1,67 @@ +app_token = $ECONOMIC_API['app_secret_token']; + $this->appAccessGrant = $ECONOMIC_API['app_access_grant']; + $this->appAccessGrant2 = $ECONOMIC_API['app_access_grant2']; + + } + + /** + * Send a request to the Economic API + * @param string $url + * @param string $method + * @param string $data + * @param bool $authToken2 + * @return string + */ + protected function send_request($url, $method, $data = '', bool $authToken2 = false): string + { + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_URL => $this->api_url . $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_HTTPHEADER => array( + 'X-AppSecretToken: ' . $this->app_token, + 'X-AgreementGrantToken: ' . ( $authToken2 ? $this->appAccessGrant2 : $this->appAccessGrant ), + 'Content-Type: application/json' + ), + )); + + if ($method === 'POST') { + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + } + + $response = curl_exec($curl); + curl_close($curl); + return $response; + } + + /** + * Allowed search filters + * @return array + */ + public function allowed_search_filters_customers(): array + { + return [ + 'address', 'balance', 'barred', 'city', 'corporateIdentificationNumber', 'country', 'creditLimit', 'currency', 'customerGroup.customerGroupNumber', 'customerNumber', 'ean', 'email', 'lastUpdated', 'mobilePhone', 'name', 'publicEntryNumber', 'telephoneAndFaxNumber', 'vatNumber', 'website', 'zip' + ]; + } +} \ No newline at end of file diff --git a/modules/economic/invoices/draft/economicInvoicesDrafts.php b/modules/economic/invoices/draft/economicInvoicesDrafts.php new file mode 100644 index 00000000..2c23a019 --- /dev/null +++ b/modules/economic/invoices/draft/economicInvoicesDrafts.php @@ -0,0 +1,21 @@ +send_request($url, 'POST', json_encode($data)); + return json_decode($response); + } + + public function getLayouts(): object + { + // Get all the layouts + $url = '/layouts'; + $response = $this->send_request($url, 'GET'); + return json_decode($response); + } + +} \ No newline at end of file diff --git a/modules/economic/invoices/draft/economic_invoice_draft_mo.php b/modules/economic/invoices/draft/economic_invoice_draft_mo.php new file mode 100644 index 00000000..fb16237a --- /dev/null +++ b/modules/economic/invoices/draft/economic_invoice_draft_mo.php @@ -0,0 +1,115 @@ +send_request($url, 'POST', json_encode($data)); + return json_decode($response); + } + + public function addLine(string $productNumber, string $description, float $quantity, float $unitNetPrice, float $discountPercentage): void + { + // We then add a 0 in front of the product number to make sure it's the right one, made by FlexPOS. + // Add a line to the invoice + $this->lines[] = [ + 'product' => [ + 'productNumber' => $productNumber, + ], + 'quantity' => $quantity, + 'unitNetPrice' => $unitNetPrice, + 'discountPercentage' => $discountPercentage, + 'description' => $description, + ]; + } + + public function addLineTEXT(string $text): void + { + // Add a line to the invoice + $this->lines[] = [ + 'product' => [ + 'productNumber' => '81234', + ], + 'description' => $text, + 'quantity' => 1, + 'unitNetPrice' => 0, + 'discountPercentage' => 0, + ]; + } + + // Example of a method that uses the createInvoiceDraft method + public function createInvoiceDraftExample(): object + { + $data = [ + 'currency' => 'DKK', + 'date' => date('Y-m-d'), + 'layout' => [ + 'layoutNumber' => 1 + ], + 'paymentTerms' => [ + 'paymentTermsNumber' => 1 + ], + 'recipient' => [ + 'name' => $this->recipient['name'], + 'address' => $this->recipient['address'], + 'zip' => $this->recipient['zip'], + 'city' => $this->recipient['city'], + 'vatZone' => [ + 'vatZoneNumber' => 1 + ] + ], + 'customer' => [ + 'customerNumber' => (int)$this->customer_number + ], + 'lines' => $this->lines // Lines added using the addLine method + ]; + return $this->createInvoiceDraft($data); + } + + public function setCustomerNumber(int $customer_number): economic_invoice_draft_mo + { + $this->customer_number = $customer_number; + return $this; + } + + public function setRecipient(string $name, string $address, string $zip, string $city): economic_invoice_draft_mo + { + $this->recipient = [ + 'name' => $name, + 'address' => $address, + 'zip' => $zip, + 'city' => $city, + ]; + return $this; + } + + public function deleteInvoiceDraft(int $value): void + { + // Delete the invoice draft + $url = '/invoices/drafts/' . $value; + $this->send_request($url, 'DELETE'); + } + + public function publishInvoiceDraft(int $invoiceDraftId): object + { + // Publish the invoice draft + $url = '/invoices/booked'; + return json_decode($this->send_request($url, 'POST', json_encode(['draftInvoice' => ['draftInvoiceNumber' => $invoiceDraftId]]))); + } + + public function getInvoicePdf(int $param) + { + // Get the invoice PDF + $url = '/invoices/booked/' . $param . '/pdf'; + return $this->send_request($url, 'GET'); + } +} \ No newline at end of file diff --git a/objects/cron_o.php b/objects/cron_o.php new file mode 100644 index 00000000..2014179f --- /dev/null +++ b/objects/cron_o.php @@ -0,0 +1,78 @@ +setTable('cron'); + } + + public function getObjectProperties(): void + { + $this->name = new object_property($this->table, $this->id, 'name', 'string', true); + $this->last_run = new object_property($this->table, $this->id, 'last_run', 'datetime', true); + $this->times_ran = new object_property($this->table, $this->id, 'times_ran', 'int', true); + } + + public function getByName(string $name): cron_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE name = '$name'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } + return $this; + } + + public function incrementTimesRan(int $id): void + { + global $db; + $this->id = $id; + // Update the record in the database + $sql = "UPDATE $this->table SET times_ran = times_ran + 1 WHERE id = $this->id"; + $db->query($sql); + } + + public function updateLastRun(int $id): void + { + global $db; + $this->id = $id; + // Update the record in the database + $sql = "UPDATE $this->table SET last_run = NOW() WHERE id = $this->id"; + $db->query($sql); + } + + public function getCronCreateIfNotExists(string $name): cron_o + { + global $db; + // Avoid SQL injection + $name = $db->escape_string($name); + // Check if the record exists + $sql = "SELECT id FROM $this->table WHERE name = '$name'"; + $result = $db->query($sql); + if ($result->num_rows == 0) { + // Create a new record in the database + $sql = "INSERT INTO $this->table (name, last_run, times_ran) VALUES ('$name', NOW(), 0)"; + $db->query($sql); + // Get the id of the new record + $this->id = $db->insert_id(); + // Set the values of the object properties + $this->getObjectProperties(); + } + return $this; + } +} \ No newline at end of file diff --git a/objects/customer_notes_o.php b/objects/customer_notes_o.php new file mode 100644 index 00000000..29c7bbe6 --- /dev/null +++ b/objects/customer_notes_o.php @@ -0,0 +1,93 @@ +setTable('customer_notes'); + } + + public function getObjectProperties(): void + { + $this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', true); + $this->note = new object_property($this->table, $this->id, 'note', 'string', true); + $this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true); + $this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false); + } + + public function add(int $customer_id, string $note, int $cashier_id): customer_notes_o + { + global $db, $response; + try { + // Avoid SQL injection + $note = $db->escape_string($note); + // Create a new record in the database + $sql = "INSERT INTO $this->table (customer_id, note, cashier_id) VALUES ($customer_id, '$note', $cashier_id)"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + return $this; + } + + public function getCustomerNotesAsArray(int $customer_id): array + { + global $db; + $sql = "SELECT * FROM $this->table WHERE customer_id = $customer_id AND deleted_at IS NULL"; + $result = $db->query($sql); + $customer_notes = []; + if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $customer_notes[] = $row; + } + } + return $customer_notes; + } + + public function getCustomerNoteById(int $id): customer_notes_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function delete(int $id): void + { + global $db; + $this->id = $id; + $sql = "UPDATE $this->table SET deleted_at = NOW() WHERE id = $this->id"; + $db->query($sql); + } + + public function restore(int $id): void + { + global $db; + $this->id = $id; + $sql = "UPDATE $this->table SET deleted_at = NULL WHERE id = $this->id"; + $db->query($sql); + } +} \ No newline at end of file diff --git a/objects/customer_vehicles_o.php b/objects/customer_vehicles_o.php new file mode 100644 index 00000000..ac2b588a --- /dev/null +++ b/objects/customer_vehicles_o.php @@ -0,0 +1,124 @@ +setTable('customer_vehicles'); + } + + public function getObjectProperties(): void + { + $this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', true); + $this->type = new object_property($this->table, $this->id, 'type', 'string', true); + $this->reg = new object_property($this->table, $this->id, 'reg', 'string', true); + $this->notes = new object_property($this->table, $this->id, 'notes', 'string', true); + $this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false); + } + + public function add(int $customer_id, string $type, string $reg, string $notes): customer_vehicles_o + { + global $db, $response; + try { + // Avoid SQL injection + $type = $db->escape_string($type); + $reg = $db->escape_string($reg); + $notes = $db->escape_string($notes); + // Create a new record in the database + $sql = "INSERT INTO $this->table (customer_id, type, reg, notes) VALUES ($customer_id, '$type', '$reg', '$notes')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + return $this; + } + + public function getCustomerVehiclesAsArray(int $customer_id): array + { + global $db; + $sql = "SELECT * FROM $this->table WHERE customer_id = $customer_id AND deleted_at IS NULL"; + $result = $db->query($sql); + $customer_notes = []; + if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $customer_notes[] = $row; + } + } + return $customer_notes; + } + + public function getCustomerVehiclesPaginated($customer_id, $page = 1 , $limit = 10): array + { + global /** @var response $response */ + $db, $response; + $sql = "SELECT * FROM $this->table WHERE customer_id = $customer_id AND deleted_at IS NULL LIMIT $limit OFFSET " . ($page - 1) * $limit; + $result = $db->query($sql); + $array = $db->fetch_all($result); + $sql = "SELECT COUNT(*) as count FROM $this->table WHERE customer_id = $customer_id AND deleted_at IS NULL"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + $total = $row['count']; + $response->paginate($page, $limit, $total); + return $array; + } + public function getCustomerVehicleById(int $id): customer_vehicles_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function delete(int $id): void + { + global $db; + $this->id = $id; + $sql = "UPDATE $this->table SET deleted_at = NOW() WHERE id = $this->id"; + $db->query($sql); + } + + public function restore(int $id): void + { + global $db; + $this->id = $id; + $sql = "UPDATE $this->table SET deleted_at = NULL WHERE id = $this->id"; + $db->query($sql); + } + + public function getArrayByObjectProperties(): array + { + return [ + 'id' => $this->id, + 'customer_id' => $this->customer_id->value(), + 'type' => $this->type->value(), + 'reg' => $this->reg->value(), + 'notes' => $this->notes->value(), + 'deleted_at' => $this->deleted_at->value() + ]; + } +} \ No newline at end of file diff --git a/objects/departments_o.php b/objects/departments_o.php new file mode 100644 index 00000000..7534061d --- /dev/null +++ b/objects/departments_o.php @@ -0,0 +1,73 @@ +setTable('departments'); + } + + public function getObjectProperties(): void + { + $this->name = new object_property($this->table, $this->id, 'name', 'string', true); + $this->description = new object_property($this->table, $this->id, 'description', 'string', false); + } + + public function create(string $name, string $description): void + { + global $db; + // Avoid SQL injection + $name = $db->escape_string($name); + $description = $db->escape_string($description); + // Create a new record in the database + $sql = "INSERT INTO $this->table (name, description) VALUES ('$name', '$description')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function edit(int $id, string $name, string $description): void + { + global $db; + $this->id = $id; + // Avoid SQL injection + $name = $db->escape_string($name); + $description = $db->escape_string($description); + // Update the record in the database + $sql = "UPDATE $this->table SET name = '$name', description = '$description' WHERE id = $this->id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function list(): array + { + global $db; + $sql = "SELECT * FROM $this->table"; + $result = $db->query($sql); + return $db->fetch_all($result); + } + + public function getDepartmentById(int $id): array + { + global $db; + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + return $db->fetch_assoc($result); + } +} \ No newline at end of file diff --git a/objects/economic_module_orders.php b/objects/economic_module_orders.php new file mode 100644 index 00000000..b602476a --- /dev/null +++ b/objects/economic_module_orders.php @@ -0,0 +1,68 @@ +setTable('economic_module_orders'); + } + + public function getObjectProperties(): void + { + $this->economic_invoice_draft_id = new object_property($this->table, $this->id, 'invoice_draft_id', 'int', true); + $this->economic_invoice_id = new object_property($this->table, $this->id, 'invoice_id', 'int', true); + } + + public function getByOrderId(int $orderId): economic_module_orders + { + global $db; + // Create a new record in the database, if it does not exist + $sql = "SELECT * FROM $this->table WHERE id = $orderId"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $orderId; + $this->getObjectProperties(); + } else { + $this->add($orderId); + } + return $this; + } + + public function add(int $orderId): void + { + global $db, $response; + try { + // Create a new record in the database + $sql = "INSERT INTO $this->table (id) VALUES ($orderId)"; + $db->query($sql); + + // Get the id of the new record + $this->id = $orderId; + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function asArray(): array + { + return [ + 'id' => $this->id, + 'invoice_draft_id' => $this->economic_invoice_draft_id->value(), + 'invoice_id' => $this->economic_invoice_id->value(), + ]; + } +} \ No newline at end of file diff --git a/objects/logs_o.php b/objects/logs_o.php new file mode 100644 index 00000000..992dcab5 --- /dev/null +++ b/objects/logs_o.php @@ -0,0 +1,52 @@ +setTable('logs'); + } + + public function getObjectProperties(): void + { + $this->module = new object_property($this->table, $this->id, 'module', 'string', true); + $this->department = new object_property($this->table, $this->id, 'department', 'string', false); + $this->type = new object_property($this->table, $this->id, 'type', 'int', true); + $this->user_id = new object_property($this->table, $this->id, 'user_id', 'int', false); + $this->action = new object_property($this->table, $this->id, 'action', 'string', true); + $this->message = new object_property($this->table, $this->id, 'message', 'string', false); + } + + public function add(string $module, string $department, int $type, int $user_id, string $action, string $message): void + { + global $db; + // Avoid SQL injection + $module = $db->escape_string($module); + $department = $db->escape_string($department); + $action = $db->escape_string($action); + $message = $db->escape_string($message); + // Create a new record in the database + $sql = "INSERT INTO $this->table (module, department, type, user_id, action, message) VALUES ('$module', '$department', $type, $user_id, '$action', '$message')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } +} \ No newline at end of file diff --git a/objects/order_items_o.php b/objects/order_items_o.php new file mode 100644 index 00000000..0ea72eb2 --- /dev/null +++ b/objects/order_items_o.php @@ -0,0 +1,146 @@ +setTable('order_items'); + } + + public function getObjectProperties(): void + { + $this->order_id = new object_property($this->table, $this->id, 'order_id', 'int', true); + $this->product_id = new object_property($this->table, $this->id, 'product_id', 'int', true); + $this->reference = new object_property($this->table, $this->id, 'reference', 'string', true); + $this->notes = new object_property($this->table, $this->id, 'notes', 'string', false); + $this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true); + $this->price = new object_property($this->table, $this->id, 'price', 'int', true); + } + + public function getOrderItemById(int $id): order_items_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(int $order_id, int $product_id, string $reference, string $notes, int $cashier_id, int $price): void + { + global $db, $response; + try { + // Avoid SQL injection + $reference = $db->escape_string($reference); + $notes = $db->escape_string($notes); + // Create a new record in the database + $sql = "INSERT INTO $this->table (order_id, product_id, reference, notes, cashier_id, price) VALUES ($order_id, $product_id, '$reference', '$notes', $cashier_id, $price)"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function edit(int $id, int $order_id, int $product_id, string $reference, string $notes, int $cashier_id, int $price): void + { + global $db, $response; + $this->id = $id; + try { + // Avoid SQL injection + $reference = $db->escape_string($reference); + $notes = $db->escape_string($notes); + // Update the record in the database + $sql = "UPDATE $this->table SET order_id = $order_id, product_id = $product_id, reference = '$reference', notes = '$notes', cashier_id = $cashier_id, price = $price WHERE id = $this->id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function addItemToOrder(int $order_id, int $product_id, int $cashier_id): void + { + global $db, $response; + try { + // Get the product price + $sql = "SELECT price FROM products WHERE id = $product_id"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + $price = $row['price']; + + // Create a new record in the database + $sql = "INSERT INTO $this->table (order_id, product_id, price, cashier_id) VALUES ($order_id, $product_id, $price, $cashier_id)"; + $db->query($sql); + // Get the id of the new record + $this->id = $db->insert_id(); + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function removeOrderItem(int $id): void + { + global $db; + $this->id = $id; + $sql = "DELETE FROM $this->table WHERE id = $this->id"; + $db->query($sql); + } + + public function getItemAsArray(): array + { + return [ + 'id' => (int)$this->id, + 'order_id' => (int)$this->order_id->value(), + 'product_id' => (int)$this->product_id->value(), + 'reference' => (string)$this->reference->value(), + 'notes' => (string)$this->notes->value(), + 'cashier_id' => (int)$this->cashier_id->value(), + 'price' => (int)$this->price->value(), + 'product' => (array)(new products_o())->getProductById($this->product_id->value())->asArray(), + 'cashier' => (array)(new users_o())->getUserById($this->cashier_id->value())->asArray() + ]; + } + + public function getAllItemsAsArray(int $orderId): array + { + global $db; + $sql = "SELECT * FROM $this->table WHERE order_id = $orderId"; + $result = $db->query($sql); + // Circumvent the repeated instantiation of the object, by just selecting the fields + $items = []; + if ($result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $items[] = $row; + } + } + return $items; + } +} \ No newline at end of file diff --git a/objects/orders_o.php b/objects/orders_o.php new file mode 100644 index 00000000..c962f1d9 --- /dev/null +++ b/objects/orders_o.php @@ -0,0 +1,192 @@ +setTable('orders'); + } + + public function getObjectProperties(): void + { + $this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', true); + $this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true); + $this->reference = new object_property($this->table, $this->id, 'reference', 'string', true); + $this->notes = new object_property($this->table, $this->id, 'notes', 'string', false); + $this->department_id = new object_property($this->table, $this->id, 'department_id', 'int', true); + $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->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false); + $this->economic_module_orders = (new economic_module_orders())->getByOrderId($this->id); + } + + public function getOrderById(int $id): orders_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(int $customer_id, int $cashier_id, string $reference, string $notes, int $department_id, string $reg_1 = '', string $reg_2 = '', string $reg_3 = ''): orders_o + { + global $db, $response; + try { + // Avoid SQL injection + $reference = $db->escape_string($reference); + $notes = $db->escape_string($notes); + $reg_1 = $db->escape_string($reg_1); + $reg_2 = $db->escape_string($reg_2); + $reg_3 = $db->escape_string($reg_3); + // Create a new record in the database + $sql = "INSERT INTO $this->table (customer_id, cashier_id, reference, notes, department_id, reg_1, reg_2, reg_3) VALUES ($customer_id, $cashier_id, '$reference', '$notes', $department_id, '$reg_1', '$reg_2', '$reg_3')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + return $this; + } catch (\Exception $e) { + $response->error($e->getMessage()); + return $this; + } + } + + public function edit(int $id, int $customer_id, int $cashier_id, string $reference, string $notes, int $department_id): void + { + global $db, $response; + $this->id = $id; + try { + // Avoid SQL injection + $reference = $db->escape_string($reference); + $notes = $db->escape_string($notes); + // Update the record in the database + $sql = "UPDATE $this->table SET customer_id = $customer_id, cashier_id = $cashier_id, reference = '$reference', notes = '$notes', department_id = $department_id WHERE id = $id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function getOrderItems(int $order_id): array + { + global $db; + $sql = "SELECT * FROM order_items WHERE order_id = $order_id"; + $result = $db->query($sql); + $order_items = []; + if ($result->num_rows > 0 && $result) { + while ($row = $result->fetch_assoc()) { + $order_item = new order_items_o(); + $order_items[] = $order_item->getOrderItemById($row['id'])->getItemAsArray(); + } + } + return $order_items; + } + + public function asArray(): array + { + return [ + 'id' => $this->id, + 'customer_id' => $this->customer_id->value(), + 'cashier_id' => $this->cashier_id->value(), + 'reference' => $this->reference->value(), + 'notes' => $this->notes->value(), + 'department_id' => $this->department_id->value(), + 'reg_1' => $this->reg_1->value(), + 'reg_2' => $this->reg_2->value(), + 'reg_3' => $this->reg_3->value(), + 'created_at' => $this->created_at->value(), + ]; + } + + public function includeIncludes(): orders_o + { + global /** @var response $response */ + $response; + $includeEverything = $response->getRequestParameter('include_all') === 'true'; + /** orderItems */ + if ($response->getRequestParameter('includeOrderItems') || $includeEverything) { + $response->add_include('orderItems', $this->getOrderItems($this->id)); + } + /** customer */ + if ($response->getRequestParameter('includeCustomer') || $includeEverything) { + $customer = new users_o(); + $response->add_include('customer', $customer->getCustomerByIdOrCustomerNumber($this->customer_id->value())->includeIncludes()->asArray()); + } + /** cashier */ + if ($response->getRequestParameter('includeCashier') || $includeEverything) { + $cashier = new users_o(); + $response->add_include('cashier', $cashier->getUserById($this->cashier_id->value())->asArray()); + } + /** + * economicModuleOrders + */ + if ($response->getRequestParameter('includeEconomicModuleOrders') || $includeEverything) { + $response->add_include('economicModuleOrders', $this->economic_module_orders->getByOrderId($this->id)->asArray()); + } + return $this; + } + + public function getCustomerByOrderId(?string $order_id): users_o + { + global $db; + $sql = "SELECT customer_id FROM orders WHERE id = $order_id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $row = $result->fetch_assoc(); + return (new users_o())->getCustomerByIdOrCustomerNumber($row['customer_id']); + } + return new users_o(); + } + + public function getCustomerOrdersPaginated(int $customer_number, int $page = 1, int $limit = 10, string $order = 'DESC'): array + { + global /** @var response $response */ + $db, $response; + $sql = "SELECT * FROM $this->table WHERE customer_id = $customer_number ORDER BY id $order LIMIT $limit OFFSET " . ($page - 1) * $limit; + $result = $db->query($sql); + $array = $db->fetch_all($result); + // Add the metadata + $sql = "SELECT COUNT(*) as count FROM $this->table WHERE customer_id = $customer_number"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + $total = $row['count']; + $response->paginate($page, $limit, $total); + return $array; + } + + public function getDepartmentByOrderId($order_id): array + { + return (new departments_o())->getDepartmentById($this->department_id->value()); + } +} \ No newline at end of file diff --git a/objects/plate_scanners_o.php b/objects/plate_scanners_o.php new file mode 100644 index 00000000..0fcef069 --- /dev/null +++ b/objects/plate_scanners_o.php @@ -0,0 +1,99 @@ +setTable('plate_scanners'); + } + + public function getObjectProperties(): void + { + $this->department_id = new object_property($this->table, $this->id, 'department_id', 'int'); + $this->name = new object_property($this->table, $this->id, 'name', 'string'); + $this->notes = new object_property($this->table, $this->id, 'notes', 'string'); + $this->api_key = new object_property($this->table, $this->id, 'api_key', 'string'); + } + + public function getPlateScannerById(int $id): plate_scanners_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(int $department_id, string $name, string $notes): void + { + global $db, $response; + try { + // Generate an API key + $api_key = bin2hex(random_bytes(32)); + // Avoid SQL injection + $name = $db->escape_string($name); + $notes = $db->escape_string($notes); + // Create a new record in the database + $sql = "INSERT INTO $this->table (department_id, name, notes, api_key) VALUES ($department_id, '$name', '$notes', '$api_key')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function edit(int $id, int $department_id, string $name, string $notes): void + { + global $db, $response; + $this->id = $id; + try { + // Avoid SQL injection + $name = $db->escape_string($name); + $notes = $db->escape_string($notes); + // Update the record in the database + $sql = "UPDATE $this->table SET department_id = $department_id, name = '$name', notes = '$notes' WHERE id = $id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function getPlateScannerByApiKey(mixed $token): plate_scanners_o + { + global $db; + // Avoid SQL injection + $token = $db->escape_string($token); + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE api_key = '$token'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } + return $this; + } +} \ No newline at end of file diff --git a/objects/plate_scans_o.php b/objects/plate_scans_o.php new file mode 100644 index 00000000..f22a6930 --- /dev/null +++ b/objects/plate_scans_o.php @@ -0,0 +1,84 @@ +setTable('plate_scans'); + } + + public function getObjectProperties(): void + { + $this->plate_scanner_id = new object_property($this->table, $this->id, 'plate_scanner_id', 'int'); + $this->plate = new object_property($this->table, $this->id, 'plate', 'string'); + } + + public function getPlateScanById(int $id): plate_scans_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(int $plate_scanner_id, string $plate): void + { + global $db, $response; + try { + // Avoid SQL injection + $plate = $db->escape_string($plate); + // Get the department id from the plate scanner id + $sql = "SELECT department_id FROM plate_scanners WHERE id = $plate_scanner_id"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + $department_id = $row['department_id']; + // Create a new record in the database + $sql = "INSERT INTO $this->table (plate_scanner_id, plate, department_id) VALUES ($plate_scanner_id, '$plate', $department_id)"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function getPlateScansByDepartment(int $department_id, int $page, int $limit): array + { + global $db; + // Avoid SQL injection + $department_id = $db->escape_string($department_id); + $page = $db->escape_string($page); + $limit = $db->escape_string($limit); + // Calculate the offset + $offset = ($page - 1) * $limit; + $sql = "SELECT * FROM $this->table WHERE department_id = $department_id ORDER BY id DESC LIMIT $limit OFFSET $offset"; + $result = $db->query($sql); + $plate_scans = []; + if ($result->num_rows > 0) { + // Return the records as an array raw data + while ($row = $result->fetch_assoc()) { + $plate_scans[] = $row; + } + } + return $plate_scans; + } +} \ No newline at end of file diff --git a/objects/products_o.php b/objects/products_o.php new file mode 100644 index 00000000..7befa981 --- /dev/null +++ b/objects/products_o.php @@ -0,0 +1,114 @@ +setTable('products'); + } + + public function getObjectProperties(): void + { + $this->name = new object_property($this->table, $this->id, 'name', 'string', true); + $this->description = new object_property($this->table, $this->id, 'description', 'string', false); + $this->price = new object_property($this->table, $this->id, 'price', 'int', true); + $this->category = new object_property($this->table, $this->id, 'category', 'string', true); + $this->piktogram = new object_property($this->table, $this->id, 'piktogram', 'string', false); + $this->economic_product_id = new object_property($this->table, $this->id, 'economic_product_id', 'int', false); + } + + public function getProductById(int $id): products_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(string $name, string $description, int $price, string|bool $category = false, string|bool $piktogram = false, string|bool $economicProductId = false): void + { + global $db, $response; + try { + // Avoid SQL injection + $name = $db->escape_string($name); + $description = $db->escape_string($description); + $category = $category ? $db->escape_string($category) : null; + $piktogram = $piktogram ? $db->escape_string($piktogram) : ''; + $economicProductId = $economicProductId ? $db->escape_string($economicProductId) : null; + // Create a new record in the database + $sql = "INSERT INTO $this->table (name, description, price, category, piktogram, economic_product_id) VALUES ('$name', '$description', $price, '$category', '$piktogram', '$economicProductId')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function edit(mixed $id, mixed $name, mixed $description, mixed $price, mixed $category = false, mixed $piktogram = false, mixed $economicProductId = false): void + { + global $db, $response; + $this->id = $id; + try { + // Avoid SQL injection + $name = $db->escape_string($name); + $description = $db->escape_string($description); + $category = $category ? $db->escape_string($category) : null; + $piktogram = $piktogram ? $db->escape_string($piktogram) : ''; + $economicProductId = $economicProductId ? $db->escape_string($economicProductId) : null; + // Update the record in the database + $sql = "UPDATE $this->table SET name = '$name', description = '$description', price = $price, category = '$category', piktogram = '$piktogram', economic_product_id = '$economicProductId' WHERE id = $id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } catch (\Exception $e) { + $response->error($e->getMessage()); + } + } + + public function listObjectsByCategory(string $category): array + { + global $db; + $category = $db->escape_string($category); + $sql = "SELECT * FROM $this->table WHERE category = '$category'"; + $result = $db->query($sql); + return $db->fetch_all($result); + } + + public function asArray(): array + { + return [ + 'id' => (int)$this->id, + 'name' => (string)$this->name->value(), + 'description' => (string)$this->description->value(), + 'price' => (int)$this->price->value(), + 'category' => $this->category->value(), + 'piktogram' => $this->piktogram->value(), + 'economic_product_id' => $this->economic_product_id->value(), + ]; + } +} \ No newline at end of file diff --git a/objects/ratelimit_o.php b/objects/ratelimit_o.php new file mode 100644 index 00000000..81d324b6 --- /dev/null +++ b/objects/ratelimit_o.php @@ -0,0 +1,111 @@ +setTable('ratelimit'); + } + + public function getObjectProperties(): void + { + $this->ip = new object_property($this->table, $this->id, 'ip', 'string', true); + $this->count = new object_property($this->table, $this->id, 'count', 'int', true); + $this->total_count = new object_property($this->table, $this->id, 'total_count', 'int', true); + } + + public function getRateLimitByIp(string $ip): ratelimit_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE ip = '$ip'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } + return $this; + } + + public function getRateLimitById(int $id): ratelimit_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function increment(int $id, int $count): void + { + global $db; + $this->id = $id; + // Update the record in the database + $sql = "UPDATE $this->table SET count = count + $count, total_count = total_count + $count WHERE id = $this->id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function reset(int $id): void + { + global $db; + $this->id = $id; + // Update the record in the database + $sql = "UPDATE $this->table SET count = 0 WHERE id = $this->id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function create(string $ip): void + { + global $db; + // Avoid SQL injection + $ip = $db->escape_string($ip); + // Create a new record in the database + $sql = "INSERT INTO $this->table (ip, count, total_count) VALUES ('$ip', 1, 1)"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function getOrCreateRateLimitByIp(string $ip): ratelimit_o + { + $ratelimit = $this->getRateLimitByIp($ip); + if (!$ratelimit->id) { + $this->create($ip); + return $this; + } + return $ratelimit; + } + + public function resetAll(): void + { + global $db; + // Reset all the ratelimits + $sql = "UPDATE $this->table SET count = 0"; + $db->query($sql); + } +} \ No newline at end of file diff --git a/objects/tokens_o.php b/objects/tokens_o.php new file mode 100644 index 00000000..8daf507b --- /dev/null +++ b/objects/tokens_o.php @@ -0,0 +1,74 @@ +setTable('tokens'); + } + + public function getObjectProperties(): void + { + $this->user_id = new object_property($this->table, $this->id, 'user_id', 'int', true); + $this->type = new object_property($this->table, $this->id, 'type', 'string', true); + $this->token = new object_property($this->table, $this->id, 'token', 'string', true); + } + + public function create(int $user_id, string $token, string $type = 'AUTH_TOKEN'): void + { + global $db; + // Avoid SQL injection + $token = $db->escape_string($token); + // Create a new record in the database + $sql = "INSERT INTO $this->table (user_id, token, type) VALUES ($user_id, '$token', '$type')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + /** + * @throws Exception + */ + public function getToken(string $token): tokens_o + { + global $db; + // Avoid SQL injection + $token = $db->escape_string($token); + // Prepare the SQL statement + $sql = "SELECT id FROM $this->table WHERE token = '$token'"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + if (!$row) { + throw new Exception("Token not found " . $token); + } + $this->id = $row['id']; + $this->getObjectProperties(); + return $this; + } + + public function delete(string $token): void + { + global $db; + // Avoid SQL injection + $token = $db->escape_string($token); + // Prepare the SQL statement + $sql = "DELETE FROM $this->table WHERE token = '$token'"; + $db->query($sql); + } +} \ No newline at end of file diff --git a/objects/users_o.php b/objects/users_o.php new file mode 100644 index 00000000..2076b157 --- /dev/null +++ b/objects/users_o.php @@ -0,0 +1,357 @@ +setTable('users'); + } + + public function getObjectProperties(): void + { + $this->customer_number = new object_property($this->table, $this->id, 'customer_number', 'string', true); + $this->password = new object_property($this->table, $this->id, 'password', 'string', true); + $this->group_id = new object_property($this->table, $this->id, 'group_id', 'int', true); + $this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false); + $this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false); + } + + public function getUserByCustomerNumber(int $customer_number): users_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE customer_number = '$customer_number'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } else { + // Import the customer + $this->importCustomerFromExternalSource($customer_number); + } + return $this; + } + + public function getUserById(int $id): users_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $id; + $this->getObjectProperties(); + } + return $this; + } + + public function add(string $customer_number, mixed $password): void + { + global $db; + // Avoid SQL injection + $customer_number = $db->escape_string($customer_number); + // Hash the password + $password = password_hash($password, PASSWORD_DEFAULT); + $password = $db->escape_string($password); + // Create a new record in the database + $sql = "INSERT INTO $this->table (customer_number, password) VALUES ('$customer_number', '$password')"; + $db->query($sql); + + // Get the id of the new record + $this->id = $db->insert_id(); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function hasPermission(string $permission): bool + { + global $db; + // Get the user's group id + $group_id = $this->group_id->value(); + // If the users is an admin, they have all permissions + if ((int)$group_id === 1) { + return true; + } + // Get the record from the database + $sql = "SELECT * FROM groups_permissions WHERE group_id = $group_id AND permission = '$permission'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + return true; + } + return false; + } + + public function edit(int $id, string $customer_number, string|null $role, string|null $password): void + { + global $db; + $this->id = $id; + // Avoid SQL injection + $customer_number = $db->escape_string($customer_number); + if ($password !== null) { + // Hash the password + $password = password_hash($password, PASSWORD_DEFAULT); + $password = $db->escape_string($password); + } + if ($role !== null) { + $role = $db->escape_string($role); + } + // Update the record in the database + $sql = "UPDATE $this->table SET customer_number = '$customer_number'"; + if ($password !== null) { + $sql .= ", password = '$password'"; + } + if ($role !== null) { + $sql .= ", group_id = '$role'"; + } + $sql .= " WHERE id = $this->id"; + $db->query($sql); + + // Set the values of the object properties + $this->getObjectProperties(); + } + + public function getCustomerByIdOrCustomerNumber(int $idOrCustomerNumber): users_o + { + global $db; + // Get the record from the database + $sql = "SELECT * FROM $this->table WHERE id = $idOrCustomerNumber OR customer_number = '$idOrCustomerNumber'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } else { + // Import the customer + $this->importCustomerFromExternalSource($idOrCustomerNumber); + } + return $this; + } + + public function automaticGetTargetUserFromRequest(): users_o + { + // Get the data from the request + if ($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'DELETE') { + $data = $_GET; + } else { + $data = json_decode(file_get_contents('php://input'), true); + } + // Check if the user id is set in the request + if (isset($data['user_id'])) { + return $this->getUserById((int)$data['user_id']); + } elseif (isset($data['customer_number'])) { + return $this->getUserByCustomerNumber($data['customer_number']); + } else { + return $this; + } + } + + public function asArray(): array + { + $array = [ + 'id' => (int)$this->id, + 'customer_number' => (int)$this->customer_number->value(), + 'group_id' => (int)$this->group_id->value(), + 'created_at' => $this->created_at->value(), + 'updated_at' => $this->updated_at->value(), + ]; + // If the economic customer data is set, add it to the array + if (isset($this->economic_customer)) { + $array['economic_customer'] = $this->economic_customer->asArray(); + } + // If the permissions are set, add them to the array + if (isset($this->permissions)) { + $array['permissions'] = $this->permissions; + } + return $array; + } + + public function getNotes():array + { + global $db; + // Create the customer notes object + $customer_notes = new customer_notes_o(); + // Get the customer notes + return $customer_notes->getCustomerNotesAsArray($this->id); + } + + public function addNote($customer_id, $note, $cashier_id): void + { + global $db; + // Create the customer notes object + $customer_notes = new customer_notes_o(); + // Add the note + $customer_notes->add($customer_id, $note, $cashier_id); + } + + public function deleteNote(int $note_id): void + { + global $db; + // Create the customer notes object + $customer_notes = new customer_notes_o(); + // Delete the note + $customer_notes->delete($note_id); + } + + public function getOrImportCustomerByCustomerNumber(int $customer_number): object|bool + { + global $db; + // Check if the customer exists + $sql = "SELECT * FROM $this->table WHERE customer_number = $customer_number"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + $this->id = $result->fetch_assoc()['id']; + $this->getObjectProperties(); + } else { + // Import the customer + return $this->importCustomerFromExternalSource($customer_number); + } + return $this; + } + + private function importCustomerFromExternalSource(int $customer_number): object|bool + { + global $db; + // Get the customer data from the external source + $economic = new economicCustomers(); + $customer_data = $economic->getCustomerId($customer_number); + // DEBUG: Return the customer data + // Check if the customer exists + if (isset($customer_data[0])) { + // Avoid SQL injection + $customer_number = $db->escape_string($customer_data[0]->customerNumber); + // Create a new record in the database + $sql = "INSERT INTO $this->table (customer_number) VALUES ('$customer_number')"; + $db->query($sql); + // Get the id of the new record + $this->id = $db->insert_id(); + // Set the values of the object properties + $this->getObjectProperties(); + } + // Else return false + return false; + } + + public function getCustomerEcocomicData(int $customer_number = null): users_o + { + // Get the customer data from the external source + $economic = new economicCustomers(); + // Check if the customer number is set + if (!isset($this->customer_number) && $customer_number === null) { + return $this; + } + $customer_number = $customer_number ?? $this->customer_number->value(); + $this->economic_customer = (new economic_customer_mo())->getCustomerByCustomerNumber($customer_number); + return $this; + } + + public function getUserAttributes(int $user_id = null): array + { + global $db; + if ($user_id === null) { + $user_id = $this->id; + } + $sql = "SELECT * FROM maintenancemode_dbtest.customer_attributes WHERE user_id = $user_id"; + $result = $db->query($sql); + return $db->fetch_all($result); + } + + public function doesUserHaveAttribute(string $attribute, int $user_id = null): bool + { + global $db; + if ($user_id === null) { + $user_id = $this->id; + } + $attribute = $db->escape_string($attribute); + $sql = "SELECT * FROM maintenancemode_dbtest.customer_attributes WHERE user_id = $user_id AND attribute = '$attribute'"; + $result = $db->query($sql); + if ($result->num_rows > 0) { + return true; + } + return false; + } + + public function addAttribute(string $attribute, int $user_id = null): void + { + global $db; + if ($user_id === null) { + $user_id = $this->id; + } + $attribute = $db->escape_string($attribute); + // Make sure the attribute does not already exist + if ($this->doesUserHaveAttribute((string)$attribute, (int)$user_id)) { + return; + } + $sql = "INSERT INTO maintenancemode_dbtest.customer_attributes (user_id, attribute) VALUES ($user_id, '$attribute')"; + $db->query($sql); + } + + public function deleteAttribute(string $attribute, int $user_id = null): void + { + global $db; + if ($user_id === null) { + $user_id = $this->id; + } + $attribute = $db->escape_string($attribute); + // Make sure the attribute exists + if (!$this->doesUserHaveAttribute((string)$attribute, (int)$user_id)) { + return; + } + $sql = "DELETE FROM maintenancemode_dbtest.customer_attributes WHERE user_id = $user_id AND attribute = '$attribute'"; + $db->query($sql); + } + + public function requiresReference(): bool + { + return $this->doesUserHaveAttribute('requiresReferenceNumber'); + } + + public function includeIncludes(array $includes = []): users_o + { + global /** @var response $response */ + $response; + $includeEverything = $response->getRequestParameter('include_all') === 'true' || in_array('all', $includes); + /** + * economicCustomer + */ + if ($includeEverything || $response->getRequestParameter('includeEconomicCustomer') === 'true' || in_array('economicCustomer', $includes)) { + $this->getCustomerEcocomicData(); + } + /** + * permissions + */ + if ($includeEverything || $response->getRequestParameter('includePermissions') === 'true' || in_array('permissions', $includes)) { + $this->getPermissions(); + } + return $this; + } + + private function getPermissions(): void + { + global $db; + $sql = "SELECT permission FROM groups_permissions WHERE group_id = " . $this->group_id->value(); + $result = $db->query($sql); + $perms = []; + while ($row = $result->fetch_assoc()) { + $perms[] = $row['permission']; + } + $this->permissions = $perms; + } +} \ No newline at end of file diff --git a/routes/authRoute.php b/routes/authRoute.php new file mode 100644 index 00000000..c521f52b --- /dev/null +++ b/routes/authRoute.php @@ -0,0 +1,78 @@ +post('/auth/login', function () { + // Get the post data + global $response; + $data = json_decode(file_get_contents('php://input'), true); + // Check if the customer number, and password are set + if (!isset($data['customer_number'])) { $response->error('Customer number is required', 400); } + if (!isset($data['password'])) { $response->error('Password is required', 400); } + // Try to log the user in + $isCredentialsValid = (new authentication())->authenticate($data['customer_number'], $data['password']); + // Log the incident + if ($isCredentialsValid) { + (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_SUCCESS', 'Customer number: ' . $data['customer_number']); + } else { + (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_FAILURE', 'Customer number: ' . $data['customer_number']); + $response->error('Invalid credentials', 401); + } + // If the credentials are valid, create a token + $token = (new authentication())->create_token($data['customer_number']); + // Return the token + $response->success(['token' => $token]); + }); + + $this->get('/auth/logout', function () { + // Get the token from the headers + global $response; + $token = $_SERVER['HTTP_AUTHORIZATION']; + // Remove the Bearer prefix + $token = str_replace('Bearer ', '', $token); + // Check if the token is valid + if (!(new authentication())->validate_token($token)) { + $response->error('Invalid token', 401); + } + // Delete the token + (new tokens_o())->delete($token); + // Return a success message + $response->success(['message' => 'Logged out']); + }); + + $this->get('/auth/session', function () { + // Get the token from the headers + global $response; + $token = $_SERVER['HTTP_AUTHORIZATION']; + // Remove the Bearer prefix + $token = str_replace('Bearer ', '', $token); + // Check if the token is valid + if (!(new authentication())->validate_token($token)) { + $response->error('Invalid token', 401); + } + // Get the user object + $user = (new authentication())->get_user(); + // Check if the user exists + if (!$user) { + $response->error('User not found', 400); + } + // Return the (session) user object + $response->success( + ($user->includeIncludes(['economicCustomer', 'permissions'])->asArray()) + ); + }); + } +} \ No newline at end of file diff --git a/routes/customerAttributes.php b/routes/customerAttributes.php new file mode 100644 index 00000000..6ecc2c89 --- /dev/null +++ b/routes/customerAttributes.php @@ -0,0 +1,115 @@ +get('/customer/attributes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_customer_attributes'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the query parameters from the URL + $data = $_GET; + // Check if the required fields are set + if (!isset($data['customer_number']) && !isset($data['user_id'])) { + $response->error('User ID or Customer Number is required', 400); + } + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, $user->id, 'LIST_CUSTOMER_ATTRIBUTES', 'Successfully listed customer attributes'); + // Check if the user exists + if (!(new users_o())->automaticGetTargetUserFromRequest()->exists()) { + $response->error('Customer not found', 400); + } + // Return the list of customer notes + $response->success( + (new users_o())->automaticGetTargetUserFromRequest()->getUserAttributes() + ); + } else { + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, 0, 'LIST_CUSTOMER_ATTRIBUTES', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/customer/attributes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_customer_attribute'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['user_id']) && !isset($data['customer_number'])) { + $response->error('User ID or Customer Number is required', 400); + } + if (!isset($data['attribute'])) { + $response->error('Attribute is required', 400); + } + // Add the note to the customer + (new users_o())->automaticGetTargetUserFromRequest()->addAttribute((string)$data['attribute']); + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, $user->id, 'ADD_CUSTOMER_ATTRIBUTE', 'Successfully added a customer attribute'); + // Return a success message + $response->success(['message' => 'Customer attribute added']); + } else { + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, 0, 'ADD_CUSTOMER_ATTRIBUTE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->delete('/customer/attributes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('delete_customer_attribute'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the query parameters from the URL + $data = $_GET; + // Check if the required fields are set + if (!isset($data['user_id']) && !isset($data['customer_number'])) { + $response->error('User ID or Customer Number is required', 400); + } + if (!isset($data['attribute'])) { + $response->error('Attribute is required', 400); + } + // Check if the user exists + if (!(new users_o())->automaticGetTargetUserFromRequest()->exists()) { + $response->error('Customer not found', 400); + } + // Add the note to the customer + (new users_o())->automaticGetTargetUserFromRequest()->deleteAttribute($data['attribute']); + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, $user->id, 'DELETE_CUSTOMER_ATTRIBUTE', 'Successfully deleted a customer attribute'); + // Return a success message + $response->success(['message' => 'Customer attribute deleted']); + } else { + // Log the incident + (new logs_o())->add('customer_attributes', 'global', 1, 0, 'DELETE_CUSTOMER_ATTRIBUTE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/customerNotes.php b/routes/customerNotes.php new file mode 100644 index 00000000..b6da5d4a --- /dev/null +++ b/routes/customerNotes.php @@ -0,0 +1,105 @@ +get('/customer/notes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_customer_notes'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the query parameters from the URL + $data = $_GET; + // Check if the required fields are set + if (!isset($data['customer_number']) && !isset($data['user_id'])) { $response->error('User ID or Customer Number is required', 400); } + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, $user->id, 'LIST_CUSTOMER_NOTES', 'Successfully listed customer notes'); + // Check if the user exists + if (!(new users_o())->automaticGetTargetUserFromRequest()->exists()) { + $response->error('Customer not found', 400); + } + // Return the list of customer notes + $response->success( + (new users_o())->automaticGetTargetUserFromRequest()->getNotes() + ); + } else { + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, 0, 'LIST_CUSTOMER_NOTES', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/customer/notes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_customer_note'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['user_id']) && !isset($data['customer_number'])) { $response->error('User ID or Customer Number is required', 400); } + if (!isset($data['note'])) { $response->error('Note is required', 400); } + // Add the note to the customer + $customer = (new users_o())->automaticGetTargetUserFromRequest(); + // Check if the customer exists + if (!$customer->exists()) { + $response->error('Customer not found', 400); + } + $customer->addNote((int)$customer->id, (string)$data['note'], (int)$user->id); + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, $user->id, 'ADD_CUSTOMER_NOTE', 'Successfully added a customer note'); + // Return a success message + $response->success(['message' => 'Customer note added']); + } else { + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, 0, 'ADD_CUSTOMER_NOTE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->delete('/customer/notes', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('delete_customer_note'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the query parameters from the URL + $data = $_GET; + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('Note ID is required', 400); } + // Delete the note from the customer + (new customer_notes_o())->delete((int)$data['id']); + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, $user->id, 'DELETE_CUSTOMER_NOTE', 'Successfully deleted a customer note'); + // Return a success message + $response->success(['message' => 'Customer note deleted']); + } else { + // Log the incident + (new logs_o())->add('customer_notes', 'global', 1, 0, 'DELETE_CUSTOMER_NOTE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/customerSearchRoute.php b/routes/customerSearchRoute.php new file mode 100644 index 00000000..1d513cd9 --- /dev/null +++ b/routes/customerSearchRoute.php @@ -0,0 +1,53 @@ +post('/customers/search', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('search_customers'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the pagination, search and sort parameters are set + if (!isset($data['search'])) { + $response->error('Missing required body parameter search', 400); + } + if (!isset($data['filter'])) { + $response->error('Missing required body parameter filter', 400); + } + // Check if the search parameter is valid + $allowedSearchFilters = (new economicCustomers())->allowed_search_filters_customers(); + if (!in_array($data['filter'], $allowedSearchFilters)) { + $response->error('Invalid search parameter', 400); + } + (new logs_o())->add('customers', 'global', 1, $user->id, 'SEARCH_CUSTOMERS', 'Successfully retrieved customers meeting search criteria'); + // Return the list of users + $response->success( + (array)(new economicCustomers())->searchCustomers((string)$data['search'], (string)$data['filter']) + ); + } else { + // Log the incident + (new logs_o())->add('customers', 'global', 1, 0, 'SEARCH_CUSTOMERS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + } +} \ No newline at end of file diff --git a/routes/departmentsRoute.php b/routes/departmentsRoute.php new file mode 100644 index 00000000..355fc557 --- /dev/null +++ b/routes/departmentsRoute.php @@ -0,0 +1,94 @@ +get('/departments', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_departments'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENTS', 'Successfully listed departments'); + // Return the list of departments + $response->success( + (new departments_o())->list() + ); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENTS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/departments', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_department'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['description'])) { $response->error('Description is required', 400); } + // Add the department + (new departments_o())->create($data['name'], $data['description']); + // Log the incident + (new logs_o())->add('departments', 'global', 1, $user->id, 'ADD_DEPARTMENT', 'Successfully added a department ' . $data['name']); + // Return a success message + $response->success(['message' => 'Department added successfully']); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'ADD_DEPARTMENT', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->put('/departments', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('edit_department'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('ID is required', 400); } + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['description'])) { $response->error('Description is required', 400); } + // Update the department + (new departments_o())->edit($data['id'], $data['name'], $data['description']); + // Log the incident + (new logs_o())->add('departments', $data['id'], 1, $user->id, 'EDIT_DEPARTMENT', 'Successfully updated a department ' . $data['name']); + // Return a success message + $response->success(['message' => 'Department updated successfully']); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'EDIT_DEPARTMENT', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/economicInvoiceRoute.php b/routes/economicInvoiceRoute.php new file mode 100644 index 00000000..e45028c7 --- /dev/null +++ b/routes/economicInvoiceRoute.php @@ -0,0 +1,202 @@ +post('/economic/invoice/draft/export', function () { + global $response; + $this->requirePermission('economic_invoice_draft_export'); + $user = (new authentication())->get_user(); + if ($user) { + $order_id = $response->getRequestParameter('order_id'); + if (!isset($order_id)) { + $response->error('Order ID is required', 400); + } + $order = (new orders_o())->getOrderById($order_id); + // Check if the order exists + if (!$order->exists()) { + $response->error('Order not found', 404); + } + // Get the order items + $order_items = (new orders_o())->getOrderItems($order_id); + // Get the customer + $customer = (new orders_o())->getCustomerByOrderId($order_id); + // Check if the customer exists + if (!$customer->exists()) { + $response->error('Customer not found', 404); + } + // Get the customer economic number + $customer_economic = $customer->getCustomerEcocomicData()->economic_customer; + $economic_invoice_draft = (new economic_invoice_draft_mo()); + // Set the customer number + $economic_invoice_draft->setCustomerNumber((int)$customer_economic->customer_number); + // Set the recipient + $economic_invoice_draft->setRecipient( + $customer_economic->name ?? 'Ukendt', + $customer_economic->address ?? 'Ukendt', + $customer_economic->zip ?? 'Ukendt', + $customer_economic->city ?? 'Ukendt' + ); + // Make sure there are order items + if (count($order_items) === 0) { + $response->error('No order items found', 404); + } + // Get the department + $department = (new departments_o())->getDepartmentById($order->department_id->value()); + // Add the department, date, reference + $economic_invoice_draft->addLineTEXT('Afdeling: ' . $department['name']); + $economic_invoice_draft->addLineTEXT('Dato: ' . $order->created_at->value()); + $economic_invoice_draft->addLineTEXT('Reference: ' . $order->reference->value()); + // Add the lines to the invoice + foreach ($order_items as $order_item) { + // If the customer requires any prefix or suffix to the product name, add it here + if ($customer->doesUserHaveAttribute('requiresRegistrationNumbersInvoice')) { + $order_item['product']['name'] = $order->reg_1->value() . ' ' . $order_item['product']['name']; + } + $economic_invoice_draft->addLine((string)$order_item['product']['economic_product_id'], (string)$order_item['product']['name'], 1, (int)$order_item['price'], 0); + } + // Create the invoice draft + $result = $economic_invoice_draft->createInvoiceDraftExample(); + // Check if the invoice draft was created + if (!isset($result->draftInvoiceNumber)) { + // Log the error + (new logs_o())->add('economic_invoice_draft', 'global', 3, $user->id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Failed to create economic invoice draft'); + // Check if we can get the errors from the response + if (isset($result->errors)) { + $response->add_meta('economic_errors', $result->errors); + } + // Try to parse the error message + $response->error($result->message ?? 'Failed to create economic invoice draft', 500); + } + // Add the economic invoice draft to the order + $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); + // Remove the existing invoice draft (if any) + if ($economic_module_orders->economic_invoice_draft_id->value() > 0) { + $economic_invoice_draft->deleteInvoiceDraft($economic_module_orders->economic_invoice_draft_id->value()); + } + $economic_module_orders->economic_invoice_draft_id->set($result->draftInvoiceNumber); + // Return the response + (new logs_o())->add('economic_invoice_draft', 'global', 1, $user->id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Successfully exported an economic invoice draft'); + $response->success($economic_module_orders->getArray()); + } else { + (new logs_o())->add('economic_invoice_draft', 'global', 1, 0, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }); + + $this->delete('/economic/invoice/draft/delete', function () { + + global /** @var response $response */ + $response; + $this->requirePermission('economic_invoice_draft_delete'); + $user = (new authentication())->get_user(); + if ($user) { + $order_id = $response->getRequestParameter('order_id'); + if (!isset($order_id)) { + $response->error('Order ID is required', 400); + } + $order = (new orders_o())->getOrderById($order_id); + // Check if the order exists + if (!$order->exists()) { + $response->error('Order not found', 404); + } + // Make sure the order has an economic invoice draft + $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); + if ($economic_module_orders->economic_invoice_draft_id->value() === 0) { + $response->error('No economic invoice draft found', 404); + } + $economic_invoice_draft = (new economic_invoice_draft_mo()); + // Get the invoice draft number + $invoiceDraftId = $economic_module_orders->economic_invoice_draft_id->value(); + // Delete the invoice draft + $economic_invoice_draft->deleteInvoiceDraft($invoiceDraftId); + // Remove the economic invoice draft from the order + $economic_module_orders->economic_invoice_draft_id->set(null); + // Return the response + (new logs_o())->add('economic_invoice_draft', 'global', 1, $user->id, 'ECONOMIC_INVOICE_DRAFT_DELETE', 'Successfully deleted an economic invoice draft'); + $response->success($economic_module_orders->getArray()); + } else { + (new logs_o())->add('economic_invoice_draft', 'global', 1, 0, 'ECONOMIC_INVOICE_DRAFT_DELETE', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }); + + $this->post('/economic/invoice/export', function () { + global $response; + $this->requirePermission('economic_invoice_export'); + $user = (new authentication())->get_user(); + if ($user) { + $order_id = $response->getRequestParameter('order_id'); + if (!isset($order_id)) { + $response->error('Order ID is required', 400); + } + $order = (new orders_o())->getOrderById($order_id); + // Check if the order exists + if (!$order->exists()) { + $response->error('Order not found', 404); + } + // Get the customer + $customer = (new orders_o())->getCustomerByOrderId($order_id); + // Check if the customer exists + if (!$customer->exists()) { + $response->error('Customer not found', 404); + } + // Make sure the order has an economic invoice draft + $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); + if ($economic_module_orders->economic_invoice_draft_id->value() === 0) { + $response->error('No economic invoice draft found', 404); + } + $economic_invoice_draft = (new economic_invoice_draft_mo()); + // Get the invoice draft number + $invoiceDraftId = $economic_module_orders->economic_invoice_draft_id->value(); + // Make sure there's not already an invoice created + $invoiceId = $economic_module_orders->economic_invoice_id->value(); + if ($invoiceId > 0) { + $response->error('An invoice has already been created, invoice ID: ' . $invoiceId, 400); + } + // Publish the invoice draft + $result = $economic_invoice_draft->publishInvoiceDraft((int)$invoiceDraftId); + // Check if the invoice was created + if (!isset($result->bookedInvoiceNumber)) { + // Log the error + (new logs_o())->add('economic_invoice', 'global', 3, $user->id, 'ECONOMIC_INVOICE_EXPORT', 'Failed to create economic invoice from draft: ' . $invoiceDraftId); + // Check if we can get the errors from the response + if (isset($result->errors)) { + $response->add_meta('economic_errors', $result->errors); + } + // Try to parse the error message + $response->error($result->message ?? 'Failed to create economic invoice', 500); + } + // Add the economic invoice to the order + $economic_module_orders = (new economic_module_orders())->getByOrderId($order_id); + $economic_module_orders->economic_invoice_id->set($result->bookedInvoiceNumber); + // Return the response + (new logs_o())->add('economic_invoice', 'global', 1, $user->id, 'ECONOMIC_INVOICE_EXPORT', 'Successfully exported an economic invoice'); + $response->success($economic_module_orders->getArray()); + } else { + (new logs_o())->add('economic_invoice', 'global', 1, 0, 'ECONOMIC_INVOICE_EXPORT', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/exampleRoute.php b/routes/exampleRoute.php new file mode 100644 index 00000000..89c54408 --- /dev/null +++ b/routes/exampleRoute.php @@ -0,0 +1,18 @@ +get('/example', function () { + global $response; + $response->success(['message' => 'Hello World!']); + }); + } +} \ No newline at end of file diff --git a/routes/intimidateRoute.php b/routes/intimidateRoute.php new file mode 100644 index 00000000..9734798b --- /dev/null +++ b/routes/intimidateRoute.php @@ -0,0 +1,42 @@ +post('/su/intimidate', function () { + // Get the post data + global $response; + // Make sure the user has the SUPERUSER_INTIMIDATE permission + if (!$this->requirePermission('SUPERUSER_INTIMIDATE')) { + $response->error('Permission denied', 403); + } + // Get the user object + $user = (new authentication())->get_user(); + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the customer number, and password are set + if (!isset($data['user_id'])) { + $response->error('User id is required', 400); + } + // Get the user object + $intimidated_user = (new users_o())->getUserById($data['user_id']); + // Log the incident + (new logs_o())->add('auth', 'global', 1, $user->id, 'AUTH_SUCCESS_INTIMIDATE', 'Created intimidate token for customer: ' . $data['user_id']); + // If the credentials are valid, create a token + $token = (new authentication())->create_token($intimidated_user->customer_number->value()); + // Return the token + $response->success(['token' => $token]); + }); + } +} \ No newline at end of file diff --git a/routes/optionsRoute.php b/routes/optionsRoute.php new file mode 100644 index 00000000..04426b34 --- /dev/null +++ b/routes/optionsRoute.php @@ -0,0 +1,22 @@ +options('/.*', function () { + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); + header('Access-Control-Allow-Headers: *'); + header('Content-Type: application/json'); + http_response_code(200); + }); + } +} \ No newline at end of file diff --git a/routes/orderItemsRoute.php b/routes/orderItemsRoute.php new file mode 100644 index 00000000..954dca9a --- /dev/null +++ b/routes/orderItemsRoute.php @@ -0,0 +1,99 @@ +post('/order/items', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_order_items'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Check if the required fields are set + $data = json_decode(file_get_contents('php://input'), true); + if (!isset($data['order_id'])) { $response->error('Order ID is required', 400); } + if (!isset($data['product_id'])) { $response->error('Product ID is required', 400); } + if (!isset($data['quantity'])) { $response->error('Quantity is required', 400); } + // Make sure we don't add more than 200 items at a time + if ($data['quantity'] > 199) { $response->error('Quantity is too high, please add less than 200 items at a time', 400); } + // Add the order item to the order This is done individually, to make the notes to the individual order items possible + for ($i = 0; $i < $data['quantity']; $i++) { + (new order_items_o())->addItemToOrder($data['order_id'], $data['product_id'], $user->id); + } + // Return the list of departments + $response->success( + ['message' => 'Order items added'] + ); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'ADD_ORDER_ITEMS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->get('/order/items', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_order_items'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = $_GET; + // Check if the required fields are set + if (!(int)$data['order_id']) { $response->error('Order ID is required', 400); } + // Return the list of departments + $response->success( + (new orders_o())->getOrderItems($data['order_id']) + ); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'LIST_ORDER_ITEMS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->delete('/order/items', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('delete_order_items'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the query data + $data = $_GET; + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('Order Item ID is required', 400); } + // Delete the order item + (new order_items_o())->removeOrderItem($data['id']); + // Return the list of departments + $response->success( + ['message' => 'Order item deleted'] + ); + } else { + // Log the incident + (new logs_o())->add('departments', 'global', 1, 0, 'DELETE_ORDER_ITEMS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/orderRoute.php b/routes/orderRoute.php new file mode 100644 index 00000000..fb927a92 --- /dev/null +++ b/routes/orderRoute.php @@ -0,0 +1,45 @@ +get('/order', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('fetch_order'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Make sure the order id is set + if (!(int)$this->fromRequest('id')) { $response->error('Order id is required', 400); } + // Make sure the order exists + if (!(new orders_o())->getOrderById($this->fromRequest('id'))->exists()) { $response->error('Order not found', 400); } + // Log the incident + (new logs_o())->add('orders', 'global', 1, $user->id, 'FETCH_ORDER', 'Successfully fetched order'); + // Return the list of departments + $response->success( + (new orders_o())->getOrderById($this->fromRequest('id'))->includeIncludes()->asArray() + ); + } else { + // Log the incident + (new logs_o())->add('orders', 'global', 1, 0, 'FETCH_ORDER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/ordersRoute.php b/routes/ordersRoute.php new file mode 100644 index 00000000..6daaa62d --- /dev/null +++ b/routes/ordersRoute.php @@ -0,0 +1,140 @@ +get('/orders', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_orders'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('orders', 'global', 1, $user->id, 'LIST_ORDERS', 'Successfully listed orders'); + // Return the list of departments + $response->success( + (new orders_o())->listObjectsWithPaginationIfSet() + ); + } else { + // Log the incident + (new logs_o())->add('orders', 'global', 1, 0, 'LIST_ORDERS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/orders', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_order'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + $data = $this->getData($data, $response); + // Validate the department + if (!(new departments_o())->getDepartmentById((int)$data['department_id'])) { + $response->error('Department not found', 400); + } + // Make sure the customer number set is valid + if (!(new users_o())->getCustomerByIdOrCustomerNumber((int)$data['customer_id'])->exists() || empty($data['customer_id'])) { + $response->error('Customer not found or invalid', 400); + } + // Check if the user requires a reference + if ((new users_o())->getCustomerByIdOrCustomerNumber((int)$data['customer_id'])->requiresReference() && empty($data['reference'])) { + $response->error('Reference is required by the customer', 400); + } + // Get the registration number + $reg_1 = $data['reg_1']; + // Get the registration numbers (If they are set, they 2-3 are optional) + $reg_2 = $data['reg_2'] ?? ''; + $reg_3 = $data['reg_3'] ?? ''; + // Create the order + $order = (new orders_o())->add((int)$data['customer_id'], $user->id, $data['reference'], $data['notes'], (int)$data['department_id'], (string)$reg_1, (string)$reg_2, (string)$reg_3); + // Log the incident + (new logs_o())->add('orders', $data['department_id'], 1, $user->id, 'ADD_ORDER', 'Successfully added an order (ID: ' . $data['department_id'] . ')'); + // Return a success message, containing the orders array + $response->success($order->asArray()); + } else { + // Log the incident + (new logs_o())->add('orders', 'global', 1, 0, 'ADD_ORDER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->put('/orders', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('edit_order'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('ID is required', 400); } + $data = $this->getData($data, $response); + // Update the order + (new orders_o())->edit((int)$data['id'], $user->id, (int)$data['customer_id'], $data['reference'], $data['notes'], (int)$data['department_id']); + // Log the incident + (new logs_o())->add('orders', $data['id'], 1, $user->id, 'EDIT_ORDER', 'Successfully updated an order (ID: ' . $data['id'] . ')'); + // Return a success message + $response->success(['message' => 'Order updated successfully']); + } else { + // Log the incident + (new logs_o())->add('orders', 'global', 1, 0, 'EDIT_ORDER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } + + /** + * @param mixed $data + * @param response $response + * @return mixed + */ + private function getData(mixed $data, response $response): mixed + { + if (!isset($data['customer_id'])) { + $response->error('Customer ID is required', 400); + } + if (!isset($data['department_id'])) { + $response->error('Department ID is required', 400); + } + if (!isset($data['reference'])) { + $response->error('Reference is required', 400); + } + if (!isset($data['notes'])) { + $response->error('Notes is required', 400); + } + if (!isset($data['reg_1'])) { + $response->error('Registration number 1 is required', 400); + } + if (strlen($data['reg_1']) < 4) { + $response->error('Registration number 1 must be at least 4 characters', 400); + } + // Optional fields are not checked here, as they are optional and can be empty + return $data; + } +} \ No newline at end of file diff --git a/routes/plateScannersRoute.php b/routes/plateScannersRoute.php new file mode 100644 index 00000000..a408fc99 --- /dev/null +++ b/routes/plateScannersRoute.php @@ -0,0 +1,96 @@ +get('/numberplatescanners', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_number_plate_scanners'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, $user->id, 'LIST_NUMBER_PLATE_SCANNERS', 'Successfully listed number plate scanners'); + // Return the list of plate scanners + $response->success( + (new plate_scanners_o())->listObjects() + ); + } else { + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, 0, 'LIST_NUMBER_PLATE_SCANNERS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/numberplatescanners', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_number_plate_scanner'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['department_id'])) { $response->error('Department ID is required', 400); } + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['notes'])) { $response->error('Notes is required', 400); } + // Add the number plate scanner + (new plate_scanners_o())->add($data['department_id'], $data['name'], $data['notes']); + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, $user->id, 'ADD_NUMBER_PLATE_SCANNER', 'Successfully added a number plate scanner'); + // Return a success message + $response->success(['message' => 'Number plate scanner added']); + } else { + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, 0, 'ADD_NUMBER_PLATE_SCANNER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->put('/numberplatescanners', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('edit_number_plate_scanner'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('ID is required', 400); } + if (!isset($data['department_id'])) { $response->error('Department ID is required', 400); } + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['notes'])) { $response->error('Notes is required', 400); } + // Edit the number plate scanner + (new plate_scanners_o())->edit($data['id'], $data['department_id'], $data['name'], $data['notes']); + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, $user->id, 'EDIT_NUMBER_PLATE_SCANNER', 'Successfully edited a number plate scanner'); + // Return a success message + $response->success(['message' => 'Number plate scanner edited']); + } else { + // Log the incident + (new logs_o())->add('numberplatescanners', 'global', 1, 0, 'EDIT_NUMBER_PLATE_SCANNER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/plateScansRoute.php b/routes/plateScansRoute.php new file mode 100644 index 00000000..d52500e7 --- /dev/null +++ b/routes/plateScansRoute.php @@ -0,0 +1,73 @@ +post('/numberplatescans', function () { + // Require the user to be logged in + global $response; + $this->requirePlateScannerAuth(); + // Get the plate scanner object + $plate_scanner = (new authentication())->get_plate_scanner(); + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['plate'])) { + $response->error('Missing required body parameter plate', 400); + } + // Add the number plate scanner + (new plate_scans_o())->add($plate_scanner->id, $data['plate']); + // Log the incident + (new logs_o())->add('numberplatescans', $plate_scanner->department_id->value(), 1, 0, 'ADD_NUMBER_PLATE_SCANS', 'Successfully added a number plate scan' . $data['plate']); + // Return a success message + $response->success(['message' => 'License plate scan recorded.', 'plate' => $data['plate'], 'scanner' => $plate_scanner->name->value()], 201); + }); + + $this->post('/numberplatescans/department', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_number_plate_scans_department'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Check if a department is set in the body + $data = json_decode(file_get_contents('php://input'), true); + if (!isset($data['department_id'])) { + $response->error('Missing required body parameter department', 400); + } + $this->requirePermission('list_number_plate_scans_department_' . $data['department_id']); + // Check if the pagination parameters are set + if (!isset($data['page'])) { + $response->error('Missing required body parameter page', 400); + } + if (!isset($data['limit'])) { + $response->error('Missing required body parameter limit', 400); + } + // Get the number plate scans + $number_plate_scans = (new plate_scans_o())->getPlateScansByDepartment((int)$data['department_id'], (int)$data['page'], (int)$data['limit']); + // Log the incident + (new logs_o())->add('numberplatescans', $data['department_id'], 1, $user->id, 'LIST_NUMBER_PLATE_SCANS_DEPARTMENT', 'Successfully listed number plate scans for department: ' . $data['department_id']); + // Return the number plate scans + $response->success($number_plate_scans); + } else { + // Log the incident + (new logs_o())->add('numberplatescans', 'global', 1, 0, 'LIST_NUMBER_PLATE_SCANS_DEPARTMENT', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/productsRoute.php b/routes/productsRoute.php new file mode 100644 index 00000000..b98c1efd --- /dev/null +++ b/routes/productsRoute.php @@ -0,0 +1,111 @@ +get('/products', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_products'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Check if the category is set in the request + $data = $_GET ?? []; + if (isset($data['category'])) { + // Log the incident + (new logs_o())->add('products', 'global', 1, $user->id, 'LIST_PRODUCTS', 'Successfully listed products in category ' . $data['category']); + // Return the list of departments + $response->success( + (new products_o())->listObjectsByCategory($data['category']) + ); + } + // Log the incident + (new logs_o())->add('products', 'global', 1, $user->id, 'LIST_PRODUCTS', 'Successfully listed products'); + // Return the list of departments + $response->success( + (new products_o())->listObjectsWithPaginationIfSet() + ); + } else { + // Log the incident + (new logs_o())->add('products', 'global', 1, 0, 'LIST_PRODUCTS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/products', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_product'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['description'])) { $response->error('Description is required', 400); } + if (!isset($data['price'])) { $response->error('Price is required', 400); } + if (!isset($data['category'])) { $response->error('Category is required', 400); } + if (!isset($data['piktogram'])) { $response->error('Piktogram is required', 400); } + if (!isset($data['economicProductId'])) { $response->error('Economic product ID is required', 400); } + // Add the product + (new products_o())->add($data['name'], $data['description'], $data['price'], $data['category'], $data['piktogram'], $data['economicProductId']); + // Log the incident + (new logs_o())->add('products', 'global', 1, $user->id, 'ADD_PRODUCT', 'Product name: ' . $data['name']); + // Return a success message + $response->success(['message' => 'Product added successfully']); + } else { + // Log the incident + (new logs_o())->add('products', 'global', 1, 0, 'ADD_PRODUCT', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->put('/products', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('edit_product'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('ID is required', 400); } + if (!isset($data['name'])) { $response->error('Name is required', 400); } + if (!isset($data['description'])) { $response->error('Description is required', 400); } + if (!isset($data['price'])) { $response->error('Price is required', 400); } + if (!isset($data['category'])) { $response->error('Category is required', 400); } + if (!isset($data['piktogram'])) { $response->error('Piktogram is required', 400); } + if (!isset($data['economicProductId'])) { $response->error('Economic product ID is required', 400); } + // Edit the product + (new products_o())->edit($data['id'], $data['name'], $data['description'], $data['price'], $data['category'], $data['piktogram'], $data['economicProductId']); + // Log the incident + (new logs_o())->add('products', 'global', 1, $user->id, 'EDIT_PRODUCT', 'Product id: ' . $data['id']); + // Return a success message + $response->success(['message' => 'Product edited successfully']); + } else { + // Log the incident + (new logs_o())->add('products', 'global', 1, 0, 'EDIT_PRODUCT', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/sessionRoute.php b/routes/sessionRoute.php new file mode 100644 index 00000000..b52e1d17 --- /dev/null +++ b/routes/sessionRoute.php @@ -0,0 +1,35 @@ +get('/auth/session', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('fetch_session'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('auth', 'global', 1, $user->id, 'FETCH_SESSION', 'User id: ' . $user->id); + // Return the user object + $response->success($user->getArray()); + } else { + // Log the incident + (new logs_o())->add('auth', 'global', 1, 0, 'FETCH_SESSION_FAILURE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/userOrdersRoute.php b/routes/userOrdersRoute.php new file mode 100644 index 00000000..f4291dfe --- /dev/null +++ b/routes/userOrdersRoute.php @@ -0,0 +1,44 @@ +get('/user/orders', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_own_orders'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('orders', 'global', 1, $user->id, 'LIST_OWN_ORDERS', 'Successfully listed own orders'); + // Return the list of the user's orders + $response->success( + (new orders_o())->getCustomerOrdersPaginated( + $user->customer_number->value(), + ($this->fromRequest('page') ?? 1), + ($this->fromRequest('limit') ?? 10), + ($this->fromRequest('order') ?? 'DESC') + ) + ); + } else { + // Log the incident + (new logs_o())->add('orders', 'global', 1, 0, 'LIST_OWN_ORDERS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/usersRoute.php b/routes/usersRoute.php new file mode 100644 index 00000000..15687e8f --- /dev/null +++ b/routes/usersRoute.php @@ -0,0 +1,133 @@ +get('/users', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_users'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('users', 'global', 1, $user->id, 'LIST_USERS', 'Successfully listed users'); + // Return the list of users + $response->success( + (new users_o())->listObjects() + ); + } else { + // Log the incident + (new logs_o())->add('users', 'global', 1, 0, 'LIST_USERS', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->get('/users/customer', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('get_user_from_customer_number'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Check if the customer number is valid + if (!(new users_o())->automaticGetTargetUserFromRequest()->exists()) { + // Log the incident + (new logs_o())->add('users', 'global', 1, $user->id, 'GET_USER_FROM_CUSTOMER_NUMBER', 'Customer not found, not imported'); + $response->error('Customer not found', 400); + } + // Check + // Log the incident + (new logs_o())->add('users', 'global', 1, $user->id, 'GET_USER_FROM_CUSTOMER_NUMBER', 'Successfully retrieved user from customer number'); + // Return the list of users + $response->success( + (new users_o())->automaticGetTargetUserFromRequest()->getCustomerEcocomicData()->asArray() + ); + } else { + // Log the incident + (new logs_o())->add('users', 'global', 1, 0, 'GET_USER_FROM_CUSTOMER_NUMBER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/users', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_user'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['customer_number'])) { $response->error('Customer number is required', 400); } + if (!isset($data['password'])) { $response->error('Password is required', 400); } + // Add the user + (new users_o())->add($data['customer_number'], $data['password']); + // Log the incident + (new logs_o())->add('users', 'global', 1, $user->id, 'ADD_USER', 'Successfully added a user'); + // Return a success message + $response->success(['message' => 'User added']); + } else { + // Log the incident + (new logs_o())->add('users', 'global', 1, 0, 'ADD_USER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->put('/users', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('edit_user'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + if (!isset($data['id'])) { $response->error('ID is required', 400); } + if (!isset($data['customer_number'])) { $response->error('Customer number is required', 400); } + // Check if a new role is set, if not, set it to null to prevent it from being updated + if (!isset($data['role']) || $data['role'] === 'null' || $data['role'] === '') { $data['role'] = null; } + // If the role is set, require the edit_user_role permission + if ($data['role']) { + $this->requirePermission('edit_user_role'); + } + // Check if a new password is set, if not, set it to null to prevent it from being updated + if (!isset($data['password']) || $data['password'] === 'null' || $data['password'] === '') { $data['password'] = null; } + // If the password is set, require the edit_user_password permission + if ($data['password']) { + $this->requirePermission('edit_user_password'); + } + // Edit the user + (new users_o())->edit((int)$data['id'], (string)$data['customer_number'], $data['role'], $data['password']); + // Log the incident + (new logs_o())->add('users', 'global', 1, $user->id, 'EDIT_USER', 'Successfully edited a user with ID: ' . $data['id']); + // Return a success message + $response->success(['message' => 'User edited']); + } else { + // Log the incident + (new logs_o())->add('users', 'global', 1, 0, 'EDIT_USER', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + } +} \ No newline at end of file diff --git a/routes/vehiclesRoute.php b/routes/vehiclesRoute.php new file mode 100644 index 00000000..e7595b89 --- /dev/null +++ b/routes/vehiclesRoute.php @@ -0,0 +1,121 @@ +get('/user/vehicles', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('list_own_vehicles'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Log the incident + (new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'Successfully listed own vehicles'); + // Return the list of the user's vehicles + $response->success( + (new customer_vehicles_o())->getCustomerVehiclesPaginated( + $user->id, + ($this->fromRequest('page') ?? 1), + ($this->fromRequest('limit') ?? 10) + ) + ); + } else { + // Log the incident + (new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_OWN_VEHICLES', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 400); + } + }); + + $this->post('/user/vehicles', function () { + // Require the user to be logged in + global $response; + $this->requirePermission('add_vehicle'); + // Get the user object + $user = (new authentication())->get_user(); + // Check if the request was successful + if ($user) { + // Get the post data + $data = json_decode(file_get_contents('php://input'), true); + // Check if the required fields are set + $data = $this->getData($data, $response); + // Make sure the registration number is valid + $this->validateRegistrationNumber($data['reg'], $response); + // Make sure the type is valid + $this->validateType($data['type'], $response); + // Make sure the notes are valid + $this->validateNotes($data['notes'], $response); + // Create a new vehicle + $vehicle = (new customer_vehicles_o())->add( + $user->id, + $data['type'], + $data['reg'], + $data['notes'] + ); + // Log the incident + (new logs_o())->add('vehicles', 'global', 1, $user->id, 'ADD_VEHICLE', 'Successfully added vehicle'); + // Return the new vehicle + $response->success($vehicle->getArrayByObjectProperties()); + } else { + // Log the incident + (new logs_o())->add('vehicles', 'global', 1, 0, 'ADD_VEHICLE', 'No user found, or invalid session'); + // Return an error + $response->error('Invalid session', 401); + } + }); + } + + private function getData(mixed $data, $response) + { + if (!isset($data['type'])) { + $response->error('Type is required', 400); + } + if (!isset($data['reg'])) { + $response->error('Registration number is required', 400); + } + if (!isset($data['notes'])) { + $response->error('Notes is required', 400); + } + return $data; + } + + private function validateRegistrationNumber(mixed $reg, $response): void + { + if (!preg_match('/^[A-Z0-9]{4,10}$/', $reg)) { + $response->error('Invalid registration number, it must be 4-10 characters long, and only contain uppercase letters and numbers', 400); + } + } + + private function validateType(mixed $type, $response): void + { + // Make sure the type is more than 2 characters + if (strlen($type) < 2) { + $response->error('Type is too short, it must be at least 2 characters', 400); + } + // Make sure the type is less than 50 characters + if (strlen($type) > 50) { + $response->error('Type is too long, it must be less than 50 characters', 400); + } + } + + private function validateNotes(mixed $notes, $response): void + { + // If the notes are set, make sure they are less than 250 characters + if (isset($notes) && strlen($notes) > 250) { + $response->error('Notes are too long, they must be less than 250 characters', 400); + } + } +} \ No newline at end of file diff --git a/traits/db_object_t.php b/traits/db_object_t.php new file mode 100644 index 00000000..59ae13f0 --- /dev/null +++ b/traits/db_object_t.php @@ -0,0 +1,172 @@ +structure(); + } + + public function __toString(): string + { + // Return the object as a string + return json_encode($this->getArray()); + } + + /** + * Set the table of the objects in the database + * @param string $table The table of the objects in the database + */ + public function setTable(string $table): void + { + $this->table = $table; + } + + + /** + * Structure: Define the table and fields of the objects in the database + */ + public function structure(): void + { + // Define the table and fields of the objects in the database + } + + /** + * Get current object row as an array + * @return array The current object row as an array + * @throws Exception If object not found + */ + public function getArray(): array + { + // Get the object from the database + global $db; + // Check if the id is set, if not throw an exception + if (!isset($this->id)) { + throw new Exception('Object not found'); + } + $id = $this->id; + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + return $db->fetch_assoc($result); + } + + /** + * List ALL objects in the table + * @return array The list of objects in the table + */ + public function listObjects(): array + { + global $db; + $sql = "SELECT * FROM $this->table"; + $result = $db->query($sql); + return $db->fetch_all($result); + } + + /** + * List objects in the table with pagination + * @param int $page The page number + * @param int $limit The number of objects per page + * @return array The list of objects in the table + */ + public function listObjectsWithPagination(int $page, int $limit, string $search = null, array $filters = null): array + { + global /** @var response $response */ + $db, $response; + $offset = ($page - 1) * $limit; + // Get all the fields of the table + $sql = "SHOW COLUMNS FROM $this->table"; + $result = $db->query($sql); + $fields = $db->fetch_all($result); + $searchfields = []; + foreach ($fields as $field) { + $searchfields[] = $field['Field']; + } + // Search for any similarities to the search query (Not case sensitive) + $searchQuery = ''; + if ($search) { + $searchQuery = 'WHERE '; + $search = strtolower($search); + $searchQuery .= '('; + foreach ($searchfields as $field) { + $searchQuery .= "LOWER($field) LIKE '%$search%' OR "; + } + $searchQuery = substr($searchQuery, 0, -4); + $searchQuery .= ')'; + } + // Filter the objects + if ($filters) { + if ($searchQuery) { + $searchQuery .= ' AND '; + } else { + $searchQuery = 'WHERE '; + } + foreach ($filters as $field => $value) { + $searchQuery .= "$field = $value AND "; + } + $searchQuery = substr($searchQuery, 0, -5); + } + // Get the objects with pagination + $sql = "SELECT * FROM $this->table $searchQuery LIMIT $limit OFFSET $offset"; + $result = $db->query($sql); + $array = $db->fetch_all($result); + $sql = "SELECT COUNT(*) AS count FROM $this->table $searchQuery"; + $result = $db->query($sql); + $row = $db->fetch_assoc($result); + $total = $row['count']; + $response->paginate($page, $limit, $total, $search, $filters); + return $array; + } + + /** + * List objects with pagination (if set) + * @return array The list of objects in the table + */ + public function listObjectsWithPaginationIfSet(): array + { + global $response; + $page = ((int) $response->getRequestParameter('page')) ?? null; // Get the page number + $limit = ((int) $response->getRequestParameter('limit')) ?? null; // Get the number of objects per page + $search = $response->getRequestParameter('search') ?? null; // Get the search query + $filters = $response->getRequestParameter('filters') ?? null; // Get the filters ( Eg. department_id:1,role_id:2 OR department_id:1 ) + // Make the filters an array + if ($filters) { + $filters = explode(',', $filters); + $temp = []; + foreach ($filters as $filter) { + $filter = explode(':', $filter); + $temp[$filter[0]] = $filter[1]; + } + $filters = $temp; + } + if ($page && $limit) { + return $this->listObjectsWithPagination($page, $limit, $search, $filters); + } + return $this->listObjects(); + } + + /** + * Does this object exist in the database? + * @return bool True if the object exists in the database, false otherwise + */ + public function exists(): bool + { + // Check if the id is set + if (!isset($this->id)) { + return false; + } + // Check if the object exists in the database + global $db; + $id = $this->id; + $sql = "SELECT * FROM $this->table WHERE id = $id"; + $result = $db->query($sql); + return $result->num_rows > 0; + } +} \ No newline at end of file diff --git a/traits/route_t.php b/traits/route_t.php new file mode 100644 index 00000000..9f02660d --- /dev/null +++ b/traits/route_t.php @@ -0,0 +1,160 @@ +route = $_SERVER['REQUEST_URI']; + } + + private function registerRoute($route, $method, $callback): void + { + global $router; + $router->add($route, $method, $callback); + } + + public function run(): void + { + // Add the routes here + } + + /** + * GET route + * @param string $route Example: /home, /home/{id} + */ + public function get(string $route, callable $callback): void + { + $this->registerRoute($route, 'GET', $callback); + } + + /** + * POST route + * @param string $route Example: /home, /home/{id} + */ + public function post(string $route, callable $callback): void + { + $this->registerRoute($route, 'POST', $callback); + } + + /** + * PUT route + * @param string $route Example: /home, /home/{id} + */ + public function put(string $route, callable $callback): void + { + $this->registerRoute($route, 'PUT', $callback); + } + + /** + * DELETE route + * @param string $route Example: /home, /home/{id} + */ + public function delete(string $route, callable $callback): void + { + $this->registerRoute($route, 'DELETE', $callback); + } + + /** + * OPTIONS route + * @param string $route Example: /home, /home/{id} + */ + public function options(string $route, callable $callback): void + { + $this->registerRoute($route, 'OPTIONS', $callback); + } + + /** + * Match route + * @param string $route Example: /home, /home/{id} + */ + private function match_route(string $route): bool + { + // Check if route is the same, or if it matches the regex pattern + return $route === $this->route || preg_match($route, $this->route); + } + + /** + * Get the parameter from the route URL by index + * @param string $index + * @return string|null + */ + public function fromRoute(string $index): ?string + { + $params = explode('/', $this->route); + $index = array_search($index, $params); + return $params[$index] ?? null; + } + + /** + * Require permission + * @param string $permission + * @return bool + */ + public function requirePermission(string $permission): bool + { + global $response; + // Check if the users authorization token has the required permission + try { + $user = (new authentication())->get_user(); + // If there is no user, return an error + if (!$user) { + (new logs_o())->add('global', 'global', 1, 0, 'AUTHENTICATION_FAILED', 'Authentication failed. Invalid, or missing token'); + $response->error('Authentication failed. Invalid or missing token.', 401); + } + if (!$user->hasPermission($permission)) { + (new logs_o())->add('global', 'global', 1, $user->id, 'PERMISSION_DENIED', 'Permission denied. Missing permission: ' . $permission); + $response->error('Permission denied. Missing permission: ' . $permission .' for user: ' . $user->id . ' In group: ' . $user->group_id->value(), 403); + } + } catch (\Exception $e) { + $response->error($e->getMessage(), 400); + } + return true; + } + + /** + * Require plate scanner authentication + * @return bool + */ + + public function requirePlateScannerAuth(): bool + { + global $response; + // Check if the plate scanner has a valid API key + try { + $plate_scanner = (new authentication())->get_plate_scanner(); + if (!$plate_scanner) { + (new logs_o())->add('global', 'global', 1, 0, 'AUTHENTICATION_FAILED', 'Authentication failed. Invalid, or missing API key'); + $response->error('Authentication failed. Invalid or missing API key.', 401); + } + } catch (\Exception $e) { + $response->error($e->getMessage(), 400); + } + return true; + } + + /** + * Get the parameter from the query string by name + * @param string $name + * @return string|null + */ + public function fromQuery(string $name): ?string + { + return (isset($_GET[$name])) ? $_GET[$name] : null; + } + + /** + * Get data from the request body or query string by name + * @param string $name + * @return string|null + */ + public function fromRequest(string $name): ?string + { + return (isset($_POST[$name])) ? $_POST[$name] : $this->fromQuery($name); + } +} \ No newline at end of file diff --git a/traits/session_t.php b/traits/session_t.php new file mode 100644 index 00000000..9dc1b76e --- /dev/null +++ b/traits/session_t.php @@ -0,0 +1,8 @@ +