Example #1
0
    def get_contest(self):
        """
        GET /contest
        """
        start_timestamp = Database.get_meta("start_time", type=int)
        start_datetime = (datetime.fromtimestamp(start_timestamp, timezone.utc)
                          if start_timestamp is not None else None)
        now = datetime.now(timezone.utc)

        if not start_timestamp or now < start_datetime:
            return {
                "has_started": False,
                "start_time":
                start_datetime.isoformat() if start_datetime else None,
                "name": Database.get_meta("contest_name"),
                "description": Database.get_meta("contest_description"),
            }

        tasks = Database.get_tasks()
        return {
            "has_started": True,
            "name": Database.get_meta("contest_name"),
            "description": Database.get_meta("contest_description"),
            "start_time": start_datetime.isoformat(),
            "tasks": tasks,
            "max_total_score": sum(task["max_score"] for task in tasks),
        }
Example #2
0
    def test_get_meta_type_bool(self):
        Database.connected = False
        Database.connect_to_database()

        Database.set_meta('boooool', True)
        self.assertTrue(Database.get_meta('boooool', type=bool))
        Database.set_meta('boooool2', False)
        self.assertFalse(Database.get_meta('boooool2', type=bool))
Example #3
0
    def test_get_meta_none(self):
        Database.connected = False
        Database.connect_to_database()

        Database.set_meta("test", None)
        Database.set_meta("test2", "None")
        self.assertEqual(Database.get_meta("test"), None)
        self.assertEqual(Database.get_meta("test", type=int), None)
        self.assertEqual(Database.get_meta("test", None, type=int), None)
        self.assertEqual(Database.get_meta("test2", None), "None")
Example #4
0
    def test_status(self):
        Database.set_meta('start_time', 1234)
        res = self.admin_handler.status(admin_token='ADMIN-TOKEN',
                                        _ip='1.2.3.4')

        start_time = int(
            datetime.datetime.strptime(res["start_time"],
                                       "%Y-%m-%dT%H:%M:%S").timestamp())

        self.assertEqual(start_time, Database.get_meta('start_time', type=int))
        self.assertEqual(0, Database.get_meta('extra_time', default=0))
Example #5
0
    def test_status(self):
        Database.set_meta("start_time", 1234)
        res = self.admin_handler.status(admin_token="ADMIN-TOKEN",
                                        _ip="1.2.3.4")

        start_time = dateutil.parser.parse(res["start_time"])

        start_time_db = datetime.fromtimestamp(
            Database.get_meta("start_time", type=int), timezone.utc)
        self.assertEqual(start_time, start_time_db)
        self.assertEqual(0, Database.get_meta("extra_time", default=0))
Example #6
0
    def test_get_meta_default(self):
        Database.connected = False
        Database.connect_to_database()

        meta = Database.get_meta("this_key_doesnt_exist",
                                 "default_value_is_cool")
        self.assertEqual("default_value_is_cool", meta)
Example #7
0
    def test_del_meta(self):
        Database.connected = False
        Database.connect_to_database()

        Database.set_meta('random_key', 4242)
        self.assertTrue(Database.del_meta('random_key'))
        self.assertIsNone(Database.get_meta('random_key'))
Example #8
0
    def test_get_meta_default(self):
        Database.connected = False
        Database.connect_to_database()

        meta = Database.get_meta('this_key_doesnt_exist',
                                 'default_value_is_cool')
        self.assertEqual('default_value_is_cool', meta)
Example #9
0
    def test_set_meta(self):
        Database.connected = False
        Database.connect_to_database()

        Database.set_meta('random_key', 42)
        value = Database.get_meta('random_key', type=int)
        self.assertEqual(42, value)
Example #10
0
    def status(self):
        """
        POST /admin/status
        """
        start_time = Database.get_meta('start_time', type=int)
        extra_time = Database.get_meta('extra_time', type=int, default=0)
        end_time = BaseHandler.get_end_time(0)

        return BaseHandler.format_dates(
            {
                "start_time": start_time,
                "extra_time": extra_time,
                "end_time": end_time,
                "loaded": ContestManager.has_contest
            },
            fields=["start_time", "end_time"])
