Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Dynamisationdujson #270

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
Binary file modified .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .flaskenv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FLASK_APP=app.server
FLASK_ENV=development
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -2,6 +2,6 @@ bin
include
lib
.Python
tests/

.envrc
__pycache__
4 changes: 4 additions & 0 deletions CACHEDIR.TAG
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by Python virtualenv.
# For information about cache directory tags, see:
# https://bford.info/cachedir/
Empty file added app/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions app/booking_manager/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# app/booking_manager/__init__.py

from .booking_service import BookingService
from .club_manager import ClubManager
from .competition_manager import CompetitionManager
from .data_loader import JSONDataLoader
36 changes: 36 additions & 0 deletions app/booking_manager/booking_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# app/booking_manager/booking_service.py

from app.booking_manager.club_manager import ClubManager
from app.booking_manager.competition_manager import CompetitionManager


class BookingService:
"""
Ordonne le processus de réservation en utilisant les gestionnaires de clubs et de compétitions.
"""

def __init__(self, clubs_file: str, competitions_file: str):
self.club_manager = ClubManager(clubs_file)
self.competition_manager = CompetitionManager(competitions_file)

def purchase_places(self, club_name: str, competition_name: str, places_requested: int) -> bool:
club = self.club_manager.find_by_name(club_name)
competition = self.competition_manager.find_by_name(competition_name)

if not club or not competition:
return False
if places_requested > 12:
return False
if places_requested > club.points:
return False
if places_requested > competition.number_of_places:
return False

competition.number_of_places -= places_requested
club.points -= places_requested

# Sauvegarde des modifications dans les fichiers JSON
self.club_manager.save_clubs()
self.competition_manager.save_competitions()

return True
55 changes: 55 additions & 0 deletions app/booking_manager/club_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# app/booking_manager/club_manager.py

import json
from typing import List, Optional
from app.models import Club
from .data_loader import JSONDataLoader


class ClubManager:
"""
Gère le chargement, la recherche et la sauvegarde des clubs.
"""

def __init__(self, clubs_file: str):
self.clubs_file = clubs_file # Pour la sauvegarde
loader = JSONDataLoader(clubs_file)
data = loader.load_data()
self.clubs: List[Club] = self._parse_clubs(data)

def _parse_clubs(self, data: dict) -> List[Club]:
clubs = []
for c in data.get("clubs", []):
clubs.append(
Club(
name=c["name"],
email=c["email"],
points=int(c["points"]),
id=c.get("id")
)
)
return clubs

def find_by_email(self, email: str) -> Optional[Club]:
return next((club for club in self.clubs if club.email == email), None)

def find_by_name(self, name: str) -> Optional[Club]:
return next((club for club in self.clubs if club.name == name), None)

def save_clubs(self, filepath: Optional[str] = None) -> None:
"""
Sauvegarde l'état actuel des clubs dans un fichier JSON.
"""
if filepath is None:
filepath = self.clubs_file
clubs_data = {"clubs": []}
for club in self.clubs:
club_dict = {
"id": club.id,
"name": club.name,
"email": club.email,
"points": str(club.points)
}
clubs_data["clubs"].append(club_dict)
with open(filepath, "w") as f:
json.dump(clubs_data, f, indent=4)
50 changes: 50 additions & 0 deletions app/booking_manager/competition_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# app/booking_manager/competition_manager.py

import json
from typing import List, Optional
from app.models import Competition
from .data_loader import JSONDataLoader


class CompetitionManager:
"""
Gère le chargement, la recherche et la sauvegarde des compétitions.
"""

def __init__(self, competitions_file: str):
self.competitions_file = competitions_file # Pour la sauvegarde
loader = JSONDataLoader(competitions_file)
data = loader.load_data()
self.competitions: List[Competition] = self._parse_competitions(data)

def _parse_competitions(self, data: dict) -> List[Competition]:
competitions = []
for c in data.get("competitions", []):
competitions.append(
Competition(
name=c["name"],
date=c["date"],
number_of_places=int(c["numberOfPlaces"])
)
)
return competitions

def find_by_name(self, name: str) -> Optional[Competition]:
return next((comp for comp in self.competitions if comp.name == name), None)

def save_competitions(self, filepath: Optional[str] = None) -> None:
"""
Sauvegarde l'état actuel des compétitions dans un fichier JSON.
"""
if filepath is None:
filepath = self.competitions_file
competitions_data = {"competitions": []}
for comp in self.competitions:
comp_dict = {
"name": comp.name,
"date": comp.date,
"numberOfPlaces": str(comp.number_of_places)
}
competitions_data["competitions"].append(comp_dict)
with open(filepath, "w") as f:
json.dump(competitions_data, f, indent=4)
21 changes: 21 additions & 0 deletions app/booking_manager/data_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# app/booking_manager/data_loader.py

import json
import os
from typing import Any


class JSONDataLoader:
"""
Classe générique pour charger des données depuis un fichier JSON.
"""

def __init__(self, filepath: str):
self.filepath = filepath

def load_data(self) -> Any:
if not os.path.exists(self.filepath):
raise FileNotFoundError(f"Fichier introuvable : {self.filepath}")
with open(self.filepath, "r") as f:
data = json.load(f)
return data
15 changes: 15 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# app/models.py

