Пример #1
0
    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
Пример #2
0
    def _task_to_db(self, session, contest, new_task, task_has_changed):
        """Add the task to the DB

        Return the task, or raise in case of one of these errors:
        - if the task is not in the DB and user did not ask to update it;
        - if the task is already in the DB and attached to another contest.

        """
        task = session.query(Task).filter(Task.name == new_task.name).first()
        if task is None:
            if contest is not None:
                logger.info("Attaching task to contest (id %s.)",
                            self.contest_id)
                new_task.num = len(contest.tasks)
                new_task.contest = contest
            session.add(new_task)
            return new_task

        if not self.update:
            raise ImportDataError("Task \"%s\" already exists in database. "
                                  "Use --update to update it." % new_task.name)

        if contest is not None and task.contest_id != contest.id:
            raise ImportDataError(
                "Task \"%s\" already tied to another contest." % task.name)

        if task_has_changed:
            logger.info("Task \"%s\" data has changed, updating it.",
                        task.name)
            update_task(task, new_task, get_statements=not self.no_statement)
        else:
            logger.info("Task \"%s\" data has not changed.", task.name)

        return task
Пример #3
0
    def _contest_to_db(self, session, new_contest, contest_has_changed):
        """Add the new contest to the DB

        session (Session): session to use.
        new_contest (Contest): contest that has to end up in the DB.
        contest_has_changed (bool): whether the loader thinks new_contest has
            changed since the last time it was imported.

        return (Contest): the contest in the DB.

        raise (ImportDataError): if the contest already exists on the DB and
            the user did not ask to update any data.

        """
        contest = session.query(Contest)\
            .filter(Contest.name == new_contest.name).first()

        if contest is None:
            # Contest not present, we import it.
            logger.info("Creating contest on the database.")
            contest = new_contest
            # Creating a new main group
            contest.main_group = Group("main")
            contest.groups = [contest.main_group]
            session.add(contest)

        else:
            if not (self.update_contest or self.update_tasks):
                # Contest already present, but user did not ask to update any
                # data. We cannot import anything and this is most probably
                # not what the user wanted, so we let them know.
                raise ImportDataError(
                    "Contest \"%s\" already exists in database. "
                    "Use --update-contest to update it." % contest.name)

            if self.update_contest:
                # Contest already present, user asked us to update it; we do so
                # if it has changed.
                if contest_has_changed:
                    logger.info("Contest data has changed, updating it.")
                    # Don't update the groups
                    groups = []
                    for g_old in contest.groups:
                        g = Group(name=g_old.name)
                        update_group(g, g_old)
                        groups.append(g)
                    new_contest.groups = groups
                    update_contest(contest, new_contest)
                    contest.main_group = [
                        g for g in contest.groups
                        if g.name == contest.main_group.name
                    ][0]
                else:
                    logger.info("Contest data has not changed.")

        return contest
Пример #4
0
 def _dataset_to_db(session, dataset, task):
     old_dataset = session.query(Dataset)\
         .filter(Dataset.task_id == task.id)\
         .filter(Dataset.description == dataset.description).first()
     if old_dataset is not None:
         raise ImportDataError("Dataset \"%s\" already exists." %
                               dataset.description)
     dataset.task = task
     session.add(dataset)
     return dataset
Пример #5
0
 def _team_to_db(session, team, update=False):
     old_team = session.query(Team).filter(Team.code == team.code).first()
     if old_team is not None and update:
         old_team.name = team.name
         return old_team
     elif old_team is not None:
         raise ImportDataError("Team \"%s\" already exists." % team.code)
     else:
         session.add(team)
         return team
Пример #6
0
    def _user_to_db(session, user):
        """Add the user to the DB

        Return the user again, or raise in case a user with the same username
        was already present in the DB.

        """
        old_user = session.query(User)\
            .filter(User.username == user.username).first()
        if old_user is not None:
            raise ImportDataError("User \"%s\" already exists." %
                                  user.username)
        session.add(user)
        return user
Пример #7
0
    def _task_to_db(self, session, contest, tasknum, taskname):
        """Add the task to the DB and attach it to the contest

        session (Session): session to use.
        contest (Contest): the contest in the DB.
        tasknum (int): num the task should have in the contest.
        taskname (string): name of the task.

        return (Task): the task in the DB.
        raise (ImportDataError): in case of one of these errors:
            - if the task is not in the DB and user did not ask to import it;
            - if the loader cannot load the task;
            - if the task is already in the DB, attached to another contest.

        """
        task_loader = self.loader.get_task_loader(taskname)
        task = session.query(Task).filter(Task.name == taskname).first()

        if task is None:
            # Task is not in the DB; if the user asked us to import it, we do
            # so, otherwise we return an error.

            if not self.import_tasks:
                raise ImportDataError("Task \"%s\" not found in database. "
                                      "Use --import-task to import it." %
                                      taskname)

            task = task_loader.get_task(get_statement=not self.no_statements)
            if task is None:
                raise ImportDataError("Could not import task \"%s\"." %
                                      taskname)

            session.add(task)

        elif not task_loader.task_has_changed():
            # Task is in the DB and has not changed, nothing to do.
            logger.info("Task \"%s\" data has not changed.", taskname)

        elif self.update_tasks:
            # Task is in the DB, but has changed, and the user asked us to
            # update it. We do so.
            new_task = task_loader.get_task(
                get_statement=not self.no_statements)
            if new_task is None:
                raise ImportDataError("Could not reimport task \"%s\"." %
                                      taskname)
            logger.info("Task \"%s\" data has changed, updating it.", taskname)
            update_task(task, new_task, get_statements=not self.no_statements)

        else:
            # Task is in the DB, has changed, and the user didn't ask to update
            # it; we just show a warning.
            logger.warning(
                "Not updating task \"%s\", even if it has changed. "
                "Use --update-tasks to update it.", taskname)

        # Finally we tie the task to the contest, if it is not already used
        # elsewhere.
        if task.contest is not None and task.contest.name != contest.name:
            raise ImportDataError(
                "Task \"%s\" is already tied to contest \"%s\"." %
                (taskname, task.contest.name))

        task.num = tasknum
        task.contest = contest
        return task
Пример #8
0
 def _team_to_db(session, team):
     old_team = session.query(Team).filter(Team.code == team.code).first()
     if old_team is not None:
         raise ImportDataError("Team \"%s\" already exists." % team.code)
     session.add(team)
     return team