Beispiel #1
0
class StatementProblem(db.Model):
    __table_args__ = {'schema': 'moodle'}
    __tablename__ = 'mdl_statements_problems_correlation'

    id = db.Column(db.Integer, primary_key=True)
    statement_id = db.Column(db.Integer,
                             db.ForeignKey('moodle.mdl_statements.id'))
    problem_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_problems.id'))
    rank = db.Column('rank', db.Integer)
    hidden = db.Column('hidden', db.Integer)

    statement = db.relationship(
        'Statement',
        backref=db.backref(
            'StatementProblems',
            collection_class=attribute_mapped_collection("rank")))

    # reference to the "Keyword" object
    problem = db.relationship('Problem',
                              backref=db.backref('StatementProblems'))

    def __init__(self, statement_id, problem_id, rank):
        self.statement_id = statement_id
        self.problem_id = problem_id
        self.rank = rank
        self.hidden = 0
class CourseModule(db.Model):
    __table_args__ = {'schema': 'moodle'}
    __tablename__ = 'mdl_course_modules'

    id = db.Column(db.Integer, primary_key=True)
    course_id = db.Column('course', db.Integer, db.ForeignKey('moodle.mdl_course.id'))
    module = db.Column(db.Integer)
    instance_id = db.Column('instance', db.Integer)
    section_id = db.Column('section', db.Integer, db.ForeignKey('moodle.mdl_course_sections.id'))
    visible = db.Column(db.Boolean)

    course = db.relationship('Course', backref=db.backref('course_modules', lazy='dynamic'))
    section = db.relationship('CourseSection', backref=db.backref('modules', lazy='dynamic'))

    @property
    def instance(self) -> Type['CourseModuleInstance']:
        if not hasattr(self, '_instance'):
            instance_class = next(
                (
                    subclass
                    for subclass in CourseModuleInstance.__subclasses__()
                    if subclass.MODULE == self.module
                ),
                None
            )
            if not instance_class:
                self._instance = None
            else:
                self._instance = db.session.query(instance_class) \
                    .filter_by(id=self.instance_id) \
                    .first()
        return self._instance

    @deprecated(' `Do not use serialize inside model!` ')
    def serialize(self):
        serialized = attrs_to_dict(
            self,
            'id',
            'course_id',
            'module',
            'section_id',
            'visible',
        )
        if self.instance:
            serialized['type'] = self.instance.MODULE_TYPE
            if self.instance.MODULE_TYPE == 'STATEMENT':
                serialized['instance'] = attrs_to_dict(
                    self.instance,
                    'id',
                    'name',
                )
            elif self.instance.MODULE_TYPE in ['BOOK', 'MONITOR']:
                serialized['instance'] = self.instance.serialize(course_module_id=self.id)
            else:
                serialized['instance'] = self.instance.serialize()

        return serialized
Beispiel #3
0
class WorkshopMonitor(db.Model):
    __table_args__ = {'schema': 'pynformatics'}
    __tablename__ = 'contest_monitor'

    id = db.Column(db.Integer, primary_key=True)

    workshop_id = db.Column(db.Integer,
                            db.ForeignKey('pynformatics.workshop.id'))
    type = db.Column(IntEnum(WorkshopMonitorType),
                     default=WorkshopMonitorType.IOI,
                     nullable=False)

    user_visibility = db.Column(IntEnum(WorkshopMonitorUserVisibility),
                                default=WorkshopMonitorUserVisibility.FULL,
                                nullable=False)

    with_penalty_time = db.Column(db.Boolean, default=False)
    freeze_time = db.Column(db.DateTime)

    workshop = db.relationship('WorkShop',
                               backref=db.backref(
                                   'monitors', cascade='all, delete-orphan'))

    def is_for_user_only(self):
        return self.user_visibility == WorkshopMonitorUserVisibility.FOR_USER_ONLY

    def is_disabled_for_students(self):
        return self.user_visibility == WorkshopMonitorUserVisibility.DISABLED_FOR_STUDENT
Beispiel #4
0
class User(SimpleUser):
    __mapper_args__ = {'polymorphic_identity': 'user'}
    username = db.Column(db.Unicode(100))
    email = db.Column(db.Unicode(100))
    city = db.Column(db.Unicode(20))
    school = db.Column(db.Unicode(255))
    problems_week_solved = db.Column(db.Integer)

    roles = db.relationship('Role',
                            secondary='moodle.mdl_role_assignments',
                            lazy='select')

    @property
    def token(self):
        return generate_auth_token(self)

    @classmethod
    def check_password(cls, password_md5: str, password: str) -> bool:
        return password_md5 == cls.hash_password(password)

    @staticmethod
    def hash_password(plan_password: str) -> str:
        """Returns MD5 hash for plan password string.
        Raises ValueError if password string is invalid.

        :param plan_password: password string to hash
        :return: hashed password
        """
        return hashlib.md5(plan_password.encode('utf-8')).hexdigest()
Beispiel #5
0
class Statement(db.Model):
    __table_args__ = {'schema': 'moodle'}
    __tablename__ = 'mdl_statements'
    __mapper_args__ = {
        'polymorphic_identity': 'statement',
        'concrete': True,
    }

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode(255))
    summary = db.Column(MEDIUMTEXT)
    numbering = db.Column(db.Integer)
    disable_printing = db.Column('disableprinting', db.Boolean)
    custom_titles = db.Column('customtitles', db.Boolean)
    time_created = db.Column('timecreated', db.Integer)
    time_modified = db.Column('timemodified', db.Integer)
    contest_id = db.Column(db.Integer)
    time_start = db.Column('timestart', db.Integer)
    time_stop = db.Column('timestop', db.Integer)
    olympiad = db.Column(db.Boolean)
    virtual_olympiad = db.Column(db.Boolean)
    virtual_duration = db.Column(db.Integer)
    settings = db.Column(JsonType)

    problems = db.relationship('Problem',
                               secondary='moodle.mdl_statements_problems_correlation')
 def course_module(cls):
     class_name = cls.__name__
     class_module = cls.MODULE
     return db.relationship(
         CourseModule,
         primaryjoin=f'and_({class_name}.id==CourseModule.instance_id,'
             f'CourseModule.module=={class_module})',
         foreign_keys='%s.id' % cls.__name__,
     )
Beispiel #7
0
class StatementStandings(StandingsMixin, db.Model):
    __tablename__ = 'statement_standings'

    statement_id = db.Column(db.Integer,
                             db.ForeignKey('moodle.mdl_statements.id'),
                             primary_key=True)
    statement = db.relationship('Statement',
                                backref=db.backref('standings',
                                                   uselist=False,
                                                   lazy='joined'))
Beispiel #8
0
class WorkshopConnection(db.Model):
    __table_args__ = (
        db.UniqueConstraint('user_id', 'workshop_id', name='_workshop_user_uc'),
        {'schema': 'pynformatics'},
    )
    __tablename__ = 'workshop_connection'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.ForeignKey('moodle.mdl_user.id'), index=True)
    workshop_id = db.Column(
        db.Integer,
        db.ForeignKey('pynformatics.workshop.id', ondelete='CASCADE', name='fk_course_id'),
        nullable=False
    )

    status = db.Column(
        IntEnum(WorkshopConnectionStatus),
        default=WorkshopConnectionStatus.APPLIED,  # TODO: возможно, вернуть на ACCEPTED
        nullable=False
    )

    user = db.relationship('User')

    workshop = db.relationship(
        'WorkShop',
        backref=db.backref('connections', cascade='all, delete-orphan')
    )

    def is_accepted(self):
        return self.status == WorkshopConnectionStatus.ACCEPTED

    def is_promoted(self):
        return self.status == WorkshopConnectionStatus.PROMOTED

    def is_avialable(self):
        return self.is_accepted() or self.is_promoted()

    def __repr__(self):
        return (
            f'<WorkshopConnection '
            f'id="{self.id}" '
            f'workshop_id="{self.workshop_id}" '
            f'user_id="{self.user_id}">'
        )
Beispiel #9
0
class ProblemStandings(StandingsMixin, db.Model):
    __tablename__ = 'problem_standings'
    __table_args__ = {'schema': 'pynformatics'}

    problem_id = db.Column(db.Integer,
                           db.ForeignKey('moodle.mdl_problems.id'),
                           primary_key=True)
    problem = db.relationship('EjudgeProblem',
                              backref=db.backref('standings',
                                                 uselist=False,
                                                 lazy='joined'))
class WorkShop(db.Model):
    __table_args__ = {'schema': 'pynformatics'}
    __tablename__ = 'workshop'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=False, default='Время Сборов.')
    status = db.Column(IntEnum(WorkshopStatus), nullable=False,
                       default=WorkshopStatus.DRAFT)
    visibility = db.Column(IntEnum(WorkshopVisibility), nullable=False,
                           default=WorkshopVisibility.PRIVATE)

    access_token = db.Column(db.String(32), nullable=False)
    contests = db.relationship('Contest', back_populates='workshop')
Beispiel #11
0
class CourseSection(db.Model):
    __table_args__ = {'schema': 'moodle'}
    __tablename__ = 'mdl_course_sections'

    id = db.Column(db.Integer, primary_key=True)
    course_id = db.Column('course', db.Integer,
                          db.ForeignKey('moodle.mdl_course.id'))
    section = db.Column(db.Integer)
    summary = db.Column(db.Text)
    sequence_text = db.Column('sequence', db.Text)
    visible = db.Column(db.Boolean)

    course = db.relationship('Course',
                             backref=db.backref(
                                 'sections',
                                 lazy='dynamic',
                                 order_by='CourseSection.section'))

    def __init__(self):
        self._sequence = None

    @property
    def sequence(self):
        if not getattr(self, '_sequence'):
            try:
                self._sequence = list(map(int, self.sequence_text.split(',')))
            except Exception:
                self._sequence = []
        return self._sequence

    @sequence.setter
    def sequence(self, value):
        self._sequence = value
        self.sequence_text = ','.join(list(map(str, value)))

    def serialize(self):
        serialized = attrs_to_dict(
            self,
            'id',
            'course_id',
            'section',
            'summary',
            'sequence',
            'visible',
        )
        serialized['modules'] = [
            module.serialize()
            for module in self.modules.filter_by(visible=True).all()
        ]

        return serialized
class RefreshToken(db.Model):
    __tablename__ = 'refresh_token'
    __table_args__ = (db.Index('search_token', 'token'), {
        'schema': 'pynformatics'
    })

    id = db.Column(db.Integer(), primary_key=True)

    token = db.Column(db.String(255))
    user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
    valid = db.Column(db.Boolean(), default=True, nullable=False)
    created_at = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
    user = db.relationship('User',
                           lazy='joined',
                           backref=backref('refresh_tokens',
                                           cascade="all, delete-orphan"),
                           single_parent=True)
Beispiel #13
0
class SimpleUser(db.Model):
    RESET_PASSWORD_LENGTH = 20

    __table_args__ = ({'schema': 'moodle'})
    __tablename__ = 'mdl_user'

    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.Unicode(100))
    lastname = db.Column(db.Unicode(100))
    deleted = db.Column('deleted', db.Boolean)
    problems_solved = db.Column(db.Integer)
    password_md5 = db.Column('password', db.Unicode(32))

    statement = db.relationship(
        'Statement',
        secondary=StatementUser.__table__,
        backref='StatementUsers1',
        lazy='dynamic',
    )
    statements = association_proxy('StatementUsers2', 'statement')
class ContestConnection(db.Model):
    __table_args__ = (
        db.UniqueConstraint('user_id', 'contest_id', name='_contest_user_uc'),
        {
            'schema': 'pynformatics'
        },
    )
    __tablename__ = 'contest_connection'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer)
    contest_id = db.Column(
        db.Integer,
        db.ForeignKey('pynformatics.contest.id', ondelete='CASCADE'),
    )

    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)

    contest = db.relationship('Contest',
                              backref=db.backref('connections',
                                                 cascade='all, delete-orphan'))
Beispiel #15
0
class User(SimpleUser):
    __mapper_args__ = {'polymorphic_identity': 'user'}
    username = db.Column(db.Unicode(100))
    email = db.Column(db.Unicode(100))
    city = db.Column(db.Unicode(20))
    school = db.Column(db.Unicode(255))
    problems_week_solved = db.Column(db.Integer)

    roles = db.relationship('Role',
                            secondary='moodle.mdl_role_assignments',
                            lazy='select')

    @property
    def token(self):
        return generate_jwt_token(self)

    @staticmethod
    def check_password(password_md5: str, password: str) -> bool:
        hashed_password = hashlib.md5(password.encode('utf-8')).hexdigest()
        if password_md5 == hashed_password:
            return True
        return False
Beispiel #16
0
class Statement(CourseModuleInstance, db.Model):
    __table_args__ = {'schema': 'moodle'}
    __tablename__ = 'mdl_statements'
    __mapper_args__ = {
        'polymorphic_identity': 'statement',
        'concrete': True,
    }

    MODULE = 19

    id = db.Column(db.Integer, primary_key=True)
    course_id = db.Column('course', db.Integer,
                          db.ForeignKey('moodle.mdl_course.id'))
    name = db.Column(db.Unicode(255))
    summary = db.Column(MEDIUMTEXT)
    numbering = db.Column(db.Integer)
    disable_printing = db.Column('disableprinting', db.Boolean)
    custom_titles = db.Column('customtitles', db.Boolean)
    time_created = db.Column('timecreated', db.Integer)
    time_modified = db.Column('timemodified', db.Integer)
    contest_id = db.Column(db.Integer)
    time_start = db.Column('timestart', db.Integer)
    time_stop = db.Column('timestop', db.Integer)
    olympiad = db.Column(db.Boolean)
    virtual_olympiad = db.Column(db.Boolean)
    virtual_duration = db.Column(db.Integer)
    settings = db.Column(JsonType)

    course = db.relationship('Course',
                             backref=db.backref('statements', lazy='dynamic'))

    user = association_proxy('StatementUsers1', 'user')

    SETTINGS_SCHEMA = {
        'type': 'object',
        'properties': {
            'allowed_languages': {
                'type': 'array',
                'uniqueItems': True,
                'items': {
                    'type': 'integer',
                    'enum': list(LANG_NAME_BY_ID.keys()),
                }
            },
            'type': {
                'oneOf': [{
                    'type': 'null',
                }, {
                    'type': 'string',
                    'enum': [
                        'olympiad',
                        'virtual',
                    ],
                }],
            },
            'group': {
                'type': 'integer',
            },
            'team': {
                'type': 'boolean',
            },
            'time_start': {
                'type': 'integer',
            },
            'time_stop': {
                'type': 'integer',
            },
            'freeze_time': {
                'type': 'integer',
            },
            'standings': {
                'type': 'boolean',
            },
            'test_only_samples': {
                'type': 'boolean',
            },
            'reset_submits_on_start': {
                'type': 'boolean',
            },
            'test_until_fail': {
                'type': 'boolean',
            },
            'start_from_scratch': {
                'type': 'boolean',
            },
            'restrict_view': {
                'type': 'boolean',
            }
        },
        'additionalProperties': False,
    }
    SETTINGS_SCHEMA_VALIDATOR = Draft4Validator(SETTINGS_SCHEMA)

    def get_allowed_languages(self):
        if not (self.settings and 'allowed_languages' in self.settings):
            return None
        return self.settings['allowed_languages']

    def set_settings(self, settings):
        validation_error = next(
            self.SETTINGS_SCHEMA_VALIDATOR.iter_errors(settings), None)
        if validation_error:
            raise ValueError(validation_error.message)
        self.settings = settings

        if settings.get('time_start'):
            self.time_start = settings['time_start']

        if settings.get('time_stop'):
            self.time_stop = settings['time_stop']

        if 'type' in settings:
            type_ = settings['type']
            if type_ == None:
                self.olympiad = False
                self.virtual_olympiad = False
            elif type_ == 'olympiad':
                self.olympiad = True
                self.virtual_olympiad = False
            else:
                self.olympiad = False
                self.virtual_olympiad = True

        self.time_modified = int(time.time())

    def start_participant(
        self,
        user,
        duration,
        password=None,
    ):
        if self.course \
                and self.course.require_password() \
                and password != self.course.password:
            raise ValueError()

        if self.participants.filter(Participant.user_id == user.id).count():
            raise ValueError()

        if user.get_active_participant():
            raise ValueError()

        new_participant = Participant(
            user_id=user.id,
            statement_id=self.id,
            start=int(time.time()),
            duration=duration,
        )
        db.session.add(new_participant)

        return new_participant

    def finish_participant(self, user):
        active_participant = user.get_active_participant()
        if not active_participant or active_participant.statement_id != self.id:
            raise ValueError()

        active_participant.duration = int(time.time() -
                                          active_participant.start)
        return active_participant

    def start(
        self,
        user,
        password=None,
    ):
        if not self.olympiad:
            raise ValueError()

        now = time.time()
        if now < self.time_start:
            raise ValueError()
        if now >= self.time_stop:
            raise ValueError()

        return self.start_participant(
            user=user,
            duration=self.time_stop - int(time.time()),
            password=password,
        )

    def finish(self, user):
        if not self.olympiad:
            raise ValueError()

        return self.finish_participant(user)

    def serialize(self, attributes=None):
        if not attributes:
            attributes = (
                'id',
                'name',
                'olympiad',
                'settings',
                'time_start',
                'time_stop',
                'virtual_olympiad',
                'virtual_duration',
                'course_module_id',
                'course',
                'require_password',
            )
        serialized = attrs_to_dict(self, *attributes)
        if 'course' in attributes and self.course:
            serialized['course'] = self.course.serialize()
        serialized['course_module_id'] = getattr(self.course_module, 'id',
                                                 None)

        if 'require_password' in attributes:
            if self.course:
                serialized['require_password'] = self.course.require_password()
            else:
                serialized['require_password'] = False

        user = getattr(g, 'user', None)
        if self.olympiad or self.virtual_olympiad:
            if not user:
                return serialized

            try:
                participant = self.participants.filter_by(
                    user_id=user.id).one()
            except NoResultFound:
                return serialized

            serialized['participant'] = participant.serialize()

        serialized['problems'] = {
            rank: {
                'id': statement_problem.problem.id,
                'name': statement_problem.problem.name,
            }
            for rank, statement_problem in self.StatementProblems.items()
            if statement_problem.problem and not statement_problem.hidden
        }
        return serialized
Beispiel #17
0
class Contest(db.Model):
    __table_args__ = {'schema': 'pynformatics'}
    __tablename__ = 'contest'

    id = db.Column(db.Integer, primary_key=True)
    workshop_id = db.Column(db.Integer,
                            db.ForeignKey('pynformatics.workshop.id'))
    statement_id = db.Column(db.Integer,
                             db.ForeignKey('moodle.mdl_statements.id'))
    author_id = db.Column(db.Integer)
    position = db.Column(db.Integer, default=1)

    protocol_visibility = db.Column(IntEnum(ContestProtocolVisibility),
                                    default=ContestProtocolVisibility.FULL,
                                    server_default=str(
                                        ContestProtocolVisibility.FULL.value),
                                    nullable=False)

    is_virtual = db.Column(db.Boolean, default=False)
    time_start = db.Column(db.DateTime)
    time_stop = db.Column(db.DateTime)
    virtual_duration = db.Column(db.Interval,
                                 default=datetime.timedelta(seconds=0))

    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)

    statement = db.relationship('Statement')
    workshop = db.relationship('WorkShop', back_populates='contests')
    languages = db.relationship('Language',
                                secondary='pynformatics.language_contest')

    def _is_available_by_duration(self) -> bool:
        """ Checks date time restrictions """
        current_time = datetime.datetime.utcnow()
        if self.time_start is not None and self.time_start > current_time:
            return False
        if self.time_stop is not None and self.time_stop < current_time:
            return False
        return True

    def _is_available_for_connection(self, cc: ContestConnection) -> bool:
        """ Checks if virtual contest is not expired for ContestConnection """
        if not self.is_virtual:
            return True

        current_time = datetime.datetime.utcnow()
        if cc.created_at + self.virtual_duration < current_time:
            return False

        return True

    def is_available(self, cc) -> bool:
        return self._is_available_by_duration() and \
               self._is_available_for_connection(cc)

    def is_started(self, cc: Optional[ContestConnection]) -> bool:
        current_time = datetime.datetime.utcnow()

        if not self.is_virtual:
            return current_time > self.time_start

        return bool(cc)