-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TM-1385] Admin create user funtionality (#590)
* [TM-1385] start up admin create user controller * [TM-1385] start up send login details controller * [TM-1385] Start up endpoint to set new password * [TM-1385] update operationId * [TM-1385] update path index
- Loading branch information
1 parent
a3e3a81
commit 9bb6341
Showing
17 changed files
with
688 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
app/Http/Controllers/V2/User/AdminUserCreationController.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
namespace App\Http\Controllers\V2\User; | ||
|
||
use App\Helpers\JsonResponseHelper; | ||
use App\Http\Controllers\Controller; | ||
use App\Http\Requests\V2\User\AdminUserCreationRequest; | ||
use App\Http\Resources\V2\User\UserResource; | ||
use App\Models\Framework; | ||
use App\Models\V2\Organisation; | ||
use App\Models\V2\User; | ||
use Illuminate\Http\JsonResponse; | ||
use Illuminate\Support\Facades\DB; | ||
use Illuminate\Support\Facades\Log; | ||
|
||
class AdminUserCreationController extends Controller | ||
{ | ||
/** | ||
* Create a new user from the admin panel | ||
*/ | ||
public function store(AdminUserCreationRequest $request): JsonResponse | ||
{ | ||
$this->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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace App\Http\Requests; | ||
|
||
use Illuminate\Foundation\Http\FormRequest; | ||
|
||
class SendLoginDetailsRequest extends FormRequest | ||
{ | ||
public function rules() | ||
{ | ||
return [ | ||
'email_address' => [ | ||
'required', | ||
'string', | ||
'email', | ||
], | ||
'callback_url' => [ | ||
'sometimes', | ||
'string', | ||
'url', | ||
'max:5000', | ||
], | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace App\Http\Requests; | ||
|
||
use Illuminate\Foundation\Http\FormRequest; | ||
use Illuminate\Validation\Rules\Password; | ||
|
||
class SetPasswordRequest extends FormRequest | ||
{ | ||
/** | ||
* Get the validation rules that apply to the request. | ||
*/ | ||
public function rules() | ||
{ | ||
return [ | ||
'token' => [ | ||
'required', | ||
'string', | ||
'exists:password_resets,token', | ||
], | ||
'password' => ['required', 'string', Password::min(8)->mixedCase()->numbers()], | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
namespace App\Http\Requests\V2\User; | ||
|
||
use Illuminate\Foundation\Http\FormRequest; | ||
|
||
class AdminUserCreationRequest extends FormRequest | ||
{ | ||
/** | ||
* Determine if the user is authorized to make this request | ||
*/ | ||
public function authorize(): bool | ||
{ | ||
return true; | ||
} | ||
|
||
public function rules(): array | ||
{ | ||
return [ | ||
'first_name' => '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.', | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
namespace App\Jobs; | ||
|
||
use App\Mail\SendLoginDetails; | ||
use App\Models\PasswordReset as PasswordResetModel; | ||
use Exception; | ||
use Illuminate\Bus\Queueable; | ||
use Illuminate\Contracts\Queue\ShouldQueue; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Foundation\Bus\Dispatchable; | ||
use Illuminate\Queue\InteractsWithQueue; | ||
use Illuminate\Queue\SerializesModels; | ||
use Illuminate\Support\Facades\Log; | ||
use Illuminate\Support\Facades\Mail; | ||
use Illuminate\Support\Str; | ||
|
||
class SendLoginDetailsJob implements ShouldQueue | ||
{ | ||
use Dispatchable; | ||
use InteractsWithQueue; | ||
use Queueable; | ||
use SerializesModels; | ||
|
||
private $model; | ||
|
||
private $callbackUrl; | ||
|
||
public function __construct(Model $model, ?string $callbackUrl) | ||
{ | ||
$this->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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace App\Mail; | ||
|
||
class SendLoginDetails extends I18nMail | ||
{ | ||
public function __construct(String $token, string $callbackUrl = null, $user) | ||
{ | ||
parent::__construct($user); | ||
$this->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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -165,6 +165,20 @@ public function run(): void | |
'If you have any questions, feel free to message us at [email protected].'); | ||
$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},<br><br>' . | ||
'We\'re thrilled to let you know that your access to TerraMatch is now active!<br><br>' . | ||
'Your user email used for your account is {mail}<br><br>' . | ||
'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.<br><br>' . | ||
'If you have any questions or require assistance, our support team is ready to help at [email protected] or +44 7456 289369 (WhatsApp only).<br><br>'. | ||
'We look forward to working with you!<br><br>' . | ||
'<br><br>' . | ||
'Best regards,<br><br>' . | ||
'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'); | ||
|
Oops, something went wrong.