class Competition:
def __init__(self, name, date, number_of_places):
self.name = name
self.date = date
self.number_of_places = number_of_places


class Club:
def __init__(self, name, email, points, id=None):
self.name = name
self.email = email
self.points = points
self.id = id
114 changes: 114 additions & 0 deletions app/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# app/server.py

from flask import Flask, render_template, request, redirect, flash, url_for
from app.booking_manager import BookingService

app = Flask(__name__, static_folder="../static")
app.secret_key = "secret_key_xyz"

# Instanciation du service de réservation, avec les JSON par défaut.
# Si vous souhaitez utiliser des fichiers de test différents,
# configurez-les dans le code ou via des variables d'environnement.
booking_service = BookingService(
clubs_file="data/clubs.json",
competitions_file="data/competitions.json"
)


@app.route("/")
def index():
"""
Page d'accueil de l'application.
"""
return render_template("index.html")


@app.route("/showSummary", methods=["POST"])
def show_summary():
"""
Récupère l'email du club et affiche la page de résumé (welcome.html).
Si le club n'est pas trouvé, renvoie vers la page d'accueil avec un message d'erreur.
"""
email = request.form.get("email", "")
club = booking_service.club_manager.find_by_email(email)
if not club:
flash("Email inconnu ou invalide.")
return redirect(url_for("index"))

# Affiche la liste des compétitions disponibles
competitions = booking_service.competition_manager.competitions
return render_template("welcome.html", club=club, competitions=competitions)


@app.route("/book/<competition>/<club>")
def book(competition, club):
"""
Affiche la page de réservation (booking.html) pour un club et une compétition donnés.
Si le club ou la compétition n'existe pas, renvoie vers l'index.
"""
found_competition = booking_service.competition_manager.find_by_name(
competition)
found_club = booking_service.club_manager.find_by_name(club)
if not found_competition or not found_club:
flash("Something went wrong - please try again")
return redirect(url_for("index"))

return render_template("booking.html", club=found_club, competition=found_competition)


@app.route("/purchasePlaces", methods=["POST"])
def purchase_places():
"""
Tente d'acheter 'places' places pour un club et une compétition.
- Si la réservation réussit, on affiche 'Great-booking complete!'
- Sinon, on affiche 'Impossible de réserver...'
"""
competition_name = request.form.get("competition")
club_name = request.form.get("club")
places_str = request.form.get("places")

try:
places_requested = int(places_str)
except ValueError:
flash("Le nombre de places est invalide.")
return redirect(url_for("index"))

# Vérification de l'existence du club et de la compétition
found_competition = booking_service.competition_manager.find_by_name(
competition_name)
found_club = booking_service.club_manager.find_by_name(club_name)
if not found_competition or not found_club:
flash("Something went wrong - please try again")
return redirect(url_for("index"))

# Appel à la logique métier
success = booking_service.purchase_places(
club_name, competition_name, places_requested)
if success:
flash("Great-booking complete!")
else:
flash("Impossible de réserver ces places (Règle non respectée).")

# Recharger les données du club et de la compétition (après mise à jour)
updated_club = booking_service.club_manager.find_by_name(club_name)
competitions = booking_service.competition_manager.competitions

return render_template("welcome.html", club=updated_club, competitions=competitions)


@app.route("/clubsPoints")
def clubs_points():
"""
Affiche la liste des clubs et leurs points disponibles.
Page publique, sans besoin de login.
"""
clubs = booking_service.club_manager.clubs
return render_template("clubs_points.html", clubs=clubs)


@app.route("/logout")
def logout():
"""
Déconnecte le club (retour à l'accueil).
"""
return redirect(url_for("index"))
31 changes: 31 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- app/templates/base.html -->
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}GUDLFT{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav>
<ul>
<li><a href="{{ url_for('index') }}">Accueil</a></li>
<li><a href="{{ url_for('clubs_points') }}">Points Clubs</a></li>
<li><a href="{{ url_for('logout') }}">Déconnexion</a></li>
</ul>
</nav>
<div class="container">
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
</body>
</html>
16 changes: 16 additions & 0 deletions app/templates/booking.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- app/templates/booking.html -->
{% extends "base.html" %}

{% block title %}Réservation | {{ competition['name'] }}{% endblock %}

{% block content %}
<h2>{{ competition['name'] }}</h2>
<p>Places disponibles: {{ competition['number_of_places'] }}</p>
<form action="/purchasePlaces" method="post">
<input type="hidden" name="club" value="{{ club['name'] }}">
<input type="hidden" name="competition" value="{{ competition['name'] }}">
<label for="places">Combien de places ?</label>
<input type="number" name="places" id="places" min="1" required>
<button type="submit">Réserver</button>
</form>
{% endblock %}
24 changes: 24 additions & 0 deletions app/templates/clubs_points.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- app/templates/clubs_points.html -->
{% extends "base.html" %}

{% block title %}Points des Clubs{% endblock %}

{% block content %}
<h2>Points des Clubs</h2>
<table border="1">
<thead>
<tr>
<th>Club</th>
<th>Points</th>
</tr>
</thead>
<tbody>
{% for club in clubs %}
<tr>
<td>{{ club['name'] }}</td>
<td>{{ club['points'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Loading