- Introduce `/subusers` route for creating subusers and linking them to companies via phone number validation. - Add token-based subuser setup flow including token generation, validation, and expiration handling. - Extend `subusers_o` with methods for subuser lookup, token handling, and secure password management. - Implement enhanced input validation for subuser creation, ensuring stricter checks for name, username, and email fields.
163 lines
7.2 KiB
PHP
163 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace routes;
|
|
|
|
use classes\authentication;
|
|
use classes\economic;
|
|
use classes\gatewayapi;
|
|
use classes\response;
|
|
use classes\virkdata;
|
|
use Exception;
|
|
use modules\virkdata\helpers\virkdata_response;
|
|
use objects\logs_o;
|
|
use objects\subusers_o;
|
|
use objects\users_o;
|
|
use traits\route_t;
|
|
|
|
class subusersRoute
|
|
{
|
|
use route_t;
|
|
|
|
private static function requireRegex(string $input, string $regex, string $error_message): void
|
|
{
|
|
if (!preg_match($regex, $input)) {
|
|
global $response;
|
|
$response->error($error_message, 400);
|
|
}
|
|
}
|
|
|
|
public function run(): void
|
|
{
|
|
$this->post('/subusers', function () {
|
|
global /** @var response $response */
|
|
$response;
|
|
self::requireParameters([
|
|
'cvr',
|
|
'phone_country_code',
|
|
'phone'
|
|
]);
|
|
|
|
$cvr = (int)self::getParameter('cvr');
|
|
$phone_country_code =(int) self::getParameter('phone_country_code');
|
|
$phone = (int)self::getParameter('phone');
|
|
/** Validation */
|
|
// Check if the CVR number is valid (8 digits)
|
|
self::requireType($cvr, self::type_int());
|
|
self::requireMinLength('cvr', 8);
|
|
self::requireMaxLength('cvr', 8);
|
|
// Check if the phone country code is valid (1-3 digits)
|
|
self::requireType($phone_country_code, self::type_int());
|
|
self::requireMinLength('phone_country_code', 1);
|
|
self::requireMaxLength('phone_country_code', 3);
|
|
// Check if the phone number is valid (4-15 digits)
|
|
self::requireType($phone, self::type_int());
|
|
self::requireMinLength('phone', 4);
|
|
self::requireMaxLength('phone', 15);
|
|
// Check if the CVR is registered to a company in the database
|
|
$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);
|
|
}
|
|
/** At this point, we know that the CVR is valid and that the company exists in the database. */
|
|
$company_user = (new users_o())->getUserByCustomerNumber((int)$results[0]->customerNumber);
|
|
$company_user->requireSelected();
|
|
/** We can now check if a subuser already exists with the same phone number. */
|
|
$subuser = (new subusers_o())->getSubuserByPhone($phone_country_code, $phone);
|
|
if ($subuser !== null) {
|
|
$response->error('Account already exists with this phone number', 400);
|
|
}
|
|
/** We can now create the subuser and send a request to the company user to link the subuser to the company. */
|
|
$subuser = (new subusers_o())->add(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
(int)$phone_country_code,
|
|
(int)$phone
|
|
);
|
|
// Send an SMS with a link to complete the registration process.
|
|
$gatewayAPI = new gatewayapi();
|
|
if ($gatewayAPI->isEnabled()) {
|
|
$token = $subuser->generateSetupToken();
|
|
$link = 'https://truckwash.io/complete-registration?token=' . $token;
|
|
$message = 'Tak for din oprettelse af chaufførkonto hos Truck Wash! Klik på linket for at fuldføre registreringen: ' . $link;
|
|
$phone_number_array = [(string)$phone_country_code . (string)$phone];
|
|
$gatewayAPI->send($phone_number_array, $message);
|
|
}
|
|
$response->success(['cvr' => $cvr, 'customer_number' => $results[0]->customerNumber]);
|
|
// Code for creating a new subuser would go here
|
|
});
|
|
$this->get('/subusers/setup', function () {
|
|
// Require the user to be logged in
|
|
global $response;
|
|
self::requireParameters(['token']);
|
|
$token = self::getParameter('token');
|
|
// Get the subuser with the setup token
|
|
$subuser = (new subusers_o())->getSubuserBySetupToken($token);
|
|
if ($subuser === null) {
|
|
$response->error('Invalid or expired token', 400);
|
|
}
|
|
$response->success(['message' => 'Token is valid', 'subuser_id' => $subuser->id]);
|
|
});
|
|
$this->post('/subusers/setup', function () {
|
|
// Require the user to be logged in
|
|
global $response;
|
|
self::requireParameters(['token', 'password', 'name']);
|
|
$token = (string)self::getParameter('token');
|
|
$password = (string)self::getParameter('password');
|
|
$name = (string)self::getParameter('name');
|
|
self::requireType($password, self::type_string());
|
|
self::requireMinLength('password', 8);
|
|
self::requireMaxLength('password', 255);
|
|
self::requireRegex($password, '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/', 'Password must contain at least one uppercase letter, one lowercase letter, and one number');
|
|
self::requireType($name, self::type_string());
|
|
self::requireMinLength('name', 3);
|
|
self::requireMaxLength('name', 255);
|
|
/**
|
|
* Optional fields:
|
|
* - username: string, 3-255 characters
|
|
* - email: string, valid email format, 3-255 characters
|
|
*/
|
|
$username = null;
|
|
$email = null;
|
|
if (self::isParametersSet(['username'])) {
|
|
$username = (string)self::getParameter('username');
|
|
self::requireType($username, self::type_string());
|
|
self::requireMinLength('username', 3);
|
|
self::requireMaxLength('username', 255);
|
|
}
|
|
if (self::isParametersSet(['email'])) {
|
|
$email = (string)self::getParameter('email');
|
|
self::requireType($email, self::type_string());
|
|
self::requireMinLength('email', 3);
|
|
self::requireMaxLength('email', 255);
|
|
self::requireRegex($email, '/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/', 'Invalid email format');
|
|
}
|
|
// Get the subuser with the setup token
|
|
$subuser = (new subusers_o())->getSubuserBySetupToken($token);
|
|
if ($subuser === null) {
|
|
$response->error('Invalid or expired token', 400);
|
|
}
|
|
// Set the password for the subuser
|
|
try {
|
|
$subuser->setPassword($password);
|
|
if (!empty($username) || !empty($email) || !empty($name)) {
|
|
$subuser->update([
|
|
...(!empty($username) ? ['username' => $username] : []),
|
|
...(!empty($email) ? ['email' => $email] : []),
|
|
...(!empty($name) ? ['name' => $name] : []),
|
|
]);
|
|
}
|
|
$response->success(['message' => 'Password set successfully']);
|
|
} catch (Exception $e) {
|
|
$response->error($e->getMessage(), 400);
|
|
}
|
|
});
|
|
}
|
|
} |