refactor: move backend in apps/backend

This commit is contained in:
Giovanni committed 2026-10-03 18:35:36 +02:00
1 parent cf529278bd
commit e2b471312c
178 files changed
+210 -193

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
<?php
namespace apps\backend\app\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use function App\Http\Controllers\response;
class AuthController extends Controller
{
public function login(Request $request): JsonResponse
{
$credentials = $request->validate([
'email' => ['required','email'],
'password' => ['required'],
]);
if (!Auth::attempt($credentials, remember: true)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$request->session()->regenerate();
return response()->json(['message' => 'ok']);
}
public function logout(Request $request): JsonResponse
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return response()->json(['message' => 'ok']);
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace apps\backend\app\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
abstract class Controller
{
use AuthorizesRequests;
}
+210
View File
@@ -0,0 +1,210 @@
<?php
namespace apps\backend\app\Http\Controllers;
use apps\backend\app\Mail\EventParticipationCancelledMail;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use apps\backend\app\Notifications\EventDeleted;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
use function App\Http\Controllers\response;
class EventsController extends Controller
{
public function create(Request $request): JsonResponse
{
if (Gate::denies('create', Event::class)) {
return response()->json(['message' => 'Forbidden'], 403);
}
try {
Event::create([
"name" => $request['name'],
"description" => $request['description'],
"start" => $request['start'],
"end" => $request['end'],
]);
return response()->json(['message' => 'Event created']);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function update(Request $request, int $id): JsonResponse {
if (Gate::denies('update', Event::class)) {
return response()->json(['message' => 'Forbidden'], 403);
}
try {
$event = Event::find($id);
$event->name = $request['name'];
$event->description = $request['description'];
$event->start = $request['start'];
$event->end = $request['end'];
$event->save();
return response()->json(["message" => "Event updated"]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getEvents(Request $request): JsonResponse {
try {
$events = Event::with('tasks')->get();
return response()->json(['data' => $events]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function delete(Request $request, int $id): JsonResponse
{
if (Gate::denies('delete', Event::class)) {
return response()->json(['message' => 'Forbidden'], 403);
}
try {
$event = Event::with('tasks.users')->findOrFail($id);
if (Carbon::now()->lessThanOrEqualTo($event->end)) {
$participants = $event->tasks
->flatMap(fn($task) => $task->users)
->unique('id');
if ($participants->isNotEmpty()) {
Notification::send($participants, new EventDeleted($event));
foreach ($participants as $user) {
if ($user->email_notifications) {
Mail::to($user->email)->send(new EventParticipationCancelledMail([
'name' => $user->name,
'lastname' => $user->lastname,
'eventName' => $event->name,
'start' => $event->start,
'end' => $event->end,
]));
}
}
}
}
$event->delete();
return response()->json(['message' => 'Event deleted and participants notified']);
} catch (\Exception $e) {
Log::error("Event delete error: " . $e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function getEvent(Request $request, int $id): JsonResponse {
try {
$event = Event::with(['tasks' => function ($query) {
$query->withCount('users');
}])->find($id);
return response()->json([
"id" => $event->id,
"name" => $event->name,
"description" => $event->description,
"start" => $event->start,
"end" => $event->end,
"created_at" => $event->created_at,
"updated_at" => $event->updated_at,
"tasks" => $event->tasks,
"event_photo_path" =>$event->event_photo_path,
]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function isUserAssigned(Request $request, int $id): JsonResponse
{
try {
$task = Task::findOrFail($id);
$isAssigned = $task->users()
->where('users.id', $request->user()->id)
->exists();
return response()->json([
'assigned' => $isAssigned
], 200);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json([
'message' => 'Server error'
], 500);
}
}
public function show(int $id)
{
$event = Event::findOrFail($id);
return response()->json([
'event_photo_path' => $event->event_photo_path
]);
}
public function updatePhoto(Request $request, int $id)
{
$request->validate([
'photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
$event = Event::findOrFail($id);
$path = $request->file('photo')->store('event-photos', 'public');
if ($event->event_photo_path) {
Storage::disk('public')->delete($event->event_photo_path);
}
$event->update([
'event_photo_path' => $path
]);
return response()->json([
'event_photo_path' => $path
]);
}
public function destroy(int $id)
{
$event = Event::findOrFail($id);
if ($event->event_photo_path) {
Storage::disk('public')->delete($event->event_photo_path);
$event->update([
'event_photo_path' => null
]);
}
return response()->json([
'message' => 'Photo supprimée'
]);
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace apps\backend\app\Http\Controllers;
use apps\backend\app\Models\User;
use Carbon\Carbon;
use function App\Http\Controllers\response;
class ExportController extends Controller
{
public function exportIcs($userId)
{
$user = User::with('tasks.event')->findOrFail($userId);
$lines = [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//VotreApp//FR',
];
$now = Carbon::now()->utc()->format('Ymd\THis\Z');
foreach ($user->tasks as $task) {
// On ignore les tâches sans dates
if (!$task->start || !$task->end) {
continue;
}
$uid = $task->id . '-' . $user->id . '@votreapp.local';
$dtstart = Carbon::parse($task->start)->utc()->format('Ymd\THis\Z');
$dtend = Carbon::parse($task->end)->utc()->format('Ymd\THis\Z');
$summary = $this->escapeText($task->name);
$description = $this->escapeText(
trim(
($task->description ?? '') .
($task->event ? "\nÉvénement: {$task->event->name}" : '')
)
);
$location = $this->escapeText($task->location ?? '');
$lines[] = 'BEGIN:VEVENT';
$lines[] = 'UID:' . $uid;
$lines[] = 'DTSTAMP:' . $now;
$lines[] = 'DTSTART:' . $dtstart;
$lines[] = 'DTEND:' . $dtend;
$lines[] = 'SUMMARY:' . $summary;
$lines[] = 'DESCRIPTION:' . $description;
$lines[] = 'LOCATION:' . $location;
$lines[] = 'END:VEVENT';
}
$lines[] = 'END:VCALENDAR';
$content = implode("\r\n", $lines) . "\r\n";
return response($content, 200, [
'Content-Type' => 'text/calendar; charset=utf-8',
'Content-Disposition' => 'attachment; filename="agenda_user_' . $user->id . '.ics"',
]);
}
protected function escapeText($text)
{
$text = (string) $text;
return str_replace(
["\\", "\r\n", "\n", "\r", ";", ","],
["\\\\", "\\n", "\\n", "\\n", "\\;", "\\,"],
$text
);
}
}
@@ -0,0 +1,51 @@
<?php
namespace apps\backend\app\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use function App\Http\Controllers\response;
class NotificationsController extends Controller
{
public function getNotifications(Request $request): JsonResponse
{
try {
$notifications = $request->user()
->notifications()
->latest()
->get();
return response()->json(['data' => $notifications]);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function deleteNotification(Request $request, string $notificationId): JsonResponse
{
try {
$notification = $request->user()->notifications()->findOrFail($notificationId);
$notification->delete();
return response()->json(['message' => 'Notification supprimée avec succès']);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Erreur lors de la suppression'], 500);
}
}
public function readNotifications(Request $request): JsonResponse
{
try {
$request->user()->unreadNotifications->markAsRead();
return response()->json(['message' => 'Notifications marquées comme lues']);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
}
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace apps\backend\app\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use Typesense\Client;
use function App\Http\Controllers\config;
use function App\Http\Controllers\response;
class SearchController extends Controller
{
protected Client $client;
public function __construct()
{
$this->client = new Client([
'api_key' => config('app.typesense_api_key'),
'nodes' => [
[
'host' => config('app.typesense_connection'),
'port' => '8108',
'protocol' => 'http',
],
],
]);
}
public function searchEvents(Request $request)
{
try {
$query = $request->input('query', '');
return response()->json(
$this->client->collections['events']
->documents
->search([
'q' => $query,
'query_by' => 'name,description',
])
);
} catch (Exception $e) {
return response()->json([
'error' => $e->getMessage()
], 500);
}
}
public function searchUsers(Request $request)
{
try {
$query = $request->input('query', '');
return response()->json(
$this->client->collections['users']
->documents
->search([
'q' => $query,
'query_by' => 'name,lastname',
'filter_by' => 'validate:=true',
])
);
} catch (Exception $e) {
return response()->json([
'error' => $e->getMessage()
], 500);
}
}
}
+287
View File
@@ -0,0 +1,287 @@
<?php
namespace apps\backend\app\Http\Controllers;
use apps\backend\app\Mail\TaskDateUpdateMail;
use apps\backend\app\Mail\TaskParticipationCancelledMail;
use apps\backend\app\Mail\VolunteerAssignToTaskMail;
use apps\backend\app\Mail\VolunteerUnassignToTaskMail;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use apps\backend\app\Models\User;
use apps\backend\app\Notifications\TaskDateUpdated;
use apps\backend\app\Notifications\TaskDeleted;
use apps\backend\app\Notifications\VolunteerAssignedToTask;
use apps\backend\app\Notifications\VolunteerUnassignedFromTask;
use apps\backend\app\Services\FormatDate;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use function App\Http\Controllers\response;
class TasksController extends Controller
{
public function create(Request $request): JsonResponse {
if(Gate::denies('create', Task::class)) {
return response()->json(["message" => "Can't create task"], 403);
}
try {
$event = Event::find($request["event_id"]);
$event->tasks()->create([
"name" => $request["name"],
"description" => $request["description"],
"start" => $request["start"],
"end" => $request["end"],
"location" => $request["location"],
"max_participants" => $request["max_participants"],
]);
return response()->json(['message' => "Task created"], 200);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function assignSelf(Request $request): JsonResponse
{
try {
$task = Task::findOrFail($request["task_id"]);
if ($task->users()->count() >= $task->max_participants) {
return response()->json(["message" => "Max participants reached"], 403);
}
if ($task->users()->where('users.id', $request->user()->id)->exists()) {
return response()->json(["message" => "Already registered"], 409);
}
$task->users()->attach($request->user()->id);
return response()->json(['message' => "Task assigned"], 200);
} catch (\Throwable $e) {
Log::error($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function assignUser(Request $request, int $id): JsonResponse
{
if (Gate::denies('assignOther', Task::class)) {
return response()->json(['message' => "Can't create task"], 403);
}
try {
$task = Task::findOrFail($request['task_id']);
$event = Event::findOrFail($task->events_id);
$user = User::findOrFail($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);
}
$task->users()->attach($id);
if (Carbon::now()->lessThanOrEqualTo($task->end)) {
$event = Event::findOrFail($task->events_id);
$user->notify(new VolunteerAssignedToTask($task, $event));
if ($user->email_notifications) {
Mail::to($user->email)->send(new VolunteerAssignToTaskMail([
'name' => $user->name,
'lastname' => $user->lastname,
'taskName' => $task->name,
'start' => $task->start,
'end' => $task->end,
'eventName' => $event->name,
]));
} }
return response()->json(['message' => 'Task assigned'], 200);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function getEventTasks(Request $request, int $id): JsonResponse {
try {
$event = Event::find($id);
return response()->json(['data' => $event->tasks()->get()]);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
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')->findOrFail($id);
$event = Event::findOrFail($task->events_id);
if (Carbon::now()->lessThanOrEqualTo($task->end) && $task->users->isNotEmpty()) {
Notification::send($task->users, new TaskDeleted($task, $event));
foreach ($task->users as $user) {
if ($user->email_notifications) {
Mail::to($user->email)->send(new TaskParticipationCancelledMail([
'name' => $user->name,
'lastname' => $user->lastname,
'taskName' => $task->name,
'start' => $event->start,
'end' => $task->end,
'eventName' => $event->name,
]));
}
}
}
$task->delete();
return response()->json(['message' => 'Task deleted and participants notified'], 200);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function update(Request $request, int $id): JsonResponse
{
if (Gate::denies('update', Task::class)) {
return response()->json(['message' => 'Forbidden'], 403);
}
try {
$task = Task::with('users')->findOrFail($id);
$datesChanged = $task->start !== $request['start'] || $task->end !== $request['end'];
if ($datesChanged && Carbon::now()->lessThanOrEqualTo($task->end)) {
$event = Event::findOrFail($task->events_id);
Notification::send($task->users, new TaskDateUpdated(
task: $task,
event: $event,
oldStart: FormatDate::formatDate($task->start),
oldEnd: FormatDate::formatDate($task->end),
newStart: FormatDate::formatDate($request['start']),
newEnd: FormatDate::formatDate($request['end']),
));
foreach ($task->users as $user) {
if ($user->email_notifications) {
Mail::to($user->email)->send(new TaskDateUpdateMail([
'name' => $user->name,
'lastname' => $user->lastname,
'taskName' => $task->name,
'oldStart' => FormatDate::formatDate($task->start),
'oldEnd' => FormatDate::formatDate($task->end),
'newStart' => $request['start'],
'newEnd' => $request['end'],
'eventName' => $event->name,
]));
}
}
}
$task->update([
'name' => $request['name'],
'description' => $request['description'],
'start' => $request['start'],
'end' => $request['end'],
'location' => $request['location'],
'max_participants' => $request['max_participants'],
]);
return response()->json(['message' => 'Task updated'], 200);
} catch (\Exception $e) {
Log::error($e->getMessage());
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::findOrFail($request['task_id']);
$user = User::findOrFail($id);
if (!$task->users()->where('user_id', $id)->exists()) {
return response()->json(['message' => 'User is not assigned to this task'], 400);
}
$task->users()->detach($id);
if (Carbon::now()->lessThanOrEqualTo($task->end)) {
$event = Event::findOrFail($task->events_id);
$user->notify(new VolunteerUnassignedFromTask($task, $event));
if ($user->email_notifications) {
Mail::to($user->email)->send(new VolunteerUnassignToTaskMail([
'name' => $user->name,
'lastname' => $user->lastname,
'taskName' => $task->name,
'start' => $task->start,
'end' => $task->end,
'eventName' => $event->name,
]));
}
}
return response()->json(['message' => 'User unassigned successfully'], 200);
} catch (\Exception $e) {
Log::error("UnassignUser error: " . $e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
}
+497
View File
@@ -0,0 +1,497 @@
<?php
namespace apps\backend\app\Http\Controllers;
use apps\backend\app\Mail\CreateUserByAdminMail;
use apps\backend\app\Mail\DeactivateAccountMail;
use apps\backend\app\Mail\DeleteAccountMail;
use apps\backend\app\Mail\EmailChangeConfirmedMail;
use apps\backend\app\Mail\NotifyEmailChangeMail;
use apps\backend\app\Mail\RegisterMail;
use apps\backend\app\Mail\RequestEmailChangeMail;
use apps\backend\app\Mail\UpdatePasswordMail;
use apps\backend\app\Mail\UpdateRoleMail;
use apps\backend\app\Mail\ValidateMail;
use apps\backend\app\Models\User;
use apps\backend\app\Notifications\UserRegistered;
use apps\backend\app\Notifications\VolunteerRoleUpdated;
use apps\backend\app\Services\GetRole;
use apps\backend\app\Services\UserService;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
use Pest\Support\Str;
use Propaganistas\LaravelPhone\PhoneNumber;
use function App\Http\Controllers\now;
use function App\Http\Controllers\response;
class UserController extends Controller
{
public function me(Request $request): JsonResponse {
try {
return response()->json(UserService::getData($request->user()->id));
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function create(Request $request): JsonResponse {
$request->validate([
'phone' => ['required', 'phone:FR,national'],
'email' => ['required', 'email:strict,rfc', 'unique:users,email'],
]);
$phone = new PhoneNumber($request["phone"], 'FR');
$user = User::create([
"name" => $request["name"],
"email" => $request["email"],
"password" => Hash::make($request["password"]),
"lastname" => $request["lastname"],
"validate" => 0,
"phone" => $phone->formatInternational(),
"web_notifications" => 1,
"email_notifications" => 1,
]);
$admins = User::whereIn('role', [1, 2])->get();
Notification::sendNow($admins, new UserRegistered($user));
foreach ($admins as $admin) {
if ($admin->email_notifications) {
Mail::to($admin->email)->send(new RegisterMail([
'adminName' => $admin->name,
'adminLastname' => $admin->lastname,
'userName' => $user->name,
'userLastname' => $user->lastname,
]));
}
}
return response()->json(['message' => 'User created successfully']);
}
public function createUserByAdmin(Request $request): JsonResponse {
if(Gate::denies('createOther', $request->user())){
return response()->json(["message" => "Can't create this user"], 403);
}
$request->validate([
'phone' => ['required', 'phone:FR,national'],
'email' => ['required', 'email:strict,rfc', 'unique:users,email'],
]);
$phone = new PhoneNumber($request["phone"], 'FR');
$password = Str::random(12);
$user = User::create([
"name" => $request["name"],
"email" => $request["email"],
"password" => Hash::make($password),
"lastname" => $request["lastname"],
"validate" => 1,
"role" => 3,
"phone" => $phone->formatInternational(),
"web_notifications" => 1,
"email_notifications" => 1,
]);
if ($user->email_notifications) {
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
];
Mail::to($user->email)->send(new CreateUserByAdminMail($data));
}
return response()->json([
'message' => 'User created successfully',
"password" => $password,
]);
}
public function delete(Request $request): JsonResponse {
try {
$user = User::find($request->user()->id);
if ($user->email_notifications) {
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
];
Mail::to($user->email)->send(new DeleteAccountMail($data));
}
$user->delete();
return response()->json(['message' => 'User deleted successfully']);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getUser(Request $request, int $id): JsonResponse {
try {
return response()->json(UserService::getData($id));
} catch (ModelNotFoundException $e) {
return response()->json(['message' => 'Utilisateur non trouvé'], 404);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function deleteById(Request $request, int $id): JsonResponse {
if(Gate::denies('deleteOther', $request->user())){
return response()->json(["message" => "Can't delete this user"], 403);
}
try {
$user = User::find($id);
if ($user->email_notifications) {
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
];
Mail::to($user->email)->send(new DeleteAccountMail($data));
}
$user->delete();
return response()->json(['message' => 'User deleted successfully']);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function deactivate(Request $request, int $id): JsonResponse {
$userToDeactivate = User::findOrFail($id);
if(Gate::denies('deactivate', $userToDeactivate)){
return response()->json(["message" => "Can't delete this user"], 403);
}
try {
$userToDeactivate->update(['validate' => 0]);
if ($userToDeactivate->email_notifications) {
$data = [
'name' => $userToDeactivate->name,
'lastname' => $userToDeactivate->lastname,
];
Mail::to($userToDeactivate->email)->send(new DeactivateAccountMail($data));
}
return response()->json(['message' => 'User deactivated successfully']);
} catch (ModelNotFoundException $e) {
return response()->json(['message' => 'Utilisateur non trouvé'], 404);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function update(Request $request): JsonResponse {
try {
$phone = new PhoneNumber($request["phone"], 'FR');
$user = User::find($request->user()->id);
$user->name = $request["name"];
$user->lastname = $request["lastname"];
$user->phone = $phone;
$user->save();
return response()->json(['message' => 'User updated successfully']);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function validate(Request $request, int $id): JsonResponse {
if(Gate::denies('validate', $request->user())){
return response()->json(["message" => "Can't validate this user"], 403);
}
try {
$user = User::find($id);
$user->validate = 1;
$user->role = 3;
$user->verified_at = now();
$user->save();
if ($user->email_notifications) {
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
];
Mail::to($user->email)->send(new ValidateMail($data));
}
return response()->json(['message' => 'User validated successfully']);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function addRole(Request $request, int $id): JsonResponse {
if(Gate::denies('addRole', $request->user())){
return response()->json(["message" => "Can't add role to this user"], 403);
}
try {
$user = User::find($id);
$user->role = $request['role'];
$user->save();
$role = GetRole::getRole($request['role']);
$user->notify(new VolunteerRoleUpdated($role));
if ($user->email_notifications) {
Mail::to($user->email)->send(new UpdateRoleMail([
'name' => $user->name,
'lastname' => $user->lastname,
'role' => $role,
]));
}
return response()->json(['message' => 'User role added successfully']);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getUsers(Request $request): JsonResponse {
try {
$users = User::where('validate', 1)
->orderBy('verified_at', 'desc')
->pluck('id');
return response()->json($users);
} catch(\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getUserTasks(Request $request): JsonResponse {
try {
return response()->json(['data' => $request->user()->tasks]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getUserByIdTasks(Request $request, int $id): JsonResponse {
try {
return response()->json(['data' => User::find($id)->tasks]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getUserTaskById(Request $request, int $idTask): JsonResponse {
try {
return response()->json(['data' => $request->user()->tasks->find($idTask)]);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function getInvalidUsers(Request $request): JsonResponse {
if(Gate::denies('getInvalidUsers', $request->user())){
return response()->json(["message" => "Can't add role to this user"], 403);
}
try {
$users = User::where('validate', 0)->pluck('id');
return response()->json($users);
} catch (\Exception $e) {
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function toggleEmailNotifications(Request $request, int $id): JsonResponse {
try {
$user = User::findOrFail($id);
$user->email_notifications = $user->email_notifications ? 0 : 1;
$user->save();
return response()->json($user);
} catch(\Exception $e){
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function toggleWebNotifications(Request $request, int $id): JsonResponse {
try {
$user = User::findOrFail($id);
$user->web_notifications = $user->web_notifications ? 0 : 1;
$user->save();
return response()->json($user);
} catch(\Exception $e){
Log::info($e->getMessage());
return response()->json(['message' => "Server error"], 500);
}
}
public function updatePassword(Request $request): JsonResponse {
try {
$request->validate([
'current_password' => ['required'],
'new_password' => ['required', 'confirmed'],
]);
$user = $request->user();
if (!Hash::check($request['current_password'], $user->password)) {
return response()->json(['message' => 'Mot de passe actuel incorrect'], 403);
}
$user->password = Hash::make($request['new_password']);
$user->save();
if ($user->email_notifications) {
Mail::to($user->email)->send(new UpdatePasswordMail([
'name' => $user->name,
'lastname' => $user->lastname,
]));
}
return response()->json(['message' => 'Mot de passe mis à jour avec succès']);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function requestEmailChange(Request $request): JsonResponse
{
try {
$request->validate([
'email' => ['required', 'email:strict,rfc', 'unique:users,email'],
]);
$user = $request->user();
$token = \Str::random(64);
$user->pending_email = $request['email'];
$user->email_change_token = hash('sha256', $token);
$user->email_change_token_expires_at = now()->addHour();
$user->save();
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
'token' => $token
];
Mail::to($user->email)->send(new NotifyEmailChangeMail($data));
Mail::to($request['email'])->send(new RequestEmailChangeMail($data));
return response()->json(['message' => 'Un email de confirmation a été envoyé à votre nouvelle adresse.']);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function confirmEmailChange(Request $request): JsonResponse
{
try {
$request->validate([
'token' => ['required', 'string'],
]);
$user = User::where('email_change_token', hash('sha256', $request['token']))
->where('email_change_token_expires_at', '>', now())
->firstOrFail();
$newEmail = $user->pending_email;
$oldEmail = $user->email;
$user->email = $newEmail;
$user->pending_email = null;
$user->email_change_token = null;
$user->email_change_token_expires_at = null;
$user->save();
$data = [
'name' => $user->name,
'lastname' => $user->lastname,
'newEmail' => $newEmail
];
Mail::to($newEmail)->send(new EmailChangeConfirmedMail($data));
Mail::to($oldEmail)->send(new EmailChangeConfirmedMail($data));
return response()->json(['message' => 'Email mis à jour avec succès']);
} catch (ModelNotFoundException $e) {
return response()->json(['message' => 'Token invalide ou expiré'], 400);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['message' => 'Server error'], 500);
}
}
public function show(Request $request)
{
$user = $request->user();
return response()->json(['profile_photo_path' => $user->profile_photo_path]);
}
public function updatePhoto(Request $request)
{
$request->validate([
'photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
$user = $request->user();
$path = $request->file('photo')->store('profile-photos', 'public');
// Supprimer l'ancienne photo si elle existe
if ($user->profile_photo_path) {
Storage::disk('public')->delete($user->profile_photo_path);
}
$user->update(['profile_photo_path' => $path]);
return response()->json(['profile_photo_path' => $path]);
}
public function destroy(Request $request)
{
$user = $request->user();
if ($user->profile_photo_path) {
Storage::disk('public')->delete($user->profile_photo_path);
$user->update(['profile_photo_path' => null]);
}
return response()->json(['message' => 'Photo supprimée']);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class CreateUserByAdminMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Compte créé - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.createUserByAdmin',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class DeactivateAccountMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Compte désactivé - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.deactivateAccount',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class DeleteAccountMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Compte supprimé - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.deleteAccount',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class EmailChangeConfirmedMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: "Validation de changement d'adresse mail - Comité des fêtes de Beaupont",
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.emailChangeConfirmed',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'newEmail' => $this->data['newEmail'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace apps\backend\app\Mail;
use apps\backend\app\Services\FormatDate;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class EventParticipationCancelledMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Evénement supprimé - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.eventParticipationCancelled',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'eventName' => $this->data['eventName'],
'start' => FormatDate::formatDate($this->data['start']),
'end' => FormatDate::formatDate($this->data['end']),
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class NotifyEmailChangeMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: "Demande de changement d'adresse mail - Comité des fêtes de Beaupont",
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.notifyEmailChange',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class RegisterMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Nouvelle demande de validation - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.register',
with: [
'adminName' => $this->data['adminName'],
'adminLastname' => $this->data['adminLastname'],
'userName' => $this->data['userName'],
'userLastname' => $this->data['userLastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class RequestEmailChangeMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: "Demande de changement d'adresse mail - Comité des fêtes de Beaupont",
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.requestEmailChange',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'token' => $this->data['token'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class TaskDateUpdateMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Date de tâche modifiée - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.updateRole',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'taskName' => $this->data['taskName'],
'oldStart' => $this->data['oldStart'],
'oldEnd' => $this->data['oldEnd'],
'newStart' => $this->data['newStart'],
'newEnd' => $this->data['newEnd'],
'eventName' => $this->data['eventName'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace apps\backend\app\Mail;
use apps\backend\app\Services\FormatDate;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class TaskParticipationCancelledMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Tâche supprimée - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.taskParticipationCancelled',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'taskName' => $this->data['taskName'],
'end' => FormatDate::formatDate($this->data['end']),
'start' => FormatDate::formatDate($this->data['start']),
'eventName' => $this->data['eventName'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class UpdatePasswordMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Mot de passe mis à jour - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.updatePassword',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class UpdateRoleMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Rôle mis à jour - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.updateRole',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'role' => $this->data['role'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
namespace apps\backend\app\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ValidateMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Compte validé - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.validate',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace apps\backend\app\Mail;
use apps\backend\app\Services\FormatDate;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class VolunteerAssignToTaskMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Assignation - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.volunteerAssignToTask',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'taskName' => $this->data['taskName'],
'start' => FormatDate::formatDate($this->data['start']),
'end' => FormatDate::formatDate($this->data['end']),
'eventName' => $this->data['eventName'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace apps\backend\app\Mail;
use apps\backend\app\Services\FormatDate;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class VolunteerUnassignToTaskMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Désassignation - Comité des fêtes de Beaupont',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'mails.volunteerUnassignToTask',
with: [
'name' => $this->data['name'],
'lastname' => $this->data['lastname'],
'taskName' => $this->data['taskName'],
'start' => FormatDate::formatDate($this->data['start']),
'end' => FormatDate::formatDate($this->data['end']),
'eventName' => $this->data['eventName'],
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace apps\backend\app\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
use HasFactory;
protected $fillable = [
"name",
"description",
"event_photo_path",
'start',
'end',
];
public function tasks() {
return $this->hasMany(Task::class, 'events_id');
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace apps\backend\app\Models;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
protected $fillable = [
'name',
'start',
'end',
'location',
'description',
'max_participants',
];
public function event() {
return $this->belongsTo(Event::class);
}
public function users() {
return $this->belongsToMany(User::class);
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace apps\backend\app\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
/** @use HasFactory<\apps\backend\database\factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'lastname',
'email',
'password',
'phone',
'validate',
'role',
'verified_at',
'profile_photo_path',
'email_notifications',
'web_notifications'
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
public function tasks() {
return $this->belongsToMany(Task::class);
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\Event;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class EventDeleted extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(public Event $event) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "L'événement {$this->event->name} a été supprimé. Vous n'y participez donc plus.",
'event_id' => $this->event->id,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class TaskDateUpdated extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(
public Task $task,
public Event $event,
public string $oldStart,
public string $oldEnd,
public string $newStart,
public string $newEnd,
) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "La date de la tâche {$this->task->name} de l'événement {$this->event->name} a été mise à jour. Cette tâche aura maintenant lieu du {$this->newStart} au {$this->newEnd}.",
'task_id' => $this->task->id,
'event_id' => $this->event->id,
'old_start' => $this->oldStart,
'old_end' => $this->oldEnd,
'new_start' => $this->newStart,
'new_end' => $this->newEnd,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class TaskDeleted extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(
public Task $task,
public Event $event,
) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "La tâche {$this->task->name} pour l'événement {$this->event->name} a été supprimée. Vous n'y participez donc plus.",
'task_id' => $this->task->id,
'event_id' => $this->event->id,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class UserRegistered extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(public User $user) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "Nouvelle demande d'inscription : {$this->user->name} {$this->user->lastname}",
'user_id' => $this->user->id,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class VolunteerAssignedToTask extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(
public Task $task,
public Event $event,
) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "Vous avez été assigné à la tâche {$this->task->name} de l'événement {$this->event->name}.",
'task_id' => $this->task->id,
'event_id' => $this->event->id,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace apps\backend\app\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class VolunteerRoleUpdated extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(public string $role) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "Votre rôle a changé pour : {$this->role}",
'role' => $this->role,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
@@ -0,0 +1,47 @@
<?php
namespace apps\backend\app\Notifications;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Mail;
class VolunteerUnassignedFromTask extends Notification implements ShouldBroadcast
{
use Queueable;
public function __construct(
public Task $task,
public Event $event,
) {}
public function via($notifiable): array
{
$channels = [];
if ($notifiable->web_notifications) {
$channels[] = 'database';
$channels[] = 'broadcast';
}
return $channels;
}
public function toDatabase($notifiable): array
{
return [
'message' => "Vous avez été désassigné de la tâche {$this->task->name} de l'événement {$this->event->name}.",
'task_id' => $this->task->id,
'event_id' => $this->event->id,
];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage($this->toDatabase($notifiable));
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace apps\backend\app\Observers;
use apps\backend\app\Models\Event;
use apps\backend\app\Services\TypesenseService;
use function App\Observers\app;
class EventObserver
{
public function created(Event $event)
{
app(TypesenseService::class)->upsertEvent($event);
}
public function updated(Event $event)
{
app(TypesenseService::class)->upsertEvent($event);
}
public function deleted(Event $event)
{
app(TypesenseService::class)->deleteEvent($event->id);
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace apps\backend\app\Observers;
use apps\backend\app\Models\User;
use apps\backend\app\Services\TypesenseService;
use function App\Observers\app;
class UserObserver
{
public function created(User $user)
{
app(TypesenseService::class)->upsertUser($user);
}
public function updated(User $user)
{
app(TypesenseService::class)->upsertUser($user);
}
public function deleted(User $user)
{
app(TypesenseService::class)->deleteUser($user->id);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace apps\backend\app\Policies;
use apps\backend\app\Models\User;
use Illuminate\Auth\Access\Response;
class EventsPolicy
{
public function create(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function update(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function delete(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace apps\backend\app\Policies;
use apps\backend\app\Models\User;
use Illuminate\Auth\Access\Response;
class TasksPolicy
{
public function create(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function assignOther(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function unassignOther(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function delete(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function update(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace apps\backend\app\Policies;
use apps\backend\app\Models\User;
use Illuminate\Auth\Access\Response;
class UsersPolicy
{
public function deleteOther(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function createOther(User $user): bool {
return $user->role === 1 || $user->role === 2;
}
public function deactivate(User $user, User $userToDeactivate): bool
{
return in_array($user->role, [1, 2])
&& $user->role < $userToDeactivate->role
&& $user->id !== $userToDeactivate->id;
}
public function validate(User $user): bool
{
return $user->role === 1 || $user->role === 2;
}
public function addRole(User $user): bool
{
return $user->role === 1;
}
public function getInvalidUsers(User $user) : bool
{
return $user->role === 1 || $user->role === 2;
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace apps\backend\app\Providers;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\User;
use apps\backend\app\Observers\EventObserver;
use apps\backend\app\Observers\UserObserver;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use function App\Providers\base_path;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Route::middleware('web')->prefix('api')->group(base_path('routes/users.php'));
Route::middleware('web')->prefix('api')->group(base_path('routes/auth.php'));
Route::middleware('web')->prefix('api')->group(base_path('routes/events.php'));
Route::middleware('web')->prefix('api')->group(base_path('routes/notifications.php'));
Route::middleware('web')->prefix('api')->group(base_path('routes/channels.php'));
User::observe(UserObserver::class);
Event::observe(EventObserver::class);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace apps\backend\app\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
use function App\Providers\base_path;
class BroadcastServiceProvider extends ServiceProvider
{
public function boot(): void
{
Broadcast::routes(['middleware' => ['web', 'auth:sanctum']]);
require base_path('routes/channels.php');
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace apps\backend\app\Providers;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\Task;
use apps\backend\app\Models\User;
use apps\backend\app\Policies\EventsPolicy;
use apps\backend\app\Policies\TasksPolicy;
use apps\backend\app\Policies\UsersPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
class GateServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
Gate::policy(User::class, UsersPolicy::class);
Gate::policy(Event::class, EventsPolicy::class);
Gate::policy(Task::class, TasksPolicy::class);
}
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace apps\backend\app\Services;
use Carbon\Carbon;
class FormatDate
{
public static function formatDate($date){
return Carbon::parse($date)->format('d/m/Y, H:i');
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace apps\backend\app\Services;
class GetRole
{
public static function getRole($role)
{
$role = (int)$role;
return match ($role) {
1 => "Président",
2 => "Gérant",
3 => "Bénévole",
default => "Utilisateur",
};
}
public static function GetAllRoles() {
return [
"Président",
"Gérant",
"Bénévole"
];
}
}
+143
View File
@@ -0,0 +1,143 @@
<?php
namespace apps\backend\app\Services;
use apps\backend\app\Models\Event;
use apps\backend\app\Models\User;
use Illuminate\Support\Facades\Cache;
use Typesense\Client;
use function App\Services\config;
use function App\Services\report;
class TypesenseService
{
protected Client $client;
public function __construct()
{
$this->client = new Client([
'api_key' => config('app.typesense_api_key'),
'nodes' => [
[
'host' => config('app.typesense_connection'),
'port' => '8108',
'protocol' => 'http',
],
],
]);
}
private function ensureCollectionsExist(): void
{
static $checked = false;
if ($checked) {
return;
}
try {
$collections = $this->client->collections->retrieve();
$names = array_column($collections, 'name');
if (!in_array('events', $names)) {
$this->client->collections->create([
'name' => 'events',
'fields' => [
['name' => 'name', 'type' => 'string'],
['name' => 'description', 'type' => 'string'],
],
]);
}
if (!in_array('users', $names)) {
$this->client->collections->create([
'name' => 'users',
'fields' => [
['name' => 'name', 'type' => 'string'],
['name' => 'lastname', 'type' => 'string'],
['name' => 'validate', 'type' => 'bool'],
],
]);
}
$checked = true;
} catch (\Throwable $e) {
report($e);
}
}
public function upsertEvent(Event $event): void
{
$this->ensureCollectionsExist();
try {
$this->client->collections['events']
->documents
->upsert([
'id' => (string) $event->id,
'name' => $event->name,
'description' => $event->description,
]);
} catch (\Throwable $e) {
report($e);
}
}
public function deleteEvent(int $eventId): void
{
$this->ensureCollectionsExist();
try {
$this->client->collections['events']
->documents[(string) $eventId]
->delete();
} catch (\Throwable $e) {
report($e);
}
}
public function upsertUser(User $user): void
{
$this->ensureCollectionsExist();
if (!$user->validate) {
try {
$this->client->collections['users']
->documents[(string) $user->id]
->retrieve();
$this->deleteUser($user->id);
} catch (\Throwable $e) {
}
return;
}
try {
$this->client->collections['users']
->documents
->upsert([
'id' => (string) $user->id,
'name' => $user->name,
'lastname' => $user->lastname,
'validate' => true,
]);
} catch (\Throwable $e) {
report($e);
}
}
public function deleteUser(int $userId): void
{
$this->ensureCollectionsExist();
try {
$this->client->collections['users']
->documents[(string) $userId]
->delete();
} catch (\Throwable $e) {
report($e);
}
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace apps\backend\app\Services;
use apps\backend\app\Models\User;
use Illuminate\Support\Facades\Log;
class UserService
{
public static function getData(int $id) : array {
$user = User::findOrFail($id);
return [
"id" => $user->id,
"name" => $user->name,
"lastname" => $user->lastname,
"email" => $user->email,
"role" => GetRole::getRole($user->role),
"isAdmin" => ($user->role === 1 || $user->role === 2),
"phone" => $user->phone,
"created_at" => $user->created_at,
"updated_at" => $user->updated_at,
"verfied_at" => $user->verfied_at,
"validate" => $user->validate,
"tasks" => $user->tasks,
"profile_photo_path" => $user->profile_photo_path,
"email_notifications" => $user->email_notifications,
"web_notifications" => $user->web_notifications,
];
}
}