From ab1df4d69207c99a3db105be7ee30f4923ae20d1 Mon Sep 17 00:00:00 2001 From: Giovanni-Josserand Date: Sun, 11 Jan 2026 19:03:58 +0100 Subject: [PATCH] Create unassignUser, unassignSelf methods and Bruno requests. Add call events when needed --- app/Http/Controllers/EventsController.php | 24 ++++- app/Http/Controllers/TasksController.php | 103 +++++++++++++++++-- app/Policies/TasksPolicy.php | 5 + routes/events.php | 6 +- tests/Events/tasks/Unassign task to user.bru | 27 +++++ tests/Events/tasks/Unassign task.bru | 26 +++++ 6 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 tests/Events/tasks/Unassign task to user.bru create mode 100644 tests/Events/tasks/Unassign task.bru diff --git a/app/Http/Controllers/EventsController.php b/app/Http/Controllers/EventsController.php index 9fa9134..28505d7 100644 --- a/app/Http/Controllers/EventsController.php +++ b/app/Http/Controllers/EventsController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Events\EventParticipationCancelled; use App\Models\Events; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; @@ -83,12 +84,29 @@ class EventsController extends Controller } try { + $event = Events::with('tasks.users')->find($id); + + if (!$event) { + return response()->json(['message' => 'Event not found'], 404); + } + + $participants = $event->tasks->flatMap(function ($task) { + return $task->users; + })->unique('id'); + + foreach ($participants as $user) { + broadcast(new EventParticipationCancelled( + $user->id, + $event + )); + } - $event = Events::find($id); $event->delete(); - return response()->json(["message" => "Event deleted"]); + + return response()->json(["message" => "Event deleted and participants notified"]); + } catch (\Exception $e) { - Log::info($e->getMessage()); + Log::error("Event delete error: " . $e->getMessage()); return response()->json(['message' => "Server error"], 500); } } diff --git a/app/Http/Controllers/TasksController.php b/app/Http/Controllers/TasksController.php index bf059a4..ab51329 100644 --- a/app/Http/Controllers/TasksController.php +++ b/app/Http/Controllers/TasksController.php @@ -2,6 +2,9 @@ namespace App\Http\Controllers; +use App\Events\TaskParticipationCancelled; +use App\Events\VolunteerAssignedToTask; +use App\Events\VolunteerUnassignedFromTask; use App\Models\Events; use App\Models\Task; use App\Models\User; @@ -46,7 +49,7 @@ class TasksController extends Controller $task = Task::find($request["task_id"]); - if($task->max_participants = $task->users()->count()) { + if($task->max_participants === $task->users()->count()) { return response()->json(["message" => "Max participants reached"], 403); } @@ -69,13 +72,24 @@ class TasksController extends Controller $task = Task::find($request["task_id"]); + if ($task->users()->where('user_id', $id)->exists()) { + return response()->json(["message" => "User already assigned to this task"], 400); + } + if($task->max_participants === $task->users()->count()) { return response()->json(["message" => "Max participants reached"], 403); } $user = User::find($id); - if($user) $task->users()->attach($id); + if($user) { + $task->users()->attach($id); + broadcast(new VolunteerAssignedToTask( + $user->id, + $task, + $task->event + )); + } return response()->json(['message' => "Task assigned"], 200); @@ -101,19 +115,33 @@ class TasksController extends Controller } public function deleteTask(Request $request, int $id): JsonResponse { - if(Gate::denies('delete', Task::class)) { return response()->json(["message" => "Can't delete task"], 403); } try { + $task = Task::with(['users', 'event'])->find($id); + + if (!$task) { + return response()->json(["message" => "Task not found"], 404); + } + + $participants = $task->users; + + foreach ($participants as $user) { + broadcast(new TaskParticipationCancelled( + $user->id, + $task, + $task->event + )); + } - $task = Task::find($id); $task->delete(); - return response()->json(['message' => "Task deleted"], 200); + + return response()->json(['message' => "Task deleted and participants notified"], 200); } catch(\Exception $e) { - Log::info($e->getMessage()); + Log::error($e->getMessage()); return response()->json(['message' => "Server error"], 500); } } @@ -142,4 +170,67 @@ class TasksController extends Controller return response()->json(['message' => "Server error"], 500); } } + + + + + + public function unassignSelf(Request $request): JsonResponse { + try { + $task = Task::find($request["task_id"]); + $userId = $request->user()->id; + + if (!$task) { + return response()->json(["message" => "Task not found"], 404); + } + + $task->users()->detach($userId); + + return response()->json(['message' => "Successfully unassigned from task"], 200); + + } catch (\Exception $e) { + Log::error("UnassignSelf error: " . $e->getMessage()); + return response()->json(['message' => "Server error"], 500); + } + } + + + + public function unassignUser(Request $request, int $id): JsonResponse { + + if(Gate::denies('unassignOther', Task::class)) { + return response()->json(["message" => "Unauthorized"], 403); + } + + try { + $task = Task::with('event')->find($request["task_id"]); + + if (!$task) { + return response()->json(["message" => "Task not found"], 404); + } + + $isAssigned = $task->users()->where('user_id', $id)->exists(); + if (!$isAssigned) { + return response()->json(["message" => "User is not assigned to this task"], 400); + } + + $user = User::find($id); + + if ($user) { + $task->users()->detach($id); + + broadcast(new VolunteerUnassignedFromTask( + $user->id, + $task, + $task->event + )); + } + + return response()->json(['message' => "User unassigned successfully"], 200); + + } catch(\Exception $e) { + Log::error("UnassignUser error: " . $e->getMessage()); + return response()->json(['message' => "Server error"], 500); + } + } } diff --git a/app/Policies/TasksPolicy.php b/app/Policies/TasksPolicy.php index bc609cc..42f576c 100644 --- a/app/Policies/TasksPolicy.php +++ b/app/Policies/TasksPolicy.php @@ -18,6 +18,11 @@ class TasksPolicy return $user->role === 1 || $user->role === 2; } + public function unassignOther(User $user, Task $model): bool + { + return $user->role === 1 || $user->role === 2; + } + public function delete(User $user, Task $model): bool { return $user->role === 1 || $user->role === 2; diff --git a/routes/events.php b/routes/events.php index 8ad3ab3..a4d3c3a 100644 --- a/routes/events.php +++ b/routes/events.php @@ -11,8 +11,12 @@ Route::middleware(['web', 'auth:sanctum'])->post('/events/task', [TasksControlle Route::middleware(['web', 'auth:sanctum'])->post('/events/task/assign', [TasksController::class, "assignSelf"]); +Route::middleware(['web', 'auth:sanctum'])->post('/events/task/unassign', [TasksController::class, "unassignSelf"]); + Route::middleware(['web', 'auth:sanctum'])->post('/events/task/assign/{id}', [TasksController::class, "assignUser"])->whereNumber('id'); +Route::middleware(['web', 'auth:sanctum'])->post('/events/task/unassign/{id}', [TasksController::class, "unassignUser"])->whereNumber('id'); + Route::middleware(['web', 'auth:sanctum'])->get('/events/{id}/tasks', [TasksController::class, "getEventTasks"]); Route::middleware(['web', 'auth:sanctum'])->delete('/events/tasks/{id}', [TasksController::class, "deleteTask"]); @@ -27,4 +31,4 @@ Route::middleware(['web', 'auth:sanctum'])->delete('/events/{id}', [EventsContro Route::middleware(['web', 'auth:sanctum'])->get('/events/search', [SearchController::class, "searchEvents"]); -Route::middleware(['web', 'auth:sanctum'])->get('/events/{id}', [EventsController::class, "getEvent"]); \ No newline at end of file +Route::middleware(['web', 'auth:sanctum'])->get('/events/{id}', [EventsController::class, "getEvent"]); diff --git a/tests/Events/tasks/Unassign task to user.bru b/tests/Events/tasks/Unassign task to user.bru new file mode 100644 index 0000000..cc84bb8 --- /dev/null +++ b/tests/Events/tasks/Unassign task to user.bru @@ -0,0 +1,27 @@ +meta { + name: Unassign task to user + type: http + seq: 7 +} + +post { + url: {{url}}/api/events/task/unassign/{{id}} + body: json + auth: inherit +} + +body:json { + { + "task_id": "{{task_id}}" + } +} + +vars:pre-request { + id: + task_id: +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/tests/Events/tasks/Unassign task.bru b/tests/Events/tasks/Unassign task.bru new file mode 100644 index 0000000..abf936e --- /dev/null +++ b/tests/Events/tasks/Unassign task.bru @@ -0,0 +1,26 @@ +meta { + name: Unassign task + type: http + seq: 6 +} + +post { + url: {{url}}/api/events/task/unassign + body: json + auth: inherit +} + +body:json { + { + "task_id": "{{taskId}}" + } +} + +vars:pre-request { + taskId: +} + +settings { + encodeUrl: true + timeout: 0 +}