Skip to content

Commit

Permalink
Add jetstream
Browse files Browse the repository at this point in the history
  • Loading branch information
lancepioch committed Jul 20, 2023
1 parent a72796c commit 4ba80e4
Show file tree
Hide file tree
Showing 125 changed files with 7,143 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_DRIVER=database
SESSION_LIFETIME=120

MEMCACHED_HOST=127.0.0.1
Expand Down
53 changes: 53 additions & 0 deletions app/Actions/Fortify/CreateNewUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Actions\Fortify;

use App\Models\Team;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;

class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;

/**
* 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' => $this->passwordRules(),
'terms' => Jetstream::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->createTeam($user);
});
});
}

/**
* Create a personal team for the user.
*/
protected function createTeam(User $user): void
{
$user->ownedTeams()->save(Team::forceCreate([
'user_id' => $user->id,
'name' => explode(' ', $user->name, 2)[0]."'s Team",
'personal_team' => true,
]));
}
}
18 changes: 18 additions & 0 deletions app/Actions/Fortify/PasswordValidationRules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Actions\Fortify;

use Laravel\Fortify\Rules\Password;

trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Contracts\Validation\Rule|array|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', new Password, 'confirmed'];
}
}
29 changes: 29 additions & 0 deletions app/Actions/Fortify/ResetUserPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Actions\Fortify;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;

class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;

/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();

$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
32 changes: 32 additions & 0 deletions app/Actions/Fortify/UpdateUserPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Actions\Fortify;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;

class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;

/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');

$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
56 changes: 56 additions & 0 deletions app/Actions/Fortify/UpdateUserProfileInformation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace App\Actions\Fortify;

use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;

class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
])->validateWithBag('updateProfileInformation');

if (isset($input['photo'])) {
$user->updateProfilePhoto($input['photo']);
}

if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}

/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
*/
protected function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();

$user->sendEmailVerificationNotification();
}
}
81 changes: 81 additions & 0 deletions app/Actions/Jetstream/AddTeamMember.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace App\Actions\Jetstream;

use App\Models\Team;
use App\Models\User;
use Closure;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
use Laravel\Jetstream\Events\AddingTeamMember;
use Laravel\Jetstream\Events\TeamMemberAdded;
use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\Rules\Role;

class AddTeamMember implements AddsTeamMembers
{
/**
* Add a new team member to the given team.
*/
public function add(User $user, Team $team, string $email, string $role = null): void
{
Gate::forUser($user)->authorize('addTeamMember', $team);

$this->validate($team, $email, $role);

$newTeamMember = Jetstream::findUserByEmailOrFail($email);

AddingTeamMember::dispatch($team, $newTeamMember);

$team->users()->attach(
$newTeamMember, ['role' => $role]
);

TeamMemberAdded::dispatch($team, $newTeamMember);
}

/**
* Validate the add member operation.
*/
protected function validate(Team $team, string $email, ?string $role): void
{
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules(), [
'email.exists' => __('We were unable to find a registered user with this email address.'),
])->after(
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
)->validateWithBag('addTeamMember');
}

/**
* Get the validation rules for adding a team member.
*
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
*/
protected function rules(): array
{
return array_filter([
'email' => ['required', 'email', 'exists:users'],
'role' => Jetstream::hasRoles()
? ['required', 'string', new Role]
: null,
]);
}

/**
* Ensure that the user is not already on the team.
*/
protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
{
return function ($validator) use ($team, $email) {
$validator->errors()->addIf(
$team->hasUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
};
}
}
37 changes: 37 additions & 0 deletions app/Actions/Jetstream/CreateTeam.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Actions\Jetstream;

use App\Models\Team;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\CreatesTeams;
use Laravel\Jetstream\Events\AddingTeam;
use Laravel\Jetstream\Jetstream;

class CreateTeam implements CreatesTeams
{
/**
* Validate and create a new team for the given user.
*
* @param array<string, string> $input
*/
public function create(User $user, array $input): Team
{
Gate::forUser($user)->authorize('create', Jetstream::newTeamModel());

Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
])->validateWithBag('createTeam');

AddingTeam::dispatch($user);

$user->switchTeam($team = $user->ownedTeams()->create([
'name' => $input['name'],
'personal_team' => false,
]));

return $team;
}
}
17 changes: 17 additions & 0 deletions app/Actions/Jetstream/DeleteTeam.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Actions\Jetstream;

use App\Models\Team;
use Laravel\Jetstream\Contracts\DeletesTeams;

class DeleteTeam implements DeletesTeams
{
/**
* Delete the given team.
*/
public function delete(Team $team): void
{
$team->purge();
}
}
52 changes: 52 additions & 0 deletions app/Actions/Jetstream/DeleteUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace App\Actions\Jetstream;

use App\Models\Team;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Laravel\Jetstream\Contracts\DeletesTeams;
use Laravel\Jetstream\Contracts\DeletesUsers;

class DeleteUser implements DeletesUsers
{
/**
* The team deleter implementation.
*
* @var \Laravel\Jetstream\Contracts\DeletesTeams
*/
protected $deletesTeams;

/**
* Create a new action instance.
*/
public function __construct(DeletesTeams $deletesTeams)
{
$this->deletesTeams = $deletesTeams;
}

/**
* Delete the given user.
*/
public function delete(User $user): void
{
DB::transaction(function () use ($user) {
$this->deleteTeams($user);
$user->deleteProfilePhoto();
$user->tokens->each->delete();
$user->delete();
});
}

/**
* Delete the teams and team associations attached to the user.
*/
protected function deleteTeams(User $user): void
{
$user->teams()->detach();

$user->ownedTeams->each(function (Team $team) {
$this->deletesTeams->delete($team);
});
}
}
Loading

0 comments on commit 4ba80e4

Please sign in to comment.