Skip to content

Commit e023a65

Browse files
committed
Handle invalid URLs properly, by redirecting them to homepage
1 parent cb6bae8 commit e023a65

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

tests/test_api.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ def test_run_challenge(question_file: Path):
2222

2323
# Verify backend can run type check and return results
2424
assert response.json is not None
25+
26+
27+
def test_invalid_challenge_redirect_to_homepage():
28+
response = app.test_client().get("/foo/bar")
29+
assert response.status_code == 302
30+
assert response.location == "/"

views/challenge.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class Level(StrEnum):
1919
ADVANCED = "advanced"
2020
EXTREME = "extreme"
2121

22+
@classmethod
23+
def is_valid_level(cls, level: str):
24+
return level in cls._value2member_map_
25+
2226

2327
ChallengeName: TypeAlias = str
2428

views/views.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import platform
2+
from functools import wraps
23

34
from flask import (
5+
abort,
46
Blueprint,
57
jsonify,
68
redirect,
@@ -14,6 +16,18 @@
1416
app_views = Blueprint("app_views", __name__)
1517

1618

19+
def validate_challenge(view_func):
20+
@wraps(view_func)
21+
def wrapper(level, name, *args, **kwargs):
22+
if Level.is_valid_level(level) and challenge_manager.has_challenge(
23+
ChallengeKey(Level(level), name)
24+
):
25+
return view_func(level, name, *args, **kwargs) # valid challenge
26+
abort(404)
27+
28+
return wrapper
29+
30+
1731
@sitemapper.include(changefreq="daily", priority=1.0)
1832
@app_views.route("/")
1933
def index():
@@ -33,12 +47,9 @@ def index():
3347
},
3448
)
3549
@app_views.route("/<level>/<name>", methods=["GET"])
50+
@validate_challenge
3651
def get_challenge(level: str, name: str):
37-
challenge_key = ChallengeKey(Level(level), name)
38-
if not challenge_manager.has_challenge(challenge_key):
39-
return redirect("/")
40-
41-
challenge = challenge_manager.get_challenge(challenge_key)
52+
challenge = challenge_manager.get_challenge(ChallengeKey(Level(level), name))
4253
return render_template(
4354
"challenge.html",
4455
name=name,
@@ -51,11 +62,12 @@ def get_challenge(level: str, name: str):
5162

5263

5364
@app_views.route("/run/<level>/<name>", methods=["POST"])
65+
@validate_challenge
5466
def run_challenge(level: str, name: str):
55-
challenge_key = ChallengeKey(Level(level), name)
5667
code = request.get_data(as_text=True)
57-
58-
result = challenge_manager.run_challenge(user_code=code, key=challenge_key)
68+
result = challenge_manager.run_challenge(
69+
user_code=code, key=ChallengeKey(Level(level), name)
70+
)
5971
if result.passed:
6072
message = "<h2>✅ Congratulations! You passed the test 🎉</h2>"
6173
return jsonify({"passed": True, "message": message})

0 commit comments

Comments
 (0)