Example #11
0
    def download_results(self):
        """
        POST /admin/download_pack
        """
        Logger.info("ADMIN", "Creating zip file")
        zip_directory = os.path.join(Config.storedir, "zips",
                                     Database.gen_id())
        os.makedirs(zip_directory, exist_ok=True)
        zipf_name = ("results-" +
                     Database.get_meta("admin_token").split("-", 1)[0] + "-" +
                     time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) +
                     ".zip")
        zipf_name = os.path.join(zip_directory, zipf_name)
        command = ("zip -r '" + zipf_name + "' db.sqlite3* log.sqlite3* "
                   "files/input files/output "
                   "files/source /version* "
                   "/proc/cpuinfo* "
                   "/var/log/nginx")

        try:
            gevent.subprocess.check_output(command,
                                           shell=True,
                                           stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            Logger.error("ADMIN", "Zip error: %s" % e.output)
            raise e
        return {
            "path": os.path.relpath(zipf_name, Config.storedir)
        }  # pragma: nocover
Example #12
0
 def _ensure_contest_running(token=None):
     """
     Makes sure that the contest is running for the user, if any. If the user has a time window it is also checked.
     :param token: The optional token of the user.
     """
     extra_time = None
     start_delay = None
     if token:
         Validators._ensure_window_start(token)
         user = Database.get_user(token)
         if user:
             extra_time = user["extra_time"]
             start_delay = user["contest_start_delay"]
     if Database.get_meta("start_time") is None:
         BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                               "The contest has not started yet")
     contest_end = BaseHandler.get_end_time(extra_time)
     window_end = BaseHandler.get_window_end_time(extra_time, start_delay)
     now = time.time()
     # check the contest is not finished
     if contest_end < now:
         BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                               "The contest has ended")
     # if a window is present check it's not finished
     if window_end and window_end < now:
         BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                               "Your window has ended")
Example #13
0
    def test_set_meta_overwrite(self):
        Database.connected = False
        Database.connect_to_database()

        Database.set_meta("random_key", 4242)
        Database.set_meta("random_key", 42)
        value = Database.get_meta("random_key", type=int)
        self.assertEqual(42, value)
Example #14
0
    def test_start_reset(self):
        Utils.start_contest(since=-100)
        out = self.admin_handler.start("reset",
                                       admin_token="ADMIN-TOKEN",
                                       _ip="1.2.3.4")

        self.assertIsNone(out["start_time"])
        self.assertIsNone(Database.get_meta("start_time"))
Example #15
0
 def test_read_from_disk_transaction_failed(self, add_task_mock):
     path = Utils.new_tmp_dir()
     self._prepare_contest_dir(path)
     Config.statementdir = Utils.new_tmp_dir()
     Config.contest_path = path
     with self.assertRaises(Exception) as ex:
         ContestManager.read_from_disk()
     self.assertEqual("ops...", ex.exception.args[0])
     self.assertIsNone(Database.get_meta("contest_duration"))
Example #16
0
    def test_start_ok(self):
        out = self.admin_handler.start(admin_token='ADMIN-TOKEN',
                                       _ip='1.2.3.4')

        start_time = datetime.datetime.strptime(
            out["start_time"], "%Y-%m-%dT%H:%M:%S").timestamp()
        self.assertTrue(start_time >= datetime.datetime.now().timestamp() - 10)

        self.assertEqual(start_time, Database.get_meta('start_time', type=int))
Example #17
0
    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))
Example #18
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))
Example #19
0
    def test_start_now(self):
        out = self.admin_handler.start("now",
                                       admin_token="ADMIN-TOKEN",
                                       _ip="1.2.3.4")

        start_time = dateutil.parser.parse(out["start_time"]).timestamp()
        self.assertTrue(start_time >= datetime.utcnow().timestamp() - 10)

        start_time_db = datetime.fromtimestamp(
            Database.get_meta("start_time", type=int), timezone.utc)
        self.assertEqual(start_time, start_time_db.timestamp())
Example #20
0
 def _ensure_contest_started():
     start_timestamp = Database.get_meta("start_time", type=int)
     start_datetime = (
         datetime.fromtimestamp(start_timestamp, timezone.utc)
         if start_timestamp is not None
         else None
     )
     if not start_datetime or start_datetime > datetime.now(timezone.utc):
         BaseHandler.raise_exc(
             Forbidden, "FORBIDDEN", "The contest has not started yet"
         )
