diff --git a/src/handlers/manage/pro.py b/src/handlers/manage/pro.py index 5844d44d..5b1b1540 100644 --- a/src/handlers/manage/pro.py +++ b/src/handlers/manage/pro.py @@ -50,6 +50,9 @@ async def get(self, page=None): elif page == "filemanager": pro_id = int(self.get_argument('proid')) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return testm_conf = pro['testm_conf'] dirs = [] @@ -116,6 +119,10 @@ async def get(self, page=None): err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + files = sorted(set(map(lambda file: file.replace('.in', '').replace('.out', ''), filter(lambda file: file.endswith('.in') or file.endswith('.out'), os.listdir(f'problem/{pro_id}/res/testdata'))))) @@ -143,7 +150,7 @@ async def post(self, page=None): err, pro_id = await ProService.inst.add_pro(name, status, pack_token) await LogService.inst.add_log( - f"{self.acct.name} had been send a request to add the problem #{pro_id}", 'manage.pro.add.pro' + f"{self.acct.name} has sent a request to add the problem #{pro_id}", 'manage.pro.add.pro' ) if err: self.error(err) @@ -165,7 +172,7 @@ async def post(self, page=None): basepath = f'problem/{pro_id}/res/testdata' if not self._is_file_access_safe(basepath, filename): await LogService.inst.add_log( - f'{self.acct.name} tried to preview file:{filename} of the problem #{pro_id}, but it was suspicious', + f'{self.acct.name} tried to preview file:{filename} for problem #{pro_id}, but it was suspicious', 'manage.pro.update.tests.preview.failed' ) self.error('Eacces') @@ -175,13 +182,13 @@ async def post(self, page=None): if not os.path.exists(filepath): await LogService.inst.add_log( - f'{self.acct.name} tried to preview file:{filename} of the problem #{pro_id} but not found', + f'{self.acct.name} tried to preview file:{filename} for problem #{pro_id} but not found', 'manage.pro.update.tests.preview.failed' ) self.error('Enoext') return - await LogService.inst.add_log(f'{self.acct.name} preview file:{filename} of the problem #{pro_id}', + await LogService.inst.add_log(f'{self.acct.name} preview file:{filename} for problem #{pro_id}', 'manage.pro.update.tests.preview') with open(filepath, 'r') as testcase_f: content = testcase_f.readlines() @@ -197,6 +204,10 @@ async def post(self, page=None): weight = int(self.get_argument('weight')) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + test_group = pro['testm_conf']['test_group'] if group not in test_group: @@ -206,7 +217,7 @@ async def post(self, page=None): test_group[group]['weight'] = weight await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to update weight of subtask#{group} of the problem #{pro_id}', + f'{self.acct.name} has sent a request to update weight of subtask#{group} for problem #{pro_id}', 'manage.pro.update.tests.updateweight', { 'weight': weight, @@ -219,6 +230,10 @@ async def post(self, page=None): weight = int(self.get_argument('weight')) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + test_group = pro['testm_conf']['test_group'] test_group[len(test_group)] = { @@ -228,7 +243,7 @@ async def post(self, page=None): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to add a new subtask of the problem #{pro_id}', + f'{self.acct.name} has sent a request to add a new subtask for problem #{pro_id}', 'manage.pro.update.tests.addtaskgroup', { 'weight': weight, @@ -242,6 +257,10 @@ async def post(self, page=None): group = int(self.get_argument('group')) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + test_group = pro['testm_conf']['test_group'] if group not in test_group: self.error('Enoext') @@ -256,7 +275,7 @@ async def post(self, page=None): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to delete a subtask of the problem #{pro_id}', + f'{self.acct.name} has sent a request to delete a subtask for problem #{pro_id}', 'manage.pro.update.tests.deletetaskgroup', ) self.finish('S') @@ -266,12 +285,16 @@ async def post(self, page=None): group = int(self.get_argument('group')) testcase = self.get_argument('testcase') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + basepath = f'problem/{pro_id}/res/testdata' if not os.path.exists(f'{basepath}/{testcase}.in') or not os.path.exists(f'{basepath}/{testcase}.out'): self.error('Enoext') return - err, pro = await ProService.inst.get_pro(pro_id, self.acct) test_group = pro['testm_conf']['test_group'] if group not in test_group: self.error('Enoext') @@ -289,7 +312,7 @@ async def post(self, page=None): test_group[group]['metadata']['data'].append(testcase) await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to add a testcase:{testcase} to group#{group} of the problem #{pro_id}', + f'{self.acct.name} has sent a request to add a testcase:{testcase} to group#{group} for problem #{pro_id}', 'manage.pro.update.tests.addsingletestcase', ) self.finish('S') @@ -300,6 +323,10 @@ async def post(self, page=None): testcase = self.get_argument('testcase') err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + test_group = pro['testm_conf']['test_group'] if group not in test_group: self.error('Enoext') @@ -313,7 +340,7 @@ async def post(self, page=None): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to delete a testcase:{testcase} to group#{group} for problem #{pro_id}', + f'{self.acct.name} has sent a request to delete a testcase:{testcase} to group#{group} for problem #{pro_id}', 'manage.pro.update.tests.deletesingletestcase', ) self.finish('S') @@ -323,6 +350,11 @@ async def post(self, page=None): old_filename = self.get_argument('old_filename') new_filename = self.get_argument('new_filename') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + # check filename basepath = f'problem/{pro_id}/res/testdata' old_inputfile_path = f'{basepath}/{old_filename}.in' @@ -356,7 +388,6 @@ async def post(self, page=None): os.rename(old_inputfile_path, new_inputfile_path) os.rename(old_outputfile_path, new_outputfile_path) - err, pro = await ProService.inst.get_pro(pro_id, self.acct) is_modified = False for test_group in pro['testm_conf']['test_group'].values(): test = test_group['metadata']['data'] @@ -369,7 +400,7 @@ async def post(self, page=None): if is_modified: await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to rename {old_filename} to {new_filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to rename {old_filename} to {new_filename} for problem #{pro_id}', 'manage.pro.update.tests.renamesinglefile', ) self.finish('S') @@ -380,6 +411,11 @@ async def post(self, page=None): test_type = self.get_argument('type') pack_token = self.get_argument('pack_token') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if test_type not in ['output', 'input']: PackService.inst.clear(pack_token) self.error('Eparam') @@ -391,7 +427,7 @@ async def post(self, page=None): if not self._is_file_access_safe(basepath, f"{filename}.{test_type[0:-3]}"): PackService.inst.clear(pack_token) await LogService.inst.add_log( - f'{self.acct.name} tried to update {filename} of the problem #{pro_id}, but it was suspicious', + f'{self.acct.name} tried to update {filename} for problem #{pro_id}, but it was suspicious', 'manage.pro.update.tests.updatesinglefile.failed' ) self.error('Eacces') @@ -407,8 +443,10 @@ async def post(self, page=None): return _ = await PackService.inst.direct_copy(pack_token, filepath) + + await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to update a single file:{filename} of the problem #{pro_id}', + f'{self.acct.name} has sent a request to update a single file:{filename} for problem #{pro_id}', 'manage.pro.update.tests.updatesinglefile', ) @@ -420,6 +458,11 @@ async def post(self, page=None): input_pack_token = self.get_argument('input_pack_token') output_pack_token = self.get_argument('output_pack_token') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + basepath = f'problem/{pro_id}/res/testdata' inputfile_path = f'{basepath}/{filename}.in' outputfile_path = f'{basepath}/{filename}.out' @@ -450,7 +493,7 @@ async def post(self, page=None): _ = await PackService.inst.direct_copy(output_pack_token, outputfile_path) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to add a single file:{filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to add a single file:{filename} for problem #{pro_id}', 'manage.pro.update.tests.addsinglefile', ) @@ -460,6 +503,11 @@ async def post(self, page=None): pro_id = int(self.get_argument('pro_id')) filename = self.get_argument('filename') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + basepath = f'problem/{pro_id}/res/testdata' if not self._is_file_access_safe(basepath, f'{filename}.in'): await LogService.inst.add_log( @@ -480,7 +528,6 @@ async def post(self, page=None): os.remove(f'{basepath}/{filename}.in') os.remove(f'{basepath}/{filename}.out') - err, pro = await ProService.inst.get_pro(pro_id, self.acct) for test_group in pro['testm_conf']['test_group'].values(): test = test_group['metadata']['data'] @@ -491,7 +538,7 @@ async def post(self, page=None): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to delete a single file:{filename} of the problem #{pro_id}', + f'{self.acct.name} has sent a request to delete a single file:{filename} for problem #{pro_id}', 'manage.pro.update.tests.deletesinglefile', ) @@ -503,6 +550,11 @@ async def post(self, page=None): filename = self.get_argument('filename') basepath = self.get_argument('path') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if basepath not in ['http', 'res/check', 'res/make']: self.error('Eparam') return @@ -543,6 +595,11 @@ async def post(self, page=None): new_filename = self.get_argument('new_filename') basepath = self.get_argument('path') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if basepath not in ['http', 'res/check', 'res/make']: self.error('Eparam') return @@ -576,7 +633,7 @@ async def post(self, page=None): os.rename(old_filepath, new_filepath) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to rename {old_filename} to {new_filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to rename {old_filename} to {new_filename} for problem #{pro_id}', 'manage.pro.update.filemanager.renamesinglefile', ) self.finish('S') @@ -587,6 +644,11 @@ async def post(self, page=None): pack_token = self.get_argument('pack_token') basepath = self.get_argument('path') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if basepath not in ['http', 'res/check', 'res/make']: self.error('Eparam') return @@ -614,7 +676,7 @@ async def post(self, page=None): _ = await PackService.inst.direct_copy(pack_token, filepath) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to update {filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to update {filename} for problem #{pro_id}', 'manage.pro.update.filemanager.updatesinglefile', ) @@ -626,6 +688,11 @@ async def post(self, page=None): pack_token = self.get_argument('pack_token') basepath = self.get_argument('path') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if basepath not in ['http', 'res/check', 'res/make']: self.error('Eparam') return @@ -653,7 +720,7 @@ async def post(self, page=None): _ = await PackService.inst.direct_copy(pack_token, filepath) await LogService.inst.add_log( - f'{self.acct.name} had been send a request to add {filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to add {filename} for problem #{pro_id}', 'manage.pro.update.filemanager.addsinglefile', ) @@ -664,6 +731,11 @@ async def post(self, page=None): filename = self.get_argument('filename') basepath = self.get_argument('path') + err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + if basepath not in ['http', 'res/check', 'res/make']: self.error('Eparam') return @@ -689,7 +761,7 @@ async def post(self, page=None): os.remove(f'{basepath}/{filename}') await LogService.inst.add_log( - f'{self.acct.name} had been send a request to delete {filename} for problem #{pro_id}', + f'{self.acct.name} has sent a request to delete {filename} for problem #{pro_id}', 'manage.pro.update.filemanager.deletesinglefile', ) @@ -702,6 +774,7 @@ async def post(self, page=None): status = int(self.get_argument('status')) tags = self.get_argument('tags') allow_submit = self.get_argument('allow_submit') == "true" + # NOTE: test config is_makefile = self.get_argument('is_makefile') == "true" check_type = int(self.get_argument('check_type')) @@ -718,6 +791,10 @@ async def post(self, page=None): pro_id, name, status, None, None, tags, allow_submit ) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + old_is_makefile = pro['testm_conf']['is_makefile'] old_check_type = pro['testm_conf']['check_type'] custom_check_type = [ProConst.CHECKER_IOREDIR, ProConst.CHECKER_CMS] @@ -736,7 +813,7 @@ async def post(self, page=None): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f"{self.acct.name} had been send a request to update the problem #{pro_id}", 'manage.pro.update.pro', + f"{self.acct.name} has sent a request to update the problem #{pro_id}", 'manage.pro.update.pro', { 'name': name, 'status': status, @@ -759,6 +836,10 @@ async def post(self, page=None): pack_token = self.get_argument('pack_token') err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return + err, _ = await ProService.inst.update_pro( pro_id, pro['name'], pro['status'], ProService.PACKTYPE_FULL, pack_token, pro['tags'], pro['allow_submit'] ) @@ -787,7 +868,7 @@ async def post(self, page=None): }) await LogService.inst.add_log( - f"{self.acct.name} had been send a request to update the problem #{pro_id} by uploading problem package", + f"{self.acct.name} has sent a request to update the problem #{pro_id} by uploading problem package", 'manage.pro.update.pro.package', ) @@ -798,6 +879,9 @@ async def post(self, page=None): limits = json.loads(self.get_argument('limits')) err, pro = await ProService.inst.get_pro(pro_id, self.acct) + if err: + self.error(err) + return ALLOW_COMPILERS = ChalConst.ALLOW_COMPILERS if pro['testm_conf']['is_makefile']: @@ -843,7 +927,7 @@ def _check(comp_type, limit): await ProService.inst.update_test_config(pro_id, pro['testm_conf']) await LogService.inst.add_log( - f"{self.acct.name} had been send a request to update the problem #{pro_id}", + f"{self.acct.name} has sent a request to update the problem #{pro_id}", 'manage.pro.update.limit', { 'limits': limits @@ -912,7 +996,7 @@ def _check(comp_type, limit): if is_all_chal: sql = "" else: - sql = '''AND "challenge_state"."state" IS NULL''' + sql = '''AND "challenge_state"."chal_id" IS NULL''' result = await con.fetch( f''' SELECT "challenge"."chal_id", "challenge"."compiler_type" FROM "challenge" diff --git a/src/handlers/pro.py b/src/handlers/pro.py index f7941cd8..fe2e52bb 100644 --- a/src/handlers/pro.py +++ b/src/handlers/pro.py @@ -164,12 +164,16 @@ async def post(self): if reqtype == "listproclass": _, accts = await UserService.inst.list_acct(UserConst.ACCTTYPE_KERNEL) accts = {acct.acct_id: acct.name for acct in accts} + _, proclass_list = await ProClassService.inst.get_proclass_list() - proclass_list = list(map(dict, proclass_list)) - for proclass in proclass_list: + def _set_creator_name(proclass): + proclass = dict(proclass) if proclass['acct_id']: proclass['creator_name'] = accts[proclass['acct_id']] + return proclass + proclass_list = list(map(_set_creator_name, proclass_list)) + proclass_cata = { "official": list(filter(lambda proclass: proclass['type'] == ProClassConst.OFFICIAL_PUBLIC, proclass_list)), "shared": list(filter(lambda proclass: proclass['type'] == ProClassConst.USER_PUBLIC, proclass_list)), diff --git a/src/services/chal.py b/src/services/chal.py index 9c58368a..d9f4951f 100644 --- a/src/services/chal.py +++ b/src/services/chal.py @@ -7,6 +7,7 @@ from services.pro import ProService from services.user import Account +TZ = datetime.timezone(datetime.timedelta(hours=+8)) class ChalConst: STATE_AC = 1 @@ -108,12 +109,12 @@ def get_sql_query_str(self): query += f' AND "challenge_state"."state" = {self.state} ' if self.compiler != 'all': - query += f' AND \"challenge\".\"compiler_type\"=\'{self.compiler}\' ' + query += f' AND "challenge"."compiler_type"=\'{self.compiler}\' ' if self.contest != 0: query += f' AND "challenge"."contest_id"={self.contest} ' else: - query += ' AND "challenge"."contest_id"=0 ' + query += f' AND "challenge"."contest_id"=0 ' return query @@ -270,10 +271,6 @@ async def get_chal(self, chal_id): } ) - owner = await self.rs.get(f'{pro_id}_owner') - unlock = [1] - - tz = datetime.timezone(datetime.timedelta(hours=+8)) return ( None, @@ -283,7 +280,7 @@ async def get_chal(self, chal_id): 'acct_id': acct_id, 'contest_id': contest_id, 'acct_name': acct_name, - 'timestamp': timestamp.astimezone(tz), + 'timestamp': timestamp.astimezone(TZ), 'testl': testl, 'response': final_response, 'comp_type': comp_type, @@ -309,13 +306,8 @@ async def emit_chal(self, chal_id, pro_id, testm_conf, comp_type, pri: int): acct_id, contest_id, timestamp = int(result['acct_id']), int(result['contest_id']), result['timestamp'] limit = testm_conf['limit'] - - if comp_type in limit: - timelimit = limit[comp_type]['timelimit'] - memlimit = limit[comp_type]['memlimit'] - else: - timelimit = limit['default']['timelimit'] - memlimit = limit['default']['memlimit'] + timelimit = limit.get(comp_type, limit['default'])['timelimit'] + memlimit = limit.get(comp_type, limit['default'])['memlimit'] async with self.db.acquire() as con: testl = [] diff --git a/src/services/pro.py b/src/services/pro.py index 2d3622b6..5614d7e0 100644 --- a/src/services/pro.py +++ b/src/services/pro.py @@ -129,7 +129,7 @@ async def get_pro(self, pro_id, acct: Account | None = None, is_contest: bool = }, ) - async def list_pro(self, acct: Account = None, is_contest=False): + async def list_pro(self, acct: Account | None = None, is_contest=False): if acct is None: max_status = ProService.STATUS_ONLINE @@ -424,10 +424,10 @@ def __init__(self, db, rs): self.rs = rs ProClassService.inst = self - async def get_proclass(self, proclass_id): + async def get_proclass(self, proclass_id: int): async with self.db.acquire() as con: res = await con.fetch( - 'SELECT "proclass_id", "name", "desc", "list", "acct_id", "type" FROM "proclass" WHERE "proclass_id" = $1 ORDER BY "proclass_id" ASC;', + 'SELECT "proclass_id", "name", "desc", "list", "acct_id", "type" FROM "proclass" WHERE "proclass_id" = $1;', int(proclass_id), ) @@ -438,11 +438,11 @@ async def get_proclass(self, proclass_id): async def get_proclass_list(self): async with self.db.acquire() as con: - res = await con.fetch('SELECT "proclass_id", "name", "acct_id", "type" FROM "proclass";') + res = await con.fetch('SELECT "proclass_id", "name", "acct_id", "type" FROM "proclass" ORDER BY "proclass_id" ASC;') return None, res - async def add_proclass(self, name, p_list, desc, acct_id, proclass_type): + async def add_proclass(self, name: str, p_list: list[int], desc: str, acct_id: int, proclass_type: int): async with self.db.acquire() as con: res = await con.fetchrow( """ @@ -458,7 +458,7 @@ async def add_proclass(self, name, p_list, desc, acct_id, proclass_type): return None, res[0] - async def remove_proclass(self, proclass_id): + async def remove_proclass(self, proclass_id: int): async with self.db.acquire() as con: await con.execute('DELETE FROM "proclass" WHERE "proclass_id" = $1', int(proclass_id)) diff --git a/src/static/index.js b/src/static/index.js index 102c2207..3e693113 100644 --- a/src/static/index.js +++ b/src/static/index.js @@ -125,11 +125,12 @@ var index = new function() { $(document).on('click', 'a', function(e) { let cur_href = location.href; + let href = $(this).attr('href'); + let target = $(this).attr('target'); if (href == undefined || href.length == 0) return; - if ($(this).attr('target') !== "") { - return; - } + if (target) return + window.history.pushState(null, document.title, $(this).attr('href')); if (href.startsWith('?')) { diff --git a/src/static/templ/acct/acct-config.html b/src/static/templ/acct/acct-config.html index c0e6ce08..3be2f330 100644 --- a/src/static/templ/acct/acct-config.html +++ b/src/static/templ/acct/acct-config.html @@ -1,4 +1,4 @@ -{{ set_page_title("Edit Account") }} +{% raw set_page_title("Edit Account") %} {% if acct.acct_id != user.acct_id and not user.is_kernel() %} You don't have permission. diff --git a/src/static/templ/proset.html b/src/static/templ/proset.html index 7fb8a01c..75f1e6ec 100644 --- a/src/static/templ/proset.html +++ b/src/static/templ/proset.html @@ -66,6 +66,12 @@ $("#infoProClass").on('click', function(e) { let body = info_dialog.querySelector('.modal-body'); body.innerHTML = DOMPurify.sanitize(marked.parse(cur_proclass_desc)); + + // NOTE: close info dialog before navigating to another page. + info_dialog.querySelectorAll('a').forEach(el => { + el.addEventListener('click', _ => info_dialog_modal.dispose()); + }) + MathJax.Hub.Queue(["Typeset", MathJax.Hub, body]); info_dialog_modal.show(); }); @@ -262,7 +268,9 @@