diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index 3c7c00c..863a7c2 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -2,16 +2,24 @@ namespace App\Actions\Fortify; +use App\Actions\Teams\AcceptTeamInvite; use App\Concerns\PasswordValidationRules; use App\Concerns\ProfileValidationRules; +use App\Models\TeamInvite; use App\Models\User; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\ValidationException; use Laravel\Fortify\Contracts\CreatesNewUsers; class CreateNewUser implements CreatesNewUsers { use PasswordValidationRules, ProfileValidationRules; + public function __construct( + private AcceptTeamInvite $acceptTeamInvite, + ) {} + /** * Validate and create a newly registered user. * @@ -19,15 +27,43 @@ class CreateNewUser implements CreatesNewUsers */ public function create(array $input): User { - Validator::make($input, [ + $validated = Validator::make($input, [ ...$this->profileRules(), 'password' => $this->passwordRules(), + 'invite_token' => ['nullable', 'string', 'size:128'], ])->validate(); - return User::create([ - 'name' => $input['name'], - 'email' => $input['email'], - 'password' => $input['password'], - ]); + return DB::transaction(function () use ($validated): User { + $invite = null; + + if (! empty($validated['invite_token'])) { + $invite = TeamInvite::findByPlainToken($validated['invite_token']) + ->lockForUpdate() + ->first(); + + if ( + $invite === null + || mb_strtolower($invite->invited_email) + !== mb_strtolower($validated['email']) + ) { + throw ValidationException::withMessages([ + 'invite_token' => 'Die Einladung ist ungültig oder gehört zu einer anderen E-Mail-Adresse.', + ]); + } + } + + $user = User::create([ + 'name' => $validated['name'], + 'email' => $validated['email'], + 'password' => $validated['password'], + ]); + + if ($invite !== null) { + $invite->team->members()->attach($user); + $invite->delete(); + } + + return $user; + }); } } diff --git a/app/Http/Controllers/TeamInviteController.php b/app/Http/Controllers/TeamInviteController.php index 9963dc6..0fea7f8 100644 --- a/app/Http/Controllers/TeamInviteController.php +++ b/app/Http/Controllers/TeamInviteController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\Team; +use App\Models\TeamInvite; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Arr; @@ -10,7 +11,6 @@ use Inertia\Inertia; class TeamInviteController extends Controller { - public function store(Request $request, Team $team) { $validated = $request->validate([ @@ -19,9 +19,22 @@ class TeamInviteController extends Controller abort_unless(auth()->user()->can('manage', $team), 403); + $invited = Arr::get($validated, 'email'); + $inviter = auth()->user()->id; + + $exists = TeamInvite::whereInvitedEmail($invited) + ->whereTeamId($team->id) + ->exists(); + + if ($exists) { + Inertia::flash('warning', 'This Person is already invited to this team.'); + + return; + } + $team->invites()->create([ - 'invited_email' => Arr::get($validated, 'email'), - 'invited_by_user_id' => auth()->user()->id, + 'invited_email' => $invited, + 'invited_by_user_id' => $inviter, ]); Inertia::flash('success', 'User invited to your team.'); diff --git a/app/Notifications/InviteToTeam.php b/app/Notifications/InviteToTeam.php index 9375dad..5c43c07 100644 --- a/app/Notifications/InviteToTeam.php +++ b/app/Notifications/InviteToTeam.php @@ -60,6 +60,11 @@ class InviteToTeam extends Notification ? 'register' : 'teams.invite.create', ['inviteToken' => $invite->plainInviteToken()] + + ( + $user === null + ? ['email' => $invite->invited_email] + : [] + ) )); } diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index 24cf595..87eae23 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -67,8 +67,10 @@ class FortifyServiceProvider extends ServiceProvider 'status' => $request->session()->get('status'), ])); - Fortify::registerView(fn () => Inertia::render('auth/Register', [ + Fortify::registerView(fn (Request $request) => Inertia::render('auth/Register', [ 'passwordRules' => Password::defaults()->toPasswordRulesString(), + 'inviteToken' => $request->query('inviteToken'), + 'email' => $request->query('email'), ])); Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/TwoFactorChallenge')); diff --git a/resources/js/pages/auth/Register.vue b/resources/js/pages/auth/Register.vue index 4767b57..c429acb 100644 --- a/resources/js/pages/auth/Register.vue +++ b/resources/js/pages/auth/Register.vue @@ -1,17 +1,19 @@ -