async def update_status(domain_id: str, doc_type: int, tid: objectid.ObjectId, uid: int, rid: objectid.ObjectId, pid: document.convert_doc_id, accept: bool, score: int): """This method returns None when the modification has been superseded by a parallel operation.""" if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') tdoc = await document.get(domain_id, doc_type, tid) tsdoc = await document.rev_push_status(domain_id, tdoc['doc_type'], tdoc['doc_id'], uid, 'journal', { 'rid': rid, 'pid': pid, 'accept': accept, 'score': score }) if 'attend' not in tsdoc or not tsdoc['attend']: if tdoc['doc_type'] == document.TYPE_CONTEST: raise error.ContestNotAttendedError(domain_id, tid, uid) elif tdoc['doc_type'] == document.TYPE_HOMEWORK: raise error.HomeworkNotAttendedError(domain_id, tid, uid) else: raise error.InvalidArgumentError('doc_type') journal = _get_status_journal(tsdoc) stats = RULES[tdoc['rule']].stat_func(tdoc, journal) tsdoc = await document.rev_set_status(domain_id, tdoc['doc_type'], tid, uid, tsdoc['rev'], journal=journal, **stats) return tsdoc
async def post(self, *, ctype: str, **kwargs): if ctype == 'homework': await self._post_homework() elif ctype == 'contest': raise error.InvalidArgumentError('ctype') # await self._post_contest() else: raise error.InvalidArgumentError('ctype')
async def get(self, *, ctype: str): if ctype == 'homework': await self._get_homework() elif ctype == 'contest': await self._get_contest() else: raise error.InvalidArgumentError('ctype')
async def get(domain_id: str, doc_type: int, tid: objectid.ObjectId): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') tdoc = await document.get(domain_id, doc_type, tid) if not tdoc: raise error.DocumentNotFoundError(domain_id, doc_type, tid) return tdoc
async def edit(domain_id: str, doc_type: int, tid: objectid.ObjectId, **kwargs): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') if 'title' in kwargs: validator.check_title(kwargs['title']) if 'content' in kwargs: validator.check_content(kwargs['content']) if 'rule' in kwargs: if doc_type == document.TYPE_CONTEST: if kwargs['rule'] not in constant.contest.CONTEST_RULES: raise error.ValidationError('rule') elif doc_type == document.TYPE_HOMEWORK: if kwargs['rule'] not in constant.contest.HOMEWORK_RULES: raise error.ValidationError('rule') if 'begin_at' in kwargs and 'end_at' in kwargs: if kwargs['begin_at'] >= kwargs['end_at']: raise error.ValidationError('begin_at', 'end_at') if 'penalty_since' in kwargs: if 'begin_at' in kwargs and kwargs['penalty_since'] < kwargs[ 'begin_at']: raise error.ValidationError('penalty_since', 'begin_at') if 'end_at' in kwargs and kwargs['penalty_since'] > kwargs['end_at']: raise error.ValidationError('penalty_since', 'end_at') return await document.set(domain_id, doc_type, tid, **kwargs)
async def add(domain_id: str, doc_type: int, title: str, content: str, owner_uid: int, rule: int, begin_at: lambda i: datetime.datetime.utcfromtimestamp(int(i)), end_at: lambda i: datetime.datetime.utcfromtimestamp(int(i)), pids=[], **kwargs): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') validator.check_title(title) validator.check_content(content) if doc_type == document.TYPE_CONTEST: if rule not in constant.contest.CONTEST_RULES: raise error.ValidationError('rule') elif doc_type == document.TYPE_HOMEWORK: if rule not in constant.contest.HOMEWORK_RULES: raise error.ValidationError('rule') if begin_at >= end_at: raise error.ValidationError('begin_at', 'end_at') if doc_type == document.TYPE_HOMEWORK: if 'penalty_since' not in kwargs: raise error.ValidationError('penalty_since') if kwargs['penalty_since'] < begin_at: raise error.ValidationError('penalty_since', 'begin_at') if kwargs['penalty_since'] > end_at: raise error.ValidationError('penalty_since', 'end_at') # TODO(twd2): should we check problem existance here? return await document.add(domain_id, content, owner_uid, doc_type, title=title, rule=rule, begin_at=begin_at, end_at=end_at, pids=pids, attend=0, **kwargs)
async def post(self, *, code: str, uname: str, password: str, verify_password: str, school_id: str = ''): doc = await token.get(code, token.TYPE_REGISTRATION) sid = None if not doc: raise error.InvalidTokenError(token.TYPE_REGISTRATION, code) if password != verify_password: raise error.VerifyPasswordError() if school_id.strip(): if not school_id.isnumeric(): raise error.InvalidArgumentError('school_id') sid = school_id.strip() uid = await system.inc_user_counter() await user.add(uid, uname, password, doc['mail'], self.remote_ip) if sid: await user.set_by_uid(uid, ojcId=sid) await token.delete(code, token.TYPE_REGISTRATION) await self.update_session(new_saved=False, uid=uid) self.json_or_redirect(self.reverse_url('domain_main'))
async def post(self, *, ctype: str, tid: objectid.ObjectId, pid: document.convert_doc_id, lang: str, code: objectid.ObjectId): doc_type = constant.contest.CTYPE_TO_DOCTYPE[ctype] # TODO(iceboy): rate limit base on ip. tdoc, pdoc = await asyncio.gather( contest.get(self.domain_id, doc_type, tid), problem.get(self.domain_id, pid)) tsdoc = await contest.get_status(self.domain_id, doc_type, tdoc['doc_id'], self.user['_id']) if not tsdoc or tsdoc.get('attend') != 1: if ctype == 'contest': raise error.ContestNotAttendedError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotAttendedError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if not self.is_ongoing(tdoc): if ctype == 'contest': raise error.ContestNotLiveError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotLiveError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if pid not in tdoc['pids']: raise error.ProblemNotFoundError(self.domain_id, pid, tdoc['doc_id']) # TODO(tc-imba): only constant.record.CODE_TYPE_TAR is supported now rid = await record.add(self.domain_id, pdoc['doc_id'], constant.record.TYPE_SUBMISSION, self.user['_id'], lang, code, tid=tdoc['doc_id'], hidden=False, code_type=constant.record.CODE_TYPE_TAR) await contest.update_status(self.domain_id, tdoc['doc_id'], self.user['_id'], rid, pdoc['doc_id'], False, 0) if not self.can_show_record(tdoc): self.json_or_redirect( self.reverse_url('contest_detail', ctype=ctype, tid=tdoc['doc_id'])) else: self.json_or_redirect(self.reverse_url('record_detail', rid=rid))
async def get(self, *, ctype: str, tid: objectid.ObjectId, pid: document.convert_doc_id): doc_type = constant.contest.CTYPE_TO_DOCTYPE[ctype] uid = self.user['_id'] if self.has_priv( builtin.PRIV_USER_PROFILE) else None tdoc, pdoc = await asyncio.gather( contest.get(self.domain_id, doc_type, tid), problem.get(self.domain_id, pid, uid)) tsdoc, udoc = await asyncio.gather( contest.get_status(self.domain_id, doc_type, tdoc['doc_id'], self.user['_id']), user.get_by_uid(tdoc['owner_uid'])) attended = tsdoc and tsdoc.get('attend') == 1 if not self.is_finished(tdoc): if not attended: if ctype == 'contest': raise error.ContestNotAttendedError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotAttendedError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if not self.is_ongoing(tdoc): if ctype == 'contest': raise error.ContestNotLiveError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotLiveError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if pid not in tdoc['pids']: raise error.ProblemNotFoundError(self.domain_id, pid, tdoc['doc_id']) path_components = self.build_path( (self.translate('page.contest_main.{0}.title'.format(ctype)), self.reverse_url('contest_main', ctype=ctype)), (tdoc['title'], self.reverse_url('contest_detail', ctype=ctype, tid=tid)), (pdoc['title'], None)) self.render('problem_detail.html', tdoc=tdoc, pdoc=pdoc, tsdoc=tsdoc, udoc=udoc, attended=attended, page_title=pdoc['title'], path_components=path_components)
def wrapped(self, **kwargs): for key, value in kwargs.items(): try: kwargs[key] = func.__annotations__[key](value) except KeyError: raise error.UnknownArgumentError(key) except Exception: raise error.InvalidArgumentError(key) return func(self, **kwargs)
def get_multi(domain_id: str, doc_type: int, fields=None, **kwargs): # TODO(twd2): projection. if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') return document.get_multi(domain_id=domain_id, doc_type=doc_type, fields=fields, **kwargs) \ .sort([('doc_id', -1)])
async def get_dict_status(domain_id, uid, doc_type, tids, *, fields=None): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') result = dict() async for tsdoc in get_multi_status(domain_id=domain_id, uid=uid, doc_type=doc_type, doc_id={'$in': list(set(tids))}, fields=fields): result[tsdoc['doc_id']] = tsdoc return result
async def get_status(domain_id: str, doc_type: int, tid: objectid.ObjectId, uid: int, fields=None): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') return await document.get_status(domain_id, doc_type, doc_id=tid, uid=uid, fields=fields)
async def get_and_list_status(domain_id: str, doc_type: int, tid: objectid.ObjectId, fields=None): # TODO(iceboy): projection, pagination. if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') tdoc = await get(domain_id, doc_type, tid) tsdocs = await document.get_multi_status(domain_id=domain_id, doc_type=doc_type, doc_id=tdoc['doc_id'], fields=fields) \ .sort(RULES[tdoc['rule']].status_sort) \ .to_list() return tdoc, tsdocs
async def attend(domain_id: str, doc_type: int, tid: objectid.ObjectId, uid: int): # TODO(iceboy): check time. if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') try: await document.capped_inc_status(domain_id, doc_type, tid, uid, 'attend', 1, 0, 1) except errors.DuplicateKeyError: if doc_type == document.TYPE_CONTEST: raise error.ContestAlreadyAttendedError(domain_id, tid, uid) from None elif doc_type == document.TYPE_HOMEWORK: raise error.HomeworkAlreadyAttendedError(domain_id, tid, uid) from None return await document.inc(domain_id, doc_type, tid, 'attend', 1)
async def get_scoreboard(self, doc_type: int, tid: objectid.ObjectId, is_export: bool=False): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') tdoc, tsdocs = await get_and_list_status(self.domain_id, doc_type, tid) if not self.can_show_scoreboard(tdoc): if doc_type == document.TYPE_CONTEST: raise error.ContestScoreboardHiddenError(self.domain_id, tid) elif doc_type == document.TYPE_HOMEWORK: raise error.HomeworkScoreboardHiddenError(self.domain_id, tid) udict, dudict, pdict = await asyncio.gather( user.get_dict([tsdoc['uid'] for tsdoc in tsdocs]), domain.get_dict_user_by_uid(self.domain_id, [tsdoc['uid'] for tsdoc in tsdocs]), problem.get_dict(self.domain_id, tdoc['pids'])) ranked_tsdocs = RULES[tdoc['rule']].rank_func(tsdocs) rows = RULES[tdoc['rule']].scoreboard_func(is_export, self.translate, tdoc, ranked_tsdocs, udict, dudict, pdict) return tdoc, rows, udict
async def recalc_status(domain_id: str, doc_type: int, tid: objectid.ObjectId): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') tdoc = await document.get(domain_id, doc_type, tid) async with document.get_multi_status(domain_id=domain_id, doc_type=doc_type, doc_id=tdoc['doc_id']) as tsdocs: async for tsdoc in tsdocs: if 'journal' not in tsdoc or not tsdoc['journal']: continue journal = _get_status_journal(tsdoc) stat_func = RULES[tdoc['rule']].stat_func if asyncio.iscoroutinefunction(stat_func): stats = await stat_func(tdoc, journal) else: stats = RULES[tdoc['rule']].stat_func(tdoc, journal) await document.rev_set_status(domain_id, doc_type, tid, tsdoc['uid'], tsdoc['rev'], return_doc=False, journal=journal, **stats)
async def get(self, *, start: str='', uid_or_name: str='', pid: str='', tid: str='', status: str=''): if not self.has_priv(builtin.PRIV_VIEW_JUDGE_STATISTICS): start = '' if start: try: start = objectid.ObjectId(start) except Exception: raise error.InvalidArgumentError('start') else: start = None query = await self.get_filter_query(uid_or_name, pid, tid, status) # TODO(iceboy): projection, pagination. rdocs = await record.get_all_multi(**query, end_id=start, get_hidden=self.has_priv(builtin.PRIV_VIEW_HIDDEN_RECORD)).sort([('_id', -1)]).limit(50).to_list() # TODO(iceboy): projection. udict, dudict, pdict = await asyncio.gather( user.get_dict(rdoc['uid'] for rdoc in rdocs), domain.get_dict_user_by_uid(domain_id=self.domain_id, uids=(rdoc['uid'] for rdoc in rdocs)), problem.get_dict_multi_domain((rdoc['domain_id'], rdoc['pid']) for rdoc in rdocs)) # statistics statistics = None if self.has_priv(builtin.PRIV_VIEW_JUDGE_STATISTICS): ts = calendar.timegm(datetime.datetime.utcnow().utctimetuple()) day_count, week_count, month_count, year_count, rcount = await asyncio.gather( record.get_count(objectid.ObjectId( struct.pack('>i', ts - 24 * 3600) + struct.pack('b', -1) * 8)), record.get_count(objectid.ObjectId( struct.pack('>i', ts - 7 * 24 * 3600) + struct.pack('b', -1) * 8)), record.get_count(objectid.ObjectId( struct.pack('>i', ts - 30 * 24 * 3600) + struct.pack('b', -1) * 8)), record.get_count(objectid.ObjectId( struct.pack('>i', ts - int(365.2425 * 24 * 3600)) + struct.pack('b', -1) * 8)), record.get_count()) statistics = {'day': day_count, 'week': week_count, 'month': month_count, 'year': year_count, 'total': rcount} url_prefix = '/d/{}'.format(urllib.parse.quote(self.domain_id)) query_string = urllib.parse.urlencode( [('uid_or_name', uid_or_name), ('pid', pid), ('tid', tid)]) self.render( 'record_main.html', rdocs=rdocs, udict=udict, dudict=dudict, pdict=pdict, statistics=statistics, filter_uid_or_name=uid_or_name, filter_pid=pid, filter_status=status, filter_tid=tid, socket_url=url_prefix + '/records-conn?' + query_string, # FIXME(twd2): magic query_string=query_string)
def get_multi_status(doc_type: int, *, fields=None, **kwargs): if doc_type not in [document.TYPE_CONTEST, document.TYPE_HOMEWORK]: raise error.InvalidArgumentError('doc_type') return document.get_multi_status(doc_type=doc_type, fields=fields, **kwargs)
async def get(self, *, ctype: str, tid: objectid.ObjectId, pid: document.convert_doc_id): doc_type = constant.contest.CTYPE_TO_DOCTYPE[ctype] uid = self.user['_id'] if self.has_priv( builtin.PRIV_USER_PROFILE) else None tdoc, pdoc = await asyncio.gather( contest.get(self.domain_id, doc_type, tid), problem.get(self.domain_id, pid, uid)) tsdoc, udoc = await asyncio.gather( contest.get_status(self.domain_id, doc_type, tdoc['doc_id'], self.user['_id']), user.get_by_uid(tdoc['owner_uid'])) attended = tsdoc and tsdoc.get('attend') == 1 if not attended: if ctype == 'contest': raise error.ContestNotAttendedError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotAttendedError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if not self.is_ongoing(tdoc): if ctype == 'contest': raise error.ContestNotLiveError(tdoc['doc_id']) elif ctype == 'homework': raise error.HomeworkNotLiveError(tdoc['doc_id']) else: raise error.InvalidArgumentError('ctype') if pid not in tdoc['pids']: raise error.ProblemNotFoundError(self.domain_id, pid, tdoc['doc_id']) if self.can_show_record(tdoc): rdocs = await record.get_user_in_problem_multi(uid, self.domain_id, pdoc['doc_id'], get_hidden=True) \ .sort([('_id', -1)]) \ .limit(10) \ .to_list() else: rdocs = [] if not self.prefer_json: path_components = self.build_path( (self.translate('page.contest_main.{0}.title'.format(ctype)), self.reverse_url('contest_main', ctype=ctype)), (tdoc['title'], self.reverse_url('contest_detail', ctype=ctype, tid=tid)), (pdoc['title'], self.reverse_url( 'contest_detail_problem', ctype=ctype, tid=tid, pid=pid)), (self.translate('page.contest_detail_problem_submit.{0}.title'. format(ctype)), None)) languages = filter_language(pdoc.get('languages') or []) default_lang = len(languages) and list(languages.keys())[0] or '' self.render('problem_submit.html', tdoc=tdoc, pdoc=pdoc, rdocs=rdocs, tsdoc=tsdoc, udoc=udoc, attended=attended, page_title=pdoc['title'], path_components=path_components, languages=languages, default_lang=default_lang) else: self.json({'rdocs': rdocs})