Add new cron tasks and enhance user synchronization logic
Introduced cron tasks for syncing user economic customer details and discounts. Enhanced caching mechanisms for users and departments, added Slack messaging capabilities, and updated CLI/script routing for better flexibility. New routes and utility methods improve cron execution and logging.
This commit is contained in:
+14
-4
@@ -87,10 +87,15 @@ class redis implements redis_i
|
||||
public function cache_department_name(int $department_id, string $department_name): self
|
||||
{
|
||||
// Cache the department name (If it is not empty or null)
|
||||
if (!empty($department_name)) {
|
||||
if (empty($department_name)) {
|
||||
$department_name = 'IS_EMPTY_OR_NULL';
|
||||
return $this;
|
||||
}
|
||||
$this->set('department_name_' . $department_id, $department_name);
|
||||
// Set the department's name in the cache
|
||||
if ($this->get_department_name($department_id) === null) {
|
||||
$this->set('department_' . $department_id, json_encode(['name' => $department_name]
|
||||
));
|
||||
};
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -100,7 +105,12 @@ class redis implements redis_i
|
||||
public function get_department_name(int $department_id): string|null
|
||||
{
|
||||
// Get the department name
|
||||
return $this->get('department_name_' . $department_id);
|
||||
$tmp_department = $this->get('department_' . $department_id);
|
||||
if ($tmp_department === 'IS_EMPTY_OR_NULL' || $tmp_department === null) {
|
||||
return null;
|
||||
}
|
||||
// Return the department name
|
||||
return json_decode($tmp_department, true)->name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +119,7 @@ class redis implements redis_i
|
||||
public function clear_department_name(int $department_id): self
|
||||
{
|
||||
// Clear the department name
|
||||
$this->delete('department_name_' . $department_id);
|
||||
$this->delete('department_' . $department_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,4 +129,11 @@ class slack implements notification_i
|
||||
. "Notes: $notes\n"
|
||||
. "Status: $status";
|
||||
}
|
||||
|
||||
public function send_message(string $string): void
|
||||
{
|
||||
global $SLACK_DEFAULT_WEBHOOK;
|
||||
// Send the message to the slack webhook
|
||||
self::add_log(self::send_webhook_message($string, $SLACK_DEFAULT_WEBHOOK));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,27 @@
|
||||
<?php
|
||||
global $EMAIL_WASH_CERTIFICATE_TOKEN;
|
||||
// This script only runs when the program is called from the command line. It is used to run the CLI script.
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
if (php_sapi_name() !== 'cli' && !isset($_GET['internalCronCall'])) {
|
||||
exit;
|
||||
}
|
||||
$args = $argv;
|
||||
// If the program was called from the command line, get the arguments
|
||||
if (php_sapi_name() === 'cli') {
|
||||
$args = $argv;
|
||||
} else {
|
||||
// If the program was called from the browser, get the arguments from the URL
|
||||
$args = [];
|
||||
$args[1] = $_GET['script'];
|
||||
$args[2] = $_GET['action'];
|
||||
$auth = $_GET['auth_key'] ?? null;
|
||||
if ($auth !== $EMAIL_WASH_CERTIFICATE_TOKEN) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid token'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the first argument is 'run', switch to the second argument
|
||||
if ($args[1] === 'run') {
|
||||
@@ -45,4 +63,6 @@ if ($args[1] === 'run') {
|
||||
echo "Invalid script name";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
echo "Invalid action";
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
<?php global $CONFIG_DB, $DEBUG, $ENCRYPTION_KEY, $CORS, $ECONOMIC_API, $WORDPRESS_STATIC_TOKEN, $USE_PROD_ECONOMIC_IN_DEBUG, $REDIS_CONFIG, $EMAIL_WASH_CERTIFICATE_TOKEN, $MINIO, $WORDPRESS_API_URL;
|
||||
<?php global $CONFIG_DB, $DEBUG, $ENCRYPTION_KEY, $CORS, $ECONOMIC_API, $WORDPRESS_STATIC_TOKEN, $USE_PROD_ECONOMIC_IN_DEBUG, $REDIS_CONFIG, $EMAIL_WASH_CERTIFICATE_TOKEN, $MINIO, $WORDPRESS_API_URL, $SLACK_DEFAULT_WEBHOOK;
|
||||
$CONFIG_DB = [
|
||||
'host' => '', // IP address of the database server e.g. 127.0.0.1
|
||||
'user' => '', // Username of the database server e.g. root
|
||||
@@ -29,6 +29,7 @@ $MINIO = [
|
||||
'access_key' => '', // Minio access
|
||||
'secret_key' => '' // Minio secret key
|
||||
];
|
||||
$SLACK_DEFAULT_WEBHOOK = ''; // Default Slack webhook URL e.g. https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX
|
||||
$REDIS_CONFIG = [
|
||||
'host' => '', // Redis host (IP address)
|
||||
'database' => 0, // Redis database number (0-15)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This script is used to sync bookings from the remote API to the local database.
|
||||
* It is run as a cron job.
|
||||
*
|
||||
* index.php run bookingSync
|
||||
*/
|
||||
|
||||
// prevent direct access
|
||||
|
||||
use objects\users_o;
|
||||
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
}
|
||||
$start = microtime(true);
|
||||
// Sync the discounts
|
||||
$users_o = new users_o();
|
||||
$users_o->clearAllUsersEconomicCustomerDetailsFromCache();
|
||||
$end = microtime(true);
|
||||
//$slack = new \classes\slack();
|
||||
//$slack->send_message("The booking sync script has finished. It took " . round($end - $start, 2) . " seconds to run.");
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This script is used to sync bookings from the remote API to the local database.
|
||||
* It is run as a cron job.
|
||||
*
|
||||
* index.php run bookingSync
|
||||
*/
|
||||
|
||||
// prevent direct access
|
||||
|
||||
use objects\users_o;
|
||||
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
}
|
||||
$start = microtime(true);
|
||||
// Sync the discounts
|
||||
$users_o = new users_o();
|
||||
$users_o->clearAllUsersEconomicCustomerDiscountsFromCache();
|
||||
$end = microtime(true);
|
||||
//$slack = new \classes\slack();
|
||||
//$slack->send_message("The booking sync script has finished. It took " . round($end - $start, 2) . " seconds to run.");
|
||||
+30
-2
@@ -3,6 +3,7 @@
|
||||
|
||||
use objects\bookings_o;
|
||||
use objects\logs_o;
|
||||
use objects\users_o;
|
||||
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
@@ -14,6 +15,8 @@ function warn($message): void
|
||||
echo "\n\033[33m$message\033[0m\n";
|
||||
}
|
||||
|
||||
$response_cron = [];
|
||||
|
||||
// Define the cron tasks
|
||||
$cron_tasks = [
|
||||
'CheckUnfulfilledBookings' => [
|
||||
@@ -35,6 +38,18 @@ $cron_tasks = [
|
||||
'next_run' => 0,
|
||||
'function' => 'syncLogsToDatabase',
|
||||
],
|
||||
'SyncUserEconomicCustomerDiscounts' => [
|
||||
'interval' => 600, // 10 minutes
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'SyncUserEconomicCustomerDiscounts',
|
||||
],
|
||||
'SyncUserEconomicCustomerDetails' => [
|
||||
'interval' => 43200, // 12 hours
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'SyncUserEconomicCustomerDetails',
|
||||
],
|
||||
];
|
||||
|
||||
function checkUnfulfilledBookings(): void
|
||||
@@ -46,7 +61,7 @@ function checkUnfulfilledBookings(): void
|
||||
function syncBookings(): void
|
||||
{
|
||||
$bookings_o = new bookings_o();
|
||||
$bookings_o->syncBookings();
|
||||
$response_cron[] = $bookings_o->syncBookings();
|
||||
}
|
||||
|
||||
function syncLogsToDatabase(): void
|
||||
@@ -55,6 +70,19 @@ function syncLogsToDatabase(): void
|
||||
$logs_o->syncLogsToDatabase();
|
||||
}
|
||||
|
||||
function SyncUserEconomicCustomerDiscounts(): void
|
||||
{
|
||||
$users_o = new users_o();
|
||||
$users_o->clearAllUsersEconomicCustomerDiscountsFromCache();
|
||||
}
|
||||
|
||||
function SyncUserEconomicCustomerDetails(): void
|
||||
{
|
||||
$users_o = new users_o();
|
||||
$users_o->clearAllUsersEconomicCustomerDetailsFromCache();
|
||||
$users_o->syncAllUsersEconomicCustomerDetails();
|
||||
}
|
||||
|
||||
foreach ( $cron_tasks as $task => $data ) {
|
||||
$lastRun = redis->get_last_crond_run($task) === null ? 0 : redis->get_last_crond_run($task);
|
||||
$nextRun = $lastRun + $data['interval'];
|
||||
@@ -64,6 +92,6 @@ foreach ( $cron_tasks as $task => $data ) {
|
||||
$data['function']();
|
||||
redis->set_last_crond_run($task, time());
|
||||
} else {
|
||||
warn('Task ' . $task . ' is not due to run yet, next run is at ' . date('Y-m-d H:i:s', $nextRun) . ' (' . ($nextRun - time()) . ' seconds)');
|
||||
$response_cron[] = $task . ' is not due to run yet, next run is at ' . date('Y-m-d H:i:s', $nextRun) . ' (' . ($nextRun - time()) . ' seconds)';
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,10 @@ use objects\bookings_o;
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
// Sync the bookings
|
||||
$bookings_o = new bookings_o();
|
||||
$bookings_o->syncBookings();
|
||||
$bookings_o->syncBookings();
|
||||
$end = microtime(true);
|
||||
//$slack = new \classes\slack();
|
||||
//$slack->send_message("The booking sync script has finished. It took " . round($end - $start, 2) . " seconds to run.");
|
||||
@@ -96,7 +96,7 @@ foreach ( glob(WD . '/objects/*.php') as $object ) {
|
||||
}
|
||||
|
||||
// If the program was called from the command line, run the cli script
|
||||
if (php_sapi_name() === 'cli') {
|
||||
if (php_sapi_name() === 'cli' || isset($_GET['internalCronCall'])) {
|
||||
require_once 'cli.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
+6
-4
@@ -58,10 +58,12 @@ class logs_o extends db
|
||||
echo "\r\033[33m" . str_repeat('=', $percentage) . str_repeat(' ', 100 - $percentage) . "\033[0m " . number_format($percentage, 2) . '%';
|
||||
}
|
||||
// Show the percentage, completed and total
|
||||
echo "\r\033[33m" . number_format($percentage, 2) . '% (' . $current . '/' . $total . ")\033[0m";
|
||||
// If the current is equal to the total, add a new line
|
||||
if ($current === $total) {
|
||||
echo "\n";
|
||||
if ($display_progress) {
|
||||
echo "\r\033[33m" . number_format($percentage, 2) . '% (' . $current . '/' . $total . ")\033[0m";
|
||||
// If the current is equal to the total, add a new line
|
||||
if ($current === $total) {
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+61
-26
@@ -259,11 +259,9 @@ class users_o extends db
|
||||
if ($customer_number === 0) {
|
||||
return null;
|
||||
}
|
||||
$tmp_user = redis->get_economic_customer_name((int)$customer_number);
|
||||
if ($tmp_user !== null) {
|
||||
return $tmp_user;
|
||||
}
|
||||
// Create a temporary user object
|
||||
$tmp_user = new users_o();
|
||||
$tmp_user->getUserByCustomerNumber($customer_number);
|
||||
// Get the customer name (Check cache first)
|
||||
$cached = $tmp_user->getCached('economic_customer');
|
||||
if (!$cached) {
|
||||
@@ -578,23 +576,6 @@ class users_o extends db
|
||||
$this->keys->setUser($this->id)->deleteValue('open_invoice_draft');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom price (DISCOUNT) for the user
|
||||
* @param int $user_id
|
||||
* @param int $object_id The ID of the object
|
||||
* @param int $discount_percentage The discount percentage
|
||||
* @param bool $is_category If the object is a category
|
||||
* @return void
|
||||
*/
|
||||
public function setCustomPrice(int $user_id, int|string $object_id, int $discount_percentage, bool $is_category = false): void
|
||||
{
|
||||
$this->id = $user_id;
|
||||
// Get the user object properties
|
||||
$this->getObjectProperties();
|
||||
// Set the custom price (key = 'custom_price')
|
||||
$this->price_overrides->setUser($this->id)->setPrice($is_category, $object_id, $discount_percentage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom price (DISCOUNT) for the user
|
||||
* @param int $object_id The ID of the object
|
||||
@@ -726,7 +707,7 @@ class users_o extends db
|
||||
// Check if the name is cached
|
||||
$cached_name = $this->getCached('economic_customer', $id);
|
||||
if (!$cached_name) {
|
||||
echo 'No cached name found for user with ID: ' . $id;
|
||||
// No cached name, get the name from the external source
|
||||
// Get the name from the external source
|
||||
$tmp_user = new users_o();
|
||||
$tmp_user->getUserById($id);
|
||||
@@ -741,6 +722,38 @@ class users_o extends db
|
||||
return $cached_name->name ?? null;
|
||||
}
|
||||
|
||||
public function hasPassword(): bool
|
||||
{
|
||||
return $this->password->value() !== null;
|
||||
}
|
||||
|
||||
public function getPassword(): string|null
|
||||
{
|
||||
return $this->password->value();
|
||||
}
|
||||
|
||||
public function clearAllUsersEconomicCustomerDiscountsFromCache(): void
|
||||
{
|
||||
// Get all the cached results matching the pattern 'users_*_economic_customer_discount_percentage'
|
||||
$cached_results = redis->get_keys('users_*_economic_customer_discount_percentage');
|
||||
// Loop through the cached results
|
||||
foreach ( $cached_results as $key ) {
|
||||
// Clear the cached discount percentage
|
||||
redis->delete($key);
|
||||
}
|
||||
}
|
||||
|
||||
public function clearAllUsersEconomicCustomerDetailsFromCache(): void
|
||||
{
|
||||
// Get all the cached results matching the pattern 'users_*_economic_customer'
|
||||
$cached_results = redis->get_keys('users_*_economic_customer');
|
||||
// Loop through the cached results
|
||||
foreach ( $cached_results as $key ) {
|
||||
// Clear the cached economic customer details
|
||||
redis->delete($key);
|
||||
}
|
||||
}
|
||||
|
||||
public function getEconomicCustomerDiscountPercentage(): int
|
||||
{
|
||||
// Check if the discount percentage is cached
|
||||
@@ -756,13 +769,35 @@ class users_o extends db
|
||||
return $discount_percentage;
|
||||
}
|
||||
|
||||
public function hasPassword(): bool
|
||||
/**
|
||||
* Set a custom price (DISCOUNT) for the user
|
||||
* @param int $user_id
|
||||
* @param int $object_id The ID of the object
|
||||
* @param int $discount_percentage The discount percentage
|
||||
* @param bool $is_category If the object is a category
|
||||
* @return void
|
||||
*/
|
||||
public function setCustomPrice(int $user_id, int|string $object_id, int $discount_percentage, bool $is_category = false): void
|
||||
{
|
||||
return $this->password->value() !== null;
|
||||
$this->id = $user_id;
|
||||
// Get the user object properties
|
||||
$this->getObjectProperties();
|
||||
// Set the custom price (key = 'custom_price')
|
||||
$this->price_overrides->setUser($this->id)->setPrice($is_category, $object_id, $discount_percentage);
|
||||
}
|
||||
|
||||
public function getPassword(): string|null
|
||||
public function syncAllUsersEconomicCustomerDetails(): void
|
||||
{
|
||||
return $this->password->value();
|
||||
// Get all users
|
||||
$users = $this->getFields(['id', 'customer_number']);
|
||||
// Loop through the users
|
||||
foreach ( $users as $user ) {
|
||||
// Check if the customer number is set (Or if it is 0)
|
||||
if ($user['customer_number'] === 0) {
|
||||
continue;
|
||||
}
|
||||
// Get the customer data from the external source
|
||||
$this->getCustomerEcocomicData($user['customer_number']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class cronRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->post('/superuser/cron', function () {
|
||||
// Get the post data
|
||||
global $response;
|
||||
// Make sure the user has the SUPERUSER_RUN_CRON permission
|
||||
if (!$this->requirePermission('SUPERUSER_RUN_CRON')) {
|
||||
$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 a specific cron job is requested
|
||||
if (isset($data['job'])) {
|
||||
// Check if the cron job exists
|
||||
if (!file_exists(WD . '/cron/' . $data['job'] . '.php')) {
|
||||
$response->error('Cron job not found', 404);
|
||||
}
|
||||
// Include the cron job
|
||||
require_once WD . '/cron/' . $data['job'] . '.php';
|
||||
// Log the incident
|
||||
(new logs_o())->add('cron', 'global', 1, $user->id, 'CRON_JOB_RUN', 'Ran cron job: ' . $data['job']);
|
||||
$response->success('Cron job ran successfully');
|
||||
}
|
||||
// If no specific cron job is requested, run all cron jobs (through the cron.php file)
|
||||
require_once WD . '/cron/Cron.php';
|
||||
// Log the incident
|
||||
(new logs_o())->add('cron', 'global', 1, $user->id, 'CRON_RUN', 'Ran all cron jobs');
|
||||
$response->success([
|
||||
'message' => 'All cron jobs ran successfully',
|
||||
'data' => $response_cron ?? []
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -375,4 +375,17 @@ trait db_object_t
|
||||
// Delete the cached data
|
||||
redis->delete($this->table . '_' . $objectId . '_' . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all objects fields
|
||||
* @param array $fields The fields to get from the objects (Eg. ['name', 'description'])
|
||||
* @return array The list of fields from the objects (Eg. [['name' => 'John', 'description' => 'Doe'], ['name' => 'Jane', 'description' => 'Doe']])
|
||||
*/
|
||||
public function getFields(array $fields): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT " . implode(', ', $fields) . " FROM $this->table";
|
||||
$result = $db->query($sql);
|
||||
return $db->fetch_all($result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user