-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tenant with company module (#21)
- Loading branch information
1 parent
eb7db94
commit 137a9e7
Showing
19 changed files
with
795 additions
and
1 deletion.
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
86 changes: 86 additions & 0 deletions
86
src/Tenant/Actions/FilamentCompanies/AddCompanyEmployee.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,86 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use App\Models\User; | ||
use Closure; | ||
use Illuminate\Auth\Access\AuthorizationException; | ||
use Illuminate\Contracts\Validation\Rule; | ||
use Illuminate\Support\Facades\Gate; | ||
use Illuminate\Support\Facades\Validator; | ||
use Wallo\FilamentCompanies\Contracts\AddsCompanyEmployees; | ||
use Wallo\FilamentCompanies\Events\AddingCompanyEmployee; | ||
use Wallo\FilamentCompanies\Events\CompanyEmployeeAdded; | ||
use Wallo\FilamentCompanies\FilamentCompanies; | ||
use Wallo\FilamentCompanies\Rules\Role; | ||
|
||
class AddCompanyEmployee implements AddsCompanyEmployees | ||
{ | ||
/** | ||
* Add a new company employee to the given company. | ||
* | ||
* @throws AuthorizationException | ||
*/ | ||
public function add(User $user, Company $company, string $email, ?string $role = null): void | ||
{ | ||
Gate::forUser($user)->authorize('addCompanyEmployee', $company); | ||
|
||
$this->validate($company, $email, $role); | ||
|
||
$newCompanyEmployee = FilamentCompanies::findUserByEmailOrFail($email); | ||
|
||
AddingCompanyEmployee::dispatch($company, $newCompanyEmployee); | ||
|
||
$company->users()->attach( | ||
$newCompanyEmployee, | ||
['role' => $role] | ||
); | ||
|
||
CompanyEmployeeAdded::dispatch($company, $newCompanyEmployee); | ||
} | ||
|
||
/** | ||
* Validate the add employee operation. | ||
*/ | ||
protected function validate(Company $company, string $email, ?string $role): void | ||
{ | ||
Validator::make([ | ||
'email' => $email, | ||
'role' => $role, | ||
], $this->rules(), [ | ||
'email.exists' => __('filament-companies::default.errors.email_not_found'), | ||
])->after( | ||
$this->ensureUserIsNotAlreadyOnCompany($company, $email) | ||
)->validateWithBag('addCompanyEmployee'); | ||
} | ||
|
||
/** | ||
* Get the validation rules for adding a company employee. | ||
* | ||
* @return array<string, Rule|array|string> | ||
*/ | ||
protected function rules(): array | ||
{ | ||
return array_filter([ | ||
'email' => ['required', 'email', 'exists:users'], | ||
'role' => FilamentCompanies::hasRoles() | ||
? ['required', 'string', new Role] | ||
: null, | ||
]); | ||
} | ||
|
||
/** | ||
* Ensure that the user is not already on the company. | ||
*/ | ||
protected function ensureUserIsNotAlreadyOnCompany(Company $company, string $email): Closure | ||
{ | ||
return static function ($validator) use ($company, $email) { | ||
$validator->errors()->addIf( | ||
$company->hasUserWithEmail($email), | ||
'email', | ||
__('filament-companies::default.errors.user_belongs_to_company') | ||
); | ||
}; | ||
} | ||
} |
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,40 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use App\Models\User; | ||
use Illuminate\Auth\Access\AuthorizationException; | ||
use Illuminate\Support\Facades\Gate; | ||
use Illuminate\Support\Facades\Validator; | ||
use Wallo\FilamentCompanies\Contracts\CreatesCompanies; | ||
use Wallo\FilamentCompanies\Events\AddingCompany; | ||
use Wallo\FilamentCompanies\FilamentCompanies; | ||
|
||
class CreateCompany implements CreatesCompanies | ||
{ | ||
/** | ||
* Validate and create a new company for the given user. | ||
* | ||
* @param array<string, string> $input | ||
* | ||
* @throws AuthorizationException | ||
*/ | ||
public function create(User $user, array $input): Company | ||
{ | ||
Gate::forUser($user)->authorize('create', FilamentCompanies::newCompanyModel()); | ||
|
||
Validator::make($input, [ | ||
'name' => ['required', 'string', 'max:255'], | ||
])->validateWithBag('createCompany'); | ||
|
||
AddingCompany::dispatch($user); | ||
|
||
$user->switchCompany($company = $user->ownedCompanies()->create([ | ||
'name' => $input['name'], | ||
'personal_company' => false, | ||
])); | ||
|
||
return $company; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/Tenant/Actions/FilamentCompanies/CreateConnectedAccount.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,32 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use Illuminate\Contracts\Auth\Authenticatable; | ||
use Laravel\Socialite\Contracts\User as ProviderUser; | ||
use Wallo\FilamentCompanies\ConnectedAccount; | ||
use Wallo\FilamentCompanies\Contracts\CreatesConnectedAccounts; | ||
use Wallo\FilamentCompanies\FilamentCompanies; | ||
|
||
class CreateConnectedAccount implements CreatesConnectedAccounts | ||
{ | ||
/** | ||
* Create a connected account for a given user. | ||
*/ | ||
public function create(Authenticatable $user, string $provider, ProviderUser $providerUser): ConnectedAccount | ||
{ | ||
return FilamentCompanies::connectedAccountModel()::forceCreate([ | ||
'user_id' => $user->getAuthIdentifier(), | ||
'provider' => strtolower($provider), | ||
'provider_id' => $providerUser->getId(), | ||
'name' => $providerUser->getName(), | ||
'nickname' => $providerUser->getNickname(), | ||
'email' => $providerUser->getEmail(), | ||
'avatar_path' => $providerUser->getAvatar(), | ||
'token' => $providerUser->token, | ||
'secret' => $providerUser->tokenSecret ?? null, | ||
'refresh_token' => $providerUser->refreshToken ?? null, | ||
'expires_at' => property_exists($providerUser, 'expiresIn') ? now()->addSeconds($providerUser->expiresIn) : null, | ||
]); | ||
} | ||
} |
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,51 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use App\Models\User; | ||
use Illuminate\Support\Facades\DB; | ||
use Illuminate\Support\Facades\Hash; | ||
use Illuminate\Support\Facades\Validator; | ||
use Wallo\FilamentCompanies\Contracts\CreatesNewUsers; | ||
use Wallo\FilamentCompanies\FilamentCompanies; | ||
|
||
class CreateNewUser implements CreatesNewUsers | ||
{ | ||
/** | ||
* Create a newly registered user. | ||
* | ||
* @param array<string, string> $input | ||
*/ | ||
public function create(array $input): User | ||
{ | ||
Validator::make($input, [ | ||
'name' => ['required', 'string', 'max:255'], | ||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], | ||
'password' => ['required', 'string', 'min:8', 'confirmed'], | ||
'terms' => FilamentCompanies::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '', | ||
])->validate(); | ||
|
||
return DB::transaction(function () use ($input) { | ||
return tap(User::create([ | ||
'name' => $input['name'], | ||
'email' => $input['email'], | ||
'password' => Hash::make($input['password']), | ||
]), function (User $user) { | ||
$this->createCompany($user); | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Create a personal company for the user. | ||
*/ | ||
protected function createCompany(User $user): void | ||
{ | ||
$user->ownedCompanies()->save(Company::forceCreate([ | ||
'user_id' => $user->id, | ||
'name' => explode(' ', $user->name, 2)[0] . "'s Company", | ||
'personal_company' => true, | ||
])); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/Tenant/Actions/FilamentCompanies/CreateUserFromProvider.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,72 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use App\Models\User; | ||
use Illuminate\Support\Facades\DB; | ||
use Laravel\Socialite\Contracts\User as ProviderUserContract; | ||
use Wallo\FilamentCompanies\Contracts\CreatesConnectedAccounts; | ||
use Wallo\FilamentCompanies\Contracts\CreatesUserFromProvider; | ||
use Wallo\FilamentCompanies\Enums\Feature; | ||
use Wallo\FilamentCompanies\FilamentCompanies; | ||
|
||
class CreateUserFromProvider implements CreatesUserFromProvider | ||
{ | ||
/** | ||
* The creates connected accounts instance. | ||
*/ | ||
public CreatesConnectedAccounts $createsConnectedAccounts; | ||
|
||
/** | ||
* Create a new action instance. | ||
*/ | ||
public function __construct(CreatesConnectedAccounts $createsConnectedAccounts) | ||
{ | ||
$this->createsConnectedAccounts = $createsConnectedAccounts; | ||
} | ||
|
||
/** | ||
* Create a new user from a social provider user. | ||
*/ | ||
public function create(string $provider, ProviderUserContract $providerUser): User | ||
{ | ||
return DB::transaction(function () use ($providerUser, $provider) { | ||
return tap(User::create([ | ||
'name' => $providerUser->getName(), | ||
'email' => $providerUser->getEmail(), | ||
]), function (User $user) use ($providerUser, $provider) { | ||
$user->markEmailAsVerified(); | ||
|
||
if ($this->shouldSetProfilePhoto($providerUser)) { | ||
$user->setProfilePhotoFromUrl($providerUser->getAvatar()); | ||
} | ||
|
||
$user->switchConnectedAccount( | ||
$this->createsConnectedAccounts->create($user, $provider, $providerUser) | ||
); | ||
|
||
$this->createCompany($user); | ||
}); | ||
}); | ||
} | ||
|
||
private function shouldSetProfilePhoto(ProviderUserContract $providerUser): bool | ||
{ | ||
return Feature::ProviderAvatars->isEnabled() && | ||
FilamentCompanies::managesProfilePhotos() && | ||
$providerUser->getAvatar(); | ||
} | ||
|
||
/** | ||
* Create a personal company for the user. | ||
*/ | ||
protected function createCompany(User $user): void | ||
{ | ||
$user->ownedCompanies()->save(Company::forceCreate([ | ||
'user_id' => $user->id, | ||
'name' => explode(' ', $user->name, 2)[0] . "'s Company", | ||
'personal_company' => 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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use Wallo\FilamentCompanies\Contracts\DeletesCompanies; | ||
|
||
class DeleteCompany implements DeletesCompanies | ||
{ | ||
/** | ||
* Delete the given company. | ||
*/ | ||
public function delete(Company $company): void | ||
{ | ||
$company->purge(); | ||
} | ||
} |
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,51 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use App\Models\Company; | ||
use App\Models\User; | ||
use Illuminate\Support\Facades\DB; | ||
use Wallo\FilamentCompanies\Contracts\DeletesCompanies; | ||
use Wallo\FilamentCompanies\Contracts\DeletesUsers; | ||
|
||
class DeleteUser implements DeletesUsers | ||
{ | ||
/** | ||
* The company deleter implementation. | ||
*/ | ||
protected DeletesCompanies $deletesCompanies; | ||
|
||
/** | ||
* Create a new action instance. | ||
*/ | ||
public function __construct(DeletesCompanies $deletesCompanies) | ||
{ | ||
$this->deletesCompanies = $deletesCompanies; | ||
} | ||
|
||
/** | ||
* Delete the given user. | ||
*/ | ||
public function delete(User $user): void | ||
{ | ||
DB::transaction(function () use ($user) { | ||
$this->deleteCompanies($user); | ||
$user->deleteProfilePhoto(); | ||
$user->connectedAccounts->each(static fn($account) => $account->delete()); | ||
$user->tokens->each(static fn($token) => $token->delete()); | ||
$user->delete(); | ||
}); | ||
} | ||
|
||
/** | ||
* Delete the companies and company associations attached to the user. | ||
*/ | ||
protected function deleteCompanies(User $user): void | ||
{ | ||
$user->companies()->detach(); | ||
|
||
$user->ownedCompanies->each(function (Company $company) { | ||
$this->deletesCompanies->delete($company); | ||
}); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/Tenant/Actions/FilamentCompanies/HandleInvalidState.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,22 @@ | ||
<?php | ||
|
||
namespace Octo\Tenant\Actions\FilamentCompanies; | ||
|
||
use Illuminate\Http\Response; | ||
use Laravel\Socialite\Two\InvalidStateException; | ||
use Wallo\FilamentCompanies\Contracts\HandlesInvalidState; | ||
|
||
class HandleInvalidState implements HandlesInvalidState | ||
{ | ||
/** | ||
* Handle an invalid state exception from a Socialite provider. | ||
*/ | ||
public function handle(InvalidStateException $exception, ?callable $callback = null): Response | ||
{ | ||
if ($callback) { | ||
return $callback($exception); | ||
} | ||
|
||
throw $exception; | ||
} | ||
} |
Oops, something went wrong.