diff --git a/.DS_Store b/.DS_Store index 04a508e6f..8518e2f64 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.coverage b/.coverage new file mode 100644 index 000000000..c46d246b3 Binary files /dev/null and b/.coverage differ diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..3dbfbb408 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = tests/* \ No newline at end of file diff --git a/CACHEDIR.TAG b/CACHEDIR.TAG new file mode 100644 index 000000000..837feeff9 --- /dev/null +++ b/CACHEDIR.TAG @@ -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/ \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 000000000..d7e6f75c9 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +filterwarnings = + ignore:ast\.Str is deprecated and will be removed in Python 3\.14; use ast\.Constant instead:DeprecationWarning + ignore:Constant\.__init__ got an unexpected keyword argument 's'\. Support for arbitrary keyword arguments is deprecated and will be removed in Python 3\.15\.:DeprecationWarning + ignore:Attribute s is deprecated and will be removed in Python 3\.14; use value instead:DeprecationWarning + ignore:Constant\.__init__ missing 1 required positional argument.*:DeprecationWarning + ignore:datetime\.datetime\.utcfromtimestamp\(\) is deprecated and scheduled for removal in a future version\..*:DeprecationWarning \ No newline at end of file diff --git a/pyvenv.cfg b/pyvenv.cfg new file mode 100644 index 000000000..5d632cc2b --- /dev/null +++ b/pyvenv.cfg @@ -0,0 +1,11 @@ +home = /Library/Frameworks/Python.framework/Versions/3.13/bin +implementation = CPython +version_info = 3.13.3.final.0 +version = 3.13.3 +executable = /Library/Frameworks/Python.framework/Versions/3.13/bin/python3.13 +command = /Library/Frameworks/Python.framework/Versions/3.13/bin/python3.13 -m virtualenv /Users/quentintellier/Documents/2 - Python Projects/P11_2 - GÜDLFT/Python_Testing +virtualenv = 21.2.4 +include-system-site-packages = false +base-prefix = /Library/Frameworks/Python.framework/Versions/3.13 +base-exec-prefix = /Library/Frameworks/Python.framework/Versions/3.13 +base-executable = /Library/Frameworks/Python.framework/Versions/3.13/bin/python3.13 diff --git a/server.py b/server.py index 4084baeac..4b187e3fd 100644 --- a/server.py +++ b/server.py @@ -1,59 +1,69 @@ -import json -from flask import Flask,render_template,request,redirect,flash,url_for +from flask import Flask,render_template,request,redirect,flash,url_for,current_app +from utils import loadClubs, loadCompetitions, getClubByEmail +def create_app(config=None, clubs=None, competitions=None): + app = Flask(__name__) + app.secret_key = 'something_special' + if config: + app.config.update(config) -def loadClubs(): - with open('clubs.json') as c: - listOfClubs = json.load(c)['clubs'] - return listOfClubs + app.config['COMPETITIONS'] = competitions if competitions is not None else loadCompetitions() + app.config['CLUBS'] = clubs if clubs is not None else loadClubs() + @app.route('/') + def index(): + return render_template('index.html') -def loadCompetitions(): - with open('competitions.json') as comps: - listOfCompetitions = json.load(comps)['competitions'] - return listOfCompetitions + @app.route('/showSummary',methods=['POST']) + def showSummary(): + available_clubs = current_app.config['CLUBS'] + available_competitions = current_app.config['COMPETITIONS'] + if available_clubs is None or available_competitions is None: + flash("Error loading clubs or competitions data.") + return redirect(url_for('index')) -app = Flask(__name__) -app.secret_key = 'something_special' + club = getClubByEmail(request.form['email'], available_clubs) + if club: + return render_template('welcome.html',club=club,competitions=available_competitions) -competitions = loadCompetitions() -clubs = loadClubs() + flash("Unfortunately, the email you entered was not found.") + return redirect(url_for('index')) -@app.route('/') -def index(): - 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) + @app.route('/book//') + def book(competition,club): + available_clubs = current_app.config['CLUBS'] + available_competitions = current_app.config['COMPETITIONS'] + foundClub = [c for c in available_clubs if c['name'] == club][0] + foundCompetition = [c for c in available_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=available_competitions) -@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) + @app.route('/purchasePlaces',methods=['POST']) + def purchasePlaces(): + available_clubs = current_app.config['CLUBS'] + available_competitions = current_app.config['COMPETITIONS'] + competition = [c for c in available_competitions if c['name'] == request.form['competition']][0] + club = [c for c in available_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=available_competitions) -@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) + # TODO: Add route for points display -# TODO: Add route for points display + @app.route('/logout') + def logout(): + return redirect(url_for('index')) + return app -@app.route('/logout') -def logout(): - return redirect(url_for('index')) \ No newline at end of file + +app = create_app() \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 926526b7d..c40ee1fcd 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6,6 +6,15 @@

Welcome to the GUDLFT Registration Portal!

+ {% with messages = get_flashed_messages() %} + {% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %} + {% endwith %} Please enter your secretary email to continue:
diff --git a/utils.py b/utils.py new file mode 100644 index 000000000..acab6669a --- /dev/null +++ b/utils.py @@ -0,0 +1,28 @@ +import json + +def loadClubs(): + with open('clubs.json') as c: + listOfClubs = json.load(c)['clubs'] + return listOfClubs + + +def loadCompetitions(): + with open('competitions.json') as comps: + listOfCompetitions = json.load(comps)['competitions'] + return listOfCompetitions + + +def getClubByEmail(email, clubs): + email = lowercaseEmail(stripWhitespace(email)) + for club in clubs: + if lowercaseEmail(stripWhitespace(club['email'])) == email: + return club + return None + +def lowercaseEmail(email): + """Convertit l'email en minuscules pour une comparaison insensible à la casse.""" + return email.lower() + +def stripWhitespace(email): + """Supprime les espaces avant et après l'email pour une comparaison précise.""" + return email.strip() \ No newline at end of file