Compare commits
388
Commits
57d68b43de
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7299a177a2 | ||
|
|
67f2b516e8 | ||
|
|
64d065caad | ||
|
|
ef0596b729 | ||
|
|
b8420f08cd | ||
|
|
e7baf34c4f | ||
|
|
7b4512bf27 | ||
|
|
eb3e00c9ce | ||
|
|
8e481dfae6 | ||
|
|
23e61c6349 | ||
|
|
74c5d2d5ce | ||
|
|
62e2420105 | ||
|
|
c4ad3e0cdf | ||
|
|
3d06596fea | ||
|
|
30987fb582 | ||
|
|
75bf1b966b | ||
|
|
99f483b89c | ||
|
|
58b471607c | ||
|
|
fc765959f9 | ||
|
|
3d70814520 | ||
|
|
840808daee | ||
|
|
9619ce44e9 | ||
|
|
d469f1b5c8 | ||
|
|
7f8db6d6ee | ||
|
|
90dea59176 | ||
|
|
9dd9f245f7 | ||
|
|
02083d6ad3 | ||
|
|
fbbb563654 | ||
|
|
aa8663a416 | ||
|
|
3feb126f07 | ||
|
|
0ca1bb7e55 | ||
|
|
7f4493666e | ||
|
|
6cf9c8c4b2 | ||
|
|
ed38086d09 | ||
|
|
e2b471312c | ||
|
|
cf529278bd | ||
|
|
31304c931d | ||
|
|
dc39113335 | ||
|
|
fed6b7c92f | ||
|
|
7a4c2f5015 | ||
|
|
76f7ed4f8d | ||
|
|
c210aec76f | ||
|
|
f1798c496b | ||
|
|
26bfdb5cb2 | ||
|
|
6bce33e9de | ||
|
|
9ae484d584 | ||
|
|
089995c84d | ||
|
|
615c084995 | ||
|
|
afbffe99a8 | ||
|
|
476f4390fe | ||
|
|
483e281acd | ||
|
|
0c0af0fd00 | ||
|
|
d9ccd7ff5f | ||
|
|
741dabd720 | ||
|
|
f4caf50f40 | ||
|
|
8e110244bb | ||
|
|
567bc306e1 | ||
|
|
1f42a5392b | ||
|
|
ac2dcef7a7 | ||
|
|
7b4280d4eb | ||
|
|
4031faf08b | ||
|
|
59598e29be | ||
|
|
51435f9257 | ||
|
|
2489aad0c8 | ||
|
|
f52d5bb5ef | ||
|
|
f0070d3557 | ||
|
|
cbe816fd17 | ||
|
|
cdc4645d92 | ||
|
|
60760d6101 | ||
|
|
4c52fa5043 | ||
|
|
f13e96c7c7 | ||
|
|
aa3d5f887d | ||
|
|
93bfc19e6e | ||
|
|
de0457c426 | ||
|
|
ef33591c2a | ||
|
|
551909aee7 | ||
|
|
bfec1752e0 | ||
|
|
0b3e9142b5 | ||
|
|
a99a610688 | ||
|
|
4a0087104c | ||
|
|
52c187dc2c | ||
|
|
f09b396826 | ||
|
|
094b25abdd | ||
|
|
3e5dc3f377 | ||
|
|
0a9b4874db | ||
|
|
33d9edc39f | ||
|
|
3789a2107a | ||
|
|
8c8fb946e1 | ||
|
|
165a24f5d0 | ||
|
|
8df5d54d14 | ||
|
|
0ffd8e8ad4 | ||
|
|
b9283136ba | ||
|
|
f31b92e0d3 | ||
|
|
42879b9d76 | ||
|
|
17fa90ab9d | ||
|
|
2374774577 | ||
|
|
7e6052d879 | ||
|
|
faa642f5d9 | ||
|
|
d4092a5a3e | ||
|
|
9b814151ff | ||
|
|
ee279cc9c2 | ||
|
|
5de0daa54a | ||
|
|
94beb74242 | ||
|
|
ab36d90796 | ||
|
|
1d9c6726b3 | ||
|
|
83ec6c9a2a | ||
|
|
c73f4bd35b | ||
|
|
3528df0571 | ||
|
|
368465b8f3 | ||
|
|
fdc79baf26 | ||
|
|
fa58184f21 | ||
|
|
78645e3cb0 | ||
|
|
712bdd02cd | ||
|
|
c1d7f5cd81 | ||
|
|
32607f32d8 | ||
|
|
1f6f280958 | ||
|
|
3457ac8282 | ||
|
|
7366c2a199 | ||
|
|
12440232da | ||
|
|
1aa367941e | ||
|
|
2252ac9547 | ||
|
|
9fbc09017b | ||
|
|
ec76ca981a | ||
|
|
b7ccc38b68 | ||
|
|
d627afdeaf | ||
|
|
cf2a29a863 | ||
|
|
8371f96388 | ||
|
|
6a825db608 | ||
|
|
16ae03e6e6 | ||
|
|
bda5aa4d50 | ||
|
|
4ebb1ad6c0 | ||
|
|
0e5d6a1270 | ||
|
|
75d80985ff | ||
|
|
ad6a0f6e90 | ||
|
|
5d256637ec | ||
|
|
77d3efc555 | ||
|
|
6966027096 | ||
|
|
400d70ff7e | ||
|
|
2ca3100b3c | ||
|
|
6c679596bd | ||
|
|
92de307017 | ||
|
|
2921cbdcbd | ||
|
|
0c04694c34 | ||
|
|
3d8fd6687d | ||
|
|
ce887d0846 | ||
|
|
0057972c2f | ||
|
|
da3bc1f534 | ||
|
|
62cb78859c | ||
|
|
5d98678d86 | ||
|
|
431b9eb0bb | ||
|
|
f3d6f6bd11 | ||
|
|
2271304044 | ||
|
|
66266d1b4b | ||
|
|
e713cc2857 | ||
|
|
96973f7884 | ||
|
|
c3fb0ec094 | ||
|
|
d9ce927d88 | ||
|
|
870151cdd3 | ||
|
|
7ff2f6a6d0 | ||
|
|
6ff9d3a6a7 | ||
|
|
138077fa75 | ||
|
|
2789f0e1d9 | ||
|
|
39702cec9f | ||
|
|
ee949da604 | ||
|
|
922b4df8b5 | ||
|
|
928d504b27 | ||
|
|
a189ce98a0 | ||
|
|
3d7c76496f | ||
|
|
c16a9d1785 | ||
|
|
d2dd44af4d | ||
|
|
c9382136ba | ||
|
|
bed8c79c0a | ||
|
|
15cd88c461 | ||
|
|
a65dcdee3b | ||
|
|
2dcc861317 | ||
|
|
d51d6a9c3f | ||
|
|
9986dfa956 | ||
|
|
e720c6c5dd | ||
|
|
a33b6354bf | ||
|
|
e67db45548 | ||
|
|
ec61d5e721 | ||
|
|
1cabe42d83 | ||
|
|
dd63f5ddd0 | ||
|
|
ffa77ad386 | ||
|
|
d77e3dc82b | ||
|
|
2c4c1cf403 | ||
|
|
3b304959a9 | ||
|
|
f32dee8e58 | ||
|
|
8c0ff638c3 | ||
|
|
6c3a11388b | ||
|
|
ac1eaca0df | ||
|
|
7768e7a9e3 | ||
|
|
d3d7292b80 | ||
|
|
a85e843863 | ||
|
|
59c8268232 | ||
|
|
7351cd5c53 | ||
|
|
97ae8366c0 | ||
|
|
7782983fef | ||
|
|
6b155d70b3 | ||
|
|
24aaf8661c | ||
|
|
4d089d004c | ||
|
|
281094fb7b | ||
|
|
06f8fec1ab | ||
|
|
e006cb1c5e | ||
|
|
c74690f68b | ||
|
|
5e232fd0af | ||
|
|
accbbe31d9 | ||
|
|
06844e4b81 | ||
|
|
b1996d153e | ||
|
|
b9ed209e5d | ||
|
|
ed5edefcc4 | ||
|
|
64455066a8 | ||
|
|
4acb8ad001 | ||
|
|
05ff869183 | ||
|
|
3a5a95cba9 | ||
|
|
880032bc28 | ||
|
|
24f0365513 | ||
|
|
b256e3b7dc | ||
|
|
f483dbe17e | ||
|
|
569b9df7f2 | ||
|
|
ae5a159d31 | ||
|
|
7f64c80b77 | ||
|
|
591127b5b6 | ||
|
|
1aa57e3e3e | ||
|
|
881e3b7775 | ||
|
|
8c1171846d | ||
|
|
a64146e227 | ||
|
|
22e6f365b0 | ||
|
|
fadaf6765c | ||
|
|
637a32314a | ||
|
|
59105c6d8a | ||
|
|
33a918d02b | ||
|
|
de7a0a85f6 | ||
|
|
8f91f480eb | ||
|
|
f66c8a8eb6 | ||
|
|
d4526487ed | ||
|
|
32341b0311 | ||
|
|
0f45a25b25 | ||
|
|
7099ad53c5 | ||
|
|
0f3beba354 | ||
|
|
260584bf89 | ||
|
|
a8132e9f13 | ||
|
|
ccc188a8c0 | ||
|
|
446bded5f9 | ||
|
|
c644c05933 | ||
|
|
53cca29b67 | ||
|
|
396519e5f9 | ||
|
|
dd2a0bc333 | ||
|
|
797887b23d | ||
|
|
8def3ee391 | ||
|
|
e118debc6b | ||
|
|
de13fa0b4a | ||
|
|
bf6deadbc0 | ||
|
|
46a4ac9c15 | ||
|
|
60012c63c3 | ||
|
|
c3122072da | ||
|
|
ab1df4d692 | ||
|
|
234717b23c | ||
|
|
9fd72c6ea4 | ||
|
|
9b70b09173 | ||
|
|
2b8487432f | ||
|
|
b4a5283547 | ||
|
|
69d6a77ff1 | ||
|
|
475a1c7052 | ||
|
|
c49a5e558f | ||
|
|
51791a3b34 | ||
|
|
2790026475 | ||
|
|
ed37808d33 | ||
|
|
f066aa88f0 | ||
|
|
3451f75b37 | ||
|
|
be3f6ba5d4 | ||
|
|
516ab77d58 | ||
|
|
6eaac7a745 | ||
|
|
ab9755ade5 | ||
|
|
e0504ea0c2 | ||
|
|
08459ac627 | ||
|
|
08c51473a7 | ||
|
|
a0e95aca3e | ||
|
|
4c3647fe30 | ||
|
|
4c907c8ba5 | ||
|
|
ae81344fe2 | ||
|
|
7390ae6116 | ||
|
|
090db4205a | ||
|
|
543db51291 | ||
|
|
8e93a0aba2 | ||
|
|
eab9565c7d | ||
|
|
dfb70cc5ce | ||
|
|
e89f00e2f9 | ||
|
|
9bc03eb46a | ||
|
|
3e43966357 | ||
|
|
b3cffe3008 | ||
|
|
8e1e8e3b7c | ||
|
|
639675c266 | ||
|
|
de08e5396a | ||
|
|
669fa6aa16 | ||
|
|
ba7146cca7 | ||
|
|
afb630d053 | ||
|
|
056f42b815 | ||
|
|
8426755db3 | ||
|
|
319f143327 | ||
|
|
04e45f3b83 | ||
|
|
6ae4fd1cdd | ||
|
|
da20be4558 | ||
|
|
b8ccef3fb5 | ||
|
|
2db242d43a | ||
|
|
ad3157807c | ||
|
|
efd87bf5cd | ||
|
|
7bf6ffe2f8 | ||
|
|
6a0125eeaf | ||
|
|
897e92d8f0 | ||
|
|
238127bc16 | ||
|
|
232804fb39 | ||
|
|
20654b2eff | ||
|
|
a7b8de3205 | ||
|
|
b7cd27be7e | ||
|
|
99655b0d84 | ||
|
|
6c4d03eb6b | ||
|
|
1f077cfdd2 | ||
|
|
60d1ec1364 | ||
|
|
1eb75b5782 | ||
|
|
457dd6679b | ||
|
|
bd4dceace6 | ||
|
|
b1a0edb474 | ||
|
|
4ae2905b48 | ||
|
|
59a5a4fde9 | ||
|
|
c83b626b9a | ||
|
|
9e271f8a3e | ||
|
|
d6a8fd3010 | ||
|
|
d5f1c7f163 | ||
|
|
016017ab30 | ||
|
|
23da5640c7 | ||
|
|
83a401bd15 | ||
|
|
5e846a8896 | ||
|
|
feef269015 | ||
|
|
d142979e49 | ||
|
|
feb901c9e8 | ||
|
|
fd65cfdc1c | ||
|
|
2c606d4fe7 | ||
|
|
347522a429 | ||
|
|
fdc4819c2e | ||
|
|
dea69e018e | ||
|
|
67048d7f4b | ||
|
|
5b01f2e9f4 | ||
|
|
ad0f51c405 | ||
|
|
901c6ab68e | ||
|
|
827ade852e | ||
|
|
55f332d28e | ||
|
|
71fc82a0e7 | ||
|
|
3c2128b9b7 | ||
|
|
f353e0c964 | ||
|
|
8341021ba5 | ||
|
|
86b7996d75 | ||
|
|
8e3f189e77 | ||
|
|
75e156ae07 | ||
|
|
294c3581f9 | ||
|
|
41cf8a5a44 | ||
|
|
adfe2a9fe1 | ||
|
|
9cf93d93c7 | ||
|
|
a3c418de46 | ||
|
|
8932c90c8a | ||
|
|
b3222f0f46 | ||
|
|
47d433eecb | ||
|
|
081cd66a8e | ||
|
|
2c94483cd9 | ||
|
|
2cf024fe3e | ||
|
|
219c71a99b | ||
|
|
5787d5fac3 | ||
|
|
7add68c780 | ||
|
|
4fdf38827d | ||
|
|
ded8e85c85 | ||
|
|
0d926d4b95 | ||
|
|
fd8c47cd95 | ||
|
|
ab50743c01 | ||
|
|
5a41d2e028 | ||
|
|
a7b9ce803b | ||
|
|
42a98f3435 | ||
|
|
c691f81ebb | ||
|
|
ef775c70fe | ||
|
|
a2e96cef5a | ||
|
|
56c9139d0c | ||
|
|
3c929f5c64 | ||
|
|
223cfe086c | ||
|
|
1c00dbdb85 | ||
|
|
70fbc02918 | ||
|
|
3d6597a246 | ||
|
|
eb7a5c7894 | ||
|
|
ed5376cb43 | ||
|
|
0f8ce7deea |
No files matched your search
Executable
+26
@@ -0,0 +1,26 @@
|
||||
DB_CONNECTION=
|
||||
DB_HOST=
|
||||
DB_PORT=
|
||||
DB_DATABASE=
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
DB_ROOT_PASSWORD=
|
||||
|
||||
TYPESENSE_API_KEY=
|
||||
|
||||
#Mettre à 1 quand vous êtes en développement et à rien en production
|
||||
DEV=
|
||||
|
||||
USER_ID=1000
|
||||
GROUP_ID=1000
|
||||
|
||||
VITE_API_URL=http://localhost:80
|
||||
VITE_BROADCASTER=reverb
|
||||
VITE_REVERB_KEY=local
|
||||
VITE_REVERB_HOST=127.0.0.1
|
||||
VITE_REVERB_PORT=8080
|
||||
VITE_FORCE_TLS=false
|
||||
VITE_DISABLE_STATS=true
|
||||
VITE_ENCRYPTED=false
|
||||
VITE_CLUSTER=mt1
|
||||
VITE_ENABLED_TRANSPORTS=['ws','wss']
|
||||
Regular → Executable
+2
-28
@@ -1,29 +1,3 @@
|
||||
.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
|
||||
.env
|
||||
backups/
|
||||
@@ -1,16 +1,203 @@
|
||||
# React + Vite
|
||||
# Gestion des bénévoles - Comité des fêtes de Beaupont
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
## Présentation du projet
|
||||
|
||||
Currently, two official plugins are available:
|
||||
L'association organise régulièrement des événements et projets mobilisant des bénévoles, mais sa coordination interne est rendue difficile par l'usage d'outils dispersés, et non communicants.
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
La création d'une plateforme web unique vise donc à centraliser et simplifier la gestion des utilisateurs, des rôles, des événements, des tâches et de la communication. Elle vise à améliorer la collaboration entre tous les bénévoles de l'association.
|
||||
|
||||
## React Compiler
|
||||
## Objectifs de l’application
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
L’application a pour objectifs principaux de :
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
- Gérer les utilisateurs et leurs rôles au sein de l’association.
|
||||
- Organiser et planifier les événements et les tâches associées.
|
||||
- Permettre aux bénévoles de s’inscrire en ligne aux événements et aux tâches.
|
||||
- Offrir aux responsables un tableau de bord pour suivre la participation et les besoins en ressources humaines.
|
||||
- Centraliser les informations et la communication autour des projets associatifs.
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
## Prérequis
|
||||
|
||||
Comme notre architecture se base sur l'utilisation de Docker, les seules prérequis pour la machine sur laquelle vous souhaitez installer cette application sont :
|
||||
- [Docker](https://www.docker.com/)
|
||||
- [Git](https://git-scm.com/)
|
||||
|
||||
## Installation
|
||||
|
||||
Pour installer ce projet il vous suffit de cloner le dépôt avec la commande suivante :
|
||||
|
||||
```bash
|
||||
git clone <adresse du dépôt>
|
||||
```
|
||||
|
||||
## Initialisation du projet
|
||||
|
||||
### 1. Configuration du fichier `.env` principal
|
||||
|
||||
1. Créez un fichier `.env` à la racine du projet.
|
||||
2. Copiez le contenu du fichier `.env.example` dans le fichier `.env`.
|
||||
3. Renseignez les variables suivantes :
|
||||
|
||||
| Variable | Description |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `DB_CONNECTION` | Type de base de données utilisée (ex : `mysql`, `mariadb`) |
|
||||
| `DB_HOST` | Adresse du serveur de base de données (ex : `localhost`, `db`) |
|
||||
| `DB_PORT` | Port de la base de données (ex : `3306` pour MySQL/MariaDB) |
|
||||
| `DB_DATABASE` | Nom de la base de données |
|
||||
| `DB_USERNAME` | Nom d’utilisateur de la base de données |
|
||||
| `DB_PASSWORD` | Mot de passe de l’utilisateur de la base de données |
|
||||
| `DB_ROOT_PASSWORD` | Mot de passe du compte root de la base de données |
|
||||
| `DEV` | Mettre `1` en environnement de développement, laisser vide sinon. |
|
||||
| `VITE_API_URL` | URL du frontend hébergé et exposé par le conteneur Nginx (par défaut sur le port 80) |
|
||||
|
||||
### 2. Configuration du fichier `.env` php
|
||||
|
||||
Répétez la même opération pour le fichier `docker/php/.env` en copiant depuis `docker/php/.env.example`.
|
||||
|
||||
De plus, un utilisateur administrateur est automatiquement créé avec les informations suivantes :
|
||||
- **Prénom :** `admin`
|
||||
- **Nom :** `admin`
|
||||
- **Adresse e-mail :** `admin@mail.com`
|
||||
- **Mot de passe :** `admin`
|
||||
- **Numéro de téléphone :** `0909090909`
|
||||
|
||||
> Il est bien sûr possible de modifier ces valeurs dans le fichier `docker/php/.env` avant le premier lancement du seeder, en utilisant les variables : `ADMIN_NAME`, `ADMIN_LASTNAME`, `ADMIN_MAIL`, `ADMIN_PASSWORD` et `ADMIN_PHONE_NUMBER`
|
||||
|
||||
### 3. Note importante
|
||||
|
||||
> ⚠️ Si vous êtes sous **Windows**, assurez-vous que tous les fichiers `.sh` utilisent des fins de ligne **LF** et non **CRLF**, sous peine d’erreurs lors de l’exécution des scripts.
|
||||
|
||||
## Lancement
|
||||
|
||||
Une fois la configuration terminée :
|
||||
|
||||
1. Ouvrez un terminal.
|
||||
2. Placez-vous à la racine du projet.
|
||||
3. Exécutez les commandes suivantes dans l'ordre :
|
||||
|
||||
```bash
|
||||
docker compose down -v
|
||||
```
|
||||
> Arrête et supprime les conteneurs existants ainsi que les volumes associés.
|
||||
> Cette étape permet de repartir sur une base propre.
|
||||
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
```
|
||||
> Reconstruit les images Docker et démarre l’ensemble des services en arrière-plan.
|
||||
|
||||
|
||||
## Point technique
|
||||
|
||||
### 1. Le nommage
|
||||
|
||||
Nous avons adopté une convention de nommage en **camelCase** pour les variables, fonctions et fichiers JavaScript côté frontend.
|
||||
Pour les composants React, nous utilisons la convention **PascalCase** afin de les différencier des éléments HTML.
|
||||
|
||||
Côté backend (Laravel), nous respectons les conventions PHP :
|
||||
- **camelCase** pour les variables et méthodes
|
||||
- **PascalCase** pour les classes (Controllers, Models, Policies, etc.)
|
||||
|
||||
Les noms sont choisis de manière explicite et descriptive afin de faciliter la compréhension du code et sa maintenance.
|
||||
|
||||
### 2. Les commentaires
|
||||
|
||||
Nous avons fait le choix de limiter l’utilisation des commentaires dans le code. En effet, nous privilégions un code clair, lisible et auto-documenté, notamment grâce à :
|
||||
- un nommage explicite des variables, fonctions et classes
|
||||
- l’utilisation du typage lorsque cela est possible
|
||||
- une structure de projet organisée
|
||||
- une documentation externe (README, Storybook, Bruno)
|
||||
|
||||
Les commentaires sont donc utilisés uniquement lorsque cela apporte une réelle valeur ajoutée, par exemple pour expliquer une logique complexe, un choix technique spécifique ou un comportement non évident.
|
||||
|
||||
### 3. La documentation
|
||||
|
||||
La documentation du projet est assurée à plusieurs niveaux :
|
||||
- Un **README** structuré expliquant l’installation, la configuration et le fonctionnement global
|
||||
- Une documentation des routes API via **Bruno**
|
||||
- L’utilisation de **Storybook** pour documenter et tester visuellement les composants UI
|
||||
|
||||
### 4. La programmation défensive
|
||||
|
||||
Nous avons appliqué la programmation défensive afin de rendre notre application plus robuste, sécurisée et fiable face aux erreurs potentielles.
|
||||
|
||||
Dans notre projet, cela se traduit notamment par :
|
||||
- Validation des données côté backend (Laravel) avant utilisation
|
||||
- Vérification des entrées utilisateur afin d’éviter les données incohérentes ou malveillantes
|
||||
- Gestion des rôles et permissions pour empêcher l’accès à des ressources non autorisées (utilisation de policies Laravel)
|
||||
- Gestion des cas d’erreur (ex : utilisateur inexistant, tâche non trouvée, accès interdit) avec des réponses HTTP adaptées
|
||||
- Utiliser des valeurs par défaut ou des vérifications avant utilisation pour éviter les erreurs inattendues
|
||||
|
||||
Enfin, grâce à Docker, nous limitons les problèmes liés à l’environnement (configuration, versions, dépendances), ce qui contribue également à une approche défensive globale du projet.
|
||||
|
||||
### 5. La gestion des erreurs
|
||||
|
||||
La gestion des erreurs est assurée à plusieurs niveaux :
|
||||
- Backend Laravel : gestion des exceptions et retour de codes HTTP appropriés (200, 401, 404, 422, etc.)
|
||||
- Frontend React : gestion des erreurs utilisateur (formulaires, affichage de messages d’erreur)
|
||||
|
||||
### 6. Le débogage
|
||||
|
||||
Le débogage a été réalisé grâce à plusieurs outils et méthodes :
|
||||
- Utilisation des outils de développement du navigateur (console, réseau)
|
||||
- Tests des routes API avec Bruno
|
||||
- Logs côté docker et backend pour analyser le comportement du serveur
|
||||
- Par exemple un membre de notre groupe rencontré quelques problèmes lors du lancement des conteneurs docker. Il a donc accédé aux logs du conteneur en question, qui indiquait un problème de clonage du repo git : `unable to access to {url du depot git}` (cela peut être du a un `Personal Access Token` expiré, ou une mauvaise connexion internet)
|
||||
- Tests manuels réguliers lors du développement
|
||||
|
||||
### 7. L'architecture
|
||||
|
||||
Nous avons choisi d’adopter une architecture basée sur trois dépôts Git distincts, afin de séparer clairement les responsabilités et de faciliter la maintenance du projet :
|
||||
- **Dépôt frontend** : contient le code de l’application développée en React
|
||||
- **Dépôt backend** : contient le code de l’API développée avec Laravel
|
||||
- **Dépôt Docker** : contient toute la configuration nécessaire à l’installation et au déploiement du projet sur n’importe quelle machine
|
||||
|
||||
Ce troisième dépôt permet de déployer l’ensemble de l’application de manière reproductible grâce à Docker, en centralisant la configuration des services.
|
||||
Notre environnement de déploiement repose sur plusieurs conteneurs Docker :
|
||||
- **Backend (Laravel)** : gestion de la logique métier et de l’API
|
||||
- **Frontend (React)** : interface utilisateur (version temporaire pour le déploiement)
|
||||
- **Base de données (MariaDB)** : stockage des données
|
||||
- **Nginx** : serveur web utilisé pour exposer les services et gérer les requêtes HTTP
|
||||
- **Typesense** : moteur de recherche utilisé pour améliorer les performances des recherches
|
||||
- **Backup** : conteneur dédié à la sauvegarde de la base de données
|
||||
- **Serveur WebSocket (Laravel Reverb)** : gestion des communications en temps réel
|
||||
|
||||
> Un schéma du fonctionnement global de l'application est disponible dans le dossier final de rendus.
|
||||
|
||||
|
||||
### 8. Concepts de programmation
|
||||
|
||||
Nous avons appliqué plusieurs concepts de programmation :
|
||||
- Programmation orientée objet (POO) côté backend (Laravel)
|
||||
- Composants réutilisables côté frontend (React)
|
||||
- Gestion d’état via les Contexts React
|
||||
- API REST pour la communication entre frontend et backend
|
||||
- Programmation modulaire pour une meilleure organisation du code
|
||||
|
||||
Pour améliorer la qualité et la robustesse du code, nous avons migré une partie du projet de JavaScript vers TypeScript.
|
||||
Cette conversion permet :
|
||||
- Moins d’erreurs grâce au typage statique.
|
||||
- Un code plus lisible et documenté avec des interfaces claires.
|
||||
- Une meilleure collaboration grâce à des types explicites.
|
||||
Les interfaces TypeScript sont regroupées dans des fichiers dédiés, ce qui centralise les définitions et simplifie les mises à jour.
|
||||
|
||||
|
||||
### 9. Tests unitaires
|
||||
|
||||
Nous avons mis en place quelques tests unitaires sur certaines fonctions utilitaires, par exemple :
|
||||
- `utils/auth/login.test.js`
|
||||
- `utils/auth/logout.test.js`
|
||||
|
||||
Suite à un échange avec notre professeur, il nous a été indiqué qu’un nombre limité de tests suffisait pour démontrer notre compréhension et notre mise en pratique de ce concept. En effet, tester l’ensemble du projet aurait demandé un temps de développement trop important au regard des contraintes du projet.
|
||||
|
||||
Nous avons donc choisi de nous concentrer sur quelques cas représentatifs, afin de valider notre approche des tests unitaires tout en respectant les délais impartis.
|
||||
|
||||
### 10. Intégration continu
|
||||
|
||||
Dans notre projet, l’intégration continue repose sur les outils et pratiques utilisés tout au long du développement.
|
||||
|
||||
Nous avons mis en place tous les outils qui permettent à termes l'intégration continu de l'application :
|
||||
- Utilisation de Git pour gérer les versions du projet et intégrer régulièrement les modifications de chaque membre de l’équipe
|
||||
- Utilisation de Docker pour garantir un environnement de développement et de déploiement identique et reproductible
|
||||
- Tests réguliers des fonctionnalités à chaque ajout de code (tests manuels et tests API avec Bruno)
|
||||
- Validation continue du projet, afin de s’assurer qu’une version fonctionnelle reste disponible à tout moment
|
||||
Executable
+18
@@ -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
@@ -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
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
.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
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
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
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\EventParticipationCancelledMail;
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use App\Notifications\EventDeleted;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
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
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Typesense\Client;
|
||||
|
||||
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
@@ -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\Models\Event;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Notifications\TaskDateUpdated;
|
||||
use App\Notifications\TaskDeleted;
|
||||
use App\Notifications\VolunteerAssignedToTask;
|
||||
use App\Notifications\VolunteerUnassignedFromTask;
|
||||
use App\Services\FormatDate;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
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
@@ -0,0 +1,495 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\CreateUserByAdminMail;
|
||||
use App\Mail\DeactivateAccountMail;
|
||||
use App\Mail\DeleteAccountMail;
|
||||
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\Mail\ValidateMail;
|
||||
use App\Models\User;
|
||||
use App\Notifications\UserRegistered;
|
||||
use App\Notifications\VolunteerRoleUpdated;
|
||||
use App\Services\GetRole;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Pest\Support\Str;
|
||||
use Propaganistas\LaravelPhone\PhoneNumber;
|
||||
|
||||
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']);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Services\FormatDate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Services\FormatDate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Services\FormatDate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Services\FormatDate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class VolunteerUnassignToTaskMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: 'Désassignation - Comité des fêtes de Beaupont',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'mails.volunteerUnassignToTask',
|
||||
with: [
|
||||
'name' => $this->data['name'],
|
||||
'lastname' => $this->data['lastname'],
|
||||
'taskName' => $this->data['taskName'],
|
||||
'start' => FormatDate::formatDate($this->data['start']),
|
||||
'end' => FormatDate::formatDate($this->data['end']),
|
||||
'eventName' => $this->data['eventName'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -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');
|
||||
}
|
||||
}
|
||||
Executable
+26
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<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);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Event;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class VolunteerRoleUpdated extends Notification implements ShouldBroadcast
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(public string $role) {}
|
||||
|
||||
public function via($notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
|
||||
if ($notifiable->web_notifications) {
|
||||
$channels[] = 'database';
|
||||
$channels[] = 'broadcast';
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
|
||||
public function toDatabase($notifiable): array
|
||||
{
|
||||
return [
|
||||
'message' => "Votre rôle a changé pour : {$this->role}",
|
||||
'role' => $this->role,
|
||||
];
|
||||
}
|
||||
|
||||
public function toBroadcast($notifiable): BroadcastMessage
|
||||
{
|
||||
return new BroadcastMessage($this->toDatabase($notifiable));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
Executable
+24
@@ -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);
|
||||
}
|
||||
}
|
||||
Executable
+24
@@ -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);
|
||||
}
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\User;
|
||||
use App\Observers\EventObserver;
|
||||
use App\Observers\UserObserver;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
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($this->app->basePath('routes/users.php'));
|
||||
Route::middleware('web')->prefix('api')
|
||||
->group($this->app->basePath('routes/auth.php'));
|
||||
Route::middleware('web')->prefix('api')
|
||||
->group($this->app->basePath('routes/events.php'));
|
||||
Route::middleware('web')->prefix('api')
|
||||
->group($this->app->basePath('routes/notifications.php'));
|
||||
Route::middleware('web')->prefix('api')
|
||||
->group($this->app->basePath('routes/channels.php'));
|
||||
User::observe(UserObserver::class);
|
||||
Event::observe(EventObserver::class);
|
||||
}
|
||||
}
|
||||
+16
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+25
@@ -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"
|
||||
];
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\User;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
use App\Models\User;
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__ . '/bootstrap/app.php';
|
||||
|
||||
$status = $app->handleCommand(new ArgvInput);
|
||||
|
||||
exit($status);
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__ . '/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
channels: __DIR__.'/../routes/channels.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
$middleware->statefulApi();
|
||||
$middleware->validateCsrfTokens(except: [
|
||||
'broadcasting/auth',
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
})->create();
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
app\Providers\AppServiceProvider::class,
|
||||
app\Providers\BroadcastServiceProvider::class,
|
||||
app\Providers\GateServiceProvider::class,
|
||||
];
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"framework"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/reverb": "^1.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"propaganistas/laravel-phone": "^6.0",
|
||||
"typesense/typesense-php": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/pail": "^1.2.2",
|
||||
"laravel/pint": "^1.24",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"pestphp/pest": "^4.1",
|
||||
"pestphp/pest-plugin-laravel": "^4.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"setup": [
|
||||
"composer install",
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||
"@php artisan key:generate",
|
||||
"@php artisan migrate --force",
|
||||
"npm install",
|
||||
"npm run build"
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd\" \"php artisan serve --host=localhost --port=8000\" \"php artisan pail --timeout=0\" --names=server,logs --kill-others"
|
||||
],
|
||||
"test": [
|
||||
"@php artisan config:clear --ansi",
|
||||
"@php artisan test"
|
||||
],
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
],
|
||||
"pre-package-uninstall": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true,
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
+11174
File diff suppressed because it is too large.
Load diff
Executable
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value is the name of your application, which will be used when the
|
||||
| framework needs to place the application's name in a notification or
|
||||
| other UI elements where an application name needs to be displayed.
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Environment
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the "environment" your application is currently
|
||||
| running in. This may determine how you prefer to configure various
|
||||
| services the application utilizes. Set this in your ".env" file.
|
||||
|
|
||||
*/
|
||||
|
||||
'env' => env('APP_ENV', 'production'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Debug Mode
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When your application is in debug mode, detailed error messages with
|
||||
| stack traces will be shown on every error that occurs within your
|
||||
| application. If disabled, a simple generic error page is shown.
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL is used by the console to properly generate URLs when using
|
||||
| the Artisan command line tool. You should set this to the root of
|
||||
| the application so that it's available within Artisan commands.
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default timezone for your application, which
|
||||
| will be used by the PHP date and date-time functions. The timezone
|
||||
| is set to "UTC" by default as it is suitable for most use cases.
|
||||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'UTC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Locale Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The application locale determines the default locale that will be used
|
||||
| by Laravel's translation / localization methods. This option can be
|
||||
| set to any locale for which you plan to have translation strings.
|
||||
|
|
||||
*/
|
||||
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
||||
|
||||
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This key is utilized by Laravel's encryption services and should be set
|
||||
| to a random, 32 character string to ensure that all encrypted values
|
||||
| are secure. You should do this prior to deploying the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
'key' => env('APP_KEY'),
|
||||
|
||||
'previous_keys' => [
|
||||
...array_filter(
|
||||
explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
|
||||
),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maintenance Mode Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options determine the driver used to determine and
|
||||
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||
| allow maintenance mode to be controlled across multiple machines.
|
||||
|
|
||||
| Supported drivers: "file", "cache"
|
||||
|
|
||||
*/
|
||||
|
||||
'maintenance' => [
|
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
'typesense_api_key' => env('TYPESENSE_API_KEY'),
|
||||
'typesense_connection' => env('TYPESENSE_CONNECTION'),
|
||||
|
||||
'dev' => env('DEV'),
|
||||
|
||||
'admin_name' => env('ADMIN_NAME') ?:'admin',
|
||||
'admin_lastname' => env('ADMIN_LASTNAME') ?: 'admin',
|
||||
'admin_email' => env('ADMIN_MAIL') ?: 'admin@mail.com',
|
||||
'admin_password' => env('ADMIN_PASSWORD') ?: 'admin',
|
||||
'admin_phone' => env('ADMIN_PHONE_NUMBER') ?: '0102030405',
|
||||
|
||||
'vite_api_url' => env('VITE_API_URL') ?: 'http://localhost:80',
|
||||
|
||||
];
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Defaults
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default authentication "guard" and password
|
||||
| reset "broker" for your application. You may change these values
|
||||
| as required, but they're a perfect start for most applications.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => env('AUTH_GUARD', 'web'),
|
||||
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, you may define every authentication guard for your application.
|
||||
| Of course, a great default configuration has been defined for you
|
||||
| which utilizes session storage plus the Eloquent user provider.
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| Supported: "session"
|
||||
|
|
||||
*/
|
||||
|
||||
'guards' => [
|
||||
'web' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| If you have multiple user tables or models you may configure multiple
|
||||
| providers to represent the model / table. These providers may then
|
||||
| be assigned to any extra authentication guards you have defined.
|
||||
|
|
||||
| Supported: "database", "eloquent"
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// 'driver' => 'database',
|
||||
// 'table' => 'users',
|
||||
// ],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resetting Passwords
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options specify the behavior of Laravel's password
|
||||
| reset functionality, including the table utilized for token storage
|
||||
| and the user provider that is invoked to actually retrieve users.
|
||||
|
|
||||
| The expiry time is the number of minutes that each reset token will be
|
||||
| considered valid. This security feature keeps tokens short-lived so
|
||||
| they have less time to be guessed. You may change this as needed.
|
||||
|
|
||||
| The throttle setting is the number of seconds a user must wait before
|
||||
| generating more password reset tokens. This prevents the user from
|
||||
| quickly generating a very large amount of password reset tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'users',
|
||||
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Confirmation Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the number of seconds before a password confirmation
|
||||
| window expires and users are asked to re-enter their password via the
|
||||
| confirmation screen. By default, the timeout lasts for three hours.
|
||||
|
|
||||
*/
|
||||
|
||||
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||
|
||||
];
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Broadcaster
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default broadcaster that will be used by the
|
||||
| framework when an event needs to be broadcast. You may set this to
|
||||
| any of the connections defined in the "connections" array below.
|
||||
|
|
||||
| Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('BROADCAST_CONNECTION', 'null'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Broadcast Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the broadcast connections that will be used
|
||||
| to broadcast events to other systems or over WebSockets. Samples of
|
||||
| each available type of connection are provided inside this array.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'reverb' => [
|
||||
'driver' => 'reverb',
|
||||
'key' => env('REVERB_APP_KEY'),
|
||||
'secret' => env('REVERB_APP_SECRET'),
|
||||
'app_id' => env('REVERB_APP_ID'),
|
||||
'options' => [
|
||||
'host' => env('REVERB_HOST'),
|
||||
'port' => env('REVERB_PORT', 443),
|
||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'pusher' => [
|
||||
'driver' => 'pusher',
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
||||
'port' => env('PUSHER_PORT', 443),
|
||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||
'encrypted' => true,
|
||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'ably' => [
|
||||
'driver' => 'ably',
|
||||
'key' => env('ABLY_KEY'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'driver' => 'log',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'null',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default cache store that will be used by the
|
||||
| framework. This connection is utilized if another isn't explicitly
|
||||
| specified when running a cache operation inside the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_STORE', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Stores
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the cache "stores" for your application as
|
||||
| well as their drivers. You may even define multiple stores for the
|
||||
| same cache driver to group types of items stored in your caches.
|
||||
|
|
||||
| Supported drivers: "array", "database", "file", "memcached",
|
||||
| "redis", "dynamodb", "octane", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'stores' => [
|
||||
|
||||
'array' => [
|
||||
'driver' => 'array',
|
||||
'serialize' => false,
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_CACHE_CONNECTION'),
|
||||
'table' => env('DB_CACHE_TABLE', 'cache'),
|
||||
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
|
||||
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
|
||||
],
|
||||
|
||||
'file' => [
|
||||
'driver' => 'file',
|
||||
'path' => storage_path('framework/cache/data'),
|
||||
'lock_path' => storage_path('framework/cache/data'),
|
||||
],
|
||||
|
||||
'memcached' => [
|
||||
'driver' => 'memcached',
|
||||
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||
'sasl' => [
|
||||
env('MEMCACHED_USERNAME'),
|
||||
env('MEMCACHED_PASSWORD'),
|
||||
],
|
||||
'options' => [
|
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||
],
|
||||
'servers' => [
|
||||
[
|
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||
'port' => env('MEMCACHED_PORT', 11211),
|
||||
'weight' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
|
||||
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
|
||||
],
|
||||
|
||||
'dynamodb' => [
|
||||
'driver' => 'dynamodb',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||
],
|
||||
|
||||
'octane' => [
|
||||
'driver' => 'octane',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Key Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
|
||||
| stores, there might be other applications using the same cache. For
|
||||
| that reason, you may prefix every cache key to avoid collisions.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'),
|
||||
|
||||
];
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your settings for cross-origin resource sharing
|
||||
| or "CORS". This determines what cross-origin operations may execute
|
||||
| in web browsers. You are free to adjust these settings as needed.
|
||||
|
|
||||
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
'paths' => explode(',', env('CORS_PATHS', 'api/*')),
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => env('DEV', 0) == 1
|
||||
? explode(',', env('DEV_CORS_ALLOWED_ORIGINS'))
|
||||
: explode(',', env('PROD_CORS_ALLOWED_ORIGINS')),
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
'allowed_headers' => ['*'],
|
||||
|
||||
'exposed_headers' => [],
|
||||
|
||||
'max_age' => 0,
|
||||
|
||||
'supports_credentials' => true,
|
||||
|
||||
];
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Database Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the database connections below you wish
|
||||
| to use as your default connection for database operations. This is
|
||||
| the connection which will be utilized unless another connection
|
||||
| is explicitly specified when you execute a query / statement.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below are all of the database connections defined for your application.
|
||||
| An example configuration is provided for each database system which
|
||||
| is supported by Laravel. You're free to add / remove connections.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'url' => env('DB_URL'),
|
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||
'prefix' => '',
|
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||
'busy_timeout' => null,
|
||||
'journal_mode' => null,
|
||||
'synchronous' => null,
|
||||
'transaction_mode' => 'DEFERRED',
|
||||
],
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'mariadb' => [
|
||||
'driver' => 'mariadb',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '5432'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'search_path' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'port' => env('DB_PORT', '1433'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migration Repository Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This table keeps track of all the migrations that have already run for
|
||||
| your application. Using this information, we can determine which of
|
||||
| the migrations on disk haven't actually been run on the database.
|
||||
|
|
||||
*/
|
||||
|
||||
'migrations' => [
|
||||
'table' => 'migrations',
|
||||
'update_date_on_publish' => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis Databases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Redis is an open source, fast, and advanced key-value store that also
|
||||
| provides a richer body of commands than a typical key-value system
|
||||
| such as Memcached. You may define your connection settings here.
|
||||
|
|
||||
*/
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-database-'),
|
||||
'persistent' => env('REDIS_PERSISTENT', false),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
'max_retries' => env('REDIS_MAX_RETRIES', 3),
|
||||
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
|
||||
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
|
||||
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
'max_retries' => env('REDIS_MAX_RETRIES', 3),
|
||||
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
|
||||
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
|
||||
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Filesystem Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default filesystem disk that should be used
|
||||
| by the framework. The "local" disk, as well as a variety of cloud
|
||||
| based disks are available to your application for file storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filesystem Disks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below you may configure as many filesystem disks as necessary, and you
|
||||
| may even configure multiple disks for the same driver. Examples for
|
||||
| most supported storage drivers are configured here for reference.
|
||||
|
|
||||
| Supported drivers: "local", "ftp", "sftp", "s3"
|
||||
|
|
||||
*/
|
||||
|
||||
'disks' => [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/private'),
|
||||
'serve' => true,
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Symbolic Links
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the symbolic links that will be created when the
|
||||
| `storage:link` Artisan command is executed. The array keys should be
|
||||
| the locations of the links and the values should be their targets.
|
||||
|
|
||||
*/
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
use Monolog\Processor\PsrLogMessageProcessor;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that is utilized to write
|
||||
| messages to your logs. The value provided here should match one of
|
||||
| the channels present in the list of "channels" configured below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Deprecations Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the log channel that should be used to log warnings
|
||||
| regarding deprecated PHP and library features. This allows you to get
|
||||
| your application ready for upcoming major versions of dependencies.
|
||||
|
|
||||
*/
|
||||
|
||||
'deprecations' => [
|
||||
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
|
||||
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Laravel
|
||||
| utilizes the Monolog PHP logging library, which includes a variety
|
||||
| of powerful log handlers and formatters that you're free to use.
|
||||
|
|
||||
| Available drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog", "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => explode(',', (string) env('LOG_STACK', 'single')),
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'days' => env('LOG_DAILY_DAYS', 14),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
|
||||
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
|
||||
'level' => env('LOG_LEVEL', 'critical'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => StreamHandler::class,
|
||||
'handler_with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mailer that is used to send all email
|
||||
| messages unless another mailer is explicitly specified when sending
|
||||
| the message. All additional mailers can be configured within the
|
||||
| "mailers" array. Examples of each type of mailer are provided.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_MAILER', 'log'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mailer Configurations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure all of the mailers used by your application plus
|
||||
| their respective settings. Several examples have been configured for
|
||||
| you and you are free to add your own as your application requires.
|
||||
|
|
||||
| Laravel supports a variety of mail "transport" drivers that can be used
|
||||
| when delivering an email. You may specify which one you're using for
|
||||
| your mailers below. You may also add additional mailers if needed.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
|
||||
| "postmark", "resend", "log", "array",
|
||||
| "failover", "roundrobin"
|
||||
|
|
||||
*/
|
||||
|
||||
'mailers' => [
|
||||
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'scheme' => env('MAIL_SCHEME'),
|
||||
'url' => env('MAIL_URL'),
|
||||
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||
'port' => env('MAIL_PORT', 2525),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
||||
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url((string) env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'transport' => 'resend',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'transport' => 'array',
|
||||
],
|
||||
|
||||
'failover' => [
|
||||
'transport' => 'failover',
|
||||
'mailers' => [
|
||||
'smtp',
|
||||
'log',
|
||||
],
|
||||
'retry_after' => 60,
|
||||
],
|
||||
|
||||
'roundrobin' => [
|
||||
'transport' => 'roundrobin',
|
||||
'mailers' => [
|
||||
'ses',
|
||||
'postmark',
|
||||
],
|
||||
'retry_after' => 60,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global "From" Address
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may wish for all emails sent by your application to be sent from
|
||||
| the same address. Here you may specify a name and address that is
|
||||
| used globally for all emails that are sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+112
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue supports a variety of backends via a single, unified
|
||||
| API, giving you convenient access to each backend using identical
|
||||
| syntax for each. The default queue connection is defined below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the connection options for every queue backend
|
||||
| used by your application. An example configuration is provided for
|
||||
| each backend supported by Laravel. You're also free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sync' => [
|
||||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_QUEUE_CONNECTION'),
|
||||
'table' => env('DB_QUEUE_TABLE', 'jobs'),
|
||||
'queue' => env('DB_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
|
||||
'queue' => env('BEANSTALKD_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => 0,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'default'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => null,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Batching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following options configure the database and table that store job
|
||||
| batching information. These options can be updated to any database
|
||||
| connection and table which has been defined by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'batching' => [
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'job_batches',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Failed Queue Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options configure the behavior of failed queue job logging so you
|
||||
| can control how and where failed jobs are stored. Laravel ships with
|
||||
| support for storing failed jobs in a simple file or in a database.
|
||||
|
|
||||
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Stateful Domains
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Requests from the following domains / hosts will receive stateful API
|
||||
| authentication cookies. Typically, these should include your local
|
||||
| and production domains which access your API via a frontend SPA.
|
||||
|
|
||||
*/
|
||||
|
||||
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||
'%s%s',
|
||||
'localhost,localhost:5173,127.0.0.1,127.0.0.1:8000,::1',
|
||||
Sanctum::currentApplicationUrlWithPort(),
|
||||
// Sanctum::currentRequestHost(),
|
||||
))),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This array contains the authentication guards that will be checked when
|
||||
| Sanctum is trying to authenticate a request. If none of these guards
|
||||
| are able to authenticate the request, Sanctum will use the bearer
|
||||
| token that's present on an incoming request for authentication.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => ['web'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expiration Minutes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value controls the number of minutes until an issued token will be
|
||||
| considered expired. This will override any values set in the token's
|
||||
| "expires_at" attribute, but first-party sessions are not affected.
|
||||
|
|
||||
*/
|
||||
|
||||
'expiration' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Token Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sanctum can prefix new tokens in order to take advantage of numerous
|
||||
| security scanning initiatives maintained by open source platforms
|
||||
| that notify developers if they commit tokens into repositories.
|
||||
|
|
||||
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
||||
|
|
||||
*/
|
||||
|
||||
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When authenticating your first-party SPA with Sanctum you may need to
|
||||
| customize some of the middleware Sanctum uses while processing the
|
||||
| request. You may change the middleware listed below as required.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
|
||||
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Third Party Services
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'postmark' => [
|
||||
'token' => env('POSTMARK_TOKEN'),
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'key' => env('RESEND_KEY'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'notifications' => [
|
||||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||||
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
Executable
+217
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Session Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines the default session driver that is utilized for
|
||||
| incoming requests. Laravel supports a variety of storage options to
|
||||
| persist session data. Database storage is a great default choice.
|
||||
|
|
||||
| Supported: "file", "cookie", "database", "memcached",
|
||||
| "redis", "dynamodb", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SESSION_DRIVER', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Lifetime
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the number of minutes that you wish the session
|
||||
| to be allowed to remain idle before it expires. If you want them
|
||||
| to expire immediately when the browser is closed then you may
|
||||
| indicate that via the expire_on_close configuration option.
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => (int) env('SESSION_LIFETIME', 120),
|
||||
|
||||
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to easily specify that all of your session data
|
||||
| should be encrypted before it's stored. All encryption is performed
|
||||
| automatically by Laravel and you may use the session like normal.
|
||||
|
|
||||
*/
|
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the "file" session driver, the session files are placed
|
||||
| on disk. The default storage location is defined here; however, you
|
||||
| are free to provide another location where they should be stored.
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => storage_path('framework/sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" or "redis" session drivers, you may specify a
|
||||
| connection that should be used to manage these sessions. This should
|
||||
| correspond to a connection in your database configuration options.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('SESSION_CONNECTION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" session driver, you may specify the table to
|
||||
| be used to store sessions. Of course, a sensible default is defined
|
||||
| for you; however, you're welcome to change this to another table.
|
||||
|
|
||||
*/
|
||||
|
||||
'table' => env('SESSION_TABLE', 'sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using one of the framework's cache driven session backends, you may
|
||||
| define the cache store which should be used to store the session data
|
||||
| between requests. This must match one of your defined cache stores.
|
||||
|
|
||||
| Affects: "dynamodb", "memcached", "redis"
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => env('SESSION_STORE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Sweeping Lottery
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some session drivers must manually sweep their storage location to get
|
||||
| rid of old sessions from storage. Here are the chances that it will
|
||||
| happen on a given request. By default, the odds are 2 out of 100.
|
||||
|
|
||||
*/
|
||||
|
||||
'lottery' => [2, 100],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the name of the session cookie that is created by
|
||||
| the framework. Typically, you should not need to change this value
|
||||
| since doing so does not grant a meaningful security improvement.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug((string) env('APP_NAME', 'laravel')).'-session'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The session cookie path determines the path for which the cookie will
|
||||
| be regarded as available. Typically, this will be the root path of
|
||||
| your application, but you're free to change this when necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('SESSION_PATH', '/'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the domain and subdomains the session cookie is
|
||||
| available to. By default, the cookie will be available to the root
|
||||
| domain and all subdomains. Typically, this shouldn't be changed.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('SESSION_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTPS Only Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By setting this option to true, session cookies will only be sent back
|
||||
| to the server if the browser has a HTTPS connection. This will keep
|
||||
| the cookie from being sent to you when it can't be done securely.
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTP Access Only
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will prevent JavaScript from accessing the
|
||||
| value of the cookie and the cookie will only be accessible through
|
||||
| the HTTP protocol. It's unlikely you should disable this option.
|
||||
|
|
||||
*/
|
||||
|
||||
'http_only' => env('SESSION_HTTP_ONLY', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Same-Site Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how your cookies behave when cross-site requests
|
||||
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||
| will set this value to "lax" to permit secure cross-site requests.
|
||||
|
|
||||
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
||||
|
|
||||
| Supported: "lax", "strict", "none", null
|
||||
|
|
||||
*/
|
||||
|
||||
'same_site' => env('SESSION_SAME_SITE', 'lax'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Partitioned Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will tie the cookie to the top-level site for
|
||||
| a cross-site context. Partitioned cookies are accepted by the browser
|
||||
| when flagged "secure" and the Same-Site attribute is set to "none".
|
||||
|
|
||||
*/
|
||||
|
||||
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
|
||||
|
||||
];
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Event;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<Event>
|
||||
*/
|
||||
class EventFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->text(15),
|
||||
'description' => $this->faker->text(50),
|
||||
];
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'lastname' => fake()->lastname(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'password' => Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
'validate' => rand(0, 1),
|
||||
'role' => rand(2, 5)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('lastname');
|
||||
$table->string('email')->unique();
|
||||
$table->string('password');
|
||||
$table->string('phone')->nullable();
|
||||
$table->integer('validate');
|
||||
$table->integer('role')->nullable();
|
||||
$table->dateTime('verified_at')->nullable();
|
||||
$table->integer('email_notifications')->default(1);
|
||||
$table->integer('web_notifications')->default(1);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
};
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('users', 'remember_token')) {
|
||||
$table->rememberToken()->nullable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('users', 'remember_token')) {
|
||||
$table->dropColumn('remember_token');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('events', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('description');
|
||||
$table->string('event_photo_path', 2048)->nullable();
|
||||
$table->dateTime('start')->nullable();
|
||||
$table->dateTime('end')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('events');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Migrations;
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('tasks', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->string('name');
|
||||
$table->string('description');
|
||||
$table->string('location');
|
||||
$table->dateTime("start");
|
||||
$table->dateTime("end");
|
||||
$table->integer('max_participants');
|
||||
|
||||
$table->foreignId("events_id")->constrained("events")->onDelete("cascade");
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tasks');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('task_user', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('task_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('profile_photo_path', 2048)->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('profile_photo_path');
|
||||
});
|
||||
}
|
||||
};
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
if (config('app.dev') == 1) {
|
||||
$this->call(DevSeeder::class);
|
||||
} else {
|
||||
$this->call(ProdSeeder::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\User;
|
||||
use App\Services\TypesenseService;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DevSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$typesense = app(TypesenseService::class);
|
||||
|
||||
$admin = User::firstOrCreate(
|
||||
['email' => config('app.admin_email')],
|
||||
[
|
||||
'name' => config('app.admin_name'),
|
||||
'lastname' => config('app.admin_lastname'),
|
||||
'password' => bcrypt(config('app.admin_password')),
|
||||
'phone' => config('app.admin_phone'),
|
||||
'role' => 1,
|
||||
'validate' => 1,
|
||||
'web_notifications' => 1,
|
||||
'email_notifications' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$typesense->upsertUser($admin);
|
||||
|
||||
User::factory()->count(10)->create();
|
||||
|
||||
Event::factory()->count(10)->create();
|
||||
}
|
||||
}
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\TypesenseService;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ProdSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$typesense = app(TypesenseService::class);
|
||||
|
||||
$admin = User::firstOrCreate(
|
||||
['email' => config('app.admin_email')],
|
||||
[
|
||||
'name' => config('app.admin_name'),
|
||||
'lastname' => config('app.admin_lastname'),
|
||||
'password' => bcrypt(config('app.admin_password')),
|
||||
'phone' => config('app.admin_phone'),
|
||||
'role' => 1,
|
||||
'validate' => 1,
|
||||
'web_notifications' => 1,
|
||||
'email_notifications' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$typesense->upsertUser($admin);
|
||||
}
|
||||
}
|
||||
+2591
File diff suppressed because it is too large.
Load diff
Executable
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite --port 5174"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"axios": "^1.11.0",
|
||||
"concurrently": "^9.0.1",
|
||||
"laravel-echo": "^2.2.7",
|
||||
"laravel-vite-plugin": "^2.0.0",
|
||||
"pusher-js": "^8.4.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"vite": "^7.0.7"
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory>tests/Feature</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<source>
|
||||
<include>
|
||||
<directory>app</directory>
|
||||
</include>
|
||||
</source>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value=":memory:"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="TELESCOPE_ENABLED" value="false"/>
|
||||
<env name="NIGHTWATCH_ENABLED" value="false"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Determine if the application is in maintenance mode...
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
require $maintenance;
|
||||
}
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the request...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__ . '/../bootstrap/app.php';
|
||||
|
||||
$app->handleRequest(Request::capture());
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
import Echo from 'laravel-echo';
|
||||
|
||||
import Pusher from 'pusher-js';
|
||||
window.Pusher = Pusher;
|
||||
|
||||
window.Echo = new Echo({
|
||||
broadcaster: 'reverb',
|
||||
key: import.meta.env.VITE_REVERB_APP_KEY,
|
||||
wsHost: import.meta.env.VITE_REVERB_HOST,
|
||||
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
||||
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
||||
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Compte créé</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>
|
||||
Un compte a été créé pour vous par un administrateur sur le site de gestion des bénévoles
|
||||
du Comité des fêtes de Beaupont.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Vous pouvez dès à présent vous connecter et accéder à votre espace personnel afin de participer
|
||||
aux activités proposées.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Veuillez vous renseigner auprès d'un administrateur pour récupérer vos identifiants.
|
||||
</p>
|
||||
|
||||
<p style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ url('/') }}"
|
||||
style="background-color: #3498db; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px;">
|
||||
Se connecter
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous n’êtes pas à l’origine de cette création de compte ou si vous avez des questions,
|
||||
merci de contacter rapidement l’équipe organisatrice.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Compte désactivé</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>
|
||||
Nous vous informons que votre compte sur le site de gestion des bénévoles
|
||||
du Comité des fêtes de Beaupont a été désactivé par un administrateur.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Vous ne pouvez désormais plus accéder à votre espace personnel ni participer aux activités proposées.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous pensez qu’il s’agit d’une erreur ou si vous souhaitez obtenir plus d’informations,
|
||||
nous vous invitons à contacter l’équipe organisatrice.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Votre compte pourra être réactivé ultérieurement si nécessaire.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Compte supprimé</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>
|
||||
Nous vous informons que votre compte sur le site de gestion des bénévoles
|
||||
du Comité des fêtes de Beaupont a été supprimé.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Vous n’avez désormais plus accès à votre espace personnel ni aux services associés.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous n’êtes pas à l’origine de cette action, merci de nous contacter rapidement.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous souhaitez à nouveau participer aux activités, vous pouvez effectuer une nouvelle inscription à tout moment.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Validation de changement d'adresse mail</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>Votre adresse email a bien été mise à jour vers {{ $newEmail }}.</p>
|
||||
|
||||
<p>Si vous n'êtes pas à l'origine de ce changement, merci de contacter l’équipe du Comité des fêtes de Beaupont.</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Événement supprimé</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>
|
||||
L’événement {{ $eventName }} a été supprimé par un administrateur.
|
||||
Vous n’y participez donc plus. Cet événement avait lieu du {{ $start }} au {{ $end }}.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous pensez qu’il s’agit d’une erreur ou si vous souhaitez plus d’informations,
|
||||
merci de contacter l’équipe du Comité des fêtes de Beaupont.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Demande de changement d'adresse mail</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>Une demande de changement d'adresse mail à été soumise.</p>
|
||||
|
||||
<p>Si vous n'êtes pas à l'origine de cette demande, veuillez contacter l'équipe du Comité des fêtes de Beaupont.</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nouvelle demande de validation</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $adminName }} {{ $adminLastname }},</p>
|
||||
|
||||
<p>
|
||||
L’utilisateur {{ $userName }} {{ $userLastname }} a créé un compte
|
||||
qui est maintenant en attente de validation sur le site du Comité des fêtes de Beaupont.
|
||||
</p>
|
||||
|
||||
<p style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ url('/admin') }}"
|
||||
style="background-color: #f39c12; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px;">
|
||||
Valider ce compte
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Vous pouvez cliquer sur le bouton ci-dessus pour vous rendre sur la page permettant de valider le compte.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Demande de changement d'adresse mail</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>Vous avez demandé à changer votre adresse email. Cliquez sur le bouton ci-dessous pour confirmer ce changement.</p>
|
||||
<p style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ config('vite_api_url') }}/confirm/email/change?token={{ $token }}"
|
||||
style="background-color: #f39c12; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px;">
|
||||
Confirmer le changement d'email
|
||||
</a>
|
||||
</p>
|
||||
<p>Ce lien expire dans 1 heure. Si vous n'êtes pas à l'origine de cette demande, ignorez ce mail.</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Date de tâche modifiée</title>
|
||||
</head>
|
||||
<body style="padding: 20px; font-family: Arial, sans-serif;">
|
||||
<div>
|
||||
<p>Bonjour {{ $name }} {{ $lastname }},</p>
|
||||
|
||||
<p>
|
||||
La date de la tâche {{ $taskName }} de l'événement {{ $eventName }} a été modifié par un administrateur.
|
||||
Cette tâche avait lieu du {{ $oldStart }} au {{ $oldEnd }}. Et aura maintenant lieu du {{ $newStart }} au {{ $newEnd }}.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous pensez qu’il s’agit d’une erreur ou si vous souhaitez plus d’informations,
|
||||
merci de contacter l’équipe du Comité des fêtes de Beaupont.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
À très bientôt,<br>
|
||||
L’équipe du Comité des fêtes de Beaupont
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 14px; color: #999; text-align: center; padding-top: 20px;">
|
||||
Cet email a été envoyé automatiquement, merci de ne pas y répondre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
Loaded 100 of 421 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user