Example #21
0
 def _ensure_window_start(token):
     """
     Makes sure that the window of the user has been started
     :param token: The token of the user
     :return: True if the user has been updated
     """
     if not Database.get_meta("window_duration", None):
         return False
     user = Database.get_user(token)
     if not user:
         return False
     start_delay = user["contest_start_delay"]
     if start_delay is not None:
         return False
     start = Database.get_meta("start_time", type=int)
     if start is None:
         return False
     now = time.time()
     delay = now - start
     Database.set_start_delay(token, delay)
     Logger.info("WINDOW_START", "Contest started for %s after %d" % (token, delay))
     return True
Example #22
0
    def test_do_write_rollback(self):
        Database.connected = False
        Database.connect_to_database()

        with patch("terry.database.Database.commit",
                   side_effect=ValueError("Ops...")):
            with self.assertRaises(ValueError):
                Database.do_write(True, """
                    INSERT INTO metadata (key, value) 
                    VALUES (:key, :value)
                """, {"key": "ciao", "value": "mondo"})

        self.assertIsNone(Database.get_meta("ciao"))
Example #23
0
    def start(self):
        """
        POST /admin/start
        """
        if Database.get_meta("start_time", default=None, type=int) is not None:
            BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                                  "Contest has already been started!")

        start_time = int(time.time())
        Database.set_meta("start_time", start_time)
        Logger.info("CONTEST", "Contest started")
        return BaseHandler.format_dates({"start_time": start_time},
                                        fields=["start_time"])
Example #24
0
    def test_start_scheduled(self):
        start_time_str = "2020-01-01T13:13:13.0Z"
        out = self.admin_handler.start(start_time_str,
                                       admin_token="ADMIN-TOKEN",
                                       _ip="1.2.3.4")

        start_time = dateutil.parser.parse(out["start_time"])
        expected_start_time = dateutil.parser.parse(start_time_str)
        self.assertEqual(start_time, expected_start_time)

        start_time_db = datetime.fromtimestamp(
            Database.get_meta("start_time", type=int), timezone.utc)
        self.assertEqual(start_time, start_time_db)
Example #25
0
    def test_read_from_disk(self):
        path = Utils.new_tmp_dir()
        self._prepare_contest_dir(path)
        Config.statementdir = Utils.new_tmp_dir()
        Config.contest_path = path

        with patch("gevent.spawn") as mock:
            ContestManager.read_from_disk()
            mock.assert_has_calls(
                [call(ContestManager.worker, "poldo")], any_order=True)

        self.assertEqual(18000, Database.get_meta(
            "contest_duration", type=int))
        tasks = Database.get_tasks()
        self.assertEqual(1, len(tasks))
        self.assertEqual("poldo", tasks[0]["name"])
        self.assertEqual("Poldo", tasks[0]["title"])
        self.assertEqual(42, tasks[0]["max_score"])
        self.assertEqual(0, tasks[0]["num"])

        users = Database.get_users()
        self.assertEqual(1, len(users))
        self.assertEqual("token", users[0]["token"])
        self.assertEqual("Test", users[0]["name"])
        self.assertEqual("User", users[0]["surname"])
        self.assertEqual(0, users[0]["extra_time"])

        user_tasks = Database.get_user_task("token", "poldo")
        self.assertEqual("token", user_tasks["token"])
        self.assertEqual("poldo", user_tasks["task"])
        self.assertEqual(0, user_tasks["score"])
        self.assertIsNone(user_tasks["current_attempt"])

        self.assertTrue(Database.get_meta("contest_imported", type=bool))
        self.assertTrue(ContestManager.has_contest)
        self.assertIn("poldo", ContestManager.tasks)
        self.assertIn("poldo", ContestManager.input_queue)
Example #26
0
 def upload_pack(self, file):
     """
     POST /admin/upload_pack
     """
     if Database.get_meta("admin_token"):
         BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                               "The pack has already been extracted")
     elif os.path.exists(Config.encrypted_file):
         BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                               "The pack has already been uploaded")
     if not crypto.validate(file["content"]):
         self.raise_exc(Forbidden, "BAD_FILE", "The uploaded file is "
                        "not valid")
     StorageManager.save_file(os.path.realpath(Config.encrypted_file),
                              file["content"])
     return {}
