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 Group(db.Model): __table_args__ = (db.ForeignKeyConstraint(['owner_id'], ['moodle.mdl_user.id']), { 'schema': 'moodle' }) __tablename__ = 'mdl_ejudge_group' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode(100)) description = db.Column(db.Text) owner_id = db.Column(db.Integer) visible = db.Column(db.Integer) owner = db.relationship('SimpleUser', backref=db.backref('groups', lazy='select'), lazy='joined') def serialize(self, attributes=None): if not attributes: attributes = ( 'name', 'description', 'owner_id', 'visible', ) serialized = attrs_to_dict(self, *attributes) return serialized
class UserGroup(db.Model): __table_args__ = ( db.UniqueConstraint('user_id', 'group_id', name='group_id'), { 'schema': 'moodle' }, ) __tablename__ = 'mdl_ejudge_group_users' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id')) group_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_ejudge_group.id')) user = db.relationship('SimpleUser', backref=db.backref('user_groups', lazy='select')) group = db.relationship('Group', backref=db.backref('user_groups', lazy='select')) @staticmethod def create_if_not_exists(user_id, group_id): user_group = db.session.query(UserGroup).filter_by( user_id=user_id, group_id=group_id).first() if user_group: return None return UserGroup(user_id=user_id, group_id=group_id)
class MonitorStatement(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_monitors_statements' id = db.Column(db.Integer, primary_key=True) statement_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_statements.id')) monitor_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_monitors.id')) sort = db.Column(db.Integer)
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 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 Rejudge(db.Model): __table_args__ = {'schema': 'pynformatics'} __tablename__ = 'rejudge' id = db.Column(db.Integer, primary_key=True) run_id = db.Column(db.Integer, db.ForeignKey('pynformatics.runs.id'), nullable=False) ejudge_contest_id = db.Column(db.Integer, nullable=False) ejudge_url = db.Column(db.String(50))
class SimpleUser(db.Model): RESET_PASSWORD_LENGTH = 20 __table_args__ = (db.Index('ej_id', 'ej_id'), {'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)) login = db.Column('ej_login', db.Unicode(50)) password = db.Column('ej_password', db.Unicode(50)) deleted = db.Column('deleted', db.Boolean) ejudge_id = db.Column('ej_id', db.Integer) 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') def reset_password(self): """ Генерирует случайный пароль для пользователя и возвращает его """ new_password = random_password(self.RESET_PASSWORD_LENGTH) self.password_md5 = hash_password(new_password) return new_password
class MonitorCacheMeta(db.Model): __table_args__ = {'schema': 'pynformatics'} __tablename__ = 'monitor_cache_meta' id = db.Column(db.Integer(), primary_key=True) prefix = db.Column(db.String(30), nullable=False) label = db.Column(db.String(30), nullable=False) key = db.Column(db.String(64), nullable=False) problem_id = db.Column(db.Integer, nullable=False) invalidate_args = db.Column(db.String(MAX_KEY_LEN)) created = db.Column(db.DateTime(), default=datetime.datetime.utcnow) when_expire = db.Column(db.DateTime(), nullable=False) @classmethod def get_invalidate_args(cls, data: Iterable[str]): """ [problem_1, problem_2] -> '|problem_1|problem_2|' """ if data: return f'|{"|".join(data)}|'[:MAX_KEY_LEN + 1] return '' @classmethod def _get_search_arg(cls, arg: str): return f'|{arg}|' @classmethod def _get_like_args(cls, args: Iterable[str]) -> Iterable[str]: return map(lambda a: f'%{a}%', args) @classmethod def get_search_like_args(cls, args: Iterable[str]) -> List[str]: """ [problem_1] -> ['%|problem_1|%'] """ return list(cls._get_like_args(map(cls._get_search_arg, args)))
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) @classmethod def search(cls, filter_func: Callable[[Query], Query], filter_deleted=True): if filter_deleted: users_query = filter_func( db.session.query(cls).filter(cls.deleted == False)) else: users_query = filter_func(db.session.query(cls)) return users_query @classmethod def search_by_string(cls, search_string): def filter_func(query: Query): if search_string.count(' '): str1, str2 = search_string.split(' ', 1) query = query.filter( or_( and_(cls.firstname.like("%{}%".format(str1)), cls.lastname.like("%{}%".format(str2))), and_(cls.lastname.like("%{}%".format(str1)), cls.firstname.like("%{}%".format(str2))), )) else: query = query.filter( or_( cls.email.like("%{}%".format(search_string)), cls.username.like("%{}%".format(search_string)), cls.firstname.like("%{}%".format(search_string)), cls.lastname.like("%{}%".format(search_string)), )) return query return cls.search(filter_func) @lazy def _get_current_olymp(self): return None
class MonitorCourseModule(CourseModuleInstance, db.Model): """ Модуль курса, описывающий монитор """ __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_monitor' __mapper_args__ = { 'polymorphic_identity': 'monitor', 'concrete': True, } MODULE = 28 id = db.Column(db.Integer, primary_key=True) course_id = db.Column('course', db.Integer) name = db.Column(db.Unicode(255), nullable=False, default='') monitor_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_monitors.id')) group_id = db.Column(db.Integer, nullable=False, default=0)
class Stars(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_stars' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id')) title = db.Column(db.Text) link = db.Column(db.Text) def __init__(self, user, title, link): self.link = link self.title = title self.user_id = user.id def __json__(self, request): return { 'id': self.id, 'user_id': self.user_id, 'title': self.title, 'link': self.link, }
class Resource(CourseModuleInstance, db.Model): """ Модуль курса, описывающий ссылку """ __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_resource' __mapper_args__ = { 'polymorphic_identity': 'resource', 'concrete': True, } MODULE = 13 id = db.Column(db.Integer, primary_key=True) course_id = db.Column('course', db.Integer) name = db.Column(db.Unicode(255)) type_ = db.Column('type', db.Unicode(30)) reference = db.Column(db.Unicode(255)) summary = db.Column(db.UnicodeText()) def serialize(self): serialized = attrs_to_dict( self, 'id', 'course_id', 'name', 'type', 'reference', 'summary', ) serialized['type'] = self.type_ return serialized
class Course(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_course' id = db.Column(db.Integer, primary_key=True) full_name = db.Column('fullname', db.Unicode(254)) short_name = db.Column('shortname', db.Unicode(100)) category = db.Column(db.Integer) password = db.Column(db.Unicode(50)) visible = db.Column(db.Boolean) def require_password(self): return bool(self.password) @deprecated('view.serializers.course.CourseSchema') def serialize(self): serialized = attrs_to_dict( self, 'id', 'full_name', 'short_name', ) serialized['require_password'] = self.require_password() if not self.require_password(): serialized['sections'] = [ section.serialize() for section in self.sections.all() if section.visible ] return serialized
class Label(CourseModuleInstance, db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_label' __mapper_args__ = { 'polymorphic_identity': 'label', 'concrete': True, } MODULE = 9 id = db.Column(db.Integer, primary_key=True) course = db.Column(db.Integer) name = db.Column(db.Unicode(255)) content = db.Column(db.UnicodeText) def serialize(self): return attrs_to_dict( self, 'id', 'name', 'content', )
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 Monitor(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_monitors' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255)) description = db.Column(db.Text) owner_id = db.Column(db.Integer) type = db.Column(db.String(20)) # Показывать ли участников без посылок show_empty = db.Column(db.Integer, default=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 EjudgeContest(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_ejudge_contest' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode(255)) ejudge_id = db.Column(db.Unicode(10)) ejudge_int_id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=False) load_time = db.Column(db.DateTime) cloned = db.Column(db.Boolean, nullable=False) def __init__(self, name='', ejudge_int_id=0): self.name = name self.ejudge_id = get_contest_str_id(ejudge_int_id) self.ejudge_int_id = ejudge_int_id self.load_time = datetime.datetime.now() self.cloned = False
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')) @classmethod def create(cls, **kwargs): instance = cls(**kwargs) db.session.add(instance) # Flush, чтобы получить из базы problem db.session.flush([instance]) # Expire, чтобы у задачи стал доступен standings db.session.expire(instance.problem) log.info('ProblemStandings(problem_id=%s) Created. Starting updates' % instance.problem_id) users = db.session.query(SimpleUser) \ .join(EjudgeRun) \ .filter( and_( EjudgeRun.contest_id == instance.problem.ejudge_contest_id, EjudgeRun.prob_id == instance.problem.problem_id ) ) \ .distinct() \ .all() with db.session.no_autoflush: for i, user in enumerate(users): instance.update(user) log.info('ProblemStandings(problem_id=%s) Updates finished.' % instance.problem_id) return instance def update(self, user): super(ProblemStandings, self).update(user) user_runs = self.problem.ejudge_runs \ .filter_by(user_id=user.ejudge_id) \ .order_by(EjudgeRun.create_time) \ .all() processed = { 'attempts': 0, 'score': 0, 'status': None, } for run in user_runs: processed['attempts'] += 1 if run.score > processed['score']: processed['score'] = run.score processed['status'] = run.status if run.score == 100: break self.json[user.id].update(processed) def serialize(self): return self.json
def json(cls): return db.Column('json', MutableDict.as_mutable(JsonType))
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')) @classmethod def create(cls, **kwargs): instance = cls(**kwargs) db.session.add(instance) # Flush, чтобы получить из базы statement db.session.flush([instance]) # Expire, чтобы у statement стал доступен standings db.session.expire(instance.statement) log.info( 'StatementStandings(statement_id=%s) Created. Starting updates' % instance.statement_id) pynformatics_runs = db.session.query(PynformaticsRun) \ .filter_by(statement_id=instance.statement_id) \ .all() with db.session.no_autoflush: for pynformatics_run in pynformatics_runs: instance.update(pynformatics_run.run) log.info('StatementStandings(statement_id=%s) Updates finished.' % instance.statement_id) return instance def update(self, run): user = run.user super(StatementStandings, self).update(user) runs = self.json[str(user.id)].get('runs', []) replace_index = index_of( runs, lambda run_json: run_json['run_id'] == run.run_id and run_json['contest_id'] == run.contest_id) if replace_index is not None: runs[replace_index] = StatementStandings.serialize_run(run) else: insert_index = index_of( runs, lambda run_json: run_json['create_time'] > run. create_time.isoformat(), len(runs)) runs.insert(insert_index, StatementStandings.serialize_run(run)) self.json[str(user.id)]['runs'] = runs self.json.changed() # TODO: добавить обработку настроек контеста def serialize(self, group_id=None): result = self.json if group_id: try: group = db.session.query(Group).filter_by(id=group_id).one() except Exception: raise ValueError('Group not found') result = { str(user_group.user_id): result[str(user_group.user_id)] for user_group in group.user_groups if str(user_group.user_id) in result } return result
class Run(db.Model): __table_args__ = ({'schema': 'pynformatics'}, ) __tablename__ = 'runs' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id')) problem_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_problems.id')) statement_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_statements.id')) score = db.Column(db.Integer) user = db.relationship('SimpleUser', backref='runs', lazy='select') problem = db.relationship('EjudgeProblem', backref=db.backref('runs', lazy='dynamic')) statement = db.relationship('Statement', backref='runs') create_time = db.Column(db.DateTime(), default=datetime.datetime.utcnow) # Поля скопированные из ejudge.runs ejudge_run_id = db.Column('ej_run_id', db.Integer) ejudge_contest_id = db.Column('ej_contest_id', db.Integer) ejudge_run_uuid = db.Column('ej_run_uuid', db.String(40)) ejudge_score = db.Column('ej_score', db.Integer) ejudge_status = db.Column('ej_status', db.Integer) ejudge_language_id = db.Column('ej_lang_id', db.Integer) ejudge_test_num = db.Column('ej_test_num', db.Integer) ejudge_create_time = db.Column('ej_create_time', db.DateTime) ejudge_last_change_time = db.Column('ej_last_change_time', db.DateTime) ejudge_url = db.Column(db.String(50)) source_hash = db.Column(db.String(32)) # We are using md5 hex digest def update_source(self, blob: bytes): mongo.db.source.insert_one({ 'run_id': self.id, 'blob': blob, }) return blob def remove_source(self): mongo.db.source.find_one_and_delete({'run_id': self.id}) def move_protocol_to_rejudge_collection(self, rejudge_id: int): protocol = mongo.db.protocol.find_one({'run_id': self.id}) if protocol: del protocol['_id'] protocol['rejudge_id'] = rejudge_id mongo.db.rejudge.insert_one(protocol) mongo.db.protocol.find_one_and_delete({'run_id': self.id}) @property def source(self) -> Optional[bytes]: data = mongo.db.source.find_one({'run_id': self.id}) if data is None: logging.error(f'Cannot find source for run #{self.id}') return None blob = data.get('blob') return blob @property def protocol(self) -> Optional[dict]: return mongo.db.protocol.find_one({'run_id': self.id}, {'_id': False}) @protocol.setter def protocol(self, protocol_source: dict): mongo.db.protocol.update({'run_id': self.id}, protocol_source, upsert=True) @staticmethod def generate_source_hash(blob: bytes) -> str: m = hashlib.md5() m.update(blob) return m.hexdigest() @property def status(self): return self.ejudge_status @property def language_id(self): return self.ejudge_language_id @staticmethod @deprecated def pick_ejudge_columns(ejudge_run): return { 'ejudge_run_id': ejudge_run.run_id, 'ejudge_contest_id': ejudge_run.contest_id, 'ejudge_run_uuid': ejudge_run.run_uuid, 'ejudge_score': ejudge_run.score, 'ejudge_status': ejudge_run.status, 'ejudge_language_id': ejudge_run.lang_id, 'ejudge_test_num': ejudge_run.test_num, 'ejudge_create_time': ejudge_run.create_time, 'ejudge_last_change_time': ejudge_run.last_change_time, } def serialize(self, attributes=None): if attributes is None: attributes = ( 'id', 'user', 'problem_id', 'statement_id', 'score', 'status', 'language_id', 'create_time', 'ejudge_run_id', 'ejudge_contest_id', ) if hasattr(g, 'user') and g.user.id == self.user_id: attributes = ( *attributes, 'source', ) serialized = attrs_to_dict(self, *attributes) if 'create_time' in attributes: serialized['create_time'] = str(self.create_time) if 'user' in attributes: serialized['user'] = self.user.serialize() return serialized
'ejudge_contest_id', ) if hasattr(g, 'user') and g.user.id == self.user_id: attributes = ( *attributes, 'source', ) serialized = attrs_to_dict(self, *attributes) if 'create_time' in attributes: serialized['create_time'] = str(self.create_time) if 'user' in attributes: serialized['user'] = self.user.serialize() return serialized # SQLAlchemy Core table to avoiding class instance creation LightWeightRun = Table('runs', MetaData(), db.Column('id', db.Integer, primary_key=True), db.Column('user_id', None, db.ForeignKey('moodle.mdl_user.id')), db.Column('problem_id', db.Integer), db.Column('create_time', db.DateTime), db.Column('ej_score', db.Integer), db.Column('ej_status', db.Integer), db.Column('ej_test_num', db.Integer), schema='pynformatics')
class Comment(db.Model): __table_args__ = ( db.ForeignKeyConstraint( ['run_id', 'contest_id'], ['ejudge.runs.run_id', 'ejudge.runs.contest_id'] ), {'schema':'ejudge'} ) __tablename__ = 'mdl_run_comments' id = db.Column(db.Integer, primary_key=True) date = db.Column(db.DateTime) run_id = db.Column(db.Integer) contest_id = db.Column(db.Integer) user_id = db.Column(db.Integer) author_user_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id')) lines = db.Column(db.Text) comment = db.Column(db.UnicodeText) is_read = db.Column(db.Boolean) author_user = db.relationship( SimpleUser, backref='simpleuser1', uselist=False, lazy=False, primaryjoin=(author_user_id == SimpleUser.id), ) run = db.relationship('EjudgeRun', backref='comment', uselist=False) def __init__(self, run, author, lines='', comment='', date=datetime.datetime.now()): self.date = date self.run_id = run.run_id self.user_id = run.user.id self.contest_id = run.contest_id self.author_user_id = author.id self.lines = lines self.comment = comment self.is_read = False def __json__(self, request): return { 'date' : str(self.date), 'id' : self.id, 'run_id' : self.run_id, 'user_id' : self.user_id, 'contest_id' : self.contest_id, 'author_user_id' : self.author_user_id, 'lines' : self.lines, 'comment' : self.comment, 'is_read' : self.is_read, 'problem_id' : self.run.problem.id, 'problem_name' : self.run.problem.name } @staticmethod 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
class EjudgeRun(db.Model): __table_args__ = (db.ForeignKeyConstraint(['contest_id', 'prob_id'], [ 'moodle.mdl_ejudge_problem.ejudge_contest_id', 'moodle.mdl_ejudge_problem.problem_id' ]), db.ForeignKeyConstraint(['user_id'], ['moodle.mdl_user.ej_id']), { 'schema': 'ejudge' }) __tablename__ = 'runs' run_id = db.Column(db.Integer, primary_key=True) contest_id = db.Column(db.Integer, primary_key=True) size = db.Column(db.Integer) create_time = db.Column(db.DateTime) create_nsec = db.Column(db.Integer) user_id = db.Column(db.Integer) prob_id = db.Column(db.Integer) # TODO: rename to problem_id lang_id = db.Column(db.Integer) status = db.Column(db.Integer) ssl_flag = db.Column(db.Integer) ip_version = db.Column(db.Integer) ip = db.Column(db.String(64)) hash = db.Column(db.String(128)) run_uuid = db.Column(db.String(40)) score = db.Column(db.Integer) test_num = db.Column(db.Integer) score_adj = db.Column(db.Integer) locale_id = db.Column(db.Integer) judge_id = db.Column(db.Integer) variant = db.Column(db.Integer) pages = db.Column(db.Integer) is_imported = db.Column(db.Integer) is_hidden = db.Column(db.Integer) is_readonly = db.Column(db.Integer) is_examinable = db.Column(db.Integer) mime_type = db.Column(db.String(64)) examiners0 = db.Column(db.Integer) examiners1 = db.Column(db.Integer) examiners2 = db.Column(db.Integer) exam_score0 = db.Column(db.Integer) exam_score1 = db.Column(db.Integer) exam_score2 = db.Column(db.Integer) last_change_time = db.Column(db.DateTime) last_change_nsec = db.Column(db.Integer) is_marked = db.Column(db.Integer) is_saved = db.Column(db.Integer) saved_status = db.Column(db.Integer) saved_score = db.Column(db.Integer) saved_test = db.Column(db.Integer) passed_mode = db.Column(db.Integer) eoln_type = db.Column(db.Integer) store_flags = db.Column(db.Integer) token_flags = db.Column(db.Integer) token_count = db.Column(db.Integer) comments = db.relationship('Comment', backref=db.backref('comments')) user = db.relationship('SimpleUser', backref=db.backref('simpleuser'), uselist=False) problem = db.relationship('EjudgeProblem', backref=db.backref('ejudge_runs', lazy='dynamic'), uselist=False) SIGNAL_DESCRIPTION = { 1: "Hangup detected on controlling terminal or death of controlling process", 2: "Interrupt from keyboard", 3: "Quit from keyboard", 4: "Illegal Instruction", 6: "Abort signal", 7: "Bus error (bad memory access)", 8: "Floating point exception", 9: "Kill signal", 11: "Invalid memory reference", 13: "Broken pipe: write to pipe with no readers", 14: "Timer signal", 15: "Termination signal" } @db.reconstructor def init_on_load(self): self.out_path = "/home/judges/{0:06d}/var/archive/output/{1}/{2}/{3}/{4:06d}.zip".format( self.contest_id, to32(self.run_id // (32**3) % 32), to32(self.run_id // (32**2) % 32), to32(self.run_id // 32 % 32), self.run_id) self._out_arch = None self._out_arch_file_names = set() @lazy def get_audit(self): data = safe_open(submit_path(audit_path, self.contest_id, self.run_id), 'r').read() if type(data) == bytes: data = data.decode('ascii') return data @lazy def get_sources(self): data = safe_open( submit_path(sources_path, self.contest_id, self.run_id), 'rb').read() for encoding in ['utf-8', 'ascii', 'windows-1251']: try: data = data.decode(encoding) except: print('decoded:', encoding) pass else: break else: return 'Ошибка кодировки' return data def get_output_file(self, test_num, tp="o", size=None): #tp: o - output, e - stderr, c - checker data = self.get_output_archive().getfile("{0:06}.{1}".format( test_num, tp)).decode('ascii') if size is not None: data = data[:size] return data def get_output_file_size(self, test_num, tp="o"): #tp: o - output, e - stderr, c - checker data = self.get_output_archive().getfile("{0:06}.{1}".format( test_num, tp)).decode('ascii') return len(data) def get_output_archive(self): if "output_archive" not in self.__dict__: self.output_archive = EjudgeArchiveReader( submit_path(output_path, self.contest_id, self.run_id)) return self.output_archive def get_test_full_protocol(self, test_num): """ Возвращает полный протокол по номеру теста :param test_num: - str """ judge_info = self.judge_tests_info[test_num] test_protocol = self.problem.get_test_full(test_num) test_protocol.update(self.tests[test_num]) test_protocol['big_output'] = False try: if self.get_output_file_size(int(test_num), tp='o') <= 255: test_protocol['output'] = self.get_output_file(int(test_num), tp='o') else: test_protocol['output'] = self.get_output_file( int(test_num), tp='o', size=255) + '...\n' test_protocol['big_output'] = True except OSError as e: test_protocol['output'] = judge_info.get('output', '') try: if self.get_output_file_size(int(test_num), tp='c') <= 255: test_protocol['checker_output'] = self.get_output_file( int(test_num), tp='c') else: test_protocol['checker_output'] = self.get_output_file( int(test_num), tp='c', size=255) + '...\n' except OSError as e: test_protocol['checker_output'] = judge_info.get('checker', '') try: if self.get_output_file_size(int(test_num), tp='e') <= 255: test_protocol['error_output'] = self.get_output_file( int(test_num), tp='e') else: test_protocol['error_output'] = self.get_output_file( int(test_num), tp='e', size=255) + '...\n' except OSError as e: test_protocol['error_output'] = judge_info.get('stderr', '') if 'term-signal' in judge_info: test_protocol['extra'] = 'Signal %(signal)s. %(description)s' % { 'signal': judge_info['term-signal'], 'description': self.SIGNAL_DESCRIPTION[judge_info['term-signal']], } if 'exit-code' in judge_info: test_protocol['extra'] = test_protocol.get( 'extra', '') + '\n Exit code %(exit_code)s. ' % { 'exit_code': judge_info['exit-code'] } for type_ in [('o', 'output'), ('c', 'checker_output'), ('e', 'error_output')]: file_name = '{0:06d}.{1}'.format(int(test_num), type_[0]) if self._out_arch is None: try: self._out_arch = zipfile.ZipFile(self.out_path, 'r') self._out_arch_file_names = set(self._out_arch.namelist()) except: pass if file_name not in self._out_arch_file_names or type_[ 1] in test_protocol: continue with self._out_arch.open(file_name, 'r') as f: test_protocol[ type_[1]] = f.read(1024).decode("utf-8") + "...\n" return test_protocol def parsetests(self): """ Parse tests data from xml archive """ self.test_count = 0 self.tests = {} self.judge_tests_info = {} self.status_string = None self.compiler_output = None self.host = None self.maxtime = None if self.xml: rep = self.xml.getElementsByTagName('testing-report')[0] self.tests_count = int(rep.getAttribute('run-tests')) self.status_string = rep.getAttribute('status') compiler_output_elements = self.xml.getElementsByTagName( 'compiler_output') if compiler_output_elements: self.compiler_output = getattr( compiler_output_elements[0].firstChild, 'nodeValue', '') host_elements = self.xml.getElementsByTagName('host') if host_elements: self.host = host_elements[0].firstChild.nodeValue for node in self.xml.getElementsByTagName('test'): number = node.getAttribute('num') status = node.getAttribute('status') time = node.getAttribute('time') real_time = node.getAttribute('real-time') max_memory_used = node.getAttribute('max-memory-used') self.test_count += 1 try: time = int(time) except ValueError: time = 0 try: real_time = int(real_time) except ValueError: real_time = 0 test = { 'status': status, 'string_status': get_string_status(status), 'real_time': real_time, 'time': time, 'max_memory_used': max_memory_used, } judge_info = {} for _type in ('input', 'output', 'correct', 'stderr', 'checker'): lst = node.getElementsByTagName(_type) if lst and lst[0].firstChild: judge_info[_type] = lst[0].firstChild.nodeValue else: judge_info[_type] = '' if node.hasAttribute('term-signal'): judge_info['term-signal'] = int( node.getAttribute('term-signal')) if node.hasAttribute('exit-code'): judge_info['exit-code'] = int( node.getAttribute('exit-code')) self.judge_tests_info[number] = judge_info self.tests[number] = test try: #print([test['time'] for test in self.tests.values()] + [test['real_time'] for test in self.tests.values()]) self.maxtime = max( [test['time'] for test in self.tests.values()] + [test['real_time'] for test in self.tests.values()]) except ValueError: pass @staticmethod def get_by(run_id, contest_id): try: return db.session.query(EjudgeRun).filter( EjudgeRun.run_id == int(run_id)).filter( EjudgeRun.contest_id == int(contest_id)).first() except: return None @lazy def _get_compilation_protocol(self): filename = submit_path(protocols_path, self.contest_id, self.run_id) if filename: if os.path.isfile(filename): myopen = lambda x, y: open(x, y, encoding='utf-8') else: filename += '.gz' myopen = gzip.open try: xml_file = myopen(filename, 'r') try: res = xml_file.read() try: res = res.decode('cp1251').encode('utf8') except: pass try: return str(res, encoding='UTF-8') except TypeError: try: res = res.decode('cp1251').encode('utf8') except Exception: pass return res except Exception as e: return e except IOError as e: return e else: return '' @lazy def _get_protocol(self): filename = submit_path(protocols_path, self.contest_id, self.run_id) if filename != '': return get_protocol_from_file(filename) else: return '<a></a>' protocol = property(_get_protocol) compilation_protocol = property(_get_compilation_protocol) @lazy def fetch_tested_protocol_data(self): self.xml = xml.dom.minidom.parseString(str(self.protocol)) self.parsetests() def _set_output_archive(self, val): self.output_archive = val def get_pynformatics_run(self): if self.pynformatics_run: return self.pynformatics_run pynformatics_run = PynformaticsRun( run=self, source=self.get_sources(), ) db.session.add(pynformatics_run) return pynformatics_run def serialize(self, attributes=None): if not attributes: attributes = ( 'run_id', 'contest_id', 'create_time', 'lang_id', 'prob_id', 'score', 'size', 'status', 'problem_id', ) serialized = attrs_to_dict(self, *attributes) if 'create_time' in attributes: serialized['create_time'] = str(serialized['create_time']) if 'problem_id' in attributes: serialized['problem_id'] = self.problem.id serialized.update(self.get_pynformatics_run().serialize()) user = getattr(g, 'user', None) if not user or user.ejudge_id != self.user.ejudge_id: serialized['user'] = self.user.serialize() return serialized
class Ideal(db.Model): __table_args__ = {'schema': 'moodle'} __tablename__ = 'mdl_ideal_solution' id = db.Column(db.Integer, primary_key=True) problem_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_problems.id')) run_id = db.Column(db.Integer, db.ForeignKey('ejudge.runs.run_id')) contest_id = db.Column(db.Integer, db.ForeignKey('ejudge.runs.contest_id')) lang_id = db.Column(db.Integer) lang = db.Column(db.Unicode(100)) code = db.Column(db.UnicodeText) author_id = db.Column(db.Integer, db.ForeignKey('moodle.mdl_user.id')) author_name = db.Column(db.Unicode(200)) comment = db.Column(db.UnicodeText) status = db.Column(db.Integer) def __init__(self, problem_id, run_id, contest_id, author_id, comment, status=0): self.problem_id = problem_id self.run_id = run_id self.contest_id = contest_id run = db.session.query(EjudgeRun) \ .filter_by(contest_id=contest_id) \ .filter_by(run_id=run_id) \ .one() user = db.session.query(User) \ .filter_by(id=author_id) \ .one() self.lang_id = run.lang_id self.lang = LANG[self.lang_id] self.code = get_run_code(run_id, contest_id) self.author_id = author_id self.author_name = user.firstname + ' ' + user.lastname self.comment = comment self.status = status def __json__(self, request): return { 'id': self.id, 'problem_id': self.problem_id, 'lang': self.lang, 'code': self.code, 'author_name': self.author_name, 'author_id': self.author_id, 'comment': self.comment, }
)) return query return cls.search(filter_func) @lazy def _get_current_olymp(self): return None 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) # SQLAlchemy Core table to avoiding class instance creation LightWeightUser = Table('mdl_user', MetaData(), db.Column('id', db.Integer, primary_key=True), db.Column('firstname', db.Unicode(100)), db.Column('lastname', db.Unicode(100)), db.Column('email', db.Unicode(100)), db.Column('username', db.Unicode(100)), schema='moodle')
class EjudgeProblem(Problem): """ Модель задачи из ejudge ejudge_prid -- primary key, на который ссылается Problem.pr_id. После инициализации, соответствтующему объекту Problem проставляется корректный pr_id contest_id -- ejudge_contest_id -- соответствует contest_id из ejudge secondary_ejudge_contest_id -- problem_id -- соответствует problem_id из ejudge short_id -- короткий id (обычно буква) Здесь используется наследование и polymorphic_identity Это значит, что можно написать problem_id = Problem.id query(EjudgeProblem).filter(EjudgeProblem.id == problem_id) # вернет Problem При этом неявно приджойнится Problem.pr_id == EjudgeProblem.id Ещё это даёт нам интересные эффекты, например query(EjudgeProblem).all() вернёт как EjudgeProblem, так и Problem, a query(EjudgeProblem).filter(EjudgeProblem.id == 6).all() -- только Problem А вот такое query(EjudgeProblem).get(6) -- вообще вернёт None, потому что join не отработает Ещё в Runs у нас ссылка на обе таблицы, и это тоже работает нормально """ __table_args__ = ( db.Index('ejudge_contest_id_problem_id', 'ejudge_contest_id', 'problem_id'), {'schema':'moodle', 'extend_existing': True} ) __tablename__ = 'mdl_ejudge_problem' __mapper_args__ = {'polymorphic_identity': 'ejudgeproblem'} ejudge_prid = db.Column('id', db.Integer, primary_key=True) #global id in ejudge contest_id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=False) ejudge_contest_id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=False) secondary_ejudge_contest_id = db.Column(db.Integer, nullable=True) problem_id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=False) #id in contest short_id = db.Column(db.Unicode(50)) ejudge_name = db.Column('name', db.Unicode(255)) @staticmethod def create(**kwargs): """ При создании EjudgeProblem сначала в базу пишет Problem потом EjudgeProblem, из-за чего pr_id не проставляется """ instance = EjudgeProblem(**kwargs) db.session.add(instance) db.session.flush([instance]) problem_id = instance.id ejudge_problem_id = instance.pr_id db.session.commit() problem_instance = db.session.query(Problem).filter_by(id=problem_id).one() problem_instance.pr_id = ejudge_problem_id db.session.commit() return db.session.query(EjudgeProblem).filter_by(id=problem_id).one() @deprecated('view.serializers.ProblemSchema') def serialize(self): if self.sample_tests: self.generateSamplesJson(force_update=True) attrs = [ 'id', 'name', 'content', 'timelimit', 'memorylimit', 'show_limits', 'sample_tests_json', 'output_only', ] problem_dict = { attr: getattr(self, attr, 'undefined') for attr in attrs } problem_dict['content'] = problem_dict['content'].replace("\\)", "$").replace("\\(", "$") # problem_dict['languages'] = context.get_allowed_languages() return problem_dict def get_test(self, test_num, size=255): conf = EjudgeContestCfg(number=self.ejudge_contest_id) prob = conf.getProblem(self.problem_id) test_file_name = (prob.tests_dir + prob.test_pat) % int(test_num) error_str = None if os.path.exists(test_file_name): res = read_file_unknown_encoding(test_file_name, size) else: res = test_file_name return res def get_test_size(self, test_num): conf = EjudgeContestCfg(number=self.ejudge_contest_id) prob = conf.getProblem(self.problem_id) test_file_name = (prob.tests_dir + prob.test_pat) % int(test_num) return os.stat(test_file_name).st_size def get_corr(self, test_num, size=255): conf = EjudgeContestCfg(number = self.ejudge_contest_id) prob = conf.getProblem(self.problem_id) corr_file_name = (prob.tests_dir + prob.corr_pat) % int(test_num) error_str = None if os.path.exists(corr_file_name): res = read_file_unknown_encoding(corr_file_name, size) else: res = corr_file_name return res def get_test_full(self, test_num, size=255): """ Возвращает словарь с полной информацией о тесте """ test = {} if self.get_test_size(int(test_num)) <= 255: test["input"] = self.get_test(int(test_num), size=size) test["big_input"] = False else: test["input"] = self.get_test(int(test_num), size=size) + "...\n" test["big_input"] = True if self.get_corr_size(int(test_num)) <= 255: test["corr"] = self.get_corr(int(test_num), size=size) test["big_corr"] = False else: test["corr"] = self.get_corr(int(test_num), size=size) + "...\n" test["big_corr"] = True return test def get_corr_size(self, test_num): conf = EjudgeContestCfg(number = self.ejudge_contest_id) prob = conf.getProblem(self.problem_id) corr_file_name = (prob.tests_dir + prob.corr_pat) % int(test_num) return os.stat(corr_file_name).st_size def get_checker(self): conf = EjudgeContestCfg(number = self.ejudge_contest_id) prob = conf.getProblem(self.problem_id) #generate dir with checker checker_dir = None if conf.advanced_layout: checker_dir = os.path.join(conf.contest_path, "problems", prob.internal_name) else: checker_dir = os.path.join(conf.contest_path, "checkers") #trying to find checker find_res = glob.glob(os.path.join(checker_dir, "check_{0}.*".format(prob.internal_name))) check_src = None checker_ext = None if find_res: check_src = open(find_res[0], "r").read() checker_ext = os.path.splitext(find_res[0])[1] #if checker not found then try polygon package downloads_dir = os.path.join(conf.contest_path, "download") if check_src is None and os.path.exists(downloads_dir): download_archive_mask = "{0}-*$linux.zip".format(prob.internal_name) find_archive_result = glob.glob(os.path.join(downloads_dir, download_archive_mask)) download_archive_path = find_archive_result[0] if find_archive_result else None archive = None if download_archive_path is not None: archive = ZipFile(download_archive_path) if archive is not None: member_path = None for file in archive.namelist(): if file.startswith("check."): member_path = file break try: check_src = archive.open(member_path).read() checker_ext = os.path.splitext(member_path)[1] except KeyError: check_src = None if check_src is None: check_src = "checker not found" return check_src, checker_ext def generateSamples(self): res = "" if self.sample_tests != '': res = "<div class='problem-statement'><div class='sample-tests'><div class='section-title'>Примеры</div>" for i in self.sample_tests.split(","): inp = self.get_test(i, 4096) if inp[-1] == '\n': inp = inp[:-1] corr = self.get_corr(i, 4096) if corr[-1] == '\n': corr = corr[:-1] res += "<div class='sample-test'>" res += "<div class='input'><div class='title'>Входные данные</div><pre class='content'>" res += inp res += "</pre></div><div class='output'><div class='title'>Выходные данные</div><pre class='content'>" res += corr res += "</pre></div></div>" res += "</div></div>" self.sample_tests_html = res return self.sample_tests def generateSamplesJson(self, force_update=False): if self.sample_tests != '': if not self.sample_tests_json: self.sample_tests_json = {} for test in self.sample_tests.split(','): if not force_update and test in self.sample_tests_json: continue test_input = self.get_test(test, 4096) test_correct = self.get_corr(test, 4096) self.sample_tests_json[test] = { 'input': test_input, 'correct': test_correct, }
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