diff --git a/openapi.yaml b/openapi.yaml
index 853a18aa..5599cdaf 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -296,6 +296,40 @@ paths:
'400':
$ref: '#/components/responses/BadRequest'
+ /auth/password-reset/request:
+ post:
+ tags:
+ - Authentication
+ summary: Request a customer password reset email
+ description: Send an email with a password reset token to the customer's email address
+ operationId: requestPasswordReset
+ security: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - customer_number
+ properties:
+ customer_number:
+ type: integer
+ description: The customer number
+ example: 123456
+ responses:
+ '200':
+ description: Request processed
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ '400':
+ $ref: '#/components/responses/BadRequest'
+
/auth/password-reset/validate:
get:
tags:
diff --git a/services/nginx/app/objects/users_o.php b/services/nginx/app/objects/users_o.php
index 8e1607cb..31ff1f89 100644
--- a/services/nginx/app/objects/users_o.php
+++ b/services/nginx/app/objects/users_o.php
@@ -157,6 +157,14 @@ class users_o extends db
$this->add($customer_number, '', 0);
// Nullify the password
$this->password->nullify();
+ // If the customer has an email address, save it
+ if (isset($customer_data->email)) {
+ $this->email->set($customer_data->email);
+ }
+ // If the customer has a name, save it as the display name
+ if (isset($customer_data->name)) {
+ $this->display_name->set($customer_data->name);
+ }
}
}
// Else return false
diff --git a/services/nginx/app/routes/authRoute.php b/services/nginx/app/routes/authRoute.php
index 906b01d7..d23d7c60 100644
--- a/services/nginx/app/routes/authRoute.php
+++ b/services/nginx/app/routes/authRoute.php
@@ -4,8 +4,10 @@ namespace routes;
use classes\authentication;
use classes\economic;
+use classes\email;
use classes\recaptcha;
use classes\virkdata;
+use Exception;
use objects\customer_password_reset_keys_o;
use objects\logs_o;
use objects\tokens_o;
@@ -268,6 +270,50 @@ class authRoute
}
});
+ $this->post('/auth/password-reset/request', function () {
+ global $response;
+ $this->requireRecaptcha();
+ self::requireParameters(['customer_number']);
+ $customer_number = (int)self::getParameter('customer_number');
+
+ $user = (new users_o())->getUserByCustomerNumber($customer_number);
+ if (!$user->id) {
+ // For security reasons, don't reveal if the user exists
+ $response->success(['message' => 'If the customer exists, a password reset email has been sent.']);
+ }
+
+ $email_address = $user->email->value();
+ if (empty($email_address)) {
+ // If no email is set, we can't send the reset email
+ $response->error('No email address associated with this account. Please contact support.', 400);
+ }
+
+ // Generate token
+ $token = customer_password_reset_keys_o::generateToken();
+
+ // Save token
+ $reset_key_o = new customer_password_reset_keys_o();
+ $reset_key_o->add([
+ 'customer_id' => $customer_number,
+ 'token' => $token,
+ 'note' => 'Requested via API'
+ ]);
+
+ // Send email
+ $email = new email();
+ $reset_link = "https://truckwash.io/auth/password-reset/" . $token;
+
+ $subject = 'Adgangskode nulstilling';
+ $message = "Du har anmodet om at nulstille din adgangskode. Klik på linket herunder for at fortsætte:
$reset_link
Linket er gyldigt i 1 time.";
+
+ try {
+ $email->sendEmail($email_address, $user->display_name->value() ?? 'Kunde', $subject, $message, null);
+ $response->success(['message' => 'If the customer exists, a password reset email has been sent.']);
+ } catch (Exception $e) {
+ $response->error('Failed to send email: ' . $e->getMessage(), 500);
+ }
+ });
+
$this->get('/auth/password-reset/validate', function () {
global $response;
self::requireParameters(['token']);