Compare commits

...
353 Commits
Author SHA1 Message Date
Giovanni cf529278bd Merge backend history 2026-10-03 18:28:20 +02:00
Giovanni 31304c931d refactor: move frontend in apps/frontend 2026-10-03 18:26:34 +02:00
Giovanni dc39113335 add to my own gitea 2026-07-15 18:52:21 +02:00
Giovanni fed6b7c92f add to my own Gitea 2026-07-15 18:51:43 +02:00
Giovanni 7a4c2f5015 fix spelling mistake 2026-04-02 10:11:34 +02:00
Giovanni 76f7ed4f8d fix checkbox css 2026-04-02 00:22:04 +02:00
Giovanni c210aec76f adapt pictures for EventCards 2026-04-01 23:52:56 +02:00
Giovanni f1798c496b Merge branch 'features/header' into dev 2026-04-01 23:35:38 +02:00
Giovanni 26bfdb5cb2 Merge branch 'features/eventPhoto' into dev 2026-04-01 23:33:47 +02:00
Giovanni 6bce33e9de add eventPicture 2026-04-01 23:31:12 +02:00
Giovanni 9ae484d584 add methods for EventPicture' 2026-04-01 23:30:17 +02:00
p2405951 089995c84d add ProfilePicture into header when user login 2026-04-01 21:24:37 +02:00
Giovanni 615c084995 add event_photo_path attribut to Event model 2026-04-01 20:15:13 +02:00
Giovanni afbffe99a8 add event_photo_path attribut to create_events_table migration 2026-04-01 20:15:06 +02:00
ORDONNEAU Antoine 476f4390fe Merge branch 'dev' into fixcss/VolunteersPage 2026-04-01 18:20:25 +02:00
ORDONNEAU Antoine 483e281acd fixcss de la page Vonlontaire 2026-04-01 18:17:59 +02:00
Giovanni 0c0af0fd00 use vite_api_url in requestEmailChange link 2026-03-28 19:23:19 +01:00
Giovanni d9ccd7ff5f add vite_api_url in app variable 2026-03-28 19:21:07 +01:00
Giovanni 741dabd720 create confirmEmailChange route in User route 2026-03-28 18:53:54 +01:00
Giovanni f4caf50f40 create confirmEmailChange method in User controller 2026-03-28 18:53:43 +01:00
Giovanni 8e110244bb create requestEmailChange route in User route 2026-03-28 18:53:21 +01:00
Giovanni 567bc306e1 create requestEmailChange method in User controller 2026-03-28 18:52:50 +01:00
Giovanni 1f42a5392b Add email to new address on email change request apply 2026-03-28 18:52:07 +01:00
Giovanni ac2dcef7a7 Add email to new address on email change request 2026-03-28 18:51:53 +01:00
Giovanni 7b4280d4eb Add email to old address on email change request 2026-03-28 18:51:42 +01:00
Giovanni 4031faf08b use updatePassword mail 2026-03-28 17:58:58 +01:00
Giovanni 59598e29be create updatePassword mail 2026-03-28 17:57:57 +01:00
Giovanni 51435f9257 create updatePassword.blade 2026-03-28 17:57:50 +01:00
Giovanni 2489aad0c8 create updatePassword route in User route 2026-03-28 17:55:04 +01:00
Giovanni f52d5bb5ef create updatePassword method in User controller 2026-03-28 17:54:36 +01:00
Giovanni f0070d3557 update default admin password and email 2026-03-28 17:14:10 +01:00
Giovanni cbe816fd17 use uuid instead of id to delete notifications 2026-03-28 17:02:00 +01:00
Giovanni cdc4645d92 fix typesense error to delete unexisting user 2026-03-28 16:45:57 +01:00
Giovanni 60760d6101 use native Laravel notification methods 2026-03-28 16:41:38 +01:00
Giovanni 4c52fa5043 remove Mail use from Notifications classes 2026-03-28 16:37:02 +01:00
Giovanni f13e96c7c7 use the right Notification Facades 2026-03-28 16:23:01 +01:00
Giovanni aa3d5f887d use native Notification table and migration 2026-03-28 16:13:46 +01:00
Giovanni 93bfc19e6e use native Notification table and migration 2026-03-28 16:03:18 +01:00
Giovanni de0457c426 update channels route to use native laravel notifications 2026-03-28 15:52:37 +01:00
Giovanni ef33591c2a use EventDeleted notification 2026-03-28 15:50:17 +01:00
Giovanni 551909aee7 create EventDeleted notification 2026-03-28 15:50:13 +01:00
Giovanni bfec1752e0 delete EventParticipationCancelled event 2026-03-28 15:49:58 +01:00
Giovanni 0b3e9142b5 remove spaces 2026-03-28 15:48:34 +01:00
Giovanni a99a610688 remove spaces 2026-03-28 15:47:25 +01:00
Giovanni 4a0087104c use VolunteerUnassignedFromTask notification 2026-03-28 15:43:50 +01:00
Giovanni 52c187dc2c create VolunteerUnassignedFromTask notification 2026-03-28 15:43:45 +01:00
Giovanni f09b396826 delete VolunteerUnassignedFromTask event 2026-03-28 15:43:35 +01:00
Giovanni 094b25abdd use TaskDateUpdated notification 2026-03-28 15:40:57 +01:00
Giovanni 3e5dc3f377 use TaskDateUpdated notification 2026-03-28 15:40:26 +01:00
Giovanni 0a9b4874db create TaskDateUpdated notification 2026-03-28 15:40:22 +01:00
Giovanni 33d9edc39f delete TaskDateUpdated event 2026-03-28 15:40:12 +01:00
Giovanni 3789a2107a use TaskDeleted notification 2026-03-28 15:37:14 +01:00
Giovanni 8c8fb946e1 create TaskDeleted notification 2026-03-28 15:37:10 +01:00
Giovanni 165a24f5d0 delete TaskParticipationCancelled event 2026-03-28 15:36:54 +01:00
Giovanni 8df5d54d14 use VolunteerAssignedToTask notification 2026-03-28 15:34:36 +01:00
Giovanni 0ffd8e8ad4 create VolunteerAssignedToTask notification 2026-03-28 15:34:31 +01:00
Giovanni b9283136ba remove VolunteerAssignedToTask event 2026-03-28 15:34:16 +01:00
Giovanni f31b92e0d3 use VolunteerRoleUpdated notification 2026-03-28 15:31:38 +01:00
Giovanni 42879b9d76 create VolunteerRoleUpdated notification 2026-03-28 15:31:34 +01:00
Giovanni 17fa90ab9d remove VolunteerRoleUpdated event 2026-03-28 15:31:10 +01:00
Giovanni 2374774577 create UserRegistered notification 2026-03-28 15:28:33 +01:00
Giovanni 7e6052d879 use UserRegistered notification 2026-03-28 15:27:30 +01:00
Giovanni faa642f5d9 create UserRegistered notification 2026-03-28 15:27:26 +01:00
Giovanni d4092a5a3e remove UserCreated event 2026-03-28 15:27:06 +01:00
ORDONNEAU Antoine 9b814151ff changement des couleurs des progressBar pour les tasks 2026-03-27 17:25:24 +01:00
ORDONNEAU Antoine ee279cc9c2 optimisation du css 2026-03-27 17:12:43 +01:00
T'JAMPENS QUENTIN p2406187 5de0daa54a Send users_count on event task 2026-03-27 16:28:34 +01:00
T'JAMPENS QUENTIN p2406187 94beb74242 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	app/Http/Controllers/EventsController.php
2026-03-27 14:50:40 +01:00
T'JAMPENS QUENTIN p2406187 ab36d90796 Send users_count on event task 2026-03-27 14:49:44 +01:00
Giovanni 1d9c6726b3 check if user accept notifications 2026-03-26 10:29:51 +01:00
Giovanni 83ec6c9a2a correct wrong spelling of web_notifications 2026-03-26 10:19:18 +01:00
Giovanni c73f4bd35b correct wrong ternary condition 2026-03-26 09:57:47 +01:00
Giovanni 3528df0571 fix toggleWebNotifications method name 2026-03-26 09:54:32 +01:00
Giovanni 368465b8f3 add default value to email_notifications and web_notifications 2026-03-26 09:48:36 +01:00
Giovanni fdc79baf26 create /users/{id}/web-notifications route in user route 2026-03-26 09:15:21 +01:00
Giovanni fa58184f21 create toggleWebNotifications method in user controller 2026-03-26 09:14:55 +01:00
Giovanni 78645e3cb0 create /users/{id}/email-notifications route in user route 2026-03-26 09:14:17 +01:00
Giovanni 712bdd02cd create toggleEmailNotifications method in user controller 2026-03-26 09:13:57 +01:00
Giovanni c1d7f5cd81 add web_notifications and email_notifications value to the created user in create method of user controller 2026-03-26 09:06:13 +01:00
Giovanni 32607f32d8 add web_notifications and email_notifications value to admin user in seeders 2026-03-26 09:05:40 +01:00
Giovanni 1f6f280958 add web_notifications and email_notifications attributs to User migration and model 2026-03-26 09:03:51 +01:00
JOSSERAND GIOVANNI p2405212 3457ac8282 Merge branch 'main' into 'dev'
create notification, broadcast notification and mail when a futur or ongoing...

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!30
2026-03-26 07:52:08 +00:00
T'JAMPENS QUENTIN p2406187 7366c2a199 Merge branch 'doc/tests' into dev 2026-03-25 14:32:10 +01:00
T'JAMPENS QUENTIN p2406187 12440232da Updagre tests 2026-03-25 14:31:54 +01:00
T'JAMPENS QUENTIN p2406187 1aa367941e Merge branch 'dev' into 'main'
create notification, broadcast notification and mail when a futur or ongoing...

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!29
2026-03-25 13:10:59 +00:00
Giovanni 2252ac9547 add $notificationId to every broadcast notification 2026-03-19 18:22:36 +01:00
Giovanni 9fbc09017b add $notificationId to every broadcast notification 2026-03-19 18:09:11 +01:00
Giovanni ec76ca981a add information in notifications 2026-03-19 18:01:55 +01:00
Giovanni b7ccc38b68 add information in task date updated notification 2026-03-19 17:51:18 +01:00
Giovanni d627afdeaf add information in task date updated notification 2026-03-19 17:49:41 +01:00
Giovanni cf2a29a863 rename $task->title into $task->name 2026-03-19 17:43:02 +01:00
Giovanni 8371f96388 add event name in mail 2026-03-19 17:38:06 +01:00
Giovanni 6a825db608 create notification, broadcast notification and mail when a futur or ongoing date of a task is updated 2026-03-19 17:37:55 +01:00
Giovanni 16ae03e6e6 create broadcast notification when the user role is updated 2026-03-19 17:11:34 +01:00
Giovanni bda5aa4d50 remove debug Log::info 2026-03-19 17:02:27 +01:00
Giovanni 4ebb1ad6c0 fix attribut name 2026-03-19 10:22:59 +01:00
Giovanni 0e5d6a1270 merge dev into features/notifications 2026-03-19 10:00:18 +01:00
Giovanni 75d80985ff Merge branch dev into features/notifications 2026-03-19 09:56:35 +01:00
Giovanni ad6a0f6e90 check if the task is future or ongoing to send email and notification on unassign user 2026-03-19 08:44:12 +01:00
Giovanni 5d256637ec check if the task is future or ongoing to send email and notification on assign user 2026-03-19 08:43:53 +01:00
Giovanni 77d3efc555 check if the task is future or ongoing to send email and notification on deletion 2026-03-19 08:42:20 +01:00
Giovanni 6966027096 check if the event is future or ongoing to send email and notification on deletion 2026-03-19 08:41:07 +01:00
Giovanni 400d70ff7e use formatDate method 2026-03-18 16:30:27 +01:00
Giovanni 2ca3100b3c create a formatDate service and method 2026-03-18 16:30:13 +01:00
Giovanni 6c679596bd add date to eventParticipationCancelled mail 2026-03-18 16:18:12 +01:00
Giovanni 92de307017 create a mail when a user is unassigned to a task by an administrator 2026-03-18 16:14:35 +01:00
Giovanni 2921cbdcbd create a mail when a user is assigned to a task by an administrator 2026-03-18 11:48:54 +01:00
Giovanni 0c04694c34 fix spelling in taskParticipationCancelled blade 2026-03-18 11:44:23 +01:00
Giovanni 3d8fd6687d create a mail when a task is deleted to the participants 2026-03-18 11:37:47 +01:00
Giovanni ce887d0846 fix broadcast error with event 2026-03-18 11:33:42 +01:00
Giovanni 0057972c2f remove unecessary use 2026-03-18 11:07:58 +01:00
Giovanni da3bc1f534 Merge branch 'dev' into features/mails 2026-03-18 10:58:06 +01:00
Giovanni 62cb78859c improve deactivate account mail 2026-03-18 10:17:24 +01:00
Giovanni 5d98678d86 improve register mail 2026-03-18 10:13:17 +01:00
Giovanni 431b9eb0bb improve delete account mail 2026-03-18 10:11:56 +01:00
Giovanni f3d6f6bd11 create a mail when an event is deleted to the participants 2026-03-18 10:06:12 +01:00
Giovanni 2271304044 create a mail when a user registered 2026-03-18 10:00:47 +01:00
Giovanni 66266d1b4b remove notification deletion code when validating an account 2026-03-18 09:55:10 +01:00
Giovanni e713cc2857 create a mail when the role of the user is updated 2026-03-18 09:53:54 +01:00
Giovanni 96973f7884 create a mail when the role of the user is updated 2026-03-18 09:53:42 +01:00
Giovanni c3fb0ec094 create a mail when an account is deactivated by an administrator 2026-03-18 09:48:20 +01:00
Giovanni d9ce927d88 create a mail when an account is deleted by an administrator or by the user 2026-03-18 09:45:55 +01:00
Giovanni 870151cdd3 create a mail when an account is created by an administrator 2026-03-18 09:41:54 +01:00
Giovanni 7ff2f6a6d0 improve validate mail 2026-03-18 09:40:43 +01:00
Giovanni 6ff9d3a6a7 remove test email 2026-03-18 09:32:36 +01:00
T'JAMPENS QUENTIN p2406187 138077fa75 Merge branch 'features/admin-inscription' into 'dev'
Features/admin inscription

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!28
2026-03-15 15:14:59 +00:00
T'JAMPENS QUENTIN p2406187 2789f0e1d9 remove condition 2026-03-15 16:13:13 +01:00
T'JAMPENS QUENTIN p2406187 39702cec9f fix cors 2026-03-15 16:12:55 +01:00
Giovanni ee949da604 Merge branch 'dev' into features/mails 2026-03-13 15:31:37 +01:00
Giovanni 922b4df8b5 rename model in singular 2026-03-13 15:30:54 +01:00
Giovanni 928d504b27 Merge remote-tracking branch 'origin/dev' into features/notifications 2026-03-12 15:52:54 +01:00
Giovanni a189ce98a0 call .env variables in cors.php 2026-03-12 15:52:07 +01:00
Giovanni 3d7c76496f remove unecessary delete notifications on validate user 2026-03-12 11:01:54 +01:00
Giovanni c16a9d1785 remove unecessary delete notifications on validate user 2026-03-12 11:01:44 +01:00
Giovanni d2dd44af4d update channel name into users.admin 2026-03-12 10:19:58 +01:00
p2405951 c9382136ba Merge branch 'features/profile' into dev 2026-03-12 09:53:58 +01:00
Giovanni bed8c79c0a create event on user validated 2026-03-12 09:40:29 +01:00
Giovanni 15cd88c461 rename privateChannel to users.admin 2026-03-12 09:40:14 +01:00
Giovanni a65dcdee3b add user_id property on notification 2026-03-12 09:39:36 +01:00
Giovanni 2dcc861317 create notification on delete event 2026-03-12 09:38:58 +01:00
Giovanni d51d6a9c3f create notification on delete task, assign user and unassign user 2026-03-12 09:38:25 +01:00
Giovanni 9986dfa956 add user_id attribut on Notifications table 2026-03-09 16:53:38 +01:00
Giovanni e720c6c5dd create and send an email on account validate 2026-03-08 22:12:12 +01:00
Giovanni a33b6354bf create a test mail 2026-03-08 22:11:46 +01:00
p2405951 e67db45548 fix bug d'affichage profile-photod 2026-03-08 18:55:28 +01:00
T'JAMPENS QUENTIN p2406187 ec61d5e721 Merge branch 'fix/phone-number-update' into 'dev'
format phone number on update user

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!27
2026-03-03 11:27:43 +00:00
T'JAMPENS QUENTIN p2406187 1cabe42d83 format phone number on update user 2026-03-03 12:25:19 +01:00
p2405951 dd63f5ddd0 fix UserService.php 2026-02-24 17:02:55 +01:00
p2405951 ffa77ad386 recup stash 2026-02-24 16:43:16 +01:00
Giovanni d77e3dc82b remove useless notification when admin create an account 2026-02-24 16:04:26 +01:00
Giovanni 2c4c1cf403 update cors.php 2026-02-24 15:45:33 +01:00
Giovanni 3b304959a9 except broadcasting/auth from csrf token 2026-02-14 10:42:30 +01:00
Giovanni f32dee8e58 add broadcasting/auth to paths in cors.php 2026-02-14 10:32:22 +01:00
Giovanni 8c0ff638c3 test firstOrCreate method 2026-02-14 10:11:25 +01:00
Giovanni 6c3a11388b set config variables for env variables 2026-02-12 18:31:11 +01:00
Giovanni ac1eaca0df set config variables for env variables 2026-02-12 18:27:06 +01:00
Giovanni 7768e7a9e3 set config variables for env variables 2026-02-12 18:07:23 +01:00
Giovanni d3d7292b80 re-create DatabaseSeeder 2026-02-11 20:02:34 +01:00
LEBLOND MALO p2405951 a85e843863 Merge branch 'features/export' into 'dev'
add in stash export

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!26
2026-02-11 15:57:54 +00:00
p2405951 59c8268232 add in stash export 2026-02-11 17:52:46 +01:00
JOSSERAND GIOVANNI p2405212 7351cd5c53 Merge branch 'features/adminInCollection' into 'dev'
Features/adminincollection

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!25
2026-02-11 15:54:34 +00:00
Giovanni 97ae8366c0 add env variables for admin informations 2026-02-11 16:36:51 +01:00
Giovanni 7782983fef add env variables for admin informations 2026-02-11 16:31:23 +01:00
Giovanni 6b155d70b3 delete DatabaseSeeder 2026-02-11 16:01:49 +01:00
Giovanni 24aaf8661c create DevSeeder 2026-02-11 16:01:18 +01:00
Giovanni 4d089d004c create ProdSeeder 2026-02-11 16:01:11 +01:00
Giovanni 281094fb7b create ProdSeeder 2026-02-11 15:59:54 +01:00
Giovanni 06f8fec1ab create DevSeeder 2026-02-11 15:59:49 +01:00
Giovanni e006cb1c5e add the admin user in users collection 2026-02-11 15:48:50 +01:00
T'JAMPENS QUENTIN p2406187 c74690f68b Add default role when user is created by an admin 2026-02-11 14:51:28 +01:00
T'JAMPENS QUENTIN p2406187 5e232fd0af Create other user route 2026-02-11 14:51:28 +01:00
Giovanni accbbe31d9 test .gitignore 2026-02-10 16:39:33 +01:00
JOSSERAND GIOVANNI p2405212 06844e4b81 Merge branch 'fix/typesense' into 'dev'
Fix/typesense

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!24
2026-02-10 15:36:16 +00:00
Giovanni b1996d153e test 2026-02-10 16:33:06 +01:00
Giovanni b9ed209e5d test 2026-02-10 15:31:12 +01:00
Giovanni ed5edefcc4 update AppServiceProvider to add Observer 2026-02-10 15:28:22 +01:00
Giovanni 64455066a8 update SearchController 2026-02-10 15:28:04 +01:00
Giovanni 4acb8ad001 add TypesenseService 2026-02-10 15:27:55 +01:00
Giovanni 05ff869183 add Observer 2026-02-10 15:27:46 +01:00
Giovanni 3a5a95cba9 call TYPESENSE_API_KEY in SearchController.php 2026-02-07 21:28:49 +01:00
JOSSERAND GIOVANNI p2405212 880032bc28 Merge branch 'features/fixDocker' into 'dev'
Features/fixdocker

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!23
2026-02-07 19:03:26 +00:00
Giovanni 24f0365513 test 2026-02-06 15:45:42 +01:00
Giovanni b256e3b7dc test 2026-02-06 15:34:55 +01:00
Giovanni f483dbe17e test 2026-02-03 17:23:50 +01:00
Giovanni 569b9df7f2 test 2026-02-03 17:22:10 +01:00
Giovanni ae5a159d31 test 2026-02-03 17:14:32 +01:00
Giovanni 7f64c80b77 test 2026-02-03 17:11:41 +01:00
Giovanni 591127b5b6 test 2026-02-03 17:02:15 +01:00
Giovanni 1aa57e3e3e test 2026-02-03 16:42:42 +01:00
T'JAMPENS QUENTIN p2406187 881e3b7775 Fix event middleware 2026-02-03 14:42:13 +01:00
Giovanni 8c1171846d test 2026-01-31 18:09:54 +01:00
Giovanni a64146e227 test 2026-01-31 17:56:34 +01:00
Giovanni 22e6f365b0 test 2026-01-31 17:37:23 +01:00
Giovanni fadaf6765c test 2026-01-31 17:26:20 +01:00
Giovanni 637a32314a test 2026-01-31 16:20:12 +01:00
Giovanni 59105c6d8a test 2026-01-31 16:13:28 +01:00
Giovanni 33a918d02b test 2026-01-31 16:02:37 +01:00
Giovanni de7a0a85f6 test 2026-01-31 15:25:16 +01:00
Giovanni 8f91f480eb test 2026-01-31 15:00:25 +01:00
Giovanni f66c8a8eb6 update filesystems to change dynamically the storage path 2026-01-30 23:41:21 +01:00
Giovanni d4526487ed test public 2026-01-30 17:34:43 +01:00
Giovanni 32341b0311 update .env.example 2026-01-27 14:36:43 +01:00
Giovanni 0f45a25b25 delete docker folder 2026-01-27 14:35:49 +01:00
T'JAMPENS QUENTIN p2406187 7099ad53c5 Fix event middleware 2026-01-27 14:20:24 +01:00
p2405951 0f3beba354 test 2026-01-19 09:02:05 +01:00
p2405951 260584bf89 backup ignore 2026-01-19 08:58:44 +01:00
p2405951 a8132e9f13 end 2026-01-15 09:21:58 +01:00
T'JAMPENS QUENTIN p2406187 ccc188a8c0 Merge branch 'dev' into 'main'
Dev

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!21
2026-01-14 21:44:35 +00:00
Giovanni 446bded5f9 update deactivate 2026-01-14 22:59:13 +01:00
JOSSERAND GIOVANNI p2405212 c644c05933 Merge branch 'features/permissions' into 'dev'
permissions review

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!20
2026-01-14 20:42:20 +00:00
Giovanni 53cca29b67 permissions review 2026-01-14 22:41:03 +01:00
T'JAMPENS QUENTIN p2406187 396519e5f9 Merge branch 'dev' into 'main'
add reverb container, unread attribute in notification pivot table and private...

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!19
2026-01-14 15:47:43 +00:00
T'JAMPENS QUENTIN p2406187 dd2a0bc333 Create get all roles method 2026-01-13 23:46:08 +01:00
T'JAMPENS QUENTIN p2406187 797887b23d Create get all roles route 2026-01-13 09:29:26 +01:00
T'JAMPENS QUENTIN p2406187 8def3ee391 Add isUserAssigned route 2026-01-12 15:52:42 +01:00
T'JAMPENS QUENTIN p2406187 e118debc6b Improve assignSelf function 2026-01-12 14:15:08 +01:00
Giovanni de13fa0b4a add TYPESENSE_API_KEY in .env.example 2026-01-12 10:04:32 +01:00
Giovanni bf6deadbc0 add policies for getInvalidUsers route 2026-01-12 09:55:19 +01:00
JOSSERAND GIOVANNI p2405212 46a4ac9c15 Merge branch 'features/notifications' into 'dev'
add reverb container, unread attribute in notification pivot table and private...

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!18
2026-01-11 22:22:26 +00:00
Giovanni 60012c63c3 merge dev into features/notifications 2026-01-11 23:09:57 +01:00
Giovanni c3122072da correct some issues 2026-01-11 20:10:39 +01:00
Giovanni ab1df4d692 Create unassignUser, unassignSelf methods and Bruno requests. Add call events when needed 2026-01-11 19:03:58 +01:00
Giovanni 234717b23c multiplex user notifications over a single private channel 2026-01-11 12:09:58 +01:00
Giovanni 9fd72c6ea4 multiplex user notifications over a single private channel 2026-01-11 12:06:27 +01:00
Giovanni 9b70b09173 rename admins-private to users.registration 2026-01-09 14:41:10 +01:00
p2405951 2b8487432f --allow_empty 2026-01-09 09:35:21 +01:00
p2405951 b4a5283547 fix bug && test 2026-01-09 09:23:56 +01:00
Giovanni 69d6a77ff1 untrack public/index.html 2026-01-08 14:59:03 +01:00
Giovanni 475a1c7052 set the notification getting system by created_at desc order 2026-01-08 14:51:21 +01:00
Giovanni c49a5e558f add readNotifications route and bruno's request 2026-01-08 14:10:17 +01:00
Giovanni 51791a3b34 add readNotifications route and bruno's request 2026-01-08 14:04:53 +01:00
Giovanni 2790026475 add reverb container, unread attribute in notification pivot table and private channel and event for new register 2026-01-07 16:50:51 +01:00
LEBLOND MALO p2405951 ed37808d33 Merge branch 'features/backup' into 'dev'
Features/backup

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!16
2026-01-07 15:33:33 +00:00
p2405951 f066aa88f0 Nettoyage des backups 2026-01-07 16:30:33 +01:00
p2405951 3451f75b37 recup modif dev 2026-01-07 16:04:12 +01:00
T'JAMPENS QUENTIN p2406187 be3f6ba5d4 Create getInvalidUser route 2026-01-05 09:48:20 +01:00
T'JAMPENS QUENTIN p2406187 516ab77d58 Create getInvalidUser route 2026-01-05 09:48:13 +01:00
Giovanni 6eaac7a745 rename UserPolicy to UsersPolicy 2025-12-17 17:32:03 +01:00
Giovanni ab9755ade5 rename UserPolicy to UsersPolicy 2025-12-17 17:31:54 +01:00
JOSSERAND GIOVANNI p2405212 e0504ea0c2 Merge branch 'features/authorizations' into 'features/notifications'
Features/authorizations

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!14
2025-12-17 16:19:31 +00:00
Giovanni 08459ac627 change notifications functions 2025-12-17 17:18:37 +01:00
Giovanni 08c51473a7 add TasksPolicy and EventsPolicy 2025-12-17 17:11:12 +01:00
Giovanni a0e95aca3e remove unecessary gates for users routes and add UserPolicy 2025-12-17 16:52:43 +01:00
Giovanni 4c3647fe30 add gates for users routes 2025-12-17 16:14:19 +01:00
T'JAMPENS QUENTIN p2406187 4c907c8ba5 Return 404 if user not found 2025-12-17 15:16:03 +01:00
Giovanni ae81344fe2 add notification when user role is changed 2025-12-17 14:46:33 +01:00
Giovanni 7390ae6116 create notification bruno request and move some routes 2025-12-17 14:32:01 +01:00
Giovanni 090db4205a search only validate users 2025-12-16 11:44:32 +01:00
Giovanni 543db51291 search only validate users 2025-12-16 11:44:12 +01:00
Giovanni 8e93a0aba2 delete notification and notification_user when validate 2025-12-16 10:11:08 +01:00
Giovanni eab9565c7d create notification when register 2025-12-15 16:45:51 +01:00
Giovanni dfb70cc5ce create notification_user table migration 2025-12-10 17:02:45 +01:00
JOSSERAND GIOVANNI p2405212 e89f00e2f9 Merge branch 'features/searchUser' into 'dev'
Features/searchuser

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!12
2025-12-10 15:52:16 +00:00
JOSSERAND GIOVANNI p2405212 9bc03eb46a Merge branch 'dev' into 'features/searchUser'
# Conflicts:
#   tests/Users/Create user.bru
#   tests/collection.bru
2025-12-10 15:52:04 +00:00
T'JAMPENS QUENTIN p2406187 3e43966357 Send error if email is already used 2025-12-10 15:09:34 +01:00
T'JAMPENS QUENTIN p2406187 b3cffe3008 Return isAdmin 2025-12-10 12:10:50 +01:00
T'JAMPENS QUENTIN p2406187 8e1e8e3b7c Merge branch 'dev' of https://iutbg-gitlab.iutbourg.univ-lyon1.fr/sae-but2/2025-26/gestion-benevoles-association/backend into dev 2025-12-10 11:42:25 +01:00
T'JAMPENS QUENTIN p2406187 639675c266 Update user role on validation 2025-12-10 11:41:27 +01:00
T'JAMPENS QUENTIN p2406187 de08e5396a Update create user test 2025-12-10 11:40:56 +01:00
Giovanni 669fa6aa16 add TYPESENSE_CONNECTION in .env.example 2025-12-10 11:25:48 +01:00
Giovanni ba7146cca7 test commit 2025-12-10 11:23:33 +01:00
T'JAMPENS QUENTIN p2406187 afb630d053 Merge branch 'features/emailValidation' into 'dev'
Check user email

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!10
2025-12-10 08:53:13 +00:00
T'JAMPENS QUENTIN p2406187 056f42b815 Check user email 2025-12-10 09:52:22 +01:00
Giovanni 8426755db3 add user search in SearchController, add start and end datetime in events table 2025-12-09 12:28:02 +01:00
T'JAMPENS QUENTIN p2406187 319f143327 Merge branch 'dev' into features/phoneValidation
# Conflicts:
#	composer.json
#	composer.lock
2025-12-09 12:27:19 +01:00
T'JAMPENS QUENTIN p2406187 04e45f3b83 Check user phone 2025-12-09 12:20:12 +01:00
T'JAMPENS QUENTIN p2406187 6ae4fd1cdd Install propaganistas/laravel-phone 2025-12-09 12:19:56 +01:00
JOSSERAND GIOVANNI p2405212 da20be4558 Merge branch 'features/typesense' into 'dev'
Features/typesense

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!8
2025-12-07 15:14:57 +00:00
JOSSERAND GIOVANNI p2405212 b8ccef3fb5 Merge branch 'dev' into 'features/typesense'
# Conflicts:
#   routes/events.php
2025-12-07 15:14:51 +00:00
Giovanni 2db242d43a Replace bind mount with Docker managed volume for Typesense 2025-12-07 16:13:03 +01:00
T'JAMPENS QUENTIN p2406187 ad3157807c Send task on get all events route 2025-12-07 01:08:18 +01:00
T'JAMPENS QUENTIN p2406187 efd87bf5cd Create UserService 2025-12-05 15:08:18 +01:00
T'JAMPENS QUENTIN p2406187 7bf6ffe2f8 Create get event route doc 2025-12-02 16:25:30 +01:00
T'JAMPENS QUENTIN p2406187 6a0125eeaf Create get event route 2025-12-02 16:25:18 +01:00
T'JAMPENS QUENTIN p2406187 897e92d8f0 Create get role fct 2025-12-02 16:12:48 +01:00
T'JAMPENS QUENTIN p2406187 238127bc16 Update /me route 2025-12-02 16:12:29 +01:00
T'JAMPENS QUENTIN p2406187 232804fb39 Update composer.json 2025-12-02 15:28:56 +01:00
Giovanni 20654b2eff add of Search events route 2025-11-29 20:11:06 +01:00
Giovanni a7b8de3205 add of typesense container, searchEvents route and SearchController and method 2025-11-29 20:10:09 +01:00
T'JAMPENS QUENTIN p2406187 b7cd27be7e Fix errors 2025-11-29 01:48:20 +01:00
T'JAMPENS QUENTIN p2406187 99655b0d84 Merge branch 'feature/docker' into 'dev'
Feature/docker

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!7
2025-11-28 07:52:16 +00:00
T'JAMPENS QUENTIN p2406187 6c4d03eb6b Update 2025-11-24 23:18:10 +01:00
T'JAMPENS QUENTIN p2406187 1f077cfdd2 Update README.md 2025-11-24 22:19:26 +01:00
T'JAMPENS QUENTIN p2406187 60d1ec1364 Update docker conf 2025-11-24 22:16:16 +01:00
T'JAMPENS QUENTIN p2406187 1eb75b5782 Merge branch 'feature/docker' into 'dev'
Feature/docker

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!6
2025-11-23 22:38:51 +00:00
T'JAMPENS QUENTIN p2406187 457dd6679b Update README.md 2025-11-23 23:37:33 +01:00
T'JAMPENS QUENTIN p2406187 bd4dceace6 Add sample website 2025-11-23 23:35:32 +01:00
T'JAMPENS QUENTIN p2406187 b1a0edb474 Create docker configuration 2025-11-23 23:35:24 +01:00
T'JAMPENS QUENTIN p2406187 4ae2905b48 Merge branch 'feature/tasks' into 'dev'
Feature/tasks

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!5
2025-11-21 23:39:59 +00:00
T'JAMPENS QUENTIN p2406187 59a5a4fde9 add delete event route 2025-11-22 00:37:59 +01:00
T'JAMPENS QUENTIN p2406187 c83b626b9a add get all events route 2025-11-22 00:33:51 +01:00
T'JAMPENS QUENTIN p2406187 9e271f8a3e add update event task route 2025-11-21 16:16:34 +01:00
T'JAMPENS QUENTIN p2406187 d6a8fd3010 add update event route 2025-11-21 16:08:04 +01:00
T'JAMPENS QUENTIN p2406187 d5f1c7f163 add delete event tasks route 2025-11-21 15:44:25 +01:00
T'JAMPENS QUENTIN p2406187 016017ab30 add get event tasks route 2025-11-21 12:07:23 +01:00
T'JAMPENS QUENTIN p2406187 23da5640c7 Merge branch 'feature/front' into 'dev'
Host frontend

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!4
2025-11-21 10:52:25 +00:00
T'JAMPENS QUENTIN p2406187 83a401bd15 Host frontend 2025-11-21 11:49:03 +01:00
T'JAMPENS QUENTIN p2406187 5e846a8896 Add get user task by id 2025-11-21 11:08:11 +01:00
T'JAMPENS QUENTIN p2406187 feef269015 Add get user by id tasks 2025-11-20 12:16:38 +01:00
T'JAMPENS QUENTIN p2406187 d142979e49 Split routes 2025-11-20 12:09:17 +01:00
T'JAMPENS QUENTIN p2406187 feb901c9e8 Add get user's tasks route 2025-11-20 11:23:56 +01:00
T'JAMPENS QUENTIN p2406187 fd65cfdc1c fix max participant reached 2025-11-20 11:23:21 +01:00
T'JAMPENS QUENTIN p2406187 2c606d4fe7 resolve conflits 2025-11-20 09:01:13 +01:00
T'JAMPENS QUENTIN p2406187 347522a429 Merge branch 'docs' into 'dev'
Docs

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!3
2025-11-17 21:52:15 +00:00
T'JAMPENS QUENTIN p2406187 fdc4819c2e Update README.md 2025-11-17 22:51:25 +01:00
T'JAMPENS QUENTIN p2406187 dea69e018e Remove vars values + move headers to collection headers 2025-11-17 22:40:08 +01:00
T'JAMPENS QUENTIN p2406187 67048d7f4b Add methods 2025-11-17 22:35:09 +01:00
T'JAMPENS QUENTIN p2406187 5b01f2e9f4 Update doc 2025-11-17 22:32:30 +01:00
T'JAMPENS QUENTIN p2406187 ad0f51c405 Add /me route 2025-11-16 01:53:46 +01:00
Giovanni 901c6ab68e creation of the create and get routes for Notifications 2025-11-14 17:41:01 +01:00
T'JAMPENS QUENTIN p2406187 827ade852e Create assign task to user route 2025-11-14 12:22:59 +01:00
T'JAMPENS QUENTIN p2406187 55f332d28e Create assign task route 2025-11-14 09:47:13 +01:00
T'JAMPENS QUENTIN p2406187 71fc82a0e7 Create relationship task_user 2025-11-14 09:46:57 +01:00
Giovanni 3c2128b9b7 creation of Notifications table and migration 2025-11-09 18:04:25 +01:00
T'JAMPENS QUENTIN p2406187 f353e0c964 Creation table tasks 2025-11-09 16:17:10 +01:00
T'JAMPENS QUENTIN p2406187 8341021ba5 Merge branch 'features/events' into 'dev'
Features/events

