From ce0c04c815519b1faf62cbd25b5ffbe22aaeca69 Mon Sep 17 00:00:00 2001 From: cesarLima1 Date: Mon, 25 Nov 2024 09:06:31 -0400 Subject: [PATCH 1/5] [TM-1385] start up admin create user controller --- .../V2/User/AdminUserCreationController.php | 68 ++++++++++++++ .../V2/User/AdminUserCreationRequest.php | 62 +++++++++++++ .../V2/definitions/AdminUserCreate.yml | 22 +++++ openapi-src/V2/definitions/_index.yml | 2 + openapi-src/V2/paths/_index.yml | 17 ++++ resources/docs/swagger-v2.yml | 91 +++++++++++++++++++ routes/api_v2.php | 2 + 7 files changed, 264 insertions(+) create mode 100644 app/Http/Controllers/V2/User/AdminUserCreationController.php create mode 100644 app/Http/Requests/V2/User/AdminUserCreationRequest.php create mode 100644 openapi-src/V2/definitions/AdminUserCreate.yml diff --git a/app/Http/Controllers/V2/User/AdminUserCreationController.php b/app/Http/Controllers/V2/User/AdminUserCreationController.php new file mode 100644 index 000000000..dd510bfd5 --- /dev/null +++ b/app/Http/Controllers/V2/User/AdminUserCreationController.php @@ -0,0 +1,68 @@ +authorize('create', User::class); + + try { + return DB::transaction(function () use ($request) { + $validatedData = $request->validated(); + + $user = new User($validatedData); + $user->save(); + + $user->email_address_verified_at = $user->created_at; + $user->save(); + + $role = $validatedData['role']; + $user->syncRoles([$role]); + + if (! empty($validatedData['organisation'])) { + $organisation = Organisation::isUuid($validatedData['organisation'])->first(); + if ($organisation) { + $organisation->partners()->updateExistingPivot($user, ['status' => 'approved'], false); + $user->organisation_id = $organisation->id; + $user->save(); + } + } + + if (! empty($validatedData['direct_frameworks'])) { + $frameworkIds = Framework::whereIn('slug', $validatedData['direct_frameworks']) + ->pluck('id') + ->toArray(); + $user->frameworks()->sync($frameworkIds); + } + + return JsonResponseHelper::success(new UserResource($user), 201); + }); + } catch (\Exception $e) { + Log::error('User creation failed', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return JsonResponseHelper::error([ + 'message' => 'Failed to create user', + 'details' => $e->getMessage(), + ], 500); + } + } +} diff --git a/app/Http/Requests/V2/User/AdminUserCreationRequest.php b/app/Http/Requests/V2/User/AdminUserCreationRequest.php new file mode 100644 index 000000000..0c8f2d9a2 --- /dev/null +++ b/app/Http/Requests/V2/User/AdminUserCreationRequest.php @@ -0,0 +1,62 @@ + 'required|string|max:255', + 'last_name' => 'required|string|max:255', + 'email_address' => [ + 'required', + 'string', + 'email', + 'max:255', + 'unique:users,email_address', + ], + 'role' => 'required|string', + 'job_role' => 'sometimes|nullable|string|max:255', + 'country' => 'sometimes|nullable|string|max:2', + 'phone_number' => 'sometimes|nullable|string|max:20', + 'program' => 'sometimes|nullable|string|max:255', + 'organisation' => [ + 'sometimes', + 'nullable', + 'array', + function ($attribute, $value, $fail) { + if (! empty($value) && empty($value['uuid'])) { + $fail('The organisation must contain a uuid.'); + } + }, + ], + 'monitoring_organisations' => 'sometimes|array', + 'monitoring_organisations.*' => 'uuid|exists:organisations,uuid', + 'direct_frameworks' => 'sometimes|array', + 'direct_frameworks.*' => 'string|exists:frameworks,slug', + ]; + } + + public function messages(): array + { + return [ + 'email_address.unique' => 'This email address is already in use.', + 'role.in' => 'Invalid role selected.', + 'organisation.uuid' => 'Invalid organisation identifier.', + 'organisation.exists' => 'Organisation not found.', + 'country.max' => 'Country code must be 2 characters long.', + 'phone_number.max' => 'Phone number cannot exceed 20 characters.', + ]; + } +} diff --git a/openapi-src/V2/definitions/AdminUserCreate.yml b/openapi-src/V2/definitions/AdminUserCreate.yml new file mode 100644 index 000000000..47702f755 --- /dev/null +++ b/openapi-src/V2/definitions/AdminUserCreate.yml @@ -0,0 +1,22 @@ +type: object +properties: + first_name: + type: string + last_name: + type: string + email_address: + type: string + job_role: + type: string + phone_number: + type: string + organisation: + type: string + role: + type: string + country: + type: string + program: + type: string + direct_frameworks: + type: boolean \ No newline at end of file diff --git a/openapi-src/V2/definitions/_index.yml b/openapi-src/V2/definitions/_index.yml index fb2f8e31c..3e84461b9 100644 --- a/openapi-src/V2/definitions/_index.yml +++ b/openapi-src/V2/definitions/_index.yml @@ -238,6 +238,8 @@ ProjectReportRead: $ref: './ProjectReportRead.yml' UserCreate: $ref: './UserCreate.yml' +AdminUserCreate: + $ref: './AdminUserCreate.yml' UpdateRequestsPaginated: $ref: './UpdateRequestsPaginated.yml' UpdateRequestRead: diff --git a/openapi-src/V2/paths/_index.yml b/openapi-src/V2/paths/_index.yml index 8f9fa32b8..af9f29113 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -793,6 +793,23 @@ description: OK schema: $ref: '../definitions/_index.yml#/V2AdminUserRead' +/v2/admin/users/create: + post: + summary: Create a user + operationId: v2-admin-post-user + tags: + - V2 Admin + - V2 Users + parameters: + - in: body + name: body + schema: + $ref: '../definitions/_index.yml#/AdminUserCreate' + responses: + '201': + description: Created + schema: + $ref: '../definitions/_index.yml#/V2AdminUserRead' /v2/admin/users/export: get: summary: Export CSV document of all users diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index 2884a7c92..eecc0b5b6 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -42333,6 +42333,29 @@ definitions: type: string program: type: string + AdminUserCreate: + type: object + properties: + first_name: + type: string + last_name: + type: string + email_address: + type: string + job_role: + type: string + phone_number: + type: string + organisation: + type: string + role: + type: string + country: + type: string + program: + type: string + direct_frameworks: + type: boolean UpdateRequestsPaginated: title: UpdateRequestsPaginated type: object @@ -69086,6 +69109,74 @@ paths: type: string date_added: type: string + /v2/admin/users/create: + post: + summary: Create a user + operationId: v2-admin-post-user + tags: + - V2 Admin + - V2 Users + parameters: + - in: body + name: body + schema: + type: object + properties: + first_name: + type: string + last_name: + type: string + email_address: + type: string + job_role: + type: string + phone_number: + type: string + organisation: + type: string + role: + type: string + country: + type: string + program: + type: string + direct_frameworks: + type: boolean + responses: + '201': + description: Created + schema: + title: AdminUserRead + type: object + properties: + uuid: + type: string + status: + type: string + readable_status: + type: string + type: + type: string + first_name: + type: string + last_name: + type: string + email_address: + type: string + job_role: + type: string + facebook: + type: string + instagram: + type: string + linkedin: + type: string + twitter: + type: string + whatsapp_phone: + type: string + date_added: + type: string /v2/admin/users/export: get: summary: Export CSV document of all users diff --git a/routes/api_v2.php b/routes/api_v2.php index e1d77685e..1df197c28 100644 --- a/routes/api_v2.php +++ b/routes/api_v2.php @@ -214,6 +214,7 @@ use App\Http\Controllers\V2\User\AdminExportUsersController; use App\Http\Controllers\V2\User\AdminResetPasswordController; use App\Http\Controllers\V2\User\AdminUserController; +use App\Http\Controllers\V2\User\AdminUserCreationController; use App\Http\Controllers\V2\User\AdminUserMultiController; use App\Http\Controllers\V2\User\AdminUsersOrganizationController; use App\Http\Controllers\V2\User\AdminVerifyUserController; @@ -363,6 +364,7 @@ Route::put('reset-password/{user}', AdminResetPasswordController::class); Route::patch('verify/{user}', AdminVerifyUserController::class); Route::get('users-organisation-list/{organisation}', AdminUsersOrganizationController::class); + Route::post('/create', [AdminUserCreationController::class, 'store']); }); Route::resource('users', AdminUserController::class); From 83eab466493cb9e4677a9d1b7c753c0085643b8a Mon Sep 17 00:00:00 2001 From: cesarLima1 Date: Tue, 26 Nov 2024 12:10:44 -0400 Subject: [PATCH 2/5] [TM-1385] start up send login details controller --- app/Http/Controllers/AuthController.php | 52 ++++++++++++++++++ app/Http/Requests/SendLoginDetailsRequest.php | 25 +++++++++ app/Jobs/SendLoginDetailsJob.php | 54 +++++++++++++++++++ app/Mail/SendLoginDetails.php | 25 +++++++++ .../seeders/LocalizationKeysTableSeeder.php | 14 +++++ openapi-src/V2/paths/_index.yml | 3 ++ resources/docs/swagger-v2.yml | 27 ++++++++++ routes/api.php | 1 + 8 files changed, 201 insertions(+) create mode 100644 app/Http/Requests/SendLoginDetailsRequest.php create mode 100644 app/Jobs/SendLoginDetailsJob.php create mode 100644 app/Mail/SendLoginDetails.php diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 28312b72c..164ea0b78 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -11,9 +11,11 @@ use App\Http\Requests\ResendByEmailRequest; use App\Http\Requests\ResendRequest; use App\Http\Requests\ResetRequest; +use App\Http\Requests\SendLoginDetailsRequest; use App\Http\Requests\VerifyRequest; use App\Http\Resources\V2\User\MeResource; use App\Jobs\ResetPasswordJob; +use App\Jobs\SendLoginDetailsJob; use App\Jobs\UserVerificationJob; use App\Models\PasswordReset as PasswordResetModel; use App\Models\V2\Projects\ProjectInvite; @@ -160,6 +162,56 @@ public function resetAction(ResetRequest $request): JsonResponse return JsonResponseHelper::success((object) [], 200); } + public function sendLoginDetailsAction(SendLoginDetailsRequest $request): JsonResponse + { + $this->authorize('reset', 'App\\Models\\Auth'); + $data = $request->json()->all(); + + try { + $user = UserModel::where('email_address', '=', $data['email_address']) + ->whereNull('password') + ->firstOrFail(); + } catch (Exception $exception) { + return JsonResponseHelper::success((object) [], 200); + } + + // Delete any existing reset tokens for this user + // PasswordResetModel::where('user_id', $user->id)->delete(); + + SendLoginDetailsJob::dispatch($user, isset($data['callback_url']) ? $data['callback_url'] : null); + + return JsonResponseHelper::success((object) [], 200); + } + + // public function setPasswordAction(SetPasswordRequest $request): JsonResponse + // { + // $data = $request->json()->all(); + + // try { + // $passwordReset = PasswordResetModel::where('token', $data['token']) + // ->with('user') + // ->firstOrFail(); + + // // Check if token is expired (older than 7 days) + // if (Carbon::parse($passwordReset->created_at)->addDays(7)->isPast()) { + // $passwordReset->delete(); + // throw new Exception('Token expired'); + // } + + // // Update user password + // $user = $passwordReset->user; + // $user->password = bcrypt($data['password']); + // $user->saveOrFail(); + + // // Delete the token to ensure one-time use + // $passwordReset->delete(); + + // return JsonResponseHelper::success((object) [], 200); + // } catch (Exception $exception) { + // return JsonResponseHelper::error('Invalid or expired token', 400); + // } + // } + public function changeAction(ChangePasswordRequest $request): JsonResponse { $this->authorize('change', 'App\\Models\\Auth'); diff --git a/app/Http/Requests/SendLoginDetailsRequest.php b/app/Http/Requests/SendLoginDetailsRequest.php new file mode 100644 index 000000000..095d90b0a --- /dev/null +++ b/app/Http/Requests/SendLoginDetailsRequest.php @@ -0,0 +1,25 @@ + [ + 'required', + 'string', + 'email', + ], + 'callback_url' => [ + 'sometimes', + 'string', + 'url', + 'max:5000', + ], + ]; + } +} diff --git a/app/Jobs/SendLoginDetailsJob.php b/app/Jobs/SendLoginDetailsJob.php new file mode 100644 index 000000000..0c6925407 --- /dev/null +++ b/app/Jobs/SendLoginDetailsJob.php @@ -0,0 +1,54 @@ +model = $model; + $this->callbackUrl = $callbackUrl; + } + + public function handle() + { + try { + if (get_class($this->model) !== \App\Models\V2\User::class) { + throw new Exception('Invalid model type'); + } + + $passwordReset = new PasswordResetModel(); + $passwordReset->user_id = $this->model->id; + $passwordReset->token = Str::random(32); + $passwordReset->saveOrFail(); + Mail::to($this->model->email_address) + ->send(new SendLoginDetails($passwordReset->token, $this->callbackUrl, $this->model)); + } catch (\Throwable $e) { + Log::error('Job failed', ['error' => $e->getMessage()]); + + throw $e; + } + } +} diff --git a/app/Mail/SendLoginDetails.php b/app/Mail/SendLoginDetails.php new file mode 100644 index 000000000..af448a717 --- /dev/null +++ b/app/Mail/SendLoginDetails.php @@ -0,0 +1,25 @@ +setSubjectKey('send-login-details.subject') + ->setTitleKey('send-login-details.title') + ->setBodyKey('send-login-details.body') + ->setParams([ + '{userName}' => e($user->first_name . ' ' . $user->last_name), + '{mail}' => e($user->email_address), + ]) + ->setCta('send-login-details.cta'); + + $this->link = $callbackUrl ? + $callbackUrl . urlencode($token) : + '/set-password?token=' . urlencode($token); + + $this->transactional = true; + } +} diff --git a/database/seeders/LocalizationKeysTableSeeder.php b/database/seeders/LocalizationKeysTableSeeder.php index 18b304341..2a29b909c 100644 --- a/database/seeders/LocalizationKeysTableSeeder.php +++ b/database/seeders/LocalizationKeysTableSeeder.php @@ -165,6 +165,20 @@ public function run(): void 'If you have any questions, feel free to message us at info@terramatch.org.'); $this->createLocalizationKey('reset-password.cta', 'Reset Password'); + // send-login-details + $this->createLocalizationKey('send-login-details.subject', 'Welcome to TerraMatch!'); + $this->createLocalizationKey('send-login-details.title', 'Welcome to TerraMatch 🌱 !'); + $this->createLocalizationKey('send-login-details.body', 'Hi {userName},

' . + 'We\'re thrilled to let you know that your access to TerraMatch is now active!

' . + 'Your user email used for your account is {mail}

' . + 'Please click on the button below to set your new password. This link is valid for 7 days from the day you received this email.

' . + 'If you have any questions or require assistance, our support team is ready to help at info@terramatch.org or +44 7456 289369 (WhatsApp only).

'. + 'We look forward to working with you!

' . + '

' . + 'Best regards,' . + 'TerraMatch Support'); + $this->createLocalizationKey('send-login-details.cta', 'Set Password'); + // satellite-map-created $this->createLocalizationKey('satellite-map-created.subject', 'Remote Sensing Map Received'); $this->createLocalizationKey('satellite-map-created.title', 'Remote Sensing Map Received'); diff --git a/openapi-src/V2/paths/_index.yml b/openapi-src/V2/paths/_index.yml index af9f29113..4cc4b3d96 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -2500,6 +2500,9 @@ /auth/reset: post: $ref: './Auth/post-auth-reset.yml' +/auth/send-login-details: + post: + $ref: './Auth/post-auth-reset.yml' /v2/auth/verify: patch: $ref: './Auth/patch-v2-auth-verify.yml' diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index eecc0b5b6..1096e9257 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -93200,6 +93200,33 @@ paths: description: OK schema: type: object + /auth/send-login-details: + post: + operationId: post-auth-reset + summary: Send a password reset email to a user or admin + tags: + - Auth + security: [] + consumes: + - application/json + produces: + - application/json + parameters: + - name: Body + in: body + required: true + schema: + type: object + properties: + email_address: + type: string + callback_url: + type: string + responses: + '200': + description: OK + schema: + type: object /v2/auth/verify: patch: operationId: patch-v2-auth-verify diff --git a/routes/api.php b/routes/api.php index 372b4b028..28faa0a84 100644 --- a/routes/api.php +++ b/routes/api.php @@ -115,6 +115,7 @@ Route::get('/auth/resend', [AuthController::class, 'resendAction']); Route::post('/auth/reset', [AuthController::class, 'resetAction']); Route::patch('/auth/change', [AuthController::class, 'changeAction']); + Route::post('/auth/send-login-details', [AuthController::class, 'sendLoginDetailsAction']); Route::patch('/v2/auth/verify', [AuthController::class, 'verifyUnauthorizedAction']); Route::put('/v2/auth/complete/signup', [AuthController::class, 'completeUserSignup']); }); From 91bad8fdb6c204ec7f985612f53a665ddc6271da Mon Sep 17 00:00:00 2001 From: cesarLima1 Date: Tue, 26 Nov 2024 17:11:02 -0400 Subject: [PATCH 3/5] [TM-1385] Start up endpoint to set new password --- app/Http/Controllers/AuthController.php | 82 ++++++++++++------- app/Http/Requests/SetPasswordRequest.php | 24 ++++++ .../seeders/LocalizationKeysTableSeeder.php | 2 +- openapi-src/V2/paths/Auth/get-auth-mail.yml | 51 ++++++++++++ openapi-src/V2/paths/Auth/post-auth-store.yml | 20 +++++ openapi-src/V2/paths/_index.yml | 6 ++ resources/docs/swagger-v2.yml | 80 ++++++++++++++++++ routes/api.php | 2 + 8 files changed, 235 insertions(+), 32 deletions(-) create mode 100644 app/Http/Requests/SetPasswordRequest.php create mode 100644 openapi-src/V2/paths/Auth/get-auth-mail.yml create mode 100644 openapi-src/V2/paths/Auth/post-auth-store.yml diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 164ea0b78..3d7cd8ce9 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -12,6 +12,7 @@ use App\Http\Requests\ResendRequest; use App\Http\Requests\ResetRequest; use App\Http\Requests\SendLoginDetailsRequest; +use App\Http\Requests\SetPasswordRequest; use App\Http\Requests\VerifyRequest; use App\Http\Resources\V2\User\MeResource; use App\Jobs\ResetPasswordJob; @@ -26,6 +27,7 @@ use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; @@ -175,42 +177,60 @@ public function sendLoginDetailsAction(SendLoginDetailsRequest $request): JsonRe return JsonResponseHelper::success((object) [], 200); } - // Delete any existing reset tokens for this user - // PasswordResetModel::where('user_id', $user->id)->delete(); - SendLoginDetailsJob::dispatch($user, isset($data['callback_url']) ? $data['callback_url'] : null); return JsonResponseHelper::success((object) [], 200); } - // public function setPasswordAction(SetPasswordRequest $request): JsonResponse - // { - // $data = $request->json()->all(); - - // try { - // $passwordReset = PasswordResetModel::where('token', $data['token']) - // ->with('user') - // ->firstOrFail(); - - // // Check if token is expired (older than 7 days) - // if (Carbon::parse($passwordReset->created_at)->addDays(7)->isPast()) { - // $passwordReset->delete(); - // throw new Exception('Token expired'); - // } - - // // Update user password - // $user = $passwordReset->user; - // $user->password = bcrypt($data['password']); - // $user->saveOrFail(); - - // // Delete the token to ensure one-time use - // $passwordReset->delete(); - - // return JsonResponseHelper::success((object) [], 200); - // } catch (Exception $exception) { - // return JsonResponseHelper::error('Invalid or expired token', 400); - // } - // } + public function getEmailByResetTokenAction(Request $request): JsonResponse + { + $data = $request->query(); + + $passwordReset = PasswordResetModel::where('token', '=', $data['token'])->first(); + + if (! $passwordReset) { + return JsonResponseHelper::success((object) [ + 'email_address' => null, + 'token_used' => true, + ], 200); + } + if (Carbon::parse($passwordReset->created_at)->addDays(7)->isPast()) { + $passwordReset->delete(); + + return JsonResponseHelper::success((object) [ + 'email_address' => null, + 'token_used' => true, + ], 200); + } + + $user = UserModel::findOrFail($passwordReset->user_id); + + return JsonResponseHelper::success((object) [ + 'email_address' => $user->email_address, + 'token_used' => false, + ], 200); + } + + public function setNewPasswordAction(SetPasswordRequest $request): JsonResponse + { + $this->authorize('change', 'App\\Models\\Auth'); + $data = $request->json()->all(); + $passwordReset = PasswordResetModel::where('token', '=', $data['token'])->firstOrFail(); + $user = UserModel::findOrFail($passwordReset->user_id); + if (Hash::check($data['password'], $user->password)) { + throw new SamePasswordException(); + } + $user->password = $data['password']; + + if (empty($user->email_address_verified_at)) { + $user->email_address_verified_at = new DateTime('now', new DateTimeZone('UTC')); + } + + $user->saveOrFail(); + $passwordReset->delete(); + + return JsonResponseHelper::success((object) [], 200); + } public function changeAction(ChangePasswordRequest $request): JsonResponse { diff --git a/app/Http/Requests/SetPasswordRequest.php b/app/Http/Requests/SetPasswordRequest.php new file mode 100644 index 000000000..f75541d5c --- /dev/null +++ b/app/Http/Requests/SetPasswordRequest.php @@ -0,0 +1,24 @@ + [ + 'required', + 'string', + 'exists:password_resets,token', + ], + 'password' => ['required', 'string', Password::min(8)->mixedCase()->numbers()], + ]; + } +} diff --git a/database/seeders/LocalizationKeysTableSeeder.php b/database/seeders/LocalizationKeysTableSeeder.php index 2a29b909c..1676b6c68 100644 --- a/database/seeders/LocalizationKeysTableSeeder.php +++ b/database/seeders/LocalizationKeysTableSeeder.php @@ -175,7 +175,7 @@ public function run(): void 'If you have any questions or require assistance, our support team is ready to help at info@terramatch.org or +44 7456 289369 (WhatsApp only).

'. 'We look forward to working with you!

' . '

' . - 'Best regards,' . + 'Best regards,

' . 'TerraMatch Support'); $this->createLocalizationKey('send-login-details.cta', 'Set Password'); diff --git a/openapi-src/V2/paths/Auth/get-auth-mail.yml b/openapi-src/V2/paths/Auth/get-auth-mail.yml new file mode 100644 index 000000000..6b997c49f --- /dev/null +++ b/openapi-src/V2/paths/Auth/get-auth-mail.yml @@ -0,0 +1,51 @@ +summary: "Get email address by reset token" +description: "Retrieves the email address associated with a reset token. If the token has already been used or does not exist, indicates that the token is used." +parameters: + - in: query + name: token + required: true + description: "The reset token" + type: string +responses: + 200: + description: "Successful response" + schema: + type: "object" + properties: + success: + type: "boolean" + example: true + data: + type: "object" + properties: + email_address: + type: "string" + nullable: true + example: "user@example.com" + description: "The email address associated with the reset token, or null if the token is already used." + token_used: + type: "boolean" + example: false + description: "Indicates whether the token has already been used. `true` if the token was used or does not exist, and `false` otherwise." + 404: + description: "User not found for the associated token" + schema: + type: "object" + properties: + success: + type: "boolean" + example: false + message: + type: "string" + example: "User not found" + 500: + description: "Internal server error" + schema: + type: "object" + properties: + success: + type: "boolean" + example: false + message: + type: "string" + example: "Internal Server Error" \ No newline at end of file diff --git a/openapi-src/V2/paths/Auth/post-auth-store.yml b/openapi-src/V2/paths/Auth/post-auth-store.yml new file mode 100644 index 000000000..1f4feee31 --- /dev/null +++ b/openapi-src/V2/paths/Auth/post-auth-store.yml @@ -0,0 +1,20 @@ +operationId: post-auth-store +summary: set a user's or admin's password +tags: + - Auth +security: [] +consumes: + - application/json +produces: + - application/json +parameters: + - name: Body + in: body + required: true + schema: + $ref: '../../definitions/_index.yml#/AuthChange' +responses: + '200': + description: OK + schema: + $ref: '../../definitions/_index.yml#/Empty' \ No newline at end of file diff --git a/openapi-src/V2/paths/_index.yml b/openapi-src/V2/paths/_index.yml index 4cc4b3d96..87c55f76b 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -2503,6 +2503,12 @@ /auth/send-login-details: post: $ref: './Auth/post-auth-reset.yml' +/auth/mail: + get: + $ref: './Auth/get-auth-mail.yml' +/auth/store: + post: + $ref: './Auth/post-auth-store.yml' /v2/auth/verify: patch: $ref: './Auth/patch-v2-auth-verify.yml' diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index 1096e9257..45576633d 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -93227,6 +93227,86 @@ paths: description: OK schema: type: object + /auth/mail: + get: + summary: Get email address by reset token + description: 'Retrieves the email address associated with a reset token. If the token has already been used or does not exist, indicates that the token is used.' + parameters: + - in: query + name: token + required: true + description: The reset token + type: string + responses: + '200': + description: Successful response + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + email_address: + type: string + nullable: true + example: user@example.com + description: 'The email address associated with the reset token, or null if the token is already used.' + token_used: + type: boolean + example: false + description: 'Indicates whether the token has already been used. `true` if the token was used or does not exist, and `false` otherwise.' + '404': + description: User not found for the associated token + schema: + type: object + properties: + success: + type: boolean + example: false + message: + type: string + example: User not found + '500': + description: Internal server error + schema: + type: object + properties: + success: + type: boolean + example: false + message: + type: string + example: Internal Server Error + /auth/store: + post: + operationId: post-auth-store + summary: set a user's or admin's password + tags: + - Auth + security: [] + consumes: + - application/json + produces: + - application/json + parameters: + - name: Body + in: body + required: true + schema: + type: object + properties: + token: + type: string + password: + type: string + responses: + '200': + description: OK + schema: + type: object /v2/auth/verify: patch: operationId: patch-v2-auth-verify diff --git a/routes/api.php b/routes/api.php index 28faa0a84..640697e0a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -116,6 +116,8 @@ Route::post('/auth/reset', [AuthController::class, 'resetAction']); Route::patch('/auth/change', [AuthController::class, 'changeAction']); Route::post('/auth/send-login-details', [AuthController::class, 'sendLoginDetailsAction']); + Route::get('/auth/mail', [AuthController::class, 'getEmailByResetTokenAction']); + Route::post('/auth/store', [AuthController::class, 'setNewPasswordAction']); Route::patch('/v2/auth/verify', [AuthController::class, 'verifyUnauthorizedAction']); Route::put('/v2/auth/complete/signup', [AuthController::class, 'completeUserSignup']); }); From 8109acd5db1354634ce7d48383ee7528435c7884 Mon Sep 17 00:00:00 2001 From: cesarLima1 Date: Tue, 26 Nov 2024 17:21:07 -0400 Subject: [PATCH 4/5] [TM-1385] update operationId --- openapi-src/V2/paths/Auth/post-auth-reset.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-src/V2/paths/Auth/post-auth-reset.yml b/openapi-src/V2/paths/Auth/post-auth-reset.yml index 30e04f42b..bedd8bcef 100644 --- a/openapi-src/V2/paths/Auth/post-auth-reset.yml +++ b/openapi-src/V2/paths/Auth/post-auth-reset.yml @@ -1,4 +1,4 @@ -operationId: post-auth-reset +operationId: post-auth-send-login-details summary: Send a password reset email to a user or admin tags: - Auth From d35b281b3d51a389d3714f46686e2e27782fd29a Mon Sep 17 00:00:00 2001 From: cesarLima1 Date: Tue, 26 Nov 2024 17:30:48 -0400 Subject: [PATCH 5/5] [TM-1385] update path index --- openapi-src/V2/paths/Auth/post-auth-reset.yml | 2 +- .../Auth/post-auth-send-login-details.yml | 20 +++++++++++++++++++ openapi-src/V2/paths/_index.yml | 2 +- resources/docs/swagger-v2.yml | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 openapi-src/V2/paths/Auth/post-auth-send-login-details.yml diff --git a/openapi-src/V2/paths/Auth/post-auth-reset.yml b/openapi-src/V2/paths/Auth/post-auth-reset.yml index bedd8bcef..30e04f42b 100644 --- a/openapi-src/V2/paths/Auth/post-auth-reset.yml +++ b/openapi-src/V2/paths/Auth/post-auth-reset.yml @@ -1,4 +1,4 @@ -operationId: post-auth-send-login-details +operationId: post-auth-reset summary: Send a password reset email to a user or admin tags: - Auth diff --git a/openapi-src/V2/paths/Auth/post-auth-send-login-details.yml b/openapi-src/V2/paths/Auth/post-auth-send-login-details.yml new file mode 100644 index 000000000..bedd8bcef --- /dev/null +++ b/openapi-src/V2/paths/Auth/post-auth-send-login-details.yml @@ -0,0 +1,20 @@ +operationId: post-auth-send-login-details +summary: Send a password reset email to a user or admin +tags: + - Auth +security: [] +consumes: + - application/json +produces: + - application/json +parameters: + - name: Body + in: body + required: true + schema: + $ref: '../../definitions/_index.yml#/AuthReset' +responses: + '200': + description: OK + schema: + $ref: '../../definitions/_index.yml#/Empty' \ No newline at end of file diff --git a/openapi-src/V2/paths/_index.yml b/openapi-src/V2/paths/_index.yml index 87c55f76b..fa643036d 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -2502,7 +2502,7 @@ $ref: './Auth/post-auth-reset.yml' /auth/send-login-details: post: - $ref: './Auth/post-auth-reset.yml' + $ref: './Auth/post-auth-send-login-details.yml' /auth/mail: get: $ref: './Auth/get-auth-mail.yml' diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index 45576633d..6ffff9c2a 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -93202,7 +93202,7 @@ paths: type: object /auth/send-login-details: post: - operationId: post-auth-reset + operationId: post-auth-send-login-details summary: Send a password reset email to a user or admin tags: - Auth