Example #27
0
def process_pack(pack, workdir):
    global data

    with common.extract_and_connect(pack, workdir):
        contest_start = Database.get_meta("start_time", type=int)
        tasks = common.get_tasks()

        Database.c.execute("""
            SELECT
                submissions.date AS date,
                inputs.date AS input_date
            FROM submissions
            JOIN inputs ON submissions.input = inputs.id
            ORDER BY date ASC
        """)
        submissions = Database.dictify(all=True)
        add_dates(data["submissions"], submissions, contest_start)
        for sub in submissions:
            delta = sub["date"] - sub["input_date"]
            if delta not in data["delta"]:
                data["delta"][delta] = 0
            data["delta"][delta] += 1

        Database.c.execute("""
            SELECT
                inputs.date AS date
            FROM inputs
            ORDER BY date ASC
        """)
        inputs = Database.dictify(all=True)
        add_dates(data["inputs"], inputs, contest_start)

        for task in tasks:
            Database.c.execute(
                """
                SELECT
                    submissions.date AS date
                FROM submissions
                WHERE task = :task
                ORDER BY date ASC
            """, {"task": task})
            submissions = Database.dictify(all=True)
            if task not in data["tasks"]:
                data["tasks"][task] = dict()
            add_dates(data["tasks"][task], submissions, contest_start)
Example #28
0
    def drop_contest(self, admin_token):
        """
        POST /admin/drop_contest
        """
        if not os.path.exists(Config.encrypted_file):
            self.raise_exc(NotFound, "NOT_FOUND", "No packs found")
        Logger.warning("DROP_CONTEST", "Started dropping contest")
        with open(Config.encrypted_file, "rb") as f:
            pack = f.read()

        db_token = Database.get_meta("admin_token")
        # contest has been extracted but the token is wrong
        if db_token is not None and db_token != admin_token:
            self.raise_exc(Forbidden, "FORBIDDEN", "Wrong token")
        # contest has not been extracted
        if db_token is None:
            try:
                password = crypto.recover_file_password_from_token(admin_token)
                crypto.decode(password, pack)
            except nacl.exceptions.CryptoError:
                # pack password is wrong
                self.raise_exc(Forbidden, "FORBIDDEN", "Wrong pack token")

        metadata = ruamel.yaml.safe_load(crypto.metadata(pack).strip(b"\x00"))
        if not metadata.get("deletable"):
            self.raise_exc(Forbidden, "FORBIDDEN", "Contest not deletable")

        shutil.rmtree(Config.storedir, ignore_errors=True)
        shutil.rmtree(Config.statementdir, ignore_errors=True)
        shutil.rmtree(Config.contest_path, ignore_errors=True)
        for f in (Config.encrypted_file, Config.decrypted_file):
            try:
                os.remove(f)
            except FileNotFoundError:
                pass

        Database.disconnect_database()
        for f in glob.glob(Config.db + "*"):
            os.remove(f)
        Database.connect_to_database()
        Logger.warning("DROP_CONTEST", "Contest dropped")
        return {}
Example #29
0
    def start(self, start_time: str):
        """
        POST /admin/start
        """
        previous_start = Database.get_meta("start_time", type=int)
        now = int(time.time())
        if previous_start and now > previous_start:
            BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                                  "Contest has already been started!")

        actual_start = None
        if start_time == "reset":
            Database.del_meta("start_time")
            return {"start_time": None}
        elif start_time == "now":
            actual_start = now
        else:
            actual_start = dateutil.parser.parse(start_time).timestamp()
        Database.set_meta("start_time", int(actual_start))
        Logger.info("CONTEST", "Contest starts at " + str(actual_start))
        return BaseHandler.format_dates({"start_time": actual_start},
                                        fields=["start_time"])
Example #30
0
    def _validate_admin_token(token, ip):
        """
        Ensure the admin token is valid
        :param token: Token to check
        :param ip: IP of the client
        """

        correct_token = Database.get_meta("admin_token")

        if correct_token is None:
            ContestManager.extract_contest(token)
            ContestManager.read_from_disk()
            correct_token = token

        if token != correct_token:
            Logger.warning("LOGIN_ADMIN", "Admin login failed from %s" % ip)
            BaseHandler.raise_exc(Forbidden, "FORBIDDEN",
                                  "Invalid admin token!")
        else:
            if Database.register_admin_ip(ip):
                Logger.info("LOGIN_ADMIN",
                            "An admin has connected from a new ip: %s" % ip)