diff --git a/.gitignore b/.gitignore
index 2cba99d87..fe057cdd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,6 @@ bin
include
lib
.Python
-tests/
.envrc
-__pycache__
\ No newline at end of file
+__pycache__
+.vscode
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..b3955fbd0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+PYTHON := python
+PYTEST := pytest
+
+TEST_FILES := \
+ tests/test_purchase_place.py \
+ tests/test_booking_page.py \
+ tests/test_show_summary.py
+
+# Commande pour exécuter tous les tests
+test:
+ $(PYTEST) $(TEST_FILES)
+
+help:
+ @echo " test Exécute les tests Pytest"
+ @echo " help Affiche cette aide"
+
+.PHONY: test install run clean help
diff --git a/README.md b/README.md
index 61307d2cd..8f7daa265 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,56 @@
-# gudlift-registration
+# GÜDLFT : Projet d'école [OpenClassrooms](https://openclassrooms.com/fr) - Améliorez une application Web Python par des tests et du débogage
-1. Why
+GUDLFT est une application web conçue pour les organisateurs de compétitions locales et régionales. L'application permet aux secrétaires de clubs de réserver des places pour des compétitions en utilisant les points accumulés, tout en garantissant une participation équitable entre tous les clubs.
- This is a proof of concept (POC) project to show a light-weight version of our competition booking platform. The aim is the keep things as light as possible, and use feedback from the users to iterate.
+## Installation et exécution
-2. Getting Started
+### Prérequis
- This project uses the following technologies:
+- Python 3.9 ou version supérieur
+- pip (gestionnaire de paquets Python)
- * Python v3.x+
+### Étapes d'installation
- * [Flask](https://flask.palletsprojects.com/en/1.1.x/)
+1. **Cloner le dépôt** :
+ ```bash
+ git clone https://github.com/Jbguerin13/Python_Testing.git
+ cd gudlft/PYTHON_TESTING
+ ```
- Whereas Django does a lot of things for us out of the box, Flask allows us to add only what we need.
-
+2. **Créer un environnement virtuel** :
+ Sous Windows :
+ ```bash
+ python -m venv env
+ env\Scripts\activate
+ ```
+ Sous macOS/Linux :
+ ```bash
+ python3 -m venv env
+ source env/bin/activate
+ ```
- * [Virtual environment](https://virtualenv.pypa.io/en/stable/installation.html)
+3. **Installer les dépendances** :
+ ```bash
+ pip install -r requirements.txt
+ ```
- This ensures you'll be able to install the correct packages without interfering with Python on your machine.
+4. **Lancer le serveur** :
+ ```bash
+ export FLASK_APP=server.py
+ flask run
+ ```
- Before you begin, please ensure you have this installed globally.
+5. **📌 Fonctionnalités** :
+ - **Authentification des utilisateurs** : Connexion par e-mail pour les secrétaires de clubs.
+ - **Système de réservation** : Utilisation des points des clubs pour réserver des places aux compétitions.
+ - **Gestion des points** : Affichage du solde des points et mise à jour après réservation.
+ - **Limites de réservation** : Un club ne peut pas réserver plus de 12 places par compétition.
+ - **Tableau des points** : Affichage public des points de tous les clubs pour assurer la transparence.
-3. Installation
-
- - After cloning, change into the directory and type virtualenv .
. This will then set up a a virtual python environment within that directory.
-
- - Next, type source bin/activate
. You should see that your command prompt has changed to the name of the folder. This means that you can install packages in here without affecting affecting files outside. To deactivate, type deactivate
-
- - Rather than hunting around for the packages you need, you can install in one step. Type pip install -r requirements.txt
. This will install all the packages listed in the respective file. If you install a package, make sure others know by updating the requirements.txt file. An easy way to do this is pip freeze > requirements.txt
-
- - Flask requires that you set an environmental variable to the python file. However you do that, you'll want to set the file to be server.py
. Check [here](https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application) for more details
-
- - You should now be ready to test the application. In the directory, type either flask run
or python -m flask run
. The app should respond with an address you should be able to go to using your browser.
-
-4. Current Setup
-
- The app is powered by [JSON files](https://www.tutorialspoint.com/json/json_quick_guide.htm). This is to get around having a DB until we actually need one. The main ones are:
-
- * competitions.json - list of competitions
- * clubs.json - list of clubs with relevant information. You can look here to see what email addresses the app will accept for login.
-
-5. Testing
-
- You are free to use whatever testing framework you like-the main thing is that you can show what tests you are using.
-
- We also like to show how well we're testing, so there's a module called
- [coverage](https://coverage.readthedocs.io/en/coverage-5.1/) you should add to your project.
+6. **Lancement des tests** :
+ ```bash
+ make test
+ ```
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 000000000..c24fe5bb9
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+filterwarnings =
+ ignore::DeprecationWarning
diff --git a/server.py b/server.py
index 4084baeac..71fc64003 100644
--- a/server.py
+++ b/server.py
@@ -1,59 +1,101 @@
import json
from flask import Flask,render_template,request,redirect,flash,url_for
-
+#load the clubs and competitions from the json files
def loadClubs():
with open('clubs.json') as c:
listOfClubs = json.load(c)['clubs']
return listOfClubs
-
+#load the clubs and competitions from the json files
def loadCompetitions():
with open('competitions.json') as comps:
listOfCompetitions = json.load(comps)['competitions']
return listOfCompetitions
-app = Flask(__name__)
-app.secret_key = 'something_special'
+app = Flask(__name__) #create the Flask app
+app.secret_key = 'something_special' #used to add a session flash
+#load the clubs and competitions
competitions = loadCompetitions()
clubs = loadClubs()
@app.route('/')
def index():
+ # user can connect from a form (by email)
return render_template('index.html')
-@app.route('/showSummary',methods=['POST'])
-def showSummary():
- club = [club for club in clubs if club['email'] == request.form['email']][0]
- return render_template('welcome.html',club=club,competitions=competitions)
+#display welcome page after connextion
+@app.route('/show_summary',methods=['POST','GET'])
+def show_summary():
+ email = request.form.get("email") if request.method == "POST" else request.args.get("email")
+
+ if not email:
+ flash("Email is required. Please login.", "error")
+ return redirect(url_for('index'))
+
+ club = next((club for club in clubs if club['email'] == email), None)
+
+ if club:
+ return render_template('welcome.html', club=club, competitions=competitions)
+ flash("Wrong credentials, please retry", "error")
+ return redirect(url_for('index'))
-@app.route('/book//')
-def book(competition,club):
- foundClub = [c for c in clubs if c['name'] == club][0]
- foundCompetition = [c for c in competitions if c['name'] == competition][0]
- if foundClub and foundCompetition:
- return render_template('booking.html',club=foundClub,competition=foundCompetition)
- else:
- flash("Something went wrong-please try again")
- return render_template('welcome.html', club=club, competitions=competitions)
+#display the booking page
+@app.route('/book//', methods=['GET', 'POST'])
+def book(competition, club):
+ found_club = next((c for c in clubs if c['name'] == club), None)
+ found_competition = next((c for c in competitions if c['name'] == competition), None)
+ if not found_club or not found_competition:
+ flash("Something went wrong - Please try again", "error")
+ return redirect(url_for('index'))
-@app.route('/purchasePlaces',methods=['POST'])
+ return render_template("booking.html", club=found_club, competition=found_competition)
+
+
+#purchase places
+@app.route('/purchasePlaces', methods=['POST'])
def purchasePlaces():
- competition = [c for c in competitions if c['name'] == request.form['competition']][0]
- club = [c for c in clubs if c['name'] == request.form['club']][0]
- placesRequired = int(request.form['places'])
- competition['numberOfPlaces'] = int(competition['numberOfPlaces'])-placesRequired
- flash('Great-booking complete!')
- return render_template('welcome.html', club=club, competitions=competitions)
+ competition = next((c for c in competitions if c['name'] == request.form['competition']), None)
+ club = next((c for c in clubs if c['name'] == request.form['club']), None)
+
+ if not competition or not club:
+ flash("Something went wrong - Please try again", "error")
+ return redirect(url_for('index'))
+
+ user_places_required = int(request.form['places'])
+
+ if user_places_required <= 0:
+ flash("You must book at least one place.", "error")
+ return render_template('welcome.html', club=club, competitions=competitions), 400
+ elif user_places_required > int(competition['numberOfPlaces']):
+ flash("Not enough places available.", "error")
+ return render_template('welcome.html', club=club, competitions=competitions), 400
+ elif user_places_required > int(club["points"]):
+ flash("Not enough points available.", "error")
+ return render_template('welcome.html', club=club, competitions=competitions), 400
+ elif user_places_required > 12:
+ flash("You cannot book more than 12 places per competition.", "error")
+ return render_template('welcome.html', club=club, competitions=competitions), 400
+ else:
+ competition['numberOfPlaces'] = int(competition['numberOfPlaces']) - user_places_required
+ club['points'] = int(club['points']) - user_places_required
+ flash(f"Great! Booking complete for {user_places_required} places!", "success")
+ return redirect(url_for('show_summary', email=club['email']))
+ return render_template('welcome.html', club=club, competitions=competitions)
-# TODO: Add route for points display
+@app.route('/display_points_club', methods=['POST','GET'])
+def display_points_club():
+ """Affiche les points des clubs et garde le contexte du club connecté"""
+ email = request.form.get("email") if request.method == "POST" else request.args.get("email")
+ club = next((club for club in clubs if club['email'] == email), None)
+ return render_template('display_points_club.html', clubs=clubs, club=club)
@app.route('/logout')
def logout():
- return redirect(url_for('index'))
\ No newline at end of file
+ return redirect(url_for('index'))
diff --git a/templates/booking.html b/templates/booking.html
index 06ae1156c..bc14f59bc 100644
--- a/templates/booking.html
+++ b/templates/booking.html
@@ -7,11 +7,21 @@
{{competition['name']}}
Places available: {{competition['numberOfPlaces']}}
-
+{% with messages = get_flashed_messages(with_categories=true) %}
+ {% if messages %}
+
+ {% for category, message in messages %}
+ - {{ message }}
+ {% endfor %}
+
+ {% endif %}
+{% endwith %}