Esempio n. 1
0
    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))
Esempio n. 2
0
    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))
Esempio n. 3
0
    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))
Esempio n. 4
0
    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)