From 30604f9bf512535292138955feb1431b450e64d5 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 10 Oct 2024 18:43:44 +0800 Subject: [PATCH] fixed driver creation flow to stop role breaking, added contact sync with user --- .../modals/reset-customer-credentials.hbs | 2 +- composer.json | 2 +- extension.json | 2 +- package.json | 2 +- .../Internal/v1/DriverController.php | 59 ++++-------------- server/src/Http/Filter/ContactFilter.php | 6 -- server/src/Http/Filter/DriverFilter.php | 7 +-- server/src/Models/Contact.php | 60 ++++++++++++++++++- server/src/Observers/ContactObserver.php | 37 ++++++++++++ 9 files changed, 112 insertions(+), 65 deletions(-) diff --git a/addon/components/modals/reset-customer-credentials.hbs b/addon/components/modals/reset-customer-credentials.hbs index 0ed69037..34614779 100644 --- a/addon/components/modals/reset-customer-credentials.hbs +++ b/addon/components/modals/reset-customer-credentials.hbs @@ -1,5 +1,5 @@ -
+
You are about to reset the password for {{this.customer.name}} diff --git a/composer.json b/composer.json index b36ba1a4..af3323af 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "fleetbase/fleetops-api", - "version": "0.5.9", + "version": "0.5.10", "description": "Fleet & Transport Management Extension for Fleetbase", "keywords": [ "fleetbase-extension", diff --git a/extension.json b/extension.json index 2da7c5bc..0414382a 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "Fleet-Ops", - "version": "0.5.9", + "version": "0.5.10", "description": "Fleet & Transport Management Extension for Fleetbase", "repository": "https://github.com/fleetbase/fleetops", "license": "AGPL-3.0-or-later", diff --git a/package.json b/package.json index ace9c7d9..3a539638 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/fleetops-engine", - "version": "0.5.9", + "version": "0.5.10", "description": "Fleet & Transport Management Extension for Fleetbase", "fleetbase": { "route": "fleet-ops" diff --git a/server/src/Http/Controllers/Internal/v1/DriverController.php b/server/src/Http/Controllers/Internal/v1/DriverController.php index bb89b5a9..f4a17290 100644 --- a/server/src/Http/Controllers/Internal/v1/DriverController.php +++ b/server/src/Http/Controllers/Internal/v1/DriverController.php @@ -19,7 +19,6 @@ use Fleetbase\Models\Invite; use Fleetbase\Models\User; use Fleetbase\Models\VerificationCode; -use Fleetbase\Notifications\UserInvited; use Fleetbase\Support\Auth; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -81,7 +80,7 @@ public function createRecord(Request $request) if ($existingUser) { // if exists in organization create driver profile for user - $isOrganizationMember = $existingUser->companies()->where('company_uuid', session('company'))->exists(); + $isOrganizationMember = $existingUser->companies()->where('companies.uuid', session('company'))->exists(); // Check if driver profile also already exists $existingDriverProfile = Driver::where(['company_uuid' => session('company'), 'user_uuid' => $existingUser->uuid])->first(); @@ -106,36 +105,14 @@ public function createRecord(Request $request) $input['location'] = new Point(0, 0); } - // If user is a regular user set type and role - // also if is not admin and is not Administrator role - if ($existingUser->isNotAdmin() && !$existingUser->hasRole('Administrator')) { - $existingUser->assignSingleRole('Driver'); - } - // create the profile $driverProfile = Driver::create($input); - // Assign user to company - if ($company) { + // If not already a member of the company assign them to the company and send the user an invite + if (!$isOrganizationMember && $company) { $existingUser->assignCompany($company); } - if (!$isOrganizationMember) { - // send invitation to user - $invitation = Invite::create([ - 'company_uuid' => session('company'), - 'created_by_uuid' => session('user'), - 'subject_uuid' => session('company'), - 'subject_type' => Utils::getMutationType('company'), - 'protocol' => 'email', - 'recipients' => [$existingUser->email], - 'reason' => 'join_company', - ]); - - // notify user - $existingUser->notify(new UserInvited($invitation)); - } - return ['driver' => new $this->resource($driverProfile)]; } } @@ -152,10 +129,12 @@ function (&$request, &$input) { // Get current session company $company = Auth::getCompany(); + if (!$company) { + throw new \Exception('Unable to create driver.'); + } if ($input->has('user_uuid')) { $user = User::where('uuid', $input->get('user_uuid'))->first(); - // handle `photo_uuid` if ($user && $input->has('photo_uuid')) { $user->update(['avatar_uuid' => $input->get('photo_uuid')]); } @@ -188,39 +167,25 @@ function (&$request, &$input) { $user->setType('driver'); } + // if exists in organization create driver profile for user + $isOrganizationMember = $user->companies()->where('companies.uuid', session('company'))->exists(); + // Prepare input $input = $input ->except(['name', 'password', 'email', 'phone', 'meta', 'avatar_uuid', 'photo_uuid', 'status']) ->filter() ->toArray(); - // Assign user to company - if ($company) { + // Assign user to company and send invite + if (!$isOrganizationMember && $company) { $user->assignCompany($company); - } else { - $user->deleteQuietly(); - throw new \Exception('Unable to assign driver to company.'); } // Set user type as driver and set role to driver - if ($user->isNotAdmin()) { + if ($user->type === 'driver') { $user->assignSingleRole('Driver'); } - // send invitation to user - $invitation = Invite::create([ - 'company_uuid' => session('company'), - 'created_by_uuid' => session('user'), - 'subject_uuid' => session('company'), - 'subject_type' => Utils::getMutationType('company'), - 'protocol' => 'email', - 'recipients' => [$user->email], - 'reason' => 'join_company', - ]); - - // notify user - $user->notify(new UserInvited($invitation)); - $input['user_uuid'] = $user->uuid; $input['slug'] = $user->slug; diff --git a/server/src/Http/Filter/ContactFilter.php b/server/src/Http/Filter/ContactFilter.php index b1c35b79..f609ba6a 100644 --- a/server/src/Http/Filter/ContactFilter.php +++ b/server/src/Http/Filter/ContactFilter.php @@ -12,12 +12,6 @@ public function queryForInternal() $this->builder->where( function ($query) { $query->where('company_uuid', $this->session->get('company')); - $query->orWhereHas( - 'anyUser', - function ($query) { - $query->where('company_uuid', $this->session->get('company')); - } - ); } ); } diff --git a/server/src/Http/Filter/DriverFilter.php b/server/src/Http/Filter/DriverFilter.php index 15276775..db14919f 100644 --- a/server/src/Http/Filter/DriverFilter.php +++ b/server/src/Http/Filter/DriverFilter.php @@ -13,12 +13,7 @@ public function queryForInternal() $this->builder->where( function ($query) { $query->where('company_uuid', $this->session->get('company')); - $query->orWhereHas( - 'user', - function ($query) { - $query->where('company_uuid', $this->session->get('company')); - } - ); + $query->whereHas('user'); } ); } diff --git a/server/src/Models/Contact.php b/server/src/Models/Contact.php index 3bc1bdfb..0f03bb44 100644 --- a/server/src/Models/Contact.php +++ b/server/src/Models/Contact.php @@ -271,12 +271,12 @@ public static function createFromImport(array $row, bool $saveInstance = false): public static function createUserFromContact(Contact $contact, bool $sendInvite = true): User { // Check if user already exist with email or phone number - $userAlreadyExists = User::where('type', $contact->type)->where(function ($query) use ($contact) { + $userAlreadyExists = User::where(function ($query) use ($contact) { $query->where('email', $contact->email); $query->orWhere('phone', $contact->phone); })->first(); if ($userAlreadyExists) { - throw new UserAlreadyExistsException('User already exists, try to assign the user to this contact.'); + throw new UserAlreadyExistsException('User already exists, try to assigning the user to this contact.'); } // Load company @@ -325,9 +325,39 @@ public static function createUserFromContact(Contact $contact, bool $sendInvite $user->notify(new UserInvited($invitation)); } + $contact->setRelation('user', $user); + return $user; } + public function syncWithUser(): bool + { + $updates = []; + + if ($this->isDirty('name')) { + $updates['name'] = $this->name; + } + + if ($this->isDirty('email')) { + $updates['email'] = $this->email; + } + + if ($this->isDirty('phone')) { + $updates['phone'] = $this->phone; + } + + if ($this->isDirty('timezone')) { + $updates['timezone'] = $this->timezone; + } + + $user = $this->getUser(); + if ($user) { + return $user->update($updates); + } + + return false; + } + /** * Creates a new user from the current contact instance and optionally sends an invitation. * @@ -355,4 +385,30 @@ public function deleteUser(): ?bool return false; } + + public function getUser(): ?User + { + $this->loadMissing('user'); + if ($this->user) { + return $this->user; + } + + if (Str::isUuid($this->user_uuid)) { + return User::where('uuid', $this->user_uuid)->first(); + } + + return null; + } + + public function hasUser(): bool + { + $user = $this->getUser(); + + return Str::isUuid($this->user_uuid) && $user instanceof User; + } + + public function doesntHaveUser(): bool + { + return !$this->hasUser(); + } } diff --git a/server/src/Observers/ContactObserver.php b/server/src/Observers/ContactObserver.php index d3fd54b6..264e0c94 100644 --- a/server/src/Observers/ContactObserver.php +++ b/server/src/Observers/ContactObserver.php @@ -3,6 +3,7 @@ namespace Fleetbase\FleetOps\Observers; use Fleetbase\FleetOps\Models\Contact; +use Fleetbase\Models\User; class ContactObserver { @@ -17,6 +18,32 @@ public function created(Contact $contact) $contact->createUser(); } + /** + * Handle the Contact "creating" event. + * + * @return void + */ + public function updating(Contact $contact) + { + // Get the contacts assosciated user + if ($contact->doesntHaveUser()) { + $contact->createUser(); + } + + // Validate email is available to user + if ($contact->isDirty('email') && $this->isEmailUnavailable($contact)) { + throw new \Exception('Email attempting to update for ' . $contact->type . ' is not available.'); + } + + // Validate phone is available to user + if ($contact->isDirty('phone') && $this->isPhoneUnavailable($contact)) { + throw new \Exception('Phone attempting to update for ' . $contact->type . ' is not available.'); + } + + // Sync updates from contact to user + $contact->syncWithUser(); + } + /** * Handle the Contact "deleted" event. * @@ -27,4 +54,14 @@ public function deleted(Contact $contact) // Delete the assosciated user account $contact->deleteUser(); } + + private function isEmailUnavailable(Contact $contact) + { + return User::where('email', $contact->email)->whereNot('uuid', $contact->user_uuid)->exists() || Contact::where('email', $contact->email)->whereNot('uuid', $contact->uuid)->exists(); + } + + private function isPhoneUnavailable(Contact $contact) + { + return User::where('phone', $contact->phone)->whereNot('uuid', $contact->user_uuid)->exists() || Contact::where('phone', $contact->phone)->whereNot('uuid', $contact->uuid)->exists(); + } }