Skip to content

Commit

Permalink
[OpenClassrooms-Student-Center#2] - user use more points than availab…
Browse files Browse the repository at this point in the history
…le - fix and tests

- fix: ui: booking.html: html input attribute min set to 1 and max set to club["points"]
- fix: server.py: purchase_places(): conditional structure implemented, checks redeemed points amount against competition places available

- tests: class TestPurchase created: method: test_should_not_use_more_points_than_have
- tests: class TestPurchase: method: test_should_deduct_points_from_club
  • Loading branch information
rafaRemote committed Dec 22, 2021
1 parent 138973b commit 3820986
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 36 deletions.
46 changes: 32 additions & 14 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,26 @@ def load_competitions():
app = Flask(__name__)
app.secret_key = "something_special"

PLACE_COST = 1
competitions = load_competitions()
clubs = load_clubs()


@app.route("/")
@app.route("/", strict_slashes=False)
def index():
return render_template("index.html")


@app.route("/showSummary", methods=["POST"])
def showSummary():
@app.route("/show-summary", methods=["POST"], strict_slashes=False)
def show_summary():
try:
club = [club for club in clubs if club["email"] == request.form["email"]][0]
except IndexError:
except (IndexError, TypeError):
return page_not_found()
return render_template("welcome.html", club=club, competitions=competitions)


@app.route("/book/<competition>/<club>")
@app.route("/book/<competition>/<club>", strict_slashes=False)
def book(competition, club):
found_club = [c for c in clubs if c["name"] == club][0]
found_competition = [c for c in competitions if c["name"] == competition][0]
Expand All @@ -48,22 +49,39 @@ def book(competition, club):
return render_template("welcome.html", club=club, competitions=competitions)


@app.route("/purchasePlaces", methods=["POST"])
def purchasePlaces():
competition = [c for c in competitions if c["name"] == request.form["competition"]][
@app.route("/purchase-places", methods=["POST"], strict_slashes=False)
def purchase_places():
compet = [c for c in competitions if c["name"] == request.form["competition_name"]][
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)
club = [c for c in clubs if c["name"] == request.form["club_name"]][0]
places_required = int(request.form["places"])
if places_required > int(club["points"]):
flash(
f"You cannot perform this action"
f"You asked {places_required} place(s), and you have {club['points']} point(s)"
f"A place costs {PLACE_COST} point(s)"
f"Therefore you need {places_required * PLACE_COST} point(s) to book {places_required}"
)
return render_template("booking.html", club=club, competition=compet)
elif places_required > int(compet["numberOfPlaces"]):
flash(
f"You cannot perform this action"
f"You asked {places_required} place(s)"
f"and the competition has {compet['numberOfPlaces']} places left"
)
return render_template("booking.html", club=club, competition=compet)
else:
flash("Great-booking complete!")
club["points"] = int(club["points"]) - places_required
compet["numberOfPlaces"] = int(compet["numberOfPlaces"]) - places_required
return render_template("welcome.html", club=club, competitions=competitions)


# TODO: Add route for points display


@app.route("/logout")
@app.route("/logout", strict_slashes=False)
def logout():
return redirect(url_for("index"))

Expand Down
17 changes: 13 additions & 4 deletions templates/booking.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@
<body>
<h2>{{competition['name']}}</h2>
Places available: {{competition['numberOfPlaces']}}
<form action="/purchasePlaces" method="post">
<input type="hidden" name="club" value="{{club['name']}}">
<input type="hidden" name="competition" value="{{competition['name']}}">
<label for="places">How many places?</label><input type="number" name="places" id=""/>
{% with messages = get_flashed_messages()%}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
{% endif%}
{% endwith %}
<form action="/purchase-places" method="post">
<input type="hidden" name="club_name" value="{{club['name']}}">
<input type="hidden" name="competition_name" value="{{competition['name']}}">
<label for="places">How many places?</label><input type="number" name="places" id="" min="1" max="{{club["points"]}}"/>
<button type="submit">Book</button>
</form>
</body>
Expand Down
2 changes: 1 addition & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<body>
<h1>Welcome to the GUDLFT Registration Portal!</h1>
Please enter your secretary email to continue:
<form action="showSummary" method="post">
<form action="show-summary" method="post">
<label for="email">Email:</label>
<input type="email" name="email" id="" required/>
<button type="submit">Enter</button>
Expand Down
4 changes: 2 additions & 2 deletions templates/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>Summary | GUDLFT Registration</title>
</head>
<body>
<h2>Welcome, {{club['email']}} </h2><a href="{{url_for('logout')}}">Logout</a>
<h2>Welcome, {{club['email']}} </h2><a href="{{url_for('logout')}}">Logout</a>

{% with messages = get_flashed_messages()%}
{% if messages %}
Expand All @@ -15,7 +15,7 @@ <h2>Welcome, {{club['email']}} </h2><a href="{{url_for('logout')}}">Logout</a>
{% endfor %}
</ul>
{% endif%}
Points available: {{club['points']}}
Points Available: {{club['points']}}
<h3>Competitions:</h3>
<ul>
{% for comp in competitions%}
Expand Down
19 changes: 8 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@ def client():

@pytest.fixture
def competition():
next_year = str(int(dt.datetime.now().strftime("%Y")) + 1)
competition = [
{
"name": "test future competition",
"date": dt.datetime.now().strftime(f"%{next_year}-%m-%d %H:%M:%S"),
"numberOfPlaces": "100",
}
]
return competition()
competition = {
"name": "test competition 1",
"date": "2100-12-10 10:00:00",
"numberOfPlaces": "10",
}
return competition


@pytest.fixture
Expand Down Expand Up @@ -59,7 +56,7 @@ def past_competition():

@pytest.fixture
def club():
club = {"name": "test club", "email": "test1@test.com", "points": "100"}
club = {"name": "test club 1", "email": "test1@test.com", "points": "100"}
return club


Expand All @@ -76,7 +73,7 @@ def unlisted_club():
@pytest.fixture
def clubs():
clubs = [
{"name": "test club 1", "email": "test1@test.com", "points": "10"},
{"name": "test club 1", "email": "test1@test.com", "points": "100"},
{"name": "test club 2", "email": "test2@test.com", "points": "20"},
{"name": "test club 3", "email": "test3@test.com", "points": "30"},
]
Expand Down
72 changes: 68 additions & 4 deletions tests/unit/test_server.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
import random
import server
import pytest


class TestEndpoints:
@pytest.mark.parametrize("endpoint, status_code", [("/", 200), ("/logout", 200)])
def test_access_unauthenticated_should_200(self, client, endpoint, status_code):
"""Checks response when unauthenticated user request"""
response = client.get(endpoint, follow_redirects=True)
assert response.status_code == status_code

@pytest.mark.parametrize(
"endpoint, status_code", [("/show-summary", 405), ("/purchase-places", 405)]
)
def test_access_unauthenticated_user_should_405(
self, client, endpoint, status_code
):
"""Checks response when unauthenticated user request"""
response = client.get(endpoint, follow_redirects=True)
assert response.status_code == status_code


class TestLogin:
def test_login_listed_email_shoudl_200(
def test_login_listed_email_should_200(
self, client, mocker, club, clubs, competitions
):
"""Checks response when authenticated user request"""
mocker.patch.object(server, "clubs", clubs)
mocker.patch.object(server, "competitions", competitions)
data = {"email": club["email"]}
response = client.post("/showSummary", data=data, follow_redirects=True)
response = client.post("/show-summary", data=data, follow_redirects=True)
assert response.status_code == 200

@pytest.mark.parametrize(
Expand All @@ -23,14 +43,58 @@ def test_login_listed_email_shoudl_200(
def test_login_unlisted_mails_should_404(
self, client, mocker, email, status_code, clubs, competitions
):
"""Checks response when unauthenticated user request"""
mocker.patch.object(server, "clubs", clubs)
mocker.patch.object(server, "competitions", competitions)
response = client.post("/showSummary", data=email, follow_redirects=True)
response = client.post("/show-summary", data=email, follow_redirects=True)
assert response.status_code == status_code

def test_login_bad_request(self, client, mocker, club, clubs, competitions):
"""Checks response when bad request"""
mocker.patch.object(server, "clubs", clubs)
mocker.patch.object(server, "competitions", competitions)
data = {"address": club["email"]}
response = client.post("/showSummary", data=data, follow_redirects=True)
response = client.post("/show-summary", data=data, follow_redirects=True)
assert response.status_code == 400


class TestPurchase:
def test_should_not_use_more_points_than_have(
self, client, mocker, club, competition, clubs, competitions
):
"""Checks response when user try to use more points than his club has"""
mocker.patch.object(server, "clubs", clubs)
mocker.patch.object(server, "competitions", competitions)
places = int(competition["numberOfPlaces"]) + 1
data = {
"club_name": club["name"],
"competition_name": competition["name"],
"places": str(places),
}
response = client.post("/purchase-places", data=data, follow_redirects=True)
data = response.data.decode("utf-8").split()
assert "cannot" in data

def test_should_deduct_points_from_club(
self, client, mocker, club, competition, clubs, competitions
):
"""Check club points in response after user book places"""
mocker.patch.object(server, "clubs", clubs)
mocker.patch.object(server, "competitions", competitions)
places = int(competition["numberOfPlaces"])
club_points = int(club["points"])
if places > 0:
if club_points > places:
max = places
else:
max = club_points
places_required = random.choice(range(1, max + 1))
data = {
"club_name": club["name"],
"competition_name": competition["name"],
"places": str(places_required),
}
response = client.post("/purchase-places", data=data, follow_redirects=True)
data = response.data.decode("utf-8").split()
club_points_left = int(data[(data.index("Available:") + 1)])
assert club_points_left == club_points - places_required

0 comments on commit 3820986

Please sign in to comment.