See merge request sae-but2/2025-26/gestion-benevoles-association/backend!2
2025-10-27 22:20:00 +00:00
Quentin T'JAMPENS 86b7996d75 Create events factory 2025-10-27 23:13:52 +01:00
Quentin T'JAMPENS 8e3f189e77 Fix dev url 2025-10-27 23:07:24 +01:00
Quentin T'JAMPENS 75e156ae07 Fix xsrf tokens 2025-10-27 23:07:19 +01:00
Quentin T'JAMPENS 294c3581f9 Set default password to 'password' 2025-10-27 23:06:33 +01:00
Quentin T'JAMPENS 41cf8a5a44 Create event route + doc 2025-10-27 23:06:17 +01:00
Quentin T'JAMPENS adfe2a9fe1 Create event table 2025-10-27 22:46:35 +01:00
Quentin T'JAMPENS 9cf93d93c7 Update factory and seed 2025-10-27 22:33:52 +01:00
T'JAMPENS QUENTIN p2406187 a3c418de46 Create environnement 2025-10-24 17:18:43 +02:00
T'JAMPENS QUENTIN p2406187 8932c90c8a Change return error 2025-10-24 11:33:53 +02:00
T'JAMPENS QUENTIN p2406187 b3222f0f46 Add get all users route 2025-10-24 11:32:16 +02:00
T'JAMPENS QUENTIN p2406187 47d433eecb Add verified_at column 2025-10-24 10:59:55 +02:00
T'JAMPENS QUENTIN p2406187 081cd66a8e Add delete user by id route 2025-10-24 10:02:06 +02:00
T'JAMPENS QUENTIN p2406187 2c94483cd9 Add role and validate in getUser route 2025-10-24 09:42:00 +02:00
T'JAMPENS QUENTIN p2406187 2cf024fe3e Update extractCSRF function 2025-10-24 09:39:54 +02:00
T'JAMPENS QUENTIN p2406187 219c71a99b Add modify user role route 2025-10-24 09:35:44 +02:00
T'JAMPENS QUENTIN p2406187 5787d5fac3 Add validate user route 2025-10-23 11:57:11 +02:00
T'JAMPENS QUENTIN p2406187 7add68c780 Add update user doc 2025-10-23 11:33:47 +02:00
T'JAMPENS QUENTIN p2406187 4fdf38827d Add update user route 2025-10-23 11:33:39 +02:00
T'JAMPENS QUENTIN p2406187 ded8e85c85 Add get user route 2025-10-21 22:18:15 +02:00
T'JAMPENS QUENTIN p2406187 0d926d4b95 Add delete user route 2025-10-21 22:02:53 +02:00
Dayamond fd8c47cd95 Add logout route test 2025-10-21 17:41:52 +02:00
Dayamond ab50743c01 Add logout route 2025-10-21 17:41:44 +02:00
Dayamond 5a41d2e028 Update asserts 2025-10-21 17:25:34 +02:00
Dayamond a7b9ce803b Add routes 2025-10-21 17:18:00 +02:00
Dayamond 42a98f3435 Update create user route 2025-10-21 16:48:18 +02:00
Dayamond c691f81ebb Update user table 2025-10-21 16:45:39 +02:00
Dayamond ef775c70fe rename routes 2025-10-21 16:14:34 +02:00
Dayamond a2e96cef5a change default port 2025-10-21 16:14:27 +02:00
Dayamond 56c9139d0c Remove useless imports 2025-10-21 16:14:20 +02:00
Dayamond 3c929f5c64 Change bruno collection name 2025-10-18 17:20:40 +02:00
Dayamond 223cfe086c Add Bruno tests 2025-10-18 17:17:35 +02:00
Dayamond 1c00dbdb85 Ajout de l'authentification 2025-10-18 16:52:01 +02:00
Dayamond 70fbc02918 Migrations 2025-10-14 22:38:01 +02:00
Dayamond 3d6597a246 Add cors 2025-10-14 22:37:49 +02:00
Dayamond eb7a5c7894 create user 2025-10-14 22:37:42 +02:00
Dayamond ed5376cb43 create user 2025-10-14 22:37:32 +02:00
Dayamond 0f8ce7deea Initial commit 2025-10-13 23:04:46 +02:00
401 changed files with 28333 additions and 6098 deletions

No files matched your search

Executable
+18
View File
@@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[compose.yaml]
indent_size = 4
Executable
+11
View File
@@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
Regular → Executable
+25 -26
View File
@@ -1,29 +1,28 @@
.env
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.fleet
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
Homestead.json
Homestead.yaml
Thumbs.db
/public/**
!/public/index.php
*storybook.log
storybook-static
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use \Illuminate\Http\JsonResponse;
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 App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
abstract class Controller
{
use AuthorizesRequests;
}
+209
View File
@@ -0,0 +1,209 @@
<?php
namespace App\Http\Controllers;
use App\Mail\EventParticipationCancelledMail;
use App\Models\Event;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use App\Models\Task;
use App\Notifications\EventDeleted;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
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'
]);
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Carbon\Carbon;
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
);
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
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);
}
}
}
+66
View File
@@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Typesense\Client;
use Exception;
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);
}
}
}
+286
View File
@@ -0,0 +1,286 @@
<?php
namespace App\Http\Controllers;
use App\Mail\TaskDateUpdateMail;
use App\Mail\TaskParticipationCancelledMail;
use App\Mail\VolunteerAssignToTaskMail;
use App\Mail\VolunteerUnassignToTaskMail;
use App\Notifications\TaskDateUpdated;
use App\Notifications\TaskDeleted;
use App\Notifications\VolunteerAssignedToTask;
use App\Notifications\VolunteerUnassignedFromTask;
use App\Models\Event;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use App\Models\Task;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use App\Services\FormatDate;
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);
}
}
}
+495
View File
@@ -0,0 +1,495 @@
<?php
namespace App\Http\Controllers;
use App\Mail\EmailChangeConfirmedMail;
use App\Mail\NotifyEmailChangeMail;
use App\Mail\RegisterMail;
use App\Mail\RequestEmailChangeMail;
use App\Mail\UpdatePasswordMail;
use App\Mail\UpdateRoleMail;
use App\Notifications\VolunteerRoleUpdated;
use App\Mail\CreateUserByAdminMail;
use App\Mail\DeactivateAccountMail;
use App\Mail\DeleteAccountMail;
use App\Mail\ValidateMail;
use Illuminate\Support\Facades\Notification;
use App\Models\User;
use App\Notifications\UserRegistered;
use App\Services\GetRole;
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 App\Services\UserService;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Pest\Support\Str;
use Propaganistas\LaravelPhone\PhoneNumber;
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 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 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 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 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 App\Mail;
use 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 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 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 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 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 App\Mail;
use 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 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 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 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 App\Mail;
use 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 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;
use App\Services\FormatDate;
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 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 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 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<\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);
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace App\Notifications;
use App\Mail\EventParticipationCancelledMail;
use App\Models\Event;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Notifications;
use App\Mail\TaskDateUpdateMail;
use App\Models\Event;
use App\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Notifications;
use App\Mail\TaskParticipationCancelledMail;
use App\Models\Event;
use App\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace App\Notifications;
use App\Models\User;
use App\Mail\RegisterMail;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Messages\MailMessage;
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));
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Notifications;
use App\Mail\VolunteerAssignToTaskMail;
use App\Models\Event;
use App\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Notifications;
use App\Mail\UpdateRoleMail;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Notifications;
use App\Mail\VolunteerUnassignToTaskMail;
use App\Models\Event;
use App\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
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));
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Observers;
use App\Models\Event;
use App\Services\TypesenseService;
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);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Observers;
use App\Models\User;
use App\Services\TypesenseService;
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);
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Policies;
use App\Models\Event;
use 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;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Policies;
use App\Models\Task;
use 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 App\Policies;
use 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;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace App\Providers;
use App\Models\Event;
use App\Models\User;
use App\Observers\EventObserver;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;
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);
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
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 App\Providers;
use App\Models\Event;
use App\Models\Task;
use App\Models\User;
use App\Policies\EventsPolicy;
use App\Policies\TasksPolicy;
use 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 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 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"
];
}
}
+141
View File
@@ -0,0 +1,141 @@
<?php
namespace App\Services;
use App\Models\User;
use App\Models\Event;
use Illuminate\Support\Facades\Cache;
use Typesense\Client;
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 App\Services;
use 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,
];
}
}
View File
File renamed without changes.
+29
View File
@@ -0,0 +1,29 @@
.env
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
../../.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*storybook.log
storybook-static
View File
File renamed without changes.
View File
File renamed without changes.
+1 -1
View File
@@ -1,6 +1,6 @@
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
import { setProjectAnnotations } from '@storybook/react-vite';
import * as projectAnnotations from './preview';
import * as projectAnnotations from './preview.js';
// This is an important step to apply the right configuration when testing your stories.
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
View File
File renamed without changes.
View File
File renamed without changes.
+1 -1
View File
@@ -8,6 +8,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<script type="module" src="/apps/frontend/srcs/frontend/src/main.jsx"></script>
</body>
</html>
+5860
View File
File diff suppressed because it is too large. Load diff
+57
View File
@@ -0,0 +1,57 @@
{
"name": "sae-front",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint ../..",
"preview": "vite preview",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test": "vitest"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@floating-ui/react": "^0.27.16",
"@mui/material": "^7.3.6",
"bootstrap": "^5.3.8",
"chart.js": "^4.5.1",
"laravel-echo": "^2.2.7",
"pusher-js": "^8.4.0",
"react": "^19.1.1",
"react-bootstrap": "^2.10.10",
"react-chartjs-2": "^5.3.1",
"react-dom": "^19.1.1",
"react-router": "^7.9.4",
"react-router-dom": "^7.10.1"
},
"devDependencies": {
"@chromatic-com/storybook": "^4.1.2",
"@eslint/js": "^9.36.0",
"@storybook/addon-a11y": "^10.0.6",
"@storybook/addon-docs": "^10.0.6",
"@storybook/addon-vitest": "^10.0.6",
"@storybook/react-vite": "^10.0.6",
"@types/node": "^25.0.10",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.0.4",
"@vitest/browser-playwright": "^4.0.8",
"@vitest/coverage-v8": "^4.0.8",
"baseline-browser-mapping": "^2.9.7",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.22",
"eslint-plugin-storybook": "^10.0.6",
"globals": "^16.4.0",
"playwright": "^1.56.1",
"prop-types": "^15.8.1",
"storybook": "^10.0.6",
"typescript": "^5.9.3",
"vite": "^7.1.7",
"vitest": "^4.0.8"
}
}
Generated Regular → Executable
View File
File renamed without changes.
View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 222 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1009 B

After

Width:  |  Height:  |  Size: 1009 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 844 B

After

Width:  |  Height:  |  Size: 844 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 320 B

File renamed without changes.

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 475 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

File renamed without changes.
@@ -29,7 +29,9 @@ const Background = ({ children, className }: BackgroundProps) => {
useEffect(() => {
const updateTheme = () => {
setTheme(localStorage.getItem("theme") || "light");
const t = localStorage.getItem("theme") || "light";
setTheme(t);
document.body.classList.toggle("dark", t === "dark");
};
updateTheme();
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -14,7 +14,11 @@
position: relative;
justify-content: space-between;
}
.profileImg{
width:40px;
height:40px;
border-radius: 50%;
}
.activeHeaderContent {
@@ -12,6 +12,7 @@ import { AuthContext } from "../../contexts/Auth/AuthContext.js";
import { PendingMembersContext } from "../../contexts/PendingMembers/PendingMembersContext";
import Notification from "../../interfaces/notification.interface";
function Header() {
const { update, user } = useContext(AuthContext)!;
@@ -22,7 +23,9 @@ function Header() {
const [mobileMenu, setMobileMenu] = useState<boolean>(false);
const [notifications, setNotifications] = useState<Notification[]>([]);
const notificationRef = useRef<HTMLDivElement>(null);
const profileImageUrl = user?.profile_photo_path
? `${import.meta.env.VITE_API_URL}/storage/${user.profile_photo_path}`
: "/person.svg";
useEffect(() => {
if (!user) return;
@@ -130,15 +133,21 @@ function Header() {
<div className={styles.headerRightContent}>
<button
className={`${styles.bellBtn} ${notificationMenu ? styles.activeBellBtn : ""}`}
onClick={() => {toggleNotificationMenu();}}
onClick={() => { toggleNotificationMenu(); }}
>
<img className={styles.notificationsImg} src="/bell.svg" alt="notifications"/>
<img className={styles.notificationsImg} src="/bell.svg" alt="notifications" />
{unreadNotification && <span className={styles.notificationBadge}></span>}
</button>
<Link to="/profile" className={styles.profileLink}>
<img className={styles.profileImg} src="/person.svg" alt="profile"/>
<img
className={styles.profileImg}
src={profileImageUrl}
alt="profile"
/>
</Link>
</div>
</nav>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 401 files, more files were not shown because too many files have changed in this diff. Show more