## Root cause `route_t::hasPermission()` and `requirePermission()` are instance methods. Route code was invoking them with `self::`; the new XL Vask hall-scope helper made that call from a genuinely static context, causing PHP to throw: `Non-static method routes\\xlvaskUsageLogsRoute::hasPermission() cannot be called statically` ## Changes - Invoke route permission methods through `$this` across all 273 executable legacy calls in 45 route classes. - Make `xlvaskUsageLogsRoute::allowedHallIdsForUser()` an instance helper and update all 13 callers. - Preserve the existing all-scope and own-scope hall selection rules. - Add a token-aware regression test that rejects executable `self::hasPermission()` and `self::requirePermission()` calls, while ignoring comments. - Add focused XL Vask tests for global scanner hall scope and group-limited own scope. - Update affected route contract assertions to the instance-call form. ## Verification - PHP lint: all 53 changed PHP files - Focused PHPStan: changed XL Vask route and both new regression tests — clean - Focused regression slice: 58 passed, 748 assertions - Full local unit suite: 1,300 passed, 9,442 assertions (1 unrelated existing warning, 1 environment skip) - Full local API suite: 285 passed, 11,704 assertions - Exact-SHA GitHub Tests workflow: all 7 jobs passed (unit, API, integration, legacy, edge gateway, and supporting checks) - Independent exact-SHA QA gate: PASS, no findings - Independent exact-SHA security gate: PASS, no findings - Independent exact-SHA reviewer gate: PASS, no findings - Remote comparison: exactly one commit ahead of `40b104abed7723a7d1b7028190ecda0e7aeef829`; all 53 remote blob hashes matched the reviewed worktree ## Delivery state Draft only for human review. No merge or deployment is included. Qodana is skipped while the PR remains draft and is therefore not represented as a passed gate.
142 lines
5.8 KiB
PHP
142 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace routes;
|
|
|
|
use classes\db;
|
|
use classes\economic;
|
|
use classes\release_manager;
|
|
use classes\router;
|
|
use classes\shelly;
|
|
use classes\slack;
|
|
use classes\virkdata;
|
|
use modules\shelly\helpers\shelly_device_switch;
|
|
use modules\shelly\helpers\shelly_request_body_get_states;
|
|
use modules\virkdata\helpers\virkdata_response;
|
|
use objects\departments_o;
|
|
use objects\orders_o;
|
|
use objects\product_options_o;
|
|
use objects\products_o;
|
|
use objects\users_o;
|
|
use traits\route_t;
|
|
|
|
class workerRoute
|
|
{
|
|
use route_t;
|
|
|
|
public function run(): void
|
|
{
|
|
$this->get('/worker/version', function () {
|
|
global /** @var router $router */
|
|
$response, $router;
|
|
$response->success(['version' => redis->get('worker_target_version') ?? 'unknown'] );
|
|
});
|
|
$this->get('/worker/update-version', function () {
|
|
global /** @var router $router */
|
|
$response, $router;
|
|
$this->requirePermission('worker_update_version');
|
|
self::requireParameters(['version']);
|
|
$version = (string)self::getParameter('version');
|
|
redis->set('worker_target_version', $version);
|
|
$response->success(['message' => 'Version update functionality is not yet implemented.']);
|
|
});
|
|
$this->get('/worker/test', function () {
|
|
global $response;
|
|
$response->error('This endpoint is disabled for security reasons.', 403);
|
|
});
|
|
$this->get('/worker/status', function () {
|
|
global /** @var router $router */
|
|
$response, $router, $db, $REDIS_CONFIG, $CONFIG_DB;
|
|
$response->success([
|
|
'message' => 'Worker is running',
|
|
'status' => 'OK',
|
|
'time' => date('Y-m-d H:i:s'),
|
|
'timezone' => date_default_timezone_get(),
|
|
'host' => gethostname(),
|
|
'version' => '1.0.1',
|
|
'api_commit_sha' => release_manager::backendCommitSha(),
|
|
'routes' => $router->countRoutes(),
|
|
'redis' => [
|
|
'host' => $REDIS_CONFIG['host'],
|
|
'user' => $REDIS_CONFIG['user'],
|
|
'database' => $REDIS_CONFIG['database'],
|
|
'password' => $REDIS_CONFIG['password'] ? '********' : 'NOT_SET',
|
|
'port' => $REDIS_CONFIG['port'],
|
|
'status' => (new \classes\redis())->ping() ? 'OK' : 'ERROR',
|
|
],
|
|
'database' => [
|
|
'host' => $CONFIG_DB['host'],
|
|
'database' => $CONFIG_DB['database'],
|
|
'user' => $CONFIG_DB['user'],
|
|
'status' => $db->testConnection() ? 'OK' : 'ERROR',
|
|
],
|
|
]);
|
|
});
|
|
$this->get('/worker/debug', function () {
|
|
global $response;
|
|
$response->error('This endpoint is disabled for security reasons.', 403);
|
|
});
|
|
$this->get('/worker/debug/on', function () {
|
|
global $response;
|
|
$response->error('This endpoint is disabled for security reasons.', 403);
|
|
});
|
|
$this->get('/worker/debug/off', function () {
|
|
global $response;
|
|
$response->error('This endpoint is disabled for security reasons.', 403);
|
|
});
|
|
$this->get('/worker/licenseplates', function () {
|
|
global $response;
|
|
$response->error('This endpoint is disabled for security reasons.', 403);
|
|
});
|
|
$this->get('/economic/doesCustomerExist', function () {
|
|
global $response;
|
|
$this->requirePermission( 'economic_does_customer_exist'); // TODO: Remove this
|
|
self::requireParameters(['cvr']);
|
|
$cvr = self::getParameter('cvr');
|
|
// Check if the customer exists in E-conomic.
|
|
if (!is_numeric($cvr)) {
|
|
$response->error('Invalid CVR number', 400);
|
|
}
|
|
$economic = new economic();
|
|
$results = $economic->customers->customers->search([
|
|
'corporateIdentificationNumber' => (string)$cvr,
|
|
],[
|
|
'skipPages' => 0,
|
|
'pageSize' => 1000, // Since the limit is 1000, we need to set the page size to 1000.
|
|
])->collection;
|
|
if (count($results) === 0) {
|
|
$response->error('Customer not found', 404);
|
|
}
|
|
$response->success(['cvr' => $cvr, 'result' => $results], 200);
|
|
});
|
|
$this->get('/cvr/lookup', function () {
|
|
global $response;
|
|
$this->requirePermission('cvr_lookup'); // TODO: Remove this
|
|
self::requireParameters(['cvr']);
|
|
$cvr = self::getParameter('cvr');
|
|
if (!is_numeric($cvr)) {
|
|
$response->error('Invalid CVR number', 400);
|
|
}
|
|
// Check if the result is cached
|
|
if (!empty(redis->get('cvr_lookup_' . $cvr))) {
|
|
$result = (new virkdata_response())->populate((array)json_decode(redis->get('cvr_lookup_' . $cvr)));
|
|
} else {
|
|
$virkdata = new virkdata();
|
|
$result = $virkdata->getCompanyInformation($cvr, '', []);
|
|
// Cache the result
|
|
redis->set('cvr_lookup_' . $cvr, json_encode($result->asArray()));
|
|
// Set the cache expiration time (3 days)
|
|
redis->expire('cvr_lookup_' . $cvr, (60 * 60 * 24 * 4));
|
|
}
|
|
$response->success(['cvr' => $cvr, 'result' => (object)$result->asArray(), 'phone' => $result->phone, 'email' => $result->email], 200);
|
|
});
|
|
}
|
|
|
|
protected function FORMAT_LICENSE_PLATE(string $plate): string
|
|
{
|
|
// Remove all non-alphanumeric characters
|
|
$cleaned = preg_replace('/[^A-Za-z0-9]/', '', $plate);
|
|
// Convert to uppercase
|
|
return strtoupper($cleaned);
|
|
}
|
|
}
|