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)
def do_import(self): """Get the user from the UserLoader and store it.""" # Get the user user = self.loader.get_user() if user is None: return False # Store logger.info("Creating user %s on the database.", user.username) with SessionGen() as session: try: contest = contest_from_db(self.contest_id, session) user = self._user_to_db(session, user, self.update) except ImportDataError as e: logger.error(str(e)) logger.info("Error while importing, no changes were made.") return False if contest is not None: logger.info("Creating participation of user %s in contest %s.", user.username, contest.name) session.add(Participation(user=user, contest=contest)) session.commit() user_id = user.id logger.info("Import finished (new user id: %s).", user_id) return True
def post(self, user_id): fallback_page = "/user/%s" % user_id user = self.safe_get_item(User, user_id) try: contest_id = self.get_argument("contest_id") assert contest_id != "null", "Please select a valid contest" except Exception as error: self.application.service.add_notification(make_datetime(), "Invalid field(s)", repr(error)) self.redirect(fallback_page) return self.contest = self.safe_get_item(Contest, contest_id) attrs = {} self.get_bool(attrs, "hidden") self.get_bool(attrs, "unrestricted") # Create the participation. participation = Participation(contest=self.contest, user=user, hidden=attrs["hidden"], unrestricted=attrs["unrestricted"]) self.sql_session.add(participation) if self.try_commit(): # Create the user on RWS. self.application.service.proxy_service.reinitialize() # Maybe they'll want to do this again (for another contest). self.redirect(fallback_page)
def post(self, contest_id): fallback_page = "/contest/%s/users" % contest_id self.contest = self.safe_get_item(Contest, contest_id) try: user_id = self.get_argument("user_id") assert user_id != "null", "Please select a valid user" except Exception as error: self.application.service.add_notification(make_datetime(), "Invalid field(s)", repr(error)) self.redirect(fallback_page) return user = self.safe_get_item(User, user_id) # Create the participation. participation = Participation(contest=self.contest, user=user) self.sql_session.add(participation) if self.try_commit(): # Create the user on RWS. self.application.service.proxy_service.reinitialize() # Maybe they'll want to do this again (for another user) self.redirect(fallback_page)
def add_participations(contest_id, groupname): with SessionGen() as session: users = session.query(User) contest = Contest.get_from_id(contest_id, session) if contest is None: logger.error("No contest with id `%s' found.", contest_id) return False if groupname is None: group = contest.main_group else: group = \ session.query(Group) \ .filter(Group.contest_id == contest_id, Group.name == groupname).first() if group is None: logger.error("No group with name `%s' found.", groupname) return False for user in users: if session.query(Participation) \ .filter(Participation.contest_id == contest_id, Participation.user_id == user.id).first(): logger.info( "Participation already exists (left untouched; group not verified): '%s'", user.username) else: participation = Participation(user=user, contest=contest, group=group) session.add(participation) logger.info("Participation added: '%s'", user.username) session.commit() return True
def _participation_to_db(session, contest, new_p): """Add the new participation to the DB and attach it to the contest session (Session): session to use. contest (Contest): the contest in the DB. new_p (dict): dictionary with the participation data, including at least "username"; may contain "team", "hidden", "ip", "password". return (Participation): the participation in the DB. raise (ImportDataError): in case of one of these errors: - the user for this participation does not already exist in the DB; - the team for this participation does not already exist in the DB. """ user = session.query(User)\ .filter(User.username == new_p["username"]).first() if user is None: # FIXME: it would be nice to automatically try to import. raise ImportDataError("User \"%s\" not found in database. " "Use cmsImportUser to import it." % new_p["username"]) team = session.query(Team)\ .filter(Team.code == new_p.get("team")).first() if team is None and new_p.get("team") is not None: # FIXME: it would be nice to automatically try to import. raise ImportDataError("Team \"%s\" not found in database. " "Use cmsImportTeam to import it." % new_p.get("team")) # Check that the participation is not already defined. p = session.query(Participation)\ .filter(Participation.user_id == user.id)\ .filter(Participation.contest_id == contest.id)\ .first() # FIXME: detect if some details of the participation have been updated # and thus the existing participation needs to be changed. if p is not None: logger.warning( "Participation of user %s in this contest already " "exists, not updating it.", new_p["username"]) return p # Prepare new participation args = { "user": user, "contest": contest, } if "team" in new_p: args["team"] = team if "hidden" in new_p: args["hidden"] = new_p["hidden"] if "ip" in new_p and new_p["ip"] is not None: args["ip"] = [ipaddress.ip_network(new_p["ip"])] if "password" in new_p: args["password"] = new_p["password"] new_p = Participation(**args) session.add(new_p) return new_p
def add_users(users_info, contest_name=None): """ Add the given users to the database, if they don't exist. If contest_name is given and it exists, participations are created (for existing users, too). Each user info should be a dictionary with the fields: username, password. Optionally: first_name (default is empty). last_name (default is empty). hidden (default is false). unrestricted (default is false). """ with SessionGen() as session: existing_users = session.query(User).all() existing_usernames = {user.username: user for user in existing_users} # If the contest does not exist, this raises an exception, # and participations will not be created. try: contest = get_contest(session, contest_name) participations = session.query(Participation)\ .filter(Participation.contest_id == contest.id)\ .all() existing_participations = set(participation.user.username for participation in participations) except Exception: contest = None existing_participations = set() for user_info in users_info: username = user_info["username"] # If this user exists, fetch the User database object. # Otherwise, create one. if username in existing_usernames: user = existing_usernames[username] else: first_name = user_info.get("first_name", "") last_name = user_info.get("last_name", "") password = user_info["password"] user = User(first_name=unicode(first_name), last_name=unicode(last_name), username=unicode(username), password=unicode(password)) session.add(user) # If the participation does not exist and the contest is given, # add it. if contest is not None and \ username not in existing_participations: participation = Participation( user=user, contest=contest, hidden=user_info.get("hidden", False), unrestricted=user_info.get("unrestricted", False)) session.add(participation) session.commit()
def post(self): if not self.contest.allow_registration: raise tornado.web.HTTPError(404) try: first_name = self.get_argument("first_name") last_name = self.get_argument("last_name") username = self.get_argument("username") password = self.get_argument("password") if not 1 <= len(first_name) <= self.MAX_INPUT_LENGTH: raise ValueError() if not 1 <= len(last_name) <= self.MAX_INPUT_LENGTH: raise ValueError() if not 1 <= len(username) <= self.MAX_INPUT_LENGTH: raise ValueError() if not re.match(r"^[A-Za-z0-9_-]+$", username): raise ValueError() if not self.MIN_PASSWORD_LENGTH <= len(password) \ <= self.MAX_INPUT_LENGTH: raise ValueError() except (tornado.web.MissingArgumentError, ValueError): raise tornado.web.HTTPError(400) # 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() if tot_users != 0: # HTTP 409: Conflict raise tornado.web.HTTPError(409) # Store new user and participation user = User(first_name, last_name, username, password) self.sql_session.add(user) participation = Participation(user=user, contest=self.contest, team=team) self.sql_session.add(participation) self.sql_session.commit() self.finish(username)
def add_participation(username, contest_id, ip, delay_time, extra_time, password, method, is_hashed, team_code, hidden, unrestricted): logger.info("Creating the user's participation in the database.") delay_time = delay_time if delay_time is not None else 0 extra_time = extra_time if extra_time is not None else 0 if hidden: logger.warning("The participation will be hidden") if unrestricted: logger.warning("The participation will be unrestricted") try: with SessionGen() as session: user = \ session.query(User).filter(User.username == username).first() if user is None: logger.error("No user with username `%s' found.", username) return False contest = Contest.get_from_id(contest_id, session) if contest is None: logger.error("No contest with id `%s' found.", contest_id) return False team = None if team_code is not None: team = \ session.query(Team).filter(Team.code == team_code).first() if team is None: logger.error("No team with code `%s' found.", team_code) return False if password is not None: if is_hashed: password = build_password(password, method) else: password = hash_password(password, method) participation = Participation( user=user, contest=contest, ip=[ipaddress.ip_network(ip)] if ip is not None else None, delay_time=datetime.timedelta(seconds=delay_time), extra_time=datetime.timedelta(seconds=extra_time), password=password, team=team, hidden=hidden, unrestricted=unrestricted) session.add(participation) session.commit() except IntegrityError: logger.error("A participation for this user in this contest " "already exists.") return False logger.info("Participation added.") return True
def get_participation(cls, user=None, contest=None, **kwargs): """Create a participation""" user = user if user is not None else cls.get_user() contest = contest if contest is not None else cls.get_contest() args = { "user": user, "contest": contest, } args.update(kwargs) participation = Participation(**args) return participation
def add_participation(self, user=None, contest=None, **kwargs): """Add a participation.""" user = user if user is not None else self.add_user() contest = contest if contest is not None else self.add_contest() args = { "user": user, "contest": contest, } args.update(kwargs) participation = Participation(**args) self.session.add(participation) return participation
def get(self): if not self.contest.online_registration: raise tornado.web.HTTPError(404) fail_redirect = lambda msg: self.redirect("/register?register_error=" + escape.url_escape(msg)) if self.get_argument("user", "") != "" and self.get_argument( "code", "") != "": user = self.sql_session.query(User)\ .filter(User.username == self.get_argument("user", ""))\ .first() if user is None: fail_redirect("El link ya no es válido.") return if user.activation_expire is None: self.redirect("/?msg=" + escape.url_escape("La cuenta ya está activada.")) return if user.activation_expire < datetime.now(): fail_redirect( "El link ya expiró, por favor vuelva a llenar el formulario." ) return if self.get_argument("code", "") != user.activation_code: fail_redirect("El link ingresado es inválido.") return try: # Create the participation. participation = Participation(contest=self.contest, user=user, hidden=False, unrestricted=False) self.sql_session.add(participation) user.set_attrs({ 'activation_code': None, 'activation_expire': None }) self.sql_session.commit() self.application.service.proxy_service.reinitialize() except: fail_redirect("Error al activar usuario.") return else: send_credentials(self.contest.gmail_sender, self.contest.gmail_password, user, self.request.host) self.redirect("/?msg=" + escape.url_escape( "La cuenta ha sido activada exitosamente. Se envió un mail conteniendo tus credenciales." )) else: self.render("register.html", **self.r_params)
def _makeparticipation(self, username, cdb, udb, gdb, teamdb): user = self.users[username] pdb = Participation(user=udb, contest=cdb) pdb.password = build_password(user.password) pdb.group = gdb pdb.ip = user.ip pdb.hidden = user.hidden pdb.unofficial = user.unofficial pdb.unrestricted = user.unrestricted pdb.team = teamdb return pdb
def do_import(self): """Get the user from the UserLoader and store it.""" # Get the user user = self.loader.get_user() if user is None: return False # Store logger.info("Creating user %s on the database.", user.username) with SessionGen() as session: if self.contest_id is not None: contest = session.query(Contest)\ .filter(Contest.id == self.contest_id)\ .first() if contest is None: logger.critical( "The specified contest (id %s) does not exist. " "Aborting.", self.contest_id) return False # Check whether the user already exists old_user = session.query(User) \ .filter(User.username == user.username) \ .first() if old_user is not None: logger.critical("The user already exists.") return False session.add(user) if self.contest_id is not None: logger.info("Creating participation of user %s in contest %s.", user.username, contest.name) participation = Participation(user=user, contest=contest) session.add(participation) session.commit() user_id = user.id logger.info("Import finished (new user id: %s).", user_id) return True
def add_participation(username, contest_id, ip, delay_time, extra_time, password, team_code, hidden): logger.info("Creating the user in the database.") delay_time = delay_time if delay_time is not None else 0 extra_time = extra_time if extra_time is not None else 0 try: with SessionGen() as session: user = \ session.query(User).filter(User.username == username).first() if user is None: logger.error("No user with username `%s' found.", username) return False contest = Contest.get_from_id(contest_id, session) if contest is None: logger.error("No contest with id `%s' found.", contest_id) return False team = None if team_code is not None: team = \ session.query(Team).filter(Team.code == team_code).first() if team is None: logger.error("No team with code `%s' found.", team_code) return False participation = Participation( user=user, contest=contest, ip=ip, delay_time=datetime.timedelta(seconds=delay_time), extra_time=datetime.timedelta(seconds=extra_time), password=password, team=team, hidden=hidden) session.add(participation) session.commit() except IntegrityError: logger.error("A participation for this user in this contest " "already exists.") return False logger.info("Participation added.") return True
def add_participation(username, contest_id): try: with SessionGen() as session: user = session.query(User).filter(User.username == username).first() if user is None: return False contest = Contest.get_from_id(contest_id, session) if contest is None: return False participation = Participation( user=user, contest=contest, hidden=False, unrestricted=False ) session.add(participation) session.commit() except IntegrityError: return False logger.info("Added participation for user {}".format(username)) return True
def load_participations(path): logger.info("Loading...") with open(path, 'r') as io: data = json.load(io) participations = data['participations'] with SessionGen() as session: for entry in participations: logger.info('Loading: %s' % (entry)) contest = Contest.get_from_id(entry['contest_id'], session) if contest is None: logger.error(" Contest ID %d not found" % (entry['contest_id'])) session.rollback() return False userdata = entry['user'] user = session.query(User).filter( User.username == userdata['username']).first() if user is None: user = User(username=userdata['username'], first_name=userdata['first_name'], last_name=userdata['last_name'], password=build_password( generate_random_password())) logger.info(' Creating new user: %s' % (user.username)) session.add(user) else: logger.info(' Using existing user: %s (id=%d)' % (user.username, user.id)) if 'plaintext_password' in userdata: logger.info(' * password') user.password = build_password(userdata['plaintext_password'], 'plaintext') if 'first_name' in userdata: logger.info(' * first_name: %s' % (userdata['first_name'])) user.first_name = userdata['first_name'] if 'last_name' in userdata: logger.info(' * last_name: %s' % (userdata['last_name'])) user.last_name = userdata['last_name'] participation = session.query(Participation).join( Participation.user).filter( Participation.contest == contest).filter( User.username == user.username).first() if participation is None: participation = Participation(user=user, contest=contest) logger.info( ' Creating new participation for contest_id=%d user=%s' % (contest.id, user.username)) session.add(participation) else: logger.info( ' Updating participation: id=%d contest_id=%d user=%s' % (participation.id, participation.contest_id, participation.user.username)) if 'plaintext_password' in entry: logger.info(' * plaintext_password') participation.password = build_password( entry['plaintext_password'], 'plaintext') if 'ip' in entry: logger.info(' * ip: %s' % (entry['ip'])) participation.ip = [ipaddress.ip_network(entry['ip'])] if 'delay_time' in entry: logger.info(' * delay_time: %d' % (entry['delay_time'])) participation.delay_time = datetime.timedelta( seconds=entry['delay_time']) if 'extra_time' in entry: logger.info(' * extra_time: %d' % (entry['extra_time'])) participation.extra_time = datetime.timedelta( seconds=entry['extra_time']) if 'hidden' in entry: logger.info(' * hidden: %s' % (entry['hidden'])) participation.hidden = entry['hidden'] if 'unrestricted' in entry: logger.info(' * unrestricted: %s' % (entry['unrestricted'])) participation.unrestricted = entry['unrestricted'] if 'team' in userdata: team = session.query(Team).filter( Team.code == userdata['team']['code']).first() if team is None: team = Team(code=userdata['team']['code'], name=userdata['team']['name']) logger.info(' Creating new team: %s' % (team.code)) session.add(team) else: logger.info(' Using existing team: %s' % (team.code)) if 'name' in userdata['team']: logger.info(' * name: %s' % (userdata['team']['name'])) team.name = userdata['team']['name'] participation.team = team session.commit() logger.info("Done.") return True
def user_handler(self): if local.data['action'] == 'new': try: username = local.data['username'] password = local.data['password'] email = local.data['email'].lower() firstname = local.data['firstname'] lastname = local.data['lastname'] recaptcha_response = local.data['recaptcha_response'] except KeyError: logger.warning('Missing parameters') return 'Bad request' # Check captcha r = requests.post( "https://www.google.com/recaptcha/api/siteverify", data={'secret': config.get("core", "recaptcha_secret_key"), 'response': recaptcha_response}, #, 'remoteip': ''}, verify=False) try: assert r.json()["success"] == True except: return "Bad request" token = self.hashpw(password) err = self.check_user(username) if err is not None: return err err = self.check_email(email) if err is not None: return err user = User( first_name=firstname, last_name=lastname, username=username, password=token, email=email ) social_user = SocialUser( access_level=6, registration_time=make_datetime() ) contest = local.session.query(Contest)\ .filter(Contest.id == self.CONTEST_ID)\ .first() participation = Participation( user=user, contest=contest ) social_user.user = user if 'institute' in local.data: social_user.institute_id = int(local.data['institute']) try: local.session.add(user) local.session.add(social_user) local.session.add(participation) local.session.commit() except IntegrityError: return 'User already exists' elif local.data['action'] == 'login': try: username = local.data['username'] password = local.data['password'] except KeyError: logger.warning('Missing parameter') return 'Bad request' token = self.hashpw(password) participation = self.get_participation(username, token) if participation is None: return 'login.error' else: user = participation.user local.resp['token'] = token local.resp['user'] = self.get_user_info(user) elif local.data['action'] == 'get': user = local.session.query(User)\ .filter(User.username == local.data['username']).first() if user is None: return 'Not found' local.resp = self.get_user_info(user) # Append scores of tried tasks local.resp['scores'] = [] for ts in user.social_user.taskscores: taskinfo = dict() taskinfo['name'] = ts.task.name taskinfo['score'] = ts.score taskinfo['title'] = ts.task.title local.resp['scores'].append(taskinfo) elif local.data['action'] == 'list': query = local.session.query(User)\ .join(SocialUser)\ .order_by(desc(SocialUser.score))\ .order_by(desc(SocialUser.id)) if 'institute' in local.data: query = query\ .filter(SocialUser.institute_id == local.data['institute']) users, local.resp['num'] = self.sliced_query(query) local.resp['users'] = map(self.get_user_info, users) elif local.data['action'] == 'update': if local.user is None: return 'Unauthorized' if 'institute' in local.data and \ local.data['institute'] is not None: local.user.institute_id = int(local.data['institute']) if 'email' in local.data and \ local.data['email'] != '' and \ local.user.email != local.data['email']: err = self.check_email(local.data['email']) if err is not None: return err local.user.email = local.data['email'] if 'old_password' in local.data and \ local.data['old_password'] != '': old_token = self.hashpw(local.data['old_password']) if local.user.password != old_token: return 'Wrong password' if len(local.data['password']) < 5: return 'Password\'s too short' new_token = self.hashpw(local.data['password']) local.user.password = new_token local.resp['token'] = new_token local.session.commit() else: return 'Bad request'
def post(self, contest_id): contest = self.safe_get_item(Contest, contest_id) reg_allowed = True try: attrs = contest.get_attrs() reg_allowed = attrs.get("allow_registration") self.get_string(attrs, "name", empty=None) self.get_string(attrs, "description") assert attrs.get("name") is not None, "No contest name specified." allowed_localizations = \ self.get_argument("allowed_localizations", "") if allowed_localizations: attrs["allowed_localizations"] = \ [x.strip() for x in allowed_localizations.split(",") if len(x) > 0 and not x.isspace()] else: attrs["allowed_localizations"] = [] attrs["languages"] = self.get_arguments("languages") self.get_bool(attrs, "submissions_download_allowed") self.get_bool(attrs, "allow_questions") self.get_bool(attrs, "allow_user_tests") self.get_bool(attrs, "block_hidden_participations") self.get_bool(attrs, "allow_password_authentication") self.get_bool(attrs, "allow_registration") self.get_bool(attrs, "ip_restriction") self.get_bool(attrs, "ip_autologin") self.get_string(attrs, "token_mode") self.get_int(attrs, "token_max_number") self.get_timedelta_sec(attrs, "token_min_interval") self.get_int(attrs, "token_gen_initial") self.get_int(attrs, "token_gen_number") self.get_timedelta_min(attrs, "token_gen_interval") self.get_int(attrs, "token_gen_max") self.get_int(attrs, "max_submission_number") self.get_int(attrs, "max_user_test_number") self.get_timedelta_sec(attrs, "min_submission_interval") self.get_timedelta_sec(attrs, "min_user_test_interval") self.get_datetime(attrs, "start") self.get_datetime(attrs, "stop") self.get_string(attrs, "timezone", empty=None) self.get_timedelta_sec(attrs, "per_user_time") self.get_int(attrs, "score_precision") self.get_bool(attrs, "analysis_enabled") self.get_datetime(attrs, "analysis_start") self.get_datetime(attrs, "analysis_stop") # Update the contest. contest.set_attrs(attrs) except Exception as error: self.service.add_notification(make_datetime(), "Invalid field(s).", repr(error)) self.redirect(self.url("contest", contest_id)) return # TODO update participations if attrs.get("allow_registration") and not reg_allowed: for unreg_user in self.sql_session.query(User).filter( User.id.notin_( self.sql_session.query(Participation.user_id).filter( Participation.contest == contest).all())).all(): self.sql_session.add( Participation(contest=contest, user=unreg_user)) if self.try_commit(): # Update the contest on RWS. self.service.proxy_service.reinitialize() self.redirect(self.url("contest", contest_id))
def validate_login(sql_session, contest, timestamp, username, password, ip_address): """Authenticate a user logging in, with username and password. Given the information the user provided (the username and the password) and some context information (contest, to determine which users are allowed to log in, how and with which restrictions; timestamp for cookie creation; IP address to check against) try to authenticate the user and return its participation and the cookie to set to help authenticate future visits. After finding the participation, IP login and hidden users restrictions are checked. sql_session (Session): the SQLAlchemy database session used to execute queries. contest (Contest): the contest the user is trying to access. timestamp (datetime): the date and the time of the request. username (str): the username the user provided. password (str): the password the user provided. ip_address (IPv4Address|IPv6Address): the IP address the request came from. return ((Participation, bytes)|(None, None)): if the user couldn't be authenticated then return None, otherwise return the participation that they wanted to authenticate as; if a cookie has to be set return it as well, otherwise return None. """ def log_failed_attempt(msg, *args): logger.info( "Unsuccessful login attempt from IP address %s, as user " "%r, on contest %s, at %s: " + msg, ip_address, username, contest.name, timestamp, *args) if not contest.allow_password_authentication: log_failed_attempt("password authentication not allowed") return None, None participation = sql_session.query(Participation) \ .join(Participation.user) \ .options(contains_eager(Participation.user)) \ .filter(Participation.contest == contest)\ .filter(User.username == username)\ .first() user = sql_session.query(User).filter(User.username == username).first() if participation is None: if user is None: log_failed_attemp("user not found") return None, None else: participation = Participation(user=user, contest=contest, team=None) sql_session.add(participation) sql_session.commit() if not safe_validate_password(participation, password): log_failed_attempt("wrong password") return None, None if contest.ip_restriction and participation.ip is not None \ and not any(ip_address in network for network in participation.ip): log_failed_attempt("unauthorized IP address") return None, None if contest.block_hidden_participations and participation.hidden: log_failed_attempt("participation is hidden and unauthorized") return None, None logger.info( "Successful login attempt from IP address %s, as user %r, on " "contest %s, at %s", ip_address, username, contest.name, timestamp) return (participation, json.dumps([username, password, make_timestamp(timestamp)]).encode("utf-8"))
def do_import(self): """Get the contest from the Loader and store it.""" # We need to check whether the contest has changed *before* calling # get_contest() as that method might reset the "has_changed" bit. if self.update_contest: contest_has_changed = self.loader.contest_has_changed() # Get the contest contest, tasks, participations = self.loader.get_contest() # Apply the modification flags if self.zero_time: contest.start = datetime.datetime(1970, 1, 1) contest.stop = datetime.datetime(1970, 1, 1) elif self.test: contest.start = datetime.datetime(1970, 1, 1) contest.stop = datetime.datetime(2100, 1, 1) with SessionGen() as session: # Check whether the contest already exists old_contest = session.query(Contest) \ .filter(Contest.name == contest.name).first() if old_contest is not None: if self.update_contest: if contest_has_changed: # Participations are handled later, so we ignore them # at this point (note that contest does not even have # participations). Tasks can be ignored or not, since # they can live even detached from a contest. self._update_object(old_contest, contest, ignore={"participations"}) contest = old_contest elif self.update_tasks: contest = old_contest else: logger.critical( "Contest \"%s\" already exists in database.", contest.name) return False # Check needed tasks for tasknum, taskname in enumerate(tasks): task = session.query(Task) \ .filter(Task.name == taskname).first() if task is None: if self.import_tasks: task = self.loader.get_task_loader(taskname).get_task( get_statement=not self.no_statements) if task: session.add(task) else: logger.critical("Could not import task \"%s\".", taskname) return False else: logger.critical("Task \"%s\" not found in database.", taskname) return False elif self.update_tasks: task_loader = self.loader.get_task_loader(taskname) if task_loader.task_has_changed(): new_task = task_loader.get_task( get_statement=not self.no_statements) if new_task: ignore = set(("num", )) if self.no_statements: ignore.update( ("primary_statements", "statements")) self._update_object(task, new_task, ignore=ignore) else: logger.critical("Could not reimport task \"%s\".", taskname) return False if task.contest is not None \ and task.contest.name != contest.name: logger.critical( "Task \"%s\" is already tied to a " "contest.", taskname) return False else: # We should tie this task to the contest task.num = tasknum task.contest = contest # Check needed participations if participations is None: participations = [] for p in participations: user = session.query(User) \ .filter(User.username == p["username"]).first() team = session.query(Team) \ .filter(Team.code == p.get("team")).first() if user is None: # FIXME: it would be nice to automatically try to # import. logger.critical("User \"%s\" not found in database.", p["username"]) return False if team is None and p.get("team") is not None: # FIXME: it would be nice to automatically try to # import. logger.critical("Team \"%s\" not found in database.", p.get("team")) return False # Check that the participation is not already defined. participation = session.query(Participation) \ .filter(Participation.user_id == user.id) \ .filter(Participation.contest_id == contest.id) \ .first() # FIXME: detect if some details of the participation have been # updated and thus the existing participation needs to be # changed. if participation is None: # Prepare new participation args = { "user": user, "team": team, "contest": contest, } if "hidden" in p: args["hidden"] = p["hidden"] if "ip" in p: args["ip"] = p["ip"] if "password" in p: args["password"] = p["password"] session.add(Participation(**args)) else: logger.warning( "Participation of user %s in this contest " "already exists, not going to update it.", p["username"]) # Here we could check if there are actually some tasks or # users to add: if there are not, then don't create the # contest. However, I would like to be able to create it # anyway (and later tie to it some tasks and users). if old_contest is None: logger.info("Creating contest on the database.") session.add(contest) # Final commit session.commit() logger.info("Import finished (new contest id: %s).", contest.id) return True
def post(self): if not self.contest.allow_registration: raise tornado.web.HTTPError(404) try: first_name = self.get_argument("first_name") last_name = self.get_argument("last_name") username = self.get_argument("username") password = self.get_argument("password") email = self.get_argument("email") if len(email) == 0: email = None if not 1 <= len(first_name) <= self.MAX_INPUT_LENGTH: raise ValueError() if not 1 <= len(last_name) <= self.MAX_INPUT_LENGTH: raise ValueError() if not 1 <= len(username) <= self.MAX_INPUT_LENGTH: raise ValueError() if not re.match(r"^[A-Za-z0-9_-]+$", username): raise ValueError() if not self.MIN_PASSWORD_LENGTH <= len(password) \ <= self.MAX_INPUT_LENGTH: raise ValueError() except (tornado.web.MissingArgumentError, ValueError): raise tornado.web.HTTPError(400) # 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") school = self.get_argument("school") 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 school = None # Check if the username is available tot_users = self.sql_session.query(User)\ .filter(User.username == username).count() if tot_users != 0: # HTTP 409: Conflict raise tornado.web.HTTPError(409) # Store new user and participation user = User(first_name, last_name, username, password, email=email) self.sql_session.add(user) # # Get contest IDs of all contests which are public # f = open('/home/ubuntu/public_contests') # public_contests = set() # for line in f: # digit_contain = False # if (line[0] == '#'): # continue # for c in line: # if (48 <= ord(c)) and (ord(c) <= 57): # digit_contain = True # break # if digit_contain: # public_contests.add(int(line.strip())) # f.close() # Add participation to all public contests for contest in self.sql_session.query(Contest): # if (contest.id in public_contests): if (contest.allow_registration): self.sql_session.add(Participation(user=user, contest=contest, team=team)) # Make log to add additional school if (school != None) and (len(school) > 0): f = open('/home/ubuntu/logs/TODO_logs', 'a') l = str(datetime.datetime.now()) l += " ADD SCHOOL REQUEST " l += " Username: "******" School: " + school f.write(l+'\n') f.close() self.sql_session.commit() self.finish(username)
def post(self, contest_id): fallback_page = self.url("contest", contest_id, "users", "import") self.contest = self.safe_get_item(Contest, contest_id) r_params = self.render_params() action = self.get_body_argument('action', 'upload') if action == 'upload': ignore_existing = self.get_body_argument('ignore_existing', False) load_passwords = self.get_body_argument('load_passwords', False) try: user_csv = self.request.files["users_csv"][0] users = CsvUserLoader(None, None, user_csv['body']).read_users() processed_users = [] some_participants_exist = False for user in users: username = user['username'] result = { 'participant': False, 'username': username } db_user = self.sql_session.query(User).filter_by( username=username).first() if not db_user: self.application.service.add_notification( make_datetime(), 'User missing', '"%s" doesn\'t exist. Import users first.' % username) self.redirect(fallback_page) return result['user_id'] = db_user.id result['team'] = user.get('team') participation = self.sql_session.query(Participation) \ .filter(Participation.user == db_user) \ .filter(Participation.contest == self.contest) \ .first() if participation: result['participant'] = True if not ignore_existing and not some_participants_exist: some_participants_exist = True self.application.service.add_notification( make_datetime(), 'User exists', 'Some participants already exist') if load_passwords: result['password'] = \ cmscommon.crypto.hash_password(user.get('password'), method='plaintext') else: result['password'] = None processed_users.append(result) r_params['users'] = processed_users r_params['has_errors'] = \ (some_participants_exist and not ignore_existing) r_params['load_passwords'] = load_passwords self.render('participation_preview.html', **r_params) return except Exception as error: self.application.service.add_notification( make_datetime(), "Bad CSV file", repr(error)) self.redirect(fallback_page) return elif action == 'save': user_id = self.get_body_arguments('user_id', False) teams = self.get_body_arguments('team', False) passwords = self.get_body_arguments('password', False) for i in range(len(user_id)): user = self.safe_get_item(User, user_id[i]) team = None if teams[i]: team_code = ImportParticipantsHandler \ .prepare_team_code(teams[i]) team = self.sql_session.query(Team) \ .filter_by(code=team_code).first() if not team: team = Team(code=team_code, name=teams[i]) self.sql_session.add(team) password = passwords[i] if passwords else None participation = Participation(user=user, contest=self.contest, team=team, password=password) self.sql_session.add(participation) if self.try_commit(): # Create the user on RWS. self.application.service.proxy_service.reinitialize() self.redirect(self.url("contest", contest_id, "users")) return self.redirect(fallback_page)