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 StatementUser(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_olympiad' id = db.Column(db.Integer, primary_key=True) statement_id = db.Column('contest_id', db.Integer, db.ForeignKey('moodle.mdl_statements.id')) user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id'))
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
class Problem(db.Model): __table_args__ = {'schema':'moodle'} __tablename__ = 'mdl_problems' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode(255)) content = db.Column(db.Text) review = db.Column(db.Text) hidden = db.Column(db.Boolean) timelimit = db.Column(db.Float) memorylimit = db.Column(db.Integer) description = db.Column(db.Text) analysis = db.Column(db.Text) sample_tests = db.Column(db.Unicode(255)) sample_tests_html = db.Column(db.Text) sample_tests_json = db.Column(JsonType) show_limits = db.Column(db.Boolean) output_only = db.Column(db.Boolean) pr_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_ejudge_problem.id')) ejudge_problem = relationship('EjudgeProblem', lazy='select') def __init__(self, *args, **kwargs): super(Problem, self).__init__(*args, **kwargs) self.hidden = 1 self.show_limits = True
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
class Comment(db.Model): __tablename__ = "mdl_run_comments" __table_args__ = {'schema': 'ejudge'} id = db.Column(db.Integer, primary_key=True) date = db.Column(db.DateTime, default=datetime.datetime.utcnow) contest_id = db.Column(db.Integer) user_id = db.Column(db.Integer, nullable=False) author_user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id'), nullable=False) author_user = db.relation("User", uselist=False, lazy='select') run_id = db.Column(db.Integer) # deprecated lines = db.Column(db.Text) comment = db.Column(db.Text) is_read = db.Column(db.Boolean) py_run_id = db.Column(db.Integer) def get_by(run_id, contest_id): try: return db.session.query(Comment).filter( Comment.run.run_id == int(run_id)).filter( Comment.contest_id == int(contest_id)).first() except: return None get_by = staticmethod(get_by)
class PynformaticsUser(User): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_user_settings' __mapper_args__ = {'polymorphic_identity': 'pynformaticsuser'} id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id'), primary_key=True) main_page_settings = db.Column(db.Text)
class LanguageContest(db.Model): __table_args__ = ( db.UniqueConstraint('language_id', 'contest_id', name='_language_contest_uc'), { 'schema': 'pynformatics' }, ) __tablename__ = 'language_contest' id = db.Column(db.Integer, primary_key=True) language_id = db.Column( db.Integer, db.ForeignKey('pynformatics.languages.id', ondelete='CASCADE')) contest_id = db.Column( db.Integer, db.ForeignKey('pynformatics.contest.id', ondelete='CASCADE'))
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}">' )
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'))
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 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)
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'))
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)
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