Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
UserEventNbExcededAdmin,
NotBookable,
ParticipantNbExceded,
UserEventAlreadyRegistered,
)

mail = None
Expand Down Expand Up @@ -121,6 +122,17 @@ def handle_participant_nb_exceded_error(e):
422,
)

@app.errorhandler(UserEventAlreadyRegistered)
def handle_user_event_already_registered_error(e):
return (
jsonify(
{
"error": "Vous ne pouvez pas vous inscrire plusieurs fois sur une animation"
}
),
422,
)

@app.template_filter()
def format_date(value):
format_string = "EEEE d MMMM"
Expand Down
4 changes: 4 additions & 0 deletions backend/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ class UserEventNbExcededUser(Exception):

class ParticipantNbExceded(Exception):
pass


class UserEventAlreadyRegistered(Exception):
pass
12 changes: 12 additions & 0 deletions backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
UserEventNbExceded,
NotBookable,
ParticipantNbExceded,
UserEventAlreadyRegistered,
)


Expand Down Expand Up @@ -184,6 +185,17 @@ def is_reservation_possible_for(self, nb_people, email, skip_nb_max_per_user=Fal
if not self.bookable:
raise NotBookable

# Test si utilisateur n'a pas déjà une inscription sur
# l'évènement en cours
query = select(func.count(TReservations.id_reservation)).where(
TReservations.email == email,
TReservations.id_event == self.id,
)
nb_reservation_current_event = db.session.scalar(query)

if nb_reservation_current_event:
raise UserEventAlreadyRegistered

# Test nombre de reservation par utilisateur
# Selection animations par utilisateur
from datetime import datetime
Expand Down
51 changes: 51 additions & 0 deletions backend/core/routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import datetime
from functools import wraps
import secrets
import re
from pathlib import Path

from email_validator import validate_email, EmailNotValidError, EmailSyntaxError
from flask import jsonify, request, Blueprint, render_template, session, current_app
Expand Down Expand Up @@ -820,3 +822,52 @@ def send_event_cancellation_emails(event_id):
)
db.session.commit()
return "", 200

@login_admin_required
@app_routes.route("/logs", methods=["GET"])
def get_logs():
content = []
log_dir = Path("var/log/")

# Traitement de tous les fichiers du répertoire log
for file in log_dir.iterdir():
with open(file, "r") as f:
f = f.readlines()
for line in f:
if "Email envoyé " in line:
m = re.findall(r'^(\w+) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}).*core.utils (.*) \"\[.*\] (.*)\" à \[\'(.*)\'\]', line)
log_type = m[0][0]
log_date_en = m[0][1]
log_info = m[0][2]
log_subject = m[0][3]
log_email = m[0][4]

# Ajout du statut selon le contenu du sujet
if "connexion" in log_subject:
log_status = "connexion"
elif "c'est demain !" in log_subject:
log_status = "rdv"
elif "réservation est confirmée" in log_subject:
log_status = "confirmation"
elif "Lien pour confirmer" in log_subject:
log_status = "à confirmer"
elif "liste d'attente" in log_subject:
log_status = "attente"
elif "a bien été annulée" in log_subject:
log_status = "annulation"
elif "a été annulée" in log_subject:
log_status = "info admin"
else:
log_status = ""

# Suppression des apostrophes pour email multi-destinataires (aux admins)
log_email = log_email.replace("'", "")

# Ajout des informations de logs
content.append({"type":log_type,
"date":log_date_en,
"info":log_info,
"subject":log_subject,
"email":log_email,
"status":log_status})
return jsonify(content)
22 changes: 15 additions & 7 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@

# Changelog


## (2026-07-10)

**🚀 Nouveautés**
- Ajout d'un menu "Journaux" pour permettre aux administrateurs de visualiser les emails envoyés (#105)

**🐛 Corrections**
- Correction de l'inscription multiple par email sur un évènement (#103)

## 0.4.0 (2026-05-21)

**🚀 Nouveautés**
- Le titre de l'application qui s'affiche dans la bare de menu correspond à la valeur de la variable `VITE_APP_TITLE` du fichier `.env` (#74)
- Ajout d'un menu automatique "Évènements" pointant vers les évènements de geotrek-rando. Choix d'afficher/masquer via paramètre `DISPLAY_GTR_EVENTS_MENU` (#72)
Expand All @@ -20,20 +28,20 @@
- Mise à jour des dépendances backend (#91)
- Mise à jour des librairies frontend (#92). Notamment primevue 4 et tailwindcss 4.
- Mise à jour des actions github (#91)


## 0.3.0 (2024-06-24)

**🚀 Nouveautés**

- Mise à jour vers SQLAlchemy 1.4 (#63)P
- Mise à jour des librairies javascript (#65)
- Utilisation de MenuBar pour la barre de menu (#65)
- Style page des statistiques (#65)
- Utilisation de toast pour afficher les messages d'erreur du formulaire d'inscription aux animations (#66)
- [BACK] Ajout paramètre `NB_PARTICIPANTS_MAX_PER_ANIM_PER_USER` qui permet d'indiquer le nombre maximal de participants que l'on peut enregistrer lors de la création d'une réservation
- [BACK] Ajout paramètre `NB_PARTICIPANTS_MAX_PER_ANIM_PER_USER` qui permet d'indiquer le nombre maximal de participants que l'on peut enregistrer lors de la création d'une réservation
- [BACK] Ajout paramètre `NB_ANIM_MAX_PER_USER` qui permet d'indiquer le nombre maximal d'animations auxquelles un utilisateur peut s'inscrire par an.



**🐛 Corrections**
Expand Down
7 changes: 7 additions & 0 deletions front-vite/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ const items = ref<MenuItem[]>([
isAuth: true,
isAdmin: false,
route: '/resalisting'
},
{
label: 'Journaux',
icon: 'pi pi-file',
isAuth: true,
isAdmin: true,
route: '/logs'
}
])

Expand Down
16 changes: 14 additions & 2 deletions front-vite/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import LoginView from '@/views/LoginView.vue'
import LoginCallbackView from '@/views/LoginCallbackView.vue'
import LogoutView from '@/views/LogoutView.vue'
import InfoAdminView from '@/views/InfoAdminView.vue'
import LogsView from '@/views/LogsView.vue'

export const ROUTES_NAMES = {
HOME: 'HOME',
Expand All @@ -19,7 +20,8 @@ export const ROUTES_NAMES = {
RESA_FORM: 'RESA_FORM',
RESA_LISTING: 'RESA_LISTING',
RESA_CONFIRM: 'RESA_CONFIRM',
INFO_ADMIN: 'INFO_ADMIN'
INFO_ADMIN: 'INFO_ADMIN',
LOGS: 'LOGS'
}
export const ROUTES_PATHS = {
HOME: '/',
Expand All @@ -32,7 +34,8 @@ export const ROUTES_PATHS = {
RESA_FORM: '/resa/:geotrekid',
RESA_LISTING: '/resalisting',
RESA_CONFIRM: '/resaconfirm',
INFO_ADMIN: '/info_admin'
INFO_ADMIN: '/info_admin',
LOGS: '/logs'
}

const routes = [
Expand Down Expand Up @@ -127,6 +130,15 @@ const routes = [
requiresAuth: true,
requiresAdmin: true
}
},
{
path: ROUTES_PATHS.LOGS,
name: ROUTES_NAMES.LOGS,
component: LogsView,
meta: {
requiresAuth: true,
requiresAdmin: true
}
}
]

Expand Down
6 changes: 6 additions & 0 deletions front-vite/src/utils/appli_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,9 @@ export const getGlobalStats = (data: any) =>

export const getGraphStats = (url: string, data: any) =>
getApiData(CONFIGURATION.URL_APPLICATION, url, data)

/**
* Journaux
*/
export const getLogs = () =>
getApiData(CONFIGURATION.URL_APPLICATION, 'logs')
Loading
Loading