diff --git a/AUTHORS.txt b/AUTHORS.txt index 010bc77335..600885fba5 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -46,6 +46,7 @@ Valentin Rosca Alexander Kernozhitsky Benjamin Swart Andrey Vihrov +Grace Hawkins And many other people that didn't write code, but provided useful comments, suggestions and feedback. :-) diff --git a/cms/server/contest/handlers/main.py b/cms/server/contest/handlers/main.py index 93e63f75fb..6d2fb2a51d 100644 --- a/cms/server/contest/handlers/main.py +++ b/cms/server/contest/handlers/main.py @@ -9,6 +9,7 @@ # Copyright © 2014 Artem Iglikov # Copyright © 2014 Fabian Gundlach <320pointsguy@gmail.com> # Copyright © 2015-2018 William Di Luigi +# Copyright © 2021 Grace Hawkins # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -46,7 +47,7 @@ from cms.server.contest.communication import get_communications from cms.server.contest.printing import accept_print_job, PrintingDisabled, \ UnacceptablePrintJob -from cmscommon.crypto import hash_password +from cmscommon.crypto import hash_password, validate_password from cmscommon.datetime import make_datetime, make_timestamp from .contest import ContestHandler from ..phase_management import actual_phase_required @@ -72,7 +73,8 @@ def get(self): class RegistrationHandler(ContestHandler): """Registration handler. - Used to create a user account (and participation) when this is allowed. + Used to create a participation when this is allowed. + If `new_user` argument is true, it creates a new user too. """ @@ -84,6 +86,46 @@ def post(self): if not self.contest.allow_registration: raise tornado_web.HTTPError(404) + create_new_user = self.get_argument("new_user") == "true" + + # Get or create user + if create_new_user: + user = self._create_user() + else: + user = self._get_user() + + # Check if the participation exists + contest = self.contest + tot_participants = self.sql_session.query(Participation)\ + .filter(Participation.user == user)\ + .filter(Participation.contest == contest)\ + .count() + if tot_participants > 0: + raise tornado_web.HTTPError(409) + + # Create participation + team = self._get_team() + participation = Participation(user=user, contest=self.contest, + team=team) + self.sql_session.add(participation) + + self.sql_session.commit() + + self.finish(user.username) + + @multi_contest + def get(self): + if not self.contest.allow_registration: + raise tornado_web.HTTPError(404) + + self.r_params["MAX_INPUT_LENGTH"] = self.MAX_INPUT_LENGTH + self.r_params["MIN_PASSWORD_LENGTH"] = self.MIN_PASSWORD_LENGTH + self.r_params["teams"] = self.sql_session.query(Team)\ + .order_by(Team.name).all() + + self.render("register.html", **self.r_params) + + def _create_user(self): try: first_name = self.get_argument("first_name") last_name = self.get_argument("last_name") @@ -110,18 +152,6 @@ def post(self): # Override password with its hash password = hash_password(password) - # If we have teams, we assume that the 'team' field is mandatory - if self.sql_session.query(Team).count() > 0: - try: - team_code = self.get_argument("team") - team = self.sql_session.query(Team)\ - .filter(Team.code == team_code)\ - .one() - except (tornado_web.MissingArgumentError, NoResultFound): - raise tornado_web.HTTPError(400) - else: - team = None - # Check if the username is available tot_users = self.sql_session.query(User)\ .filter(User.username == username).count() @@ -129,29 +159,43 @@ def post(self): # HTTP 409: Conflict raise tornado_web.HTTPError(409) - # Store new user and participation + # Store new user user = User(first_name, last_name, username, password, email=email) self.sql_session.add(user) - participation = Participation(user=user, contest=self.contest, - team=team) - self.sql_session.add(participation) - - self.sql_session.commit() + return user - self.finish(username) + def _get_user(self): + username = self.get_argument("username") + password = self.get_argument("password") - @multi_contest - def get(self): - if not self.contest.allow_registration: + # Find user if it exists + user = self.sql_session.query(User)\ + .filter(User.username == username)\ + .first() + if user is None: raise tornado_web.HTTPError(404) - self.r_params["MAX_INPUT_LENGTH"] = self.MAX_INPUT_LENGTH - self.r_params["MIN_PASSWORD_LENGTH"] = self.MIN_PASSWORD_LENGTH - self.r_params["teams"] = self.sql_session.query(Team)\ - .order_by(Team.name).all() + # Check if password is correct + if not validate_password(user.password, password): + raise tornado_web.HTTPError(403) - self.render("register.html", **self.r_params) + return user + + def _get_team(self): + # If we have teams, we assume that the 'team' field is mandatory + if self.sql_session.query(Team).count() > 0: + try: + team_code = self.get_argument("team") + team = self.sql_session.query(Team)\ + .filter(Team.code == team_code)\ + .one() + except (tornado_web.MissingArgumentError, NoResultFound): + raise tornado_web.HTTPError(400) + else: + team = None + + return team class LoginHandler(ContestHandler): diff --git a/cms/server/contest/static/cws_style.css b/cms/server/contest/static/cws_style.css index e82146ce6e..baa5c72cc2 100644 --- a/cms/server/contest/static/cws_style.css +++ b/cms/server/contest/static/cws_style.css @@ -219,6 +219,21 @@ div.login_box { } } +/** Register **/ + +div.register_box form { + margin-bottom: 0; +} + +div.register_box form fieldset div.control-group:last-child { + margin-bottom: 0; +} + +div.register_box { + max-width: 450px; + margin: 20px auto; +} + /* Some fixes and enhancements of Bootstrap */ @media (max-width: 767px) { diff --git a/cms/server/contest/templates/register.html b/cms/server/contest/templates/register.html index ba751bd25e..852cc5fcbc 100644 --- a/cms/server/contest/templates/register.html +++ b/cms/server/contest/templates/register.html @@ -7,16 +7,58 @@ {% block body %} - {% endblock body %}