def generate_input(self, task, user): """ POST /generate_input """ token = user["token"] if Database.get_user_task(token, task["name"])["current_attempt"]: self.raise_exc(Forbidden, "FORBIDDEN", "You already have a ready input!") attempt = Database.get_next_attempt(token, task["name"]) id, path = ContestManager.get_input(task["name"], attempt) size = StorageManager.get_file_size(path) Database.begin() try: Database.add_input(id, token, task["name"], attempt, path, size, autocommit=False) Database.set_user_attempt(token, task["name"], attempt, autocommit=False) Database.commit() except: Database.rollback() raise Logger.info( "CONTEST", "Generated input %s for user %s on task %s" % (id, token, task["name"])) return BaseHandler.format_dates(Database.get_input(id=id))
def _get_user_from_sso(jwt_token, token): try: data = jwt.decode(jwt_token, Config.jwt_secret, algorithms=['HS256']) username = data["username"] name = data.get("firstName", username) surname = data.get("lastName", "") if username != token: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "Use the same username from the SSO") if Database.get_user(username) is None: Database.begin() Database.add_user(username, name, surname, sso_user=True, autocommit=False) for task in Database.get_tasks(): Database.add_user_task(username, task["name"], autocommit=False) Database.commit() Logger.info("NEW_USER", "User %s created from SSO" % username) return Database.get_user(username) except jwt.exceptions.DecodeError: BaseHandler.raise_exc(Forbidden, "FORBIDDEN", "Please login at %s" % Config.sso_url)
def test_transaction_commit(self): Database.connected = False Database.connect_to_database() Database.begin() Database.set_meta('random_foobar', 123, autocommit=False) Database.commit() self.assertEqual(123, Database.get_meta('random_foobar', type=int))
def test_transaction_rollback(self): Database.connected = False Database.connect_to_database() Database.begin() Database.set_meta('random_foobar', 123, autocommit=False) Database.rollback() self.assertEqual(42, Database.get_meta('random_foobar', default=42, type=int))
def submit(self, output, source): """ POST /submit """ input = Database.get_input(output["input"]) if input is None: Logger.warning("DB_CONSISTENCY_ERROR", "Input %s not found in the db" % output["input"]) self.raise_exc(BadRequest, "WRONG_INPUT", "The provided input in invalid") if output["input"] != source["input"]: Logger.warning("POSSIBLE_CHEAT", "Trying to submit wrong pair source-output") self.raise_exc(Forbidden, "WRONG_OUTPUT_SOURCE", "The provided pair of source-output is invalid") score = ContestHandler.compute_score(input["task"], output["result"]) Database.begin() try: submission_id = Database.gen_id() if not Database.add_submission(submission_id, input["id"], output["id"], source["id"], score, autocommit=False): self.raise_exc(BadRequest, "INTERNAL_ERROR", "Error inserting the submission") ContestHandler.update_user_score(input["token"], input["task"], score) Database.set_user_attempt(input["token"], input["task"], None, autocommit=False) Database.commit() except sqlite3.IntegrityError as ex: Database.rollback() # provide a better error message if the input has already been # submitted if "UNIQUE constraint failed: submissions.input" in str(ex): self.raise_exc(Forbidden, "ALREADY_SUBMITTED", "This input has already been submitted") raise except: Database.rollback() raise Logger.info( "CONTEST", "User %s has submitted %s on %s" % (input["token"], submission_id, input["task"])) return InfoHandler.patch_submission( Database.get_submission(submission_id))
def read_from_disk(remove_enc=True): """ Load a task from the disk and load the data into the database """ try: contest = ContestManager.import_contest(Config.contest_path) except FileNotFoundError as ex: error = ( "Contest not found, you probably need to unzip it. Missing file %s" % ex.filename) Logger.warning("CONTEST", error) shutil.rmtree(Config.statementdir, ignore_errors=True) shutil.rmtree(Config.web_statementdir, ignore_errors=True) shutil.rmtree(Config.contest_path, ignore_errors=True) if remove_enc: with suppress(Exception): os.remove(Config.encrypted_file) with suppress(Exception): os.remove(Config.decrypted_file) Database.del_meta("admin_token") BaseHandler.raise_exc(UnprocessableEntity, "CONTEST", error) if not Database.get_meta("contest_imported", default=False, type=bool): Database.begin() try: Database.set_meta("contest_duration", contest["duration"], autocommit=False) Database.set_meta("contest_name", contest.get("name", "Contest"), autocommit=False) Database.set_meta( "contest_description", contest.get("description", ""), autocommit=False, ) Database.set_meta( "window_duration", # if None the contest is not USACO-style contest.get("window_duration"), autocommit=False, ) count = 0 for task in contest["tasks"]: Database.add_task( task["name"], task["description"], task["statement_path"], task["max_score"], count, autocommit=False, ) count += 1 for user in contest["users"]: Database.add_user(user["token"], user["name"], user["surname"], autocommit=False) for user in Database.get_users(): for task in Database.get_tasks(): Database.add_user_task(user["token"], task["name"], autocommit=False) Database.set_meta("contest_imported", True, autocommit=False) Database.commit() except: Database.rollback() raise else: # TODO: check that the contest is still the same pass # store the task in the ContestManager singleton ContestManager.tasks = dict( (task["name"], task) for task in contest["tasks"]) ContestManager.has_contest = True # create the queues for the task inputs for task in ContestManager.tasks: ContestManager.input_queue[task] = gevent.queue.Queue( Config.queue_size) gevent.spawn(ContestManager.worker, task)