-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add invitation accept and decline endpoints #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |||||||||||||||
| use Illuminate\Support\Facades\Validator; | ||||||||||||||||
| use Whilesmart\Workspaces\Enums\Role; | ||||||||||||||||
| use Whilesmart\Workspaces\Enums\WorkspaceType; | ||||||||||||||||
| use Whilesmart\Workspaces\Events\MemberInvited; | ||||||||||||||||
| use Whilesmart\Workspaces\Models\Workspace; | ||||||||||||||||
| use Whilesmart\Workspaces\Models\WorkspaceInvitation; | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -231,6 +232,8 @@ public function inviteMember(Request $request, Workspace $workspace): JsonRespon | |||||||||||||||
| 'invited_by_user_id' => auth()->id(), | ||||||||||||||||
| ]); | ||||||||||||||||
|
|
||||||||||||||||
| MemberInvited::dispatch($workspace, $invitation); | ||||||||||||||||
|
|
||||||||||||||||
| return response()->json([ | ||||||||||||||||
| 'success' => true, | ||||||||||||||||
| 'message' => 'Invitation sent successfully', | ||||||||||||||||
|
|
@@ -285,6 +288,74 @@ public function cancelInvitation(Workspace $workspace, WorkspaceInvitation $invi | |||||||||||||||
| ]); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| public function acceptInvitation(string $token): JsonResponse | ||||||||||||||||
| { | ||||||||||||||||
| $user = auth()->user(); | ||||||||||||||||
|
|
||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consistency: As with
Suggested change
|
||||||||||||||||
| if (! $user) { | ||||||||||||||||
| return response()->json(['error' => 'Unauthorized'], 401); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| $invitation = WorkspaceInvitation::where('token', $token)->firstOrFail(); | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retrieving the invitation first by token and then checking the email separately is safe, but for performance and conciseness, you can include the email check in the query. This also prevents leaking existence of a token to the wrong user via 403 vs 404.
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| if ($invitation->email !== $user->email) { | ||||||||||||||||
| return response()->json(['error' => 'This invitation was sent to a different email address'], 403); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (! $invitation->isValid()) { | ||||||||||||||||
| $reason = $invitation->isExpired() | ||||||||||||||||
| ? 'This invitation has expired' | ||||||||||||||||
| : 'This invitation has already been actioned'; | ||||||||||||||||
|
|
||||||||||||||||
| return response()->json(['error' => $reason], 422); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (! $user->acceptInvitation($invitation)) { | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is safer to wrap the acceptance logic in a database transaction to ensure that the workspace member record creation and invitation status update happen atomically.
Suggested change
|
||||||||||||||||
| return response()->json(['error' => 'Unable to accept invitation'], 422); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return response()->json([ | ||||||||||||||||
| 'success' => true, | ||||||||||||||||
| 'message' => 'Invitation accepted', | ||||||||||||||||
| 'data' => [ | ||||||||||||||||
| 'workspace' => [ | ||||||||||||||||
| 'id' => $invitation->workspace->id, | ||||||||||||||||
| 'slug' => $invitation->workspace->slug, | ||||||||||||||||
| 'name' => $invitation->workspace->name, | ||||||||||||||||
| ], | ||||||||||||||||
| 'role' => $invitation->role, | ||||||||||||||||
| ], | ||||||||||||||||
| ]); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| public function declineInvitation(string $token): JsonResponse | ||||||||||||||||
| { | ||||||||||||||||
| $user = auth()->user(); | ||||||||||||||||
|
|
||||||||||||||||
| if (! $user) { | ||||||||||||||||
| return response()->json(['error' => 'Unauthorized'], 401); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| $invitation = WorkspaceInvitation::where('token', $token)->firstOrFail(); | ||||||||||||||||
|
|
||||||||||||||||
| if ($invitation->email !== $user->email) { | ||||||||||||||||
| return response()->json(['error' => 'This invitation was sent to a different email address'], 403); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (! $invitation->isPending()) { | ||||||||||||||||
| return response()->json(['error' => 'This invitation has already been actioned'], 422); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (! $user->declineInvitation($invitation)) { | ||||||||||||||||
| return response()->json(['error' => 'Unable to decline invitation'], 422); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return response()->json([ | ||||||||||||||||
| 'success' => true, | ||||||||||||||||
| 'message' => 'Invitation declined', | ||||||||||||||||
| ]); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| public function removeMember(Workspace $workspace, string $userId): JsonResponse | ||||||||||||||||
| { | ||||||||||||||||
| if (! $this->userCanManage($workspace)) { | ||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The authentication check
if (! $user)is redundant here because this route should be protected by theauth:sanctum(or similar) middleware. Removing it simplifies the controller and leverages the framework's built-in handling.