diff --git a/src/handlers/acct.py b/src/handlers/acct.py index 2816cfa9..f1247775 100644 --- a/src/handlers/acct.py +++ b/src/handlers/acct.py @@ -44,13 +44,18 @@ async def get(self, acct_id): ac_pro_cnt = 0 for pro in prolist: pro_id = pro['pro_id'] - tmp = {'pro_id': pro_id, 'score': -1} + tmp = {'pro_id': pro_id, 'score': -1, 'state': None} if pro_id in ratemap: tmp['score'] = ratemap[pro_id]['rate'] + tmp['state'] = ratemap[pro_id]['state'] ac_pro_cnt += ratemap[pro_id]['state'] == ChalConst.STATE_AC prolist2.append(tmp) + def chunk_list(la, size): + for i in range(0, len(la), size): + yield la[i: i + size] + rate_data['rate'] = math.floor(rate_data['rate']) rate_data['ac_pro_cnt'] = ac_pro_cnt @@ -58,7 +63,7 @@ async def get(self, acct_id): acct.photo = re.sub(r'^http://', 'https://', acct.photo) acct.cover = re.sub(r'^http://', 'https://', acct.cover) - await self.render('acct/profile', acct=acct, rate=rate_data, prolist=prolist2) + await self.render('acct/profile', acct=acct, rate=rate_data, prolist=chunk_list(prolist2, 10)) class AcctConfigHandler(RequestHandler): @@ -127,6 +132,7 @@ async def post(self): class AcctProClassHandler(RequestHandler): @reqenv + @require_permission([UserConst.ACCTTYPE_USER, UserConst.ACCTTYPE_KERNEL]) async def get(self, acct_id): acct_id = int(acct_id) try: @@ -152,6 +158,7 @@ async def get(self, acct_id): await self.render('acct/proclass-update', proclass_id=proclass_id, proclass=proclass) @reqenv + @require_permission([UserConst.ACCTTYPE_USER, UserConst.ACCTTYPE_KERNEL]) async def post(self, acct_id): reqtype = self.get_argument('reqtype') acct_id = int(acct_id) diff --git a/src/handlers/base.py b/src/handlers/base.py index dae5440b..9f35a386 100644 --- a/src/handlers/base.py +++ b/src/handlers/base.py @@ -15,7 +15,8 @@ import utils.htmlgen TEMPLATE_NAMESPACE = { - 'set_page_title': utils.htmlgen.set_page_title + 'set_page_title': utils.htmlgen.set_page_title, + 'markdown_escape': utils.htmlgen.markdown_escape, } class RequestHandler(tornado.web.RequestHandler): diff --git a/src/handlers/manage/pro.py b/src/handlers/manage/pro.py index f07999ac..71ea544d 100644 --- a/src/handlers/manage/pro.py +++ b/src/handlers/manage/pro.py @@ -890,54 +890,34 @@ async def post(self, page=None): self.error(err) return - ALLOW_COMPILERS = ChalConst.ALLOW_COMPILERS + ALLOW_COMPILERS = set(list(ChalConst.ALLOW_COMPILERS) + ['default']) if pro['testm_conf']['is_makefile']: - ALLOW_COMPILERS = ['gcc', 'g++', 'clang', 'clang++', 'default'] + ALLOW_COMPILERS = {'gcc', 'g++', 'clang', 'clang++', 'default'} - def _check(comp_type, limit): - if comp_type not in ALLOW_COMPILERS and comp_type != "default": - return False - - if 'timelimit' not in limit: - return False + new_limits = {} + for comp_type, limit in limits.items(): + if comp_type not in ALLOW_COMPILERS: + continue try: - int(limit['timelimit']) - except ValueError: - return False - - if 'memlimit' not in limit: - return False + limit['timelimit'] = max(int(limit['timelimit']), 0) + limit['memlimit'] = max(int(limit['memlimit']) * 1024, 0) + except (ValueError, KeyError): + continue - try: - int(limit['memlimit']) - except ValueError: - return False + new_limits[comp_type] = limit - return True - - limits = { comp_type:limit for comp_type, limit in limits.items() if _check(comp_type, limit) } - if 'default' not in limits: + if 'default' not in new_limits: self.error('Eparam') return - for _, limit in limits.items(): - limit['timelimit'] = int(limit['timelimit']) - limit['memlimit'] = int(limit['memlimit']) * 1024 - - if limit['timelimit'] < 0: - limit['timelimit'] = 0 - - if limit['memlimit'] < 0: - limit['memlimit'] = 0 - - pro['testm_conf']['limit'] = limits + pro['testm_conf']['limit'] = new_limits await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( f"{self.acct.name} has sent a request to update the problem #{pro_id}", 'manage.pro.update.limit', { - 'limits': limits + 'limits': new_limits } ) @@ -999,11 +979,14 @@ def _check(comp_type, limit): self.error(err) return + log_type = "" async with self.db.acquire() as con: if is_all_chal: sql = "" + log_type = "manage.chal.rechalall" else: sql = '''AND "challenge_state"."chal_id" IS NULL''' + log_type = "manage.chal.rechal" result = await con.fetch( f''' SELECT "challenge"."chal_id", "challenge"."compiler_type" FROM "challenge" @@ -1015,7 +998,7 @@ def _check(comp_type, limit): ) await LogService.inst.add_log( f"{self.acct.name} made a request to rejudge the problem #{pro_id} with {len(result)} chals", - 'manage.chal.rechal', + log_type, ) # TODO: send notify to user diff --git a/src/services/pro.py b/src/services/pro.py index e9dc06fe..c5edc01f 100644 --- a/src/services/pro.py +++ b/src/services/pro.py @@ -339,19 +339,37 @@ async def unpack_pro(self, pro_id, pack_type, pack_token): check_type = self._get_check_type(conf["check"]) - ALLOW_COMPILERS = list(ChalConst.ALLOW_COMPILERS) + ['default'] + ALLOW_COMPILERS = set(list(ChalConst.ALLOW_COMPILERS) + ['default']) if is_makefile: - ALLOW_COMPILERS = ['default', 'gcc', 'g++', 'clang', 'clang++'] + ALLOW_COMPILERS = {'default', 'gcc', 'g++', 'clang', 'clang++'} if "limit" in conf: - limit = {lang: lim for lang, lim in conf["limit"].items() if lang in ALLOW_COMPILERS} + limits = {} + for comp_type, limit in conf["limit"].items(): + if comp_type not in ALLOW_COMPILERS: + continue + + try: + limit['timelimit'] = max(int(limit['timelimit']), 0) + limit['memlimit'] = max(int(limit['memlimit']) * 1024, 0) + except (ValueError, KeyError): + continue + + limits[comp_type] = limit + + if 'default' not in limits: + return "Econf", None + elif 'timelimit' in conf and 'memlimit' in conf: - limit = { - 'default': { - 'timelimit': conf["timelimit"], - 'memlimit': conf["memlimit"] * 1024 + try: + limits = { + 'default': { + 'timelimit': int(conf["timelimit"]), + 'memlimit': int(conf["memlimit"]) * 1024 + } } - } + except ValueError: + return "Econf", None else: return "Econf", None @@ -363,7 +381,7 @@ async def unpack_pro(self, pro_id, pack_type, pack_token): await con.execute('DELETE FROM "test_config" WHERE "pro_id" = $1;', int(pro_id)) await con.execute( 'UPDATE "problem" SET is_makefile = $1, check_type = $2, chalmeta = $3, "limit" = $4 WHERE pro_id = $5', - is_makefile, check_type, json.dumps(chalmeta), json.dumps(limit), pro_id + is_makefile, check_type, json.dumps(chalmeta), json.dumps(limits), pro_id ) insert_sql = [] diff --git a/src/static/index.js b/src/static/index.js index 3e693113..6dad1f3d 100644 --- a/src/static/index.js +++ b/src/static/index.js @@ -368,5 +368,11 @@ var index = new function() { } return new WebSocket(ws_link); }; + + that.unescape_html = function(html) { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + return doc.documentElement.textContent; + }; }; diff --git a/src/static/templ/acct/proclass-update.html b/src/static/templ/acct/proclass-update.html index 9853aa5d..16e34e4b 100644 --- a/src/static/templ/acct/proclass-update.html +++ b/src/static/templ/acct/proclass-update.html @@ -2,7 +2,7 @@ function init() { let j_form = $("#form"); let re = /[^0-9,\ ]/; - j_form.find("#desc").val(`{% raw proclass['desc'].replace('`', '\\`').replace('\\', '\\\\') %}`); + j_form.find("#desc").val(index.unescape_html(`{{ markdown_escape(proclass['desc']) }}`)); let desc_textarea = document.getElementById('desc'); let desc_preview = document.getElementById('descPreviewDialog'); diff --git a/src/static/templ/acct/profile.html b/src/static/templ/acct/profile.html index d09de566..88392b41 100644 --- a/src/static/templ/acct/profile.html +++ b/src/static/templ/acct/profile.html @@ -1,3 +1,4 @@ +{% from services.chal import ChalConst %}