Add reCAPTCHA support and enhance Economic configurations
Introduce reCAPTCHA integration with validation and configuration handling. Update Economic module to include layout management and dynamic configuration via API. Added traits for managing module settings and encapsulated new endpoint routes for expanded functionality.
This commit is contained in:
@@ -1,17 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace classes;
|
||||
require_once WD . '/modules/economic/economic_c.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_orders_endpoint.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_invoices_endpoint.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_departments_endpoint.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_layouts_endpoint.php';
|
||||
|
||||
use economic_c;
|
||||
use endpoints\economic_departments_endpoint;
|
||||
use endpoints\economic_invoices_endpoint;
|
||||
use endpoints\economic_layouts_endpoint;
|
||||
use endpoints\economic_orders_endpoint;
|
||||
use interfaces\economic_i;
|
||||
|
||||
class economic implements economic_i
|
||||
{
|
||||
/**
|
||||
* Configuration of the economic module
|
||||
* @var economic_c
|
||||
*/
|
||||
public economic_c $config;
|
||||
/**
|
||||
* Any endpoints reached by the /orders endpoint
|
||||
* @var economic_orders_endpoint
|
||||
@@ -27,11 +36,19 @@ class economic implements economic_i
|
||||
* @var economic_departments_endpoint
|
||||
*/
|
||||
public economic_departments_endpoint $departments;
|
||||
/**
|
||||
* Any endpoints reached by the /layouts endpoint
|
||||
* @var economic_layouts_endpoint
|
||||
*/
|
||||
public economic_layouts_endpoint $layouts;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new economic_c();
|
||||
$this->orders = new economic_orders_endpoint();
|
||||
$this->invoices = new economic_invoices_endpoint();
|
||||
$this->departments = new economic_departments_endpoint();
|
||||
$this->layouts = new economic_layouts_endpoint();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace classes;
|
||||
|
||||
require_once WD . '/modules/reCAPTCHA/reCAPTCHA_c.php';
|
||||
|
||||
use Exception;
|
||||
use interfaces\recaptcha_i;
|
||||
use reCAPTCHA\reCAPTCHA_c;
|
||||
|
||||
class recaptcha implements recaptcha_i
|
||||
{
|
||||
/**
|
||||
* Configuration of the reCAPTCHA module
|
||||
* @var recaptcha_c
|
||||
*/
|
||||
public recaptcha_c $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new recaptcha_c();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the reCAPTCHA response
|
||||
* @param string|null $response The response from the reCAPTCHA
|
||||
* @return bool Whether the response is valid
|
||||
* @throws Exception
|
||||
*/
|
||||
public function validate(string|null $response): bool
|
||||
{
|
||||
if (!$this->config->enabled->isTrue()) {
|
||||
return true;
|
||||
}
|
||||
$url = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
$data = [
|
||||
'secret' => $this->config->secret_key_v2->getVariableValue(),
|
||||
'response' => $response
|
||||
];
|
||||
$options = [
|
||||
'http' => [
|
||||
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => http_build_query($data)
|
||||
]
|
||||
];
|
||||
$context = stream_context_create($options);
|
||||
$response = file_get_contents($url, false, $context);
|
||||
$responseKeys = json_decode($response, true);
|
||||
return $responseKeys['success'];
|
||||
}
|
||||
|
||||
public function getPublicConfig(): array
|
||||
{
|
||||
return [
|
||||
'enabled' => $this->config->enabled->isTrue(),
|
||||
'site_key' => $this->config->site_key_v2->getVariableValue()
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ require_once 'classes/wordpress_bookings_remote.php';
|
||||
require_once 'classes/language_packs.php';
|
||||
require_once 'classes/economic.php';
|
||||
require_once 'classes/statistics.php';
|
||||
require_once 'classes/recaptcha.php';
|
||||
|
||||
/**
|
||||
* Modules
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace interfaces;
|
||||
|
||||
interface recaptcha_i
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace config;
|
||||
|
||||
use traits\module_config_variable;
|
||||
|
||||
class economic_invoice_layout_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'economic',
|
||||
'invoiceLayoutNumber',
|
||||
'int',
|
||||
true,
|
||||
null,
|
||||
'The layout number for the invoice',
|
||||
'1',
|
||||
false,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
require_once WD . '/modules/economic/config/economic_invoice_layout_c.php';
|
||||
|
||||
use config\economic_invoice_layout_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
class economic_c
|
||||
{
|
||||
use module_config_t;
|
||||
|
||||
public economic_invoice_layout_c $invoice_layout;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setupConfig('economic');
|
||||
$this->allowUpdate([
|
||||
economic_invoice_layout_c::class
|
||||
]);
|
||||
$this->invoice_layout = new economic_invoice_layout_c();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
|
||||
use classes\economic;
|
||||
|
||||
class economic_m
|
||||
{
|
||||
public economic $economic;
|
||||
/**
|
||||
* https://secure.e-conomic.com/secure/api1/requestaccess.aspx?appPublicToken=WeG89W2Y63wLjy1lnqfpsHlfa1mBiyNKByqtGmBOoOw&redirectUrl=truckwash.dk
|
||||
*/
|
||||
@@ -9,13 +12,25 @@ class economic_m
|
||||
private string $appAccessGrant;
|
||||
private string $app_token;
|
||||
private string $appAccessGrant2;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
global $ECONOMIC_API;
|
||||
$this->app_token = $ECONOMIC_API['app_secret_token'];
|
||||
$this->appAccessGrant = $ECONOMIC_API['app_access_grant'];
|
||||
$this->appAccessGrant2 = $ECONOMIC_API['app_access_grant2'];
|
||||
$this->economic = new economic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +55,7 @@ class economic_m
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'X-AppSecretToken: ' . $this->app_token,
|
||||
'X-AgreementGrantToken: ' . ( $authToken2 ? $this->appAccessGrant2 : $this->appAccessGrant ),
|
||||
'X-AgreementGrantToken: ' . ($authToken2 ? $this->appAccessGrant2 : $this->appAccessGrant),
|
||||
'Content-Type: application/json'
|
||||
),
|
||||
));
|
||||
@@ -53,15 +68,4 @@ class economic_m
|
||||
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'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace endpoints;
|
||||
|
||||
use traits\economic_endpoint_t;
|
||||
|
||||
class economic_layouts_endpoint
|
||||
{
|
||||
use economic_endpoint_t;
|
||||
|
||||
/**
|
||||
* List all layouts
|
||||
* @return object {collection: [layout]}
|
||||
*/
|
||||
public function get(): object
|
||||
{
|
||||
$response = $this->send_request(
|
||||
'/layouts/',
|
||||
'GET');
|
||||
// Return the response as an object
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,7 +48,7 @@ class economic_invoice_draft_mo extends economicInvoicesDrafts
|
||||
'currency' => 'DKK',
|
||||
'date' => date('Y-m-d'),
|
||||
'layout' => [
|
||||
'layoutNumber' => 1
|
||||
'layoutNumber' => (int)$this->economic->config->invoice_layout->getVariableValue()
|
||||
],
|
||||
'paymentTerms' => [
|
||||
'paymentTermsNumber' => 1
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace reCAPTCHA\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class reCAPTCHA_enabled_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'reCAPTCHA',
|
||||
'enabled',
|
||||
'bool',
|
||||
true,
|
||||
null,
|
||||
'Whether reCAPTCHA is enabled',
|
||||
'1',
|
||||
false,
|
||||
'false'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace reCAPTCHA\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class reCAPTCHA_secret_key_v2_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'reCAPTCHA',
|
||||
'secret_key_v2',
|
||||
'string',
|
||||
false,
|
||||
null,
|
||||
'The secret key for reCAPTCHA v2',
|
||||
'1',
|
||||
true,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace reCAPTCHA\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class reCAPTCHA_site_key_v2_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'reCAPTCHA',
|
||||
'site_key_v2',
|
||||
'string',
|
||||
false,
|
||||
null,
|
||||
'The site key for reCAPTCHA v2',
|
||||
'1',
|
||||
true,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace reCAPTCHA;
|
||||
require_once WD . '/modules/reCAPTCHA/config/reCAPTCHA_enabled_c.php';
|
||||
require_once WD . '/modules/reCAPTCHA/config/reCAPTCHA_secret_key_v2_c.php';
|
||||
require_once WD . '/modules/reCAPTCHA/config/reCAPTCHA_site_key_v2_c.php';
|
||||
|
||||
use reCAPTCHA\config\reCAPTCHA_enabled_c;
|
||||
use reCAPTCHA\config\reCAPTCHA_secret_key_v2_c;
|
||||
use reCAPTCHA\config\reCAPTCHA_site_key_v2_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
class reCAPTCHA_c
|
||||
{
|
||||
use module_config_t;
|
||||
|
||||
/**
|
||||
* The status of reCAPTCHA, whether it is enabled or not
|
||||
* @var reCAPTCHA_enabled_c
|
||||
*/
|
||||
public reCAPTCHA_enabled_c $enabled;
|
||||
/**
|
||||
* The site key for reCAPTCHA v2
|
||||
* @var reCAPTCHA_site_key_v2_c
|
||||
*/
|
||||
public reCAPTCHA_site_key_v2_c $site_key_v2;
|
||||
/**
|
||||
* The secret key for reCAPTCHA v2
|
||||
* @var reCAPTCHA_secret_key_v2_c
|
||||
*/
|
||||
public reCAPTCHA_secret_key_v2_c $secret_key_v2;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setupConfig('reCAPTCHA');
|
||||
$this->allowUpdate([
|
||||
reCAPTCHA_enabled_c::class,
|
||||
reCAPTCHA_secret_key_v2_c::class,
|
||||
reCAPTCHA_site_key_v2_c::class
|
||||
]);
|
||||
$this->enabled = new reCAPTCHA_enabled_c();
|
||||
$this->secret_key_v2 = new reCAPTCHA_secret_key_v2_c();
|
||||
$this->site_key_v2 = new reCAPTCHA_site_key_v2_c();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\recaptcha;
|
||||
use objects\logs_o;
|
||||
use objects\tokens_o;
|
||||
use traits\route_t;
|
||||
@@ -16,6 +17,7 @@ class authRoute
|
||||
$this->post('/auth/login', function () {
|
||||
// Get the post data
|
||||
global $response;
|
||||
$this->requireRecaptcha();
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
// Check if the customer number, and password are set
|
||||
if (!isset($data['customer_number']) || empty($data['customer_number']) || !is_numeric($data['customer_number']) || $data['customer_number'] < 1) {
|
||||
@@ -80,6 +82,7 @@ class authRoute
|
||||
$this->post('/auth/employee/login', function () {
|
||||
// Get the post data
|
||||
global $response;
|
||||
$this->requireRecaptcha();
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
// Check if the employee number, and password are set
|
||||
if (!isset($data['user_id'])) {
|
||||
@@ -102,5 +105,23 @@ class authRoute
|
||||
// Return the token
|
||||
$response->success(['token' => $token]);
|
||||
});
|
||||
|
||||
$this->get('/auth/reCAPTCHA/public', function () {
|
||||
// Check if the user:
|
||||
// 1. Is rate limited (future feature)
|
||||
// 2. Is required to solve a reCAPTCHA
|
||||
global $response;
|
||||
$recaptcha = (new recaptcha())->getPublicConfig();
|
||||
$response->success([
|
||||
'rate_limit' => [
|
||||
'enabled' => false,
|
||||
'limit' => 0,
|
||||
'remaining' => 0,
|
||||
'reset' => 0,
|
||||
'warning' => null
|
||||
],
|
||||
'recaptcha' => $recaptcha
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\economic;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class economicLayoutsRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
/** @var router $router */
|
||||
$router, $response;
|
||||
|
||||
|
||||
$this->get('/economic/layouts', function () {
|
||||
global $response;
|
||||
$this->requirePermission('economic_layouts');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('economic_layouts', 'global', 1, $user->id, 'ECONOMIC_LAYOUTS', 'Successfully fetched economic layouts');
|
||||
$response->success(
|
||||
(new economic())->layouts->get()->collection
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('economic_layouts', 'global', 1, 0, 'ECONOMIC_LAYOUTS', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\economic;
|
||||
use classes\recaptcha;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class moduleConfigRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
/** @var router $router */
|
||||
$router, $response;
|
||||
|
||||
|
||||
/** Economic config > GET */
|
||||
$this->get('/economic/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('economic_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('economic_config', 'global', 1, $user->id, 'ECONOMIC_CONFIG', 'Successfully fetched economic config');
|
||||
$response->success(
|
||||
(new economic())->config->getConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('economic_config', 'global', 1, 0, 'ECONOMIC_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
|
||||
/** Economic config > POST */
|
||||
$this->post('/economic/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('economic_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('economic_config', 'global', 1, $user->id, 'ECONOMIC_CONFIG', 'Successfully updated economic config');
|
||||
$response->success(
|
||||
(new economic())->config->postConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('economic_config', 'global', 1, 0, 'ECONOMIC_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
|
||||
/** reCAPTCHA config > GET */
|
||||
$this->get('/reCAPTCHA/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('recaptcha_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, $user->id, 'RECAPTCHA_CONFIG', 'Successfully fetched recaptcha config');
|
||||
$response->success(
|
||||
(new recaptcha())->config->getConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, 0, 'RECAPTCHA_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
|
||||
/** reCAPTCHA config > POST */
|
||||
$this->post('/reCAPTCHA/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('recaptcha_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, $user->id, 'RECAPTCHA_CONFIG', 'Successfully updated recaptcha config');
|
||||
$response->success(
|
||||
(new recaptcha())->config->postConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, 0, 'RECAPTCHA_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace traits;
|
||||
|
||||
use classes\db;
|
||||
|
||||
trait module_config_t
|
||||
{
|
||||
public string $module_name; // The name of the module
|
||||
public array $config_classes; // An array of classes that contain config variables for the module, that's allowed to be updated by the user using the API
|
||||
|
||||
/**
|
||||
* Set up the config variable
|
||||
* @param string $module_name
|
||||
* @return void
|
||||
*/
|
||||
function setupConfig(string $module_name): void
|
||||
{
|
||||
$this->module_name = $module_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to update the config variables
|
||||
* @param array $config_classes
|
||||
* @return void
|
||||
*/
|
||||
function allowUpdate(array $config_classes): void
|
||||
{
|
||||
$this->config_classes = $config_classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post config request
|
||||
* @return bool
|
||||
*/
|
||||
function postConfigRequest(): bool
|
||||
{
|
||||
// Check if the request has a variable name and value
|
||||
global $response;
|
||||
if ($response->getRequestParameter('variable') === null || $response->getRequestParameter('value') === null) {
|
||||
$response->error('Variable and value not set', 400);
|
||||
}
|
||||
// Get the variable name and value
|
||||
$variable = $response->getRequestParameter('variable');
|
||||
$value = $response->getRequestParameter('value');
|
||||
// Sanitize the variable name and value
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$variable = $db->escape_string($variable);
|
||||
$value = $db->escape_string($value);
|
||||
// Check if the variable is allowed to be updated
|
||||
if (!self::isVariableAllowed($variable)) {
|
||||
// Return an error message, telling the user that the variable is not allowed to be updated. With a list of allowed variables
|
||||
$allowed_variables = [];
|
||||
foreach ( $this->config_classes as $config_class ) {
|
||||
$allowed_variables[] = (new $config_class())->getVariableName();
|
||||
}
|
||||
$allowed_variables = implode(', ', $allowed_variables);
|
||||
echo "Variable not allowed to be updated. Allowed variables: $allowed_variables";
|
||||
return false;
|
||||
}
|
||||
// Update the config variable using the config class that contains the variable
|
||||
foreach ( $this->config_classes as $config_class ) {
|
||||
// Create a new instance of the config class
|
||||
$tmp = new $config_class();
|
||||
// Check if the variable matches the variable name in the config class
|
||||
if ($tmp->getVariableName() == $variable) {
|
||||
// Update the config variable
|
||||
$tmp->setVariableValue($value);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the updated config variable
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the variable is allowed to be updated
|
||||
* @param string $variable
|
||||
* @return bool
|
||||
*/
|
||||
function isVariableAllowed(string $variable): bool
|
||||
{
|
||||
foreach ( $this->config_classes as $config_class ) {
|
||||
// Create a new instance of the config class
|
||||
$tmp = new $config_class();
|
||||
// Check if the variable matches the variable name in the config class
|
||||
if ($tmp->getVariableName() == $variable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getConfigRequest(): array
|
||||
{
|
||||
// Get the config variable
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Check if the request has a variable name
|
||||
if (!isset($_GET['variable'])) {
|
||||
return self::getConfig();
|
||||
}
|
||||
// Get the variable name
|
||||
$variable = $_GET['variable'];
|
||||
// Sanitize the variable name
|
||||
$variable = $db->escape_string($variable);
|
||||
// Get the config variable
|
||||
$sql = "SELECT * FROM module_config WHERE module = '$this->module_name' AND variable = '$variable'";
|
||||
return $this->extracted($db, $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all config variables for the module
|
||||
* @return array
|
||||
*/
|
||||
function getConfig(): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT * FROM module_config WHERE module = '$this->module_name'";
|
||||
return $this->extracted($db, $sql);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $db
|
||||
* @param string $sql
|
||||
* @return array
|
||||
*/
|
||||
private function extracted($db, string $sql): array
|
||||
{
|
||||
$result = $db->query($sql);
|
||||
$config = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$config[] = [
|
||||
'module' => $row['module'],
|
||||
'variable' => $row['variable'],
|
||||
'type' => $row['type'],
|
||||
'value' => $this->parseConfigVariableType($row['type'], $row['value'])
|
||||
];
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
function parseConfigVariableType($type, $value)
|
||||
{
|
||||
// If the variable is an int, convert it to an int
|
||||
if ($type == 'integer') {
|
||||
return (integer)$value;
|
||||
}
|
||||
// If the variable is a boolean, convert it to a boolean
|
||||
if ($type == 'bool') {
|
||||
return $value == 'true';
|
||||
}
|
||||
// If the variable is a float, convert it to a float
|
||||
if ($type == 'float') {
|
||||
return (float)$value;
|
||||
}
|
||||
// If the variable is a JSON string, convert it to an array
|
||||
if ($type == 'json') {
|
||||
return json_decode($value, true);
|
||||
}
|
||||
// If the variable is a string, convert it to a string
|
||||
if ($type == 'string') {
|
||||
return (string)$value;
|
||||
}
|
||||
// If the variable is an array, convert it to an array
|
||||
if ($type == 'array') {
|
||||
return explode(',', $value);
|
||||
}
|
||||
// If the variable is a date, convert it to a date
|
||||
if ($type == 'date') {
|
||||
return date('Y-m-d', strtotime($value));
|
||||
}
|
||||
// If the variable is a time, convert it to a time
|
||||
if ($type == 'time') {
|
||||
return date('H:i:s', strtotime($value));
|
||||
}
|
||||
// If the variable is a datetime, convert it to a datetime
|
||||
if ($type == 'datetime') {
|
||||
return date('Y-m-d H:i:s', strtotime($value));
|
||||
}
|
||||
// If the variable is a timestamp, convert it to a timestamp
|
||||
if ($type == 'timestamp') {
|
||||
return strtotime($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module name
|
||||
* @return string
|
||||
*/
|
||||
function getModuleName(): string
|
||||
{
|
||||
return $this->module_name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
namespace traits;
|
||||
|
||||
use Exception;
|
||||
|
||||
trait module_config_variable
|
||||
{
|
||||
public string $module_name; // The name of the module
|
||||
public string $config_variable; // The name of the config variable in the database (e.g. layout_id)
|
||||
public string $config_variable_type; // The type of the config variable (e.g. int)
|
||||
public bool $config_variable_required; // Whether the config variable is required or not
|
||||
public array|null $allowed_values; // An array of allowed values for the config variable. If this is null, any value is allowed
|
||||
public string $config_variable_description; // A description of the config variable
|
||||
public string $config_variable_example; // An example of the config variable
|
||||
public bool $config_variable_is_secret; // Whether the config variable is a secret or not
|
||||
|
||||
/**
|
||||
* Set up the config variable
|
||||
* @param string $module_name
|
||||
* @param string $config_variable
|
||||
* @param string $config_variable_type
|
||||
* @param bool $config_variable_required
|
||||
* @param array|null $allowed_values
|
||||
* @param string $config_variable_description
|
||||
* @param string $config_variable_example
|
||||
* @param bool $config_variable_is_secret
|
||||
* @param mixed $default_value
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
function setupConfigVariable(
|
||||
string $module_name,
|
||||
string $config_variable,
|
||||
string $config_variable_type,
|
||||
bool $config_variable_required,
|
||||
array|null $allowed_values,
|
||||
string $config_variable_description,
|
||||
string $config_variable_example,
|
||||
bool $config_variable_is_secret = false,
|
||||
mixed $default_value = null
|
||||
): void
|
||||
{
|
||||
$this->module_name = $module_name;
|
||||
$this->config_variable = $config_variable;
|
||||
$this->config_variable_type = $config_variable_type;
|
||||
$this->config_variable_required = $config_variable_required;
|
||||
$this->allowed_values = $allowed_values;
|
||||
$this->config_variable_description = $config_variable_description;
|
||||
$this->config_variable_example = $config_variable_example;
|
||||
$this->config_variable_is_secret = $config_variable_is_secret;
|
||||
|
||||
// Check if the config variable is set in the database
|
||||
if (!self::isVariableSet($module_name, $config_variable)) {
|
||||
// If the config variable is required, throw an exception
|
||||
if ($config_variable_required && $default_value === null) {
|
||||
throw new Exception('Config variable not set: ' . $config_variable);
|
||||
} else {
|
||||
// If the config variable is not required, set the default value
|
||||
self::insertVariableValue($module_name, $config_variable, $default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the config variable is set in the database
|
||||
* @param string $module
|
||||
* @param string $variable
|
||||
* @return bool
|
||||
*/
|
||||
static function isVariableSet(string $module, string $variable): bool
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT value FROM module_config WHERE module = '$module' AND variable = '$variable'";
|
||||
$result = $db->query($sql);
|
||||
return $result->num_rows > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the value of the config variable in the database
|
||||
* @param string $module
|
||||
* @param string $variable
|
||||
* @param mixed $value
|
||||
*/
|
||||
function insertVariableValue(string $module, string $variable, mixed $value): void
|
||||
{
|
||||
global $db;
|
||||
$sql = "INSERT INTO module_config (module, variable, value, type) VALUES ('$module', '$variable', '$value', '" . self::getVariableType() . "')";
|
||||
$db->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable type
|
||||
* @return string
|
||||
*/
|
||||
function getVariableType(): string
|
||||
{
|
||||
return $this->config_variable_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is boolean variable true?
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
function isTrue(): bool
|
||||
{
|
||||
// Make sure the variable is a boolean
|
||||
if ($this->config_variable_type !== 'bool') {
|
||||
throw new Exception('Config variable is not a boolean: ' . $this->config_variable . ' (' . $this->config_variable_type . ')');
|
||||
}
|
||||
return $this->getVariableValue() === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the config variable from the database
|
||||
* @return mixed
|
||||
*/
|
||||
function getVariableValue(): mixed
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT value FROM module_config WHERE module = '$this->module_name' AND variable = '$this->config_variable'";
|
||||
$result = $db->query($sql);
|
||||
// return the value of the config variable
|
||||
return $result->fetch_assoc()['value'];
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
// Return the config variable value as a string
|
||||
return $this->getVariableValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the config variable in the database
|
||||
* @param mixed $value
|
||||
* @throws Exception
|
||||
*/
|
||||
function setVariableValue(mixed $value): void
|
||||
{
|
||||
// Check if the variable value is valid
|
||||
if (!$this->validateVariableValue($value)) {
|
||||
throw new Exception('Invalid value for config variable: ' . $this->config_variable . ' (' . $value . ')');
|
||||
}
|
||||
// If the type is a boolean, convert the value to "true" or "false"
|
||||
if ($this->config_variable_type === 'bool') {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
// Update the value of the config variable in the database, and insert it if it does not exist
|
||||
if (self::isVariableSet($this->module_name, $this->config_variable)) {
|
||||
self::updateVariableValue($this->module_name, $this->config_variable, $value);
|
||||
} else {
|
||||
self::insertVariableValue($this->module_name, $this->config_variable, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the value of the config variable
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
function validateVariableValue(mixed $value): bool
|
||||
{
|
||||
// Check if the value is empty and the variable is required
|
||||
if ($this->config_variable_required && empty($value)) {
|
||||
// If the value is empty and the type is not a boolean, return false
|
||||
if ($this->config_variable_type != 'bool') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the value is in the list of allowed values
|
||||
if ($this->allowed_values && !in_array($value, $this->allowed_values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the value is of the correct type
|
||||
switch ($this->config_variable_type) {
|
||||
case 'int':
|
||||
if (!is_numeric($value)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'bool':
|
||||
// If the value is a string, convert it to "true" or "false"
|
||||
if (is_string($value)) {
|
||||
$value = self::inputToBool($value);
|
||||
}
|
||||
if (!is_bool($value)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to a boolean
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
static function inputToBool(string $value): bool
|
||||
{
|
||||
// If the value is true, 1, or "true", return true
|
||||
if ($value === 'true' || $value === '1') {
|
||||
return true;
|
||||
}
|
||||
// If the value is false, 0, or "false", return false
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the config variable in the database
|
||||
* @param string $module
|
||||
* @param string $variable
|
||||
* @param mixed $value
|
||||
*/
|
||||
static function updateVariableValue(string $module, string $variable, mixed $value): void
|
||||
{
|
||||
global $db;
|
||||
$sql = "UPDATE module_config SET value = '$value' WHERE module = '$module' AND variable = '$variable'";
|
||||
$db->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config variable as a JSON string
|
||||
* @return string
|
||||
*/
|
||||
function asJson(): string
|
||||
{
|
||||
return json_encode($this->asArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config variable as an array
|
||||
* @return array
|
||||
*/
|
||||
function asArray(): array
|
||||
{
|
||||
return [
|
||||
'module' => $this->module_name,
|
||||
'variable' => $this->config_variable,
|
||||
'type' => $this->config_variable_type,
|
||||
'required' => $this->config_variable_required,
|
||||
'allowed_values' => $this->allowed_values,
|
||||
'description' => $this->config_variable_description,
|
||||
'example' => $this->config_variable_example,
|
||||
'value' => $this->getVariableValue(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable name
|
||||
* @return string
|
||||
*/
|
||||
function getVariableName(): string
|
||||
{
|
||||
return $this->config_variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable description
|
||||
* @return string
|
||||
*/
|
||||
function getVariableDescription(): string
|
||||
{
|
||||
return $this->config_variable_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable example
|
||||
* @return string
|
||||
*/
|
||||
function getVariableExample(): string
|
||||
{
|
||||
return $this->config_variable_example;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable is secret
|
||||
* @return bool
|
||||
*/
|
||||
function getVariableIsSecret(): bool
|
||||
{
|
||||
return $this->config_variable_is_secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable required
|
||||
* @return bool
|
||||
*/
|
||||
function getVariableRequired(): bool
|
||||
{
|
||||
return $this->config_variable_required;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace traits;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\recaptcha;
|
||||
use objects\logs_o;
|
||||
|
||||
trait route_t
|
||||
@@ -138,6 +139,27 @@ trait route_t
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require reCAPTCHA for the request
|
||||
* @return bool
|
||||
*/
|
||||
public function requireRecaptcha(): bool
|
||||
{
|
||||
global $response;
|
||||
// Check if the reCAPTCHA is valid
|
||||
try {
|
||||
$recaptcha_response = $response->getRequestParameter('g_recaptcha_response');
|
||||
$recaptcha = (new recaptcha())->validate($recaptcha_response);
|
||||
if (!$recaptcha) {
|
||||
(new logs_o())->add('global', 'global', 1, 0, 'AUTHENTICATION_FAILED', 'Authentication failed. Invalid, or missing reCAPTCHA');
|
||||
$response->error('Authentication failed. Invalid or missing reCAPTCHA.', 401);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$response->error($e->getMessage(), 400);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from the request body or query string by name
|
||||
* @param string $name
|
||||
|
||||
Reference in New Issue
Block a user