diff --git a/.gitignore b/.gitignore index 2cba99d87..f944d3e49 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ bin include lib .Python -tests/ .envrc -__pycache__ \ No newline at end of file +__pycache__ +/env +.idea/ \ No newline at end of file diff --git a/clubs.json b/clubs.json index 1d7ad1ffe..d2432dc98 100644 --- a/clubs.json +++ b/clubs.json @@ -1,16 +1,19 @@ -{"clubs":[ +{ + "clubs": [ { - "name":"Simply Lift", - "email":"john@simplylift.co", - "points":"13" + "name": "Simply Lift", + "email": "john@simplylift.co", + "points": "13" }, { - "name":"Iron Temple", - "email": "admin@irontemple.com", - "points":"4" + "name": "Iron Temple", + "email": "admin@irontemple.com", + "points": "4" }, - { "name":"She Lifts", - "email": "kate@shelifts.co.uk", - "points":"12" + { + "name": "She Lifts", + "email": "kate@shelifts.co.uk", + "points": "12" } -]} \ No newline at end of file + ] +} \ No newline at end of file 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/requirements.txt b/requirements.txt index 139affa05..94218a6e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,5 @@ itsdangerous==1.1.0 Jinja2==2.11.2 MarkupSafe==1.1.1 Werkzeug==1.0.1 + +pytest~=8.2.2 \ No newline at end of file diff --git a/server.py b/server.py index 4084baeac..3ec357c97 100644 --- a/server.py +++ b/server.py @@ -1,17 +1,22 @@ import json -from flask import Flask,render_template,request,redirect,flash,url_for +from flask import Flask, render_template, request, redirect, flash, url_for def loadClubs(): with open('clubs.json') as c: - listOfClubs = json.load(c)['clubs'] - return listOfClubs + listOfClubs = json.load(c)['clubs'] + return listOfClubs + + +def saveClub(clubs): + with open('clubs.json', 'w') as c: + json.dump({'clubs': clubs}, c) def loadCompetitions(): with open('competitions.json') as comps: - listOfCompetitions = json.load(comps)['competitions'] - return listOfCompetitions + listOfCompetitions = json.load(comps)['competitions'] + return listOfCompetitions app = Flask(__name__) @@ -20,35 +25,75 @@ def loadCompetitions(): competitions = loadCompetitions() clubs = loadClubs() + @app.route('/') def index(): return render_template('index.html') -@app.route('/showSummary',methods=['POST']) + +@app.route('/clubs-points') +def clubs_points(): + return render_template( + 'clubs-points.html', + clubs=clubs + ) + + +@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) + try: + club = \ + [club for club in clubs if club['email'] == request.form['email']][ + 0] + return render_template('welcome.html', club=club, + competitions=competitions) + except IndexError: + flash('Wrong email-please try again') + return render_template('index.html') @app.route('/book//') -def book(competition,club): +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) + 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) + return render_template('welcome.html', club=club, + competitions=competitions) -@app.route('/purchasePlaces',methods=['POST']) +@app.route('/purchasePlaces', methods=['POST']) def purchasePlaces(): - competition = [c for c in competitions if c['name'] == request.form['competition']][0] + 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 + + if placesRequired > 12: + flash('Max purchase 12.') + return render_template('welcome.html', club=club, + competitions=competitions) + + if placesRequired > int(club['points']): + flash('Insufficiant points.') + return render_template('welcome.html', club=club, + competitions=competitions) + + club['points'] = str(int(club['points']) - placesRequired) + saveClub(clubs) + + competition['numberOfPlaces'] = int( + competition['numberOfPlaces']) - placesRequired + flash('Great-booking complete!') - return render_template('welcome.html', club=club, competitions=competitions) + + return render_template('welcome.html', club=club, + competitions=competitions) # TODO: Add route for points display @@ -56,4 +101,4 @@ def purchasePlaces(): @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/clubs-points.html b/templates/clubs-points.html new file mode 100644 index 000000000..0b9dd4ed8 --- /dev/null +++ b/templates/clubs-points.html @@ -0,0 +1,26 @@ + + + + + Clubs points || GUDLFT + + +

Clubs points

+ + {% if clubs %} + + + + + {% for club in clubs %} + + {% endfor %} + +
NamePoints
{{ club['name'] }}{{ club['points'] }}
+ + {% endif %} + + Back + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 926526b7d..2cd56a3d5 100644 --- a/templates/index.html +++ b/templates/index.html @@ -5,12 +5,23 @@ GUDLFT Registration +

Welcome to the GUDLFT Registration Portal!

+ Please enter your secretary email to continue:
+ + {% with messages = get_flashed_messages()%} + {% if messages %} + {% for message in messages %} + {{message}} + {% endfor %} + {% endif %} + {% endwith %} + \ No newline at end of file diff --git a/templates/welcome.html b/templates/welcome.html index ff6b261a2..4405feda4 100644 --- a/templates/welcome.html +++ b/templates/welcome.html @@ -7,7 +7,7 @@

Welcome, {{club['email']}}

Logout - {% with messages = get_flashed_messages()%} + {% with messages = get_flashed_messages() %} {% if messages %} {% endif%} - Points available: {{club['points']}} + Points available: {{ club['points'] }}

Competitions:

- {%endwith%} + {% endwith %} \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..dce3d9e15 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,42 @@ +import pytest +import json + +import server +from server import app, competitions + + +@pytest.fixture +def client(): + app.config['TESTING'] = True + with app.test_client() as client: + yield client + + +@pytest.fixture +def test_clubs(): + with open('tests/test_clubs.json') as c: + return json.load(c)['clubs'] + + +@pytest.fixture +def test_competitions(): + with open('tests/test_competitions.json') as comps: + return json.load(comps)['competitions'] + + +@pytest.fixture +def test_competition_full(): + competitions[:] = [ + {'name': 'Test Comptetition #3', + 'date': '2020-03-27 10:00:00', + 'numberOfPlaces': '0'} + ] + + +@pytest.fixture +def setup_mocks(mocker, test_clubs, test_competitions): + mocker.patch('server.loadClubs', return_value=test_clubs) + mocker.patch('server.loadCompetitions', return_value=test_competitions) + mocker.patch('server.saveClub') + mocker.patch.object(server, 'clubs', test_clubs) + mocker.patch.object(server, 'competitions', test_competitions) diff --git a/tests/test_clubs.json b/tests/test_clubs.json new file mode 100644 index 000000000..c5a2f3679 --- /dev/null +++ b/tests/test_clubs.json @@ -0,0 +1,19 @@ +{ + "clubs": [ + { + "name": "Test club #1", + "email": "john@test.com", + "points": "13" + }, + { + "name": "Test club #2", + "email": "admin@test.com", + "points": "4" + }, + { + "name": "Test club #3", + "email": "kate@test.com", + "points": "12" + } + ] +} \ No newline at end of file diff --git a/tests/test_competitions.json b/tests/test_competitions.json new file mode 100644 index 000000000..e0022d2a5 --- /dev/null +++ b/tests/test_competitions.json @@ -0,0 +1,14 @@ +{ + "competitions": [ + { + "name": "Test Competition #1", + "date": "2020-03-27 10:00:00", + "numberOfPlaces": "25" + }, + { + "name": "Test Competition #2", + "date": "2020-10-22 13:30:00", + "numberOfPlaces": "13" + } + ] +} \ No newline at end of file diff --git a/tests/test_server.py b/tests/test_server.py new file mode 100644 index 000000000..80d582092 --- /dev/null +++ b/tests/test_server.py @@ -0,0 +1,96 @@ +from server import loadClubs + + +def test_purchase_places(client, test_clubs, test_competitions, setup_mocks): + places_to_purchase = 8 + + response = client.post('/purchasePlaces', data={ + 'club': test_clubs[0]['name'], + 'competition': test_competitions[0]['name'], + 'places': places_to_purchase + }) + + assert response.status_code == 200 + assert b'Great-booking complete!' in response.data + + +def test_max_purchase_places(client, test_clubs, test_competitions, setup_mocks): + places_to_purchase = 28 + + response = client.post('/purchasePlaces', data={ + 'club': test_clubs[0]['name'], + 'competition': test_competitions[0]['name'], + 'places': places_to_purchase + }) + + assert response.status_code == 200 + assert b'Max purchase 12.' in response.data + + +def test_has_sufficient_points(client, test_clubs, test_competitions, setup_mocks): + places_to_purchase = 9 + + response = client.post('/purchasePlaces', data={ + 'club': test_clubs[1]['name'], + 'competition': test_competitions[0]['name'], + 'places': places_to_purchase + }) + + assert response.status_code == 200 + assert b'Insufficiant points.' in response.data + + +def test_update_points_after_purchase(client, test_clubs, test_competitions, setup_mocks): + places_to_purchase = 9 + + response = client.post('/purchasePlaces', data={ + 'club': test_clubs[0]['name'], + 'competition': test_competitions[0]['name'], + 'places': str(places_to_purchase) + }) + + assert int(test_clubs[0]['points']) == 4 + assert b'Great-booking complete!' in response.data + + +def test_login(client): + + response = client.post('/showSummary', data={ + 'email': 'john@simplylift.co' + }) + assert response.status_code == 200 + + +def test_wrong_login(client): + + response = client.post('/showSummary', data={ + 'email': 'wrong-email@test.com' + }) + assert response.status_code == 200 + assert b'Wrong email-please try again' in response.data + + +def test_display_book_available(client): + + test_club = loadClubs()[0] + + response = client.post('/showSummary', data={'email': test_club['email']}) + + assert response.status_code == 200 + assert b'Number of Places: 25' in response.data + + +def test_display_book_non_available(client, test_competition_full): + + test_club = loadClubs()[0] + + response = client.post('/showSummary', data={'email': test_club['email']}) + + assert response.status_code == 200 + assert b'- Competition complete' in response.data + + +def test_display_points_table(client): + + response = client.get('/clubs-points') + assert response.status_code == 200