Add caching and Slack notification enhancements

Implemented caching for department and customer names to improve performance. Added Slack notifications for new bookings with detailed formatting. Refactored related methods to streamline functionality and ensure better code clarity.
This commit is contained in:
Jepp9350
2025-01-20 08:08:18 +01:00
parent f256e05c3d
commit 851d5f3e4c
9 changed files with 188 additions and 42 deletions
+5
View File
@@ -108,4 +108,9 @@ class db
{
return $this->conn->prepare($sql);
}
public function num_rows(\mysqli_result|bool $result): int|string
{
return $result->num_rows;
}
}
+29
View File
@@ -108,4 +108,33 @@ class redis implements redis_i
$this->delete('department_webhook_' . $department_id);
return $this;
}
/**
* @inheritDoc
*/
public function cache_department_name(int $department_id, string $department_name): self
{
// Cache the department name
$this->set('department_name_' . $department_id, $department_name);
return $this;
}
/**
* @inheritDoc
*/
public function get_department_name(int $department_id): string|null
{
// Get the department name
return $this->get('department_name_' . $department_id);
}
/**
* @inheritDoc
*/
public function clear_department_name(int $department_id): self
{
// Clear the department name
$this->delete('department_name_' . $department_id);
return $this;
}
}
+25
View File
@@ -5,6 +5,7 @@ namespace classes;
use GuzzleHttp\Client;
use interfaces\notification_i;
use objects\departments_o;
use objects\users_o;
use traits\notification_t;
@@ -78,4 +79,28 @@ class slack implements notification_i
return 'Failed to send message: ' . $e->getMessage();
}
}
public function format_new_booking($id, $customer_number, string $wash_type, string $contact_email, string $reference_number, string $regNrTraekker, string $regNrTrailer, string $washCertificateEmail, string $date, int $department, $pickup_bool, string $notes, string $washCertificateStatus, string $washCertificateUrl, string $status): string
{
// Get the department name
$department_name = (new departments_o())->getDepartmentName($department);
// Get the customer name
$customer_name = (new users_o())->getCustomerName($customer_number);
// Format the message
return "New booking created\n"
. "ID: $id\n"
. "Customer: $customer_name\n"
. "Customer number: $customer_number\n"
. "Wash type: $wash_type\n"
. "Contact email: $contact_email\n"
. "Reference number: $reference_number\n"
. "RegNr Traekker: $regNrTraekker\n"
. "RegNr Trailer: $regNrTrailer\n"
. "Wash certificate email: $washCertificateEmail\n"
. "Date: $date\n"
. "Department: $department_name\n"
. "Pickup: $pickup_bool\n"
. "Notes: $notes\n"
. "Status: $status";
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
<?php global $DEBUG, $CONFIG_DB, $ENCRYPTION_KEY, $CORS, $WD, $db, $response, $request, $router, $redis;
<?php global /** @var response $response */
$DEBUG, $CONFIG_DB, $ENCRYPTION_KEY, $CORS, $WD, $db, $response, $request, $router, $redis;
/**
* This is the main entry point to the Truck Wash API.
*/
+22
View File
@@ -69,4 +69,26 @@ interface redis_i
* @return self
*/
public function clear_department_webhook(int $department_id): self;
/**
* Cache a department name
* @param int $department_id
* @param string $department_name
* @return self
*/
public function cache_department_name(int $department_id, string $department_name): self;
/**
* Get a department name
* @param int $department_id
* @return string|null
*/
public function get_department_name(int $department_id): string|null;
/**
* Clear a department name
* @param int $department_id
* @return self
*/
public function clear_department_name(int $department_id): self;
}
+69 -38
View File
@@ -5,6 +5,7 @@ namespace objects;
use classes\db;
use classes\object_property;
use classes\response;
use classes\slack;
use traits\db_object_t;
class bookings_o extends db
@@ -31,6 +32,74 @@ class bookings_o extends db
$this->setTable('bookings');
}
public function addOrUpdate($id, $customer_number, $wash_type, $contact_email, $reference_number, $regNrTraekker, $regNrTrailer, $washCertificateEmail, $date, $department, $pickup_bool, $notes, $washCertificateStatus, $washCertificateUrl, $status): void
{
global $db;
// Avoid SQL injection
$wash_type = $db->escape_string($wash_type);
$contact_email = $db->escape_string($contact_email);
$reference_number = $db->escape_string($reference_number);
$regNrTraekker = $db->escape_string($regNrTraekker);
$regNrTrailer = $db->escape_string($regNrTrailer);
$washCertificateEmail = $db->escape_string($washCertificateEmail);
$date = $db->escape_string($date);
// Parse the department name to id
$department = $this->getDepartmentIdByLegacyName($department);
$notes = $db->escape_string($notes);
$washCertificateStatus = $db->escape_string($washCertificateStatus);
$washCertificateUrl = $db->escape_string($washCertificateUrl);
$status = $db->escape_string($status);
// Check if the entry already exists
$sql = "SELECT * FROM $this->table WHERE id = $id";
$result = $db->query($sql);
if ($db->num_rows($result) === 0) {
// Send a department webhook if the booking is new
$slack = new slack();
try {
$slack->send_department_booking_notification($department, $slack->format_new_booking(
$id,
$customer_number,
$wash_type,
$contact_email,
$reference_number,
$regNrTraekker,
$regNrTrailer,
$washCertificateEmail,
$date,
$department,
$pickup_bool,
$notes,
$washCertificateStatus,
$washCertificateUrl,
$status
));
} catch (\Exception $e) {
// Log the error
$logs = new logs_o();
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_BOOKING_NOTIFICATION', $e->getMessage());
}
}
// Create a new record in the database ( Replace the code, if an entry already exists )
$sql = "INSERT INTO $this->table (id, customer_number, wash_type, contact_email, reference_number, regNrTraekker, regNrTrailer, washCertificateEmail, date, department, pickup_bool, notes, washCertificateStatus, washCertificateUrl, status) VALUES ($id, $customer_number, '$wash_type', '$contact_email', '$reference_number', '$regNrTraekker', '$regNrTrailer', '$washCertificateEmail', '$date', '$department', $pickup_bool, '$notes', '$washCertificateStatus', '$washCertificateUrl', '$status') ON DUPLICATE KEY UPDATE customer_number = $customer_number, wash_type = '$wash_type', contact_email = '$contact_email', reference_number = '$reference_number', regNrTraekker = '$regNrTraekker', regNrTrailer = '$regNrTrailer', washCertificateEmail = '$washCertificateEmail', date = '$date', department = '$department', pickup_bool = $pickup_bool, notes = '$notes', washCertificateStatus = '$washCertificateStatus', washCertificateUrl = '$washCertificateUrl', status = '$status'";
$db->query($sql);
// Clear the cache
redis->clear_department_booking_count($department);
}
public function getDepartmentIdByLegacyName(string $departmentName): int
{
// Get the department id by the legacy name
$departmentLegacyNames = [
'køge' => 4,
'taastrup' => 2,
'aarhusc' => 5,
'roskilde' => 6,
'hvidovre' => 1,
'glostrup' => 3,
];
return $departmentLegacyNames[strtolower($departmentName)] ?? 0;
}
public function add(int $customer_number, string $wash_type, string $contact_email, string $reference_number, string $regNrTraekker, string $regNrTrailer, string $washCertificateEmail, string $date, string $department, int $pickup_bool, string $notes, string $washCertificateStatus, string $washCertificateUrl, string $status): void
{
global $db;
@@ -58,44 +127,6 @@ class bookings_o extends db
$this->id = $db->insert_id();
}
public function getDepartmentIdByLegacyName(string $departmentName): int
{
// Get the department id by the legacy name
$departmentLegacyNames = [
'køge' => 4,
'taastrup' => 2,
'aarhusc' => 5,
'roskilde' => 6,
'hvidovre' => 1,
'glostrup' => 3,
];
return $departmentLegacyNames[strtolower($departmentName)] ?? 0;
}
public function addOrUpdate($id, $customer_number, $wash_type, $contact_email, $reference_number, $regNrTraekker, $regNrTrailer, $washCertificateEmail, $date, $department, $pickup_bool, $notes, $washCertificateStatus, $washCertificateUrl, $status): void
{
global $db;
// Avoid SQL injection
$wash_type = $db->escape_string($wash_type);
$contact_email = $db->escape_string($contact_email);
$reference_number = $db->escape_string($reference_number);
$regNrTraekker = $db->escape_string($regNrTraekker);
$regNrTrailer = $db->escape_string($regNrTrailer);
$washCertificateEmail = $db->escape_string($washCertificateEmail);
$date = $db->escape_string($date);
// Parse the department name to id
$department = $this->getDepartmentIdByLegacyName($department);
$notes = $db->escape_string($notes);
$washCertificateStatus = $db->escape_string($washCertificateStatus);
$washCertificateUrl = $db->escape_string($washCertificateUrl);
$status = $db->escape_string($status);
// Create a new record in the database ( Replace the code, if an entry already exists )
$sql = "INSERT INTO $this->table (id, customer_number, wash_type, contact_email, reference_number, regNrTraekker, regNrTrailer, washCertificateEmail, date, department, pickup_bool, notes, washCertificateStatus, washCertificateUrl, status) VALUES ($id, $customer_number, '$wash_type', '$contact_email', '$reference_number', '$regNrTraekker', '$regNrTrailer', '$washCertificateEmail', '$date', '$department', $pickup_bool, '$notes', '$washCertificateStatus', '$washCertificateUrl', '$status') ON DUPLICATE KEY UPDATE customer_number = $customer_number, wash_type = '$wash_type', contact_email = '$contact_email', reference_number = '$reference_number', regNrTraekker = '$regNrTraekker', regNrTrailer = '$regNrTrailer', washCertificateEmail = '$washCertificateEmail', date = '$date', department = '$department', pickup_bool = $pickup_bool, notes = '$notes', washCertificateStatus = '$washCertificateStatus', washCertificateUrl = '$washCertificateUrl', status = '$status'";
$db->query($sql);
// Clear the cache
redis->clear_department_booking_count($department);
}
public function getCustomerBookingsPaginated(int $customer_number, int $page = 1, int $limit = 10, array $order = ['id' => 'DESC'], string $search = null, array $filters = null): array
{
global /** @var response $response */
+17
View File
@@ -147,4 +147,21 @@ class departments_o extends db
$this->getObjectProperties();
return $this;
}
public function getDepartmentName(int $department): string
{
global $db;
// Check if the department name is cached
$name = redis->get_department_name($department);
// If the department name is not cached, get it from the database
if ($name === null) {
$sql = "SELECT name FROM $this->table WHERE id = $department";
$result = $db->query($sql);
$result = $db->fetch_assoc($result);
$name = $result['name'];
// Cache the department name
redis->cache_department_name($department, $name);
}
return redis->get_department_name($department);
}
}
+14 -1
View File
@@ -642,6 +642,19 @@ class users_o extends db
return false;
}
public function parseUsers(array $listObjectsWithPaginationIfSet): array
{
return self::parseCustomerNumbers($listObjectsWithPaginationIfSet);
}
public function parseCustomerNumbers(array $listObjectsWithPaginationIfSet): array
{
foreach ( $listObjectsWithPaginationIfSet as $key => $value ) {
$listObjectsWithPaginationIfSet[$key]['customer_name'] = $this->getCustomerName($value['customer_number']);
}
return $listObjectsWithPaginationIfSet;
}
public function getCustomerName(int $customer_number): string|null
{
// Check if the customer name is cached
@@ -652,7 +665,7 @@ class users_o extends db
$economic = new economicCustomers();
$customer_name = $economic->getCustomerName($customer_number);
// Cache the customer name
redis->cache_economic_customer_name($customer_number, $customer_name);
redis->cache_economic_customer_name($customer_number, $customer_name ?? '');
return $customer_name;
}
}
+5 -2
View File
@@ -3,6 +3,7 @@
namespace routes;
use classes\authentication;
use classes\response;
use objects\logs_o;
use objects\users_o;
use traits\route_t;
@@ -15,7 +16,8 @@ class usersRoute
{
$this->get('/users', function () {
// Require the user to be logged in
global $response;
global /** @var response $response */
$response;
$this->requirePermission('list_users');
// Get the user object
$user = (new authentication())->get_user();
@@ -24,8 +26,9 @@ class usersRoute
// Log the incident
(new logs_o())->add('users', 'global', 1, $user->id, 'LIST_USERS', 'Successfully listed users');
// Return the list of users
$users_o = new users_o();
$response->success(
(new users_o())->listObjects()
$users_o->parseUsers($users_o->listObjectsWithPaginationIfSet())
);
} else {
// Log the incident