def can_post_at(user: User, path: str): # 不合法的路径不能发帖 if not legal_paths.match(path): return False # 有讨论管理权限可以在任何地方发帖 if permission_manager.has_permission(user.id, "discussion.manage"): return True match_result = legal_paths.match(path) main_path = match_result.group() if main_path == "wiki" or main_path == "broadcast": return permission_manager.has_permission(user.id, "discussion.manage") elif main_path.startswith("blog"): uid = int(match_result.groupdict()["uid"]) if not db.session.query(User.id).filter(User.id == uid).count(): return False if not permission_manager.has_permission(user.id, "blog.use"): return False if not permission_manager.has_permission(user.id, "discussion.manage") and user.id != uid: return False return True if match_result.groupdict().get("id", None): problem_id = int(match_result.groupdict()["id"]) if not Problem.has(problem_id): return False return True
def contest_update(contestID: int, data: dict): """ 更新比赛信息 { contestID:比赛ID, data:数据字典 } """ if not session.get("uid"): return make_response(-1, message="请先登录") user: User = User.by_id(session.get("uid")) contest: Contest = Contest.by_id(contestID) if contest.closed: return make_response(-1, message="比赛已关闭") if not permission_manager.has_permission(user.id, "contest.manage") and user.id != contest.owner_id: return make_response(-1, message="你没有权限这么做") # 修改比赛的人必须能够访问其所设定的题目 for problem_obj in data["problems"]: problem_id = problem_obj["id"] problem = db.session.query( Problem.id, Problem.public, Problem.uploader_id).filter_by(id=problem_id).one_or_none() if not problem: return make_response(-1, message=f"比赛题目{problem_id}不存在") if user.id != problem.uploader_id: if not problem.public and not permission_manager.has_permission(user.id, f"problem.use.{problem.id}"): return make_response(-1, message=f"你没有权限访问题目{problem_id}") contest.name = data["name"] contest.description = data["description"] contest.start_time = data["start_time"] contest.end_time = data["end_time"] contest.problems = data["problems"] contest.ranklist_visible = data["ranklist_visible"] contest.judge_result_visible = data["judge_result_visible"] contest.rank_criterion = data["rank_criterion"] if contest.private_contest and not data["private_contest"]: # 没有权限的人只能搞私有比萨 if not permission_manager.has_permission(session.get("uid"), "contest.manage"): return make_response(-1, message="你没有权限公开比赛") contest.private_contest = data["private_contest"] contest.invite_code = data["invite_code"] def from_second_to_datetime(seconds): import time import datetime time_struct = time.localtime(seconds) time_str = time.strftime("%Y-%m-%d %H:%M:%S", time_struct) # print(time_str) return datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S") contest.start_time = from_second_to_datetime(data["start_time"]) contest.end_time = from_second_to_datetime(data["end_time"]) if contest.end_time < contest.start_time: return make_response(-1, message="开始时间必须早于结束时间") # print(contest.start_time, contest.end_time) db.session.commit() import redis import main redis.Redis(connection_pool=main.redis_connection_pool).delete( f"hj2-contest-ranklist-{contest.id}") return make_response(0, message="完成")
def discussion_update(id: int, content: str, title: str, top: bool): """ 更新讨论 id:讨论ID content:内容 title:标题: top:置顶 """ if not session.get("uid"): return make_response(-1, message="请先登录") discussion: Discussion = Discussion.by_id(id) if not discussion: return make_response(-1, message="讨论ID不存在") user: User = User.by_id(session.get("uid")) if not permission_manager.has_permission(user.id, "discussion.manage") and user.id != discussion.uid: return make_response(-1, message="你没有权限这样做") import datetime discussion.content = content + \ "\n\n最后编辑于"+str(datetime.datetime.now()) discussion.title = title if top and not permission_manager.has_permission(user.id, "discussion.manage"): return make_response(-1, message="你没有权限发送置顶讨论") discussion.top = top db.session.commit() return make_response(0, message="操作成功")
def download_file(id: int, filename: str): """ 下载题目文件 参数: 无 返回: 无 """ problem = db.session.query(Problem).filter( Problem.id == id) import flask if problem.count() == 0: flask.abort(404) problem: Problem = problem.one() # filename = secure_filename(filename) if not problem.public and not session.get("uid"): flask.abort(403) if not any((x["name"] == filename for x in problem.files)): flask.abort(404) if session.get("uid"): user: User = db.session.query(User).filter( User.id == session.get("uid")).one() if not problem.public and not permission_manager.has_permission(user.id, "problem.manage") and user.id != problem.uploader_id: flask.abort(403) if problem.public and not permission_manager.has_permission(user.id, "problem.manage") and user.id != problem.uploader_id and filename not in problem.downloads: flask.abort(403) else: if not problem.public or filename not in problem.downloads: flask.abort(403) import os file = os.path.join( basedir, f"{config.UPLOAD_DIR}/{id}/{filename}") if not os.path.exists(file): flask.abort(404) return send_file(file, as_attachment=True, conditional=True)
def contest_list(page: int = 1): """ { "page":"切换到的页面", } { "code":0, "data":{ "page_count":"页面总数", "list":[ { "id":"比赛ID", "name":"比赛名", "owner_id":"所有者用户ID", "owner_username":"******", "begin_time":"开始毫秒数", "end_time":"结束毫秒数", "privateContest":"该比赛是否私有", "hasPermission":"是否有权限访问该比赛" } ] } } """ result = db.session.query(Contest).order_by(Contest.id.desc()) subquery = db.session.query( Submission.contest_id).filter(expr.and_( Submission.contest_id != -1, Submission.uid == session.get("uid", -1) )).distinct() result = db.session.query(Contest).order_by(Contest.id.desc()) if not permission_manager.has_permission(session.get("uid", None), "contest.manage"): result = result.filter(expr.or_( Contest.owner_id == session.get("uid", -1), Contest.private_contest == False, Contest.id.in_(subquery) )) count = result.count() import math result: Iterable[Contest] = result.slice( (page-1)*config.CONTESTS_PER_PAGE, (page)*config.CONTESTS_PER_PAGE).all() ret = {"page_count": int(math.ceil(count/config.CONTESTS_PER_PAGE)), "list": [ ]} import time for contest in result: user: User = User.by_id(contest.owner_id) ret["list"].append({ "id": contest.id, "name": contest.name, "owner_id": user.id, "owner_username": user.username, "start_time": int(time.mktime(contest.start_time.timetuple())), "end_time": int(time.mktime(contest.end_time.timetuple())), "privateContest": contest.private_contest, "hasPermission": permission_manager.has_permission(session.get("uid", None), f"contest.use.{contest.id}") }) return make_response(0, data=ret)
def contest_show_problem(problemID: int, contestID: int): """ 获取比赛题目信息 参数: problemID:int 题目ID(比赛中的) contestID:int 比赛ID 返回: { "code":0,//非0表示调用成功 "message":"qwq",//code非0的时候表示错误信息 "data":{ "title":"qwq",//题目名 "backcground":"qwq",//题目背景 "content":"题目内容", "input_format":"输入格式", "output_format":"输出格式", "hint":"数据范围与提示", "example":"样例,形如[{'input':'xxx','output':'xxx'}]", "files":["a.in","a.out"],//不包括具体的二进制数据! "subtasks":[ {"name": "Subtask1", "score": 40, "method": "min", "files": [], "time_limit":1000, "memory_limit":512}]. "last_code":"qwq",//上一次提交的代码, "last_lang":"qwq",//上一次选择的语言ID "score":题目总分, "extra_compile_parameter":[] } } """ contest: Contest = Contest.by_id(contestID) if not contest.running(): if not session.get("uid"): return make_response(-1, message="你没有权限跟我说话") user: User = User.by_id(session.get("uid")) if not permission_manager.has_permission( user.id, "contest.manage") and user.id != contest.owner_id: return make_response(-1, message="你没有权限跟我说话") if contest.private_contest and not permission_manager.has_permission( session.get("uid", -1), f"contest.use.{contest.id}"): return make_response(-1, message="你没有权限查看该比赛") problem: Problem = Problem.by_id(contest.problems[int(problemID)]["id"]) if problem.problem_type == "remote_judge": return make_response(-1, message="远程评测题目", is_remote=True) result = problem.as_dict() last_submission = db.session.query(Submission).filter( and_(Submission.problem_id == problem.id, Submission.uid == session.get("uid"))).filter( Submission.contest_id == contest.id).order_by( Submission.submit_time.desc()) if last_submission.count(): submit = last_submission.first() result["last_code"] = submit.code result["last_lang"] = submit.language else: result["last_lang"] = result["last_code"] = "" result["id"] = problemID del result["uploader_id"] result["score"] = problem.get_total_score() return make_response(0, data=result)
def api_get_challenge_detail(challengeID: int): """ 查询挑战详情 { "name":"名称", "id":ID, "description":描述, "level":等级, "hasFinished":是否完成 "problemsetList":[ { "name":"名称", "hasFinished":"是否完成", "id":"ID" } ] } """ if not permission_manager.has_permission( session.get("uid"), f"challenge.access.{challengeID}"): return make_response(-1, message="你没有权限访问该挑战") challenge: Challenge = db.session.query(Challenge).filter( Challenge.id == challengeID).one_or_none() if not challenge: return make_response(-1, message="该挑战不存在") result = { "name": challenge.name, "id": challenge.id, "description": challenge.description, "hasFinished": permission_manager.has_permission( session.get("uid"), f"challenge.finish.{challengeID}.all"), "level": challenge.level, "problemsetList": [] } for problemset in challenge.problemset_list: current = db.session.query( ProblemSet.id, ProblemSet.name).filter(ProblemSet.id == problemset).one() result["problemsetList"].append({ "name": current.name, "id": current.id, "hasFinished": permission_manager.has_permission( session.get("uid"), f"challenge.finish.{challengeID}.{problemset}") }) return make_response(0, data=result)
def api_problemset_update(data: dict): """ { "data":{ "name":"qwq", "id":-1, "private":true, "invitationCode":"邀请码", "showRanklist":"是否显示排行榜", "problems":["题目ID" ], "description":"说明", } } """ problemset: ProblemSet = db.session.query(ProblemSet).filter( ProblemSet.id == data["id"]).one_or_none() if not problemset: return make_response(-1, message="ID不存在") if not permission_manager.has_permission( session.get("uid"), "problemset.manage") and problemset.owner_uid != int( session.get("uid", 0)): return make_response(-1, message="你没有权限进行此操作") problemset.name = data["name"] problemset.private = data["private"] problemset.show_ranklist = data["showRanklist"] problemset.invitation_code = data["invitationCode"] # 用户所创建的习题集中的题目,则用户要么是该题目的创建者,要么有problem.manage权限,要么该题目是公开题目 for prob in data["problems"]: curr: Problem = db.session.query( Problem.public, Problem.uploader_id).filter_by(id=prob).one_or_none() if not curr: return make_response(-1, message=f"题号{prob}不存在") if not curr.public: if int( session.get("uid", -1) ) != curr.uploader_id and not permission_manager.has_permission( session.get("uid", -1), "problem.manage"): return make_response( -1, message= f"要使用非公开题目{prob},那么要么您是该题目的创建者,要么您具有problem.manage权限") problemset.problems = data["problems"] problemset.description = data["description"] for item in data["problems"]: query: BaseQuery = db.session.query( Problem.id).filter(Problem.id == item) print("querying", item) print(query.limit(1).count()) if query.limit(1).count() == 0: return make_response(-1, message=f"题目 {item} 非法") db.session.commit() return make_response(0, message="更新成功")
def contest_clarification_send(contest: int, content: str): """ 发送Clarification { } """ contest_inst: Contest = db.session.query( Contest ).filter_by(id=contest).one_or_none() has_permission = ( permission_manager.has_permission(session.get( "uid", None), f"contest.use.{contest_inst.id}") or session.get("uid", -1) == contest_inst.owner_id or (not contest_inst.private_contest)) if not has_permission: return make_response(-1, message="你没有权限执行此操作") if not contest_inst.running(): return make_response(-1, message="比赛未在运行") if not session.get("uid", None): return make_response(-1, message="请登录") db.session.add(Clarification( contest=contest_inst.id, sender=session.get("uid"), content=content )) db.session.commit() return make_response(0, message="操作完成")
def remote_judge_add_remote_problem(data: dict): """ 客户端发送添加题目请求 """ import datetime from flask import request oj, remoteProblemID = data["oj"], data["remoteProblemID"] if oj not in config.REMOTE_JUDGE_OJS: return make_response(-1, message="不合法的OJ") if not permission_manager.has_permission(session.get("uid"), "problem.create"): emit("server_response", { "message": "你没有权限这样做", "ok": False }, room=request.sid) return problem = Problem(create_time=datetime.datetime.now()) problem.uploader_id = int(session.get("uid")) db.session.add(problem) db.session.commit() print("Fetching: ", [oj, remoteProblemID, str(problem.id), request.sid]) remote_judge_queue.send_task( "judgers.remote.fetch_problem", [oj, remoteProblemID, str(problem.id), request.sid]) emit("message", {"message": "正在爬取"}, room=request.sid)
def post_discussion(title: str, content: str, path: str, top: bool): """ 发送讨论 参数: title:str 讨论题目 content:str 内容 path:str 路径 top:bool 是否置顶 返回 { "code":-1,//是否成功执行 "discussion_id":"成功执行时的讨论ID", "message":"错误信息" } """ if not session.get("uid"): return make_response(-1, message="请登录") user: User = User.by_id(int(session.get("uid"))) if not permission_manager.has_permission(user.id, "discussion.manage") and top: return make_response(-1, message="只有管理员才能发置顶讨论") if not can_post_at(user, path): return make_response(-1, message="你无权在这里发帖") if not title: return make_response(-1, message="标题不得为空") discussion = Discussion() discussion.content = content discussion.title = title discussion.path = path import datetime discussion.time = datetime.datetime.now() discussion.top = top discussion.uid = user.id db.session.add(discussion) db.session.commit() return make_response(0, discussion_id=discussion.id)
def get_discussion(id: int): """ 获取讨论信息 参数: id:int 讨论ID 返回 { "code":1, "message":"", "data":{ 同数据模型, "email":邮箱, "username":"******" } } """ discussion: Discussion = db.session.query(Discussion.id, Discussion.uid, Discussion.private).filter_by( id=id).one_or_none() import flask if not discussion: flask.abort(404) if discussion.private and session.get("uid") != discussion.uid and not permission_manager.has_permission(session.get("uid"), "discussion.manage"): return make_response(-1, message="你不能查看私有讨论") ret = { "data": db.session.query(Discussion).filter(Discussion.id == id).one().as_dict() } user = User.by_id(ret["data"]["uid"]) ret["data"]["email"] = user.email ret["data"]["username"] = user.username ret["data"]["time"] = str(ret["data"]["time"]) return make_response(0, **ret)
def virtualcotest_create(contestID: int, startAt: int): """ 创建虚拟比赛,返回比赛ID { "id":虚拟比赛ID } """ contest: Contest = db.session.query( Contest.id, Contest.private_contest, Contest.start_time, Contest.end_time, Contest.closed, Contest.owner_id).filter_by(id=contestID).one_or_none() user: User = db.session.query( User.id).filter_by(id=session.get("uid", -1)).one_or_none() if not contest: return make_response(-1, message="比赛ID不存在") if not user: return make_response(-1, message="请先登录") if not contest.closed: return make_response(-1, message="此比赛尚未关闭") if user.id != contest.owner_id and contest.private_contest and not permission_manager.has_permission( user.id, f"contest.use.{contest.id}"): return make_response(-1, message="你没有权限使用该比赛") if time.time() >= startAt: return make_response(-1, message="开始时间不得早于当前时间") start_time = datetime.datetime.fromtimestamp(startAt) virtual = VirtualContest(owner_id=user.id, contest_id=contest.id, start_time=start_time, end_time=contest.end_time - contest.start_time + start_time) db.session.add(virtual) db.session.commit() return make_response(0, data={"id": virtual.id})
def regenerate_filelist(): """ 重新生成文件列表 problem_id:int 题目ID { "code":"" "data":[ "新生成的文件列表" ] } """ if not session.get("uid"): return make_response(-1, message="请先登录") user: User = User.by_id(session.get("uid")) problem: Problem = Problem.by_id(request.form["problem_id"]) if not permission_manager.has_permission(user.id, "problem.manage") and user.id != problem.uploader_id: return make_response(-1, message="你没有权限执行此操作") import pathlib import os import shutil path = pathlib.PurePath(config.UPLOAD_DIR)/str(problem.id) os.makedirs(path, exist_ok=True) for file in filter(lambda x: x.endswith(".lock"), os.listdir(path)): os.remove(path/file) for file in filter(lambda x: not x.endswith(".lock"), os.listdir(path)): with open(path/(file+".lock"), "w") as f: import time f.write(str(time.time())) from utils import generate_file_list file_list = generate_file_list(problem.id) file_list.sort(key=lambda x: x["name"]) problem.files = file_list db.session.commit() return make_response(0, data=file_list)
def api_finish_problemset(challengeID: int, problemsetID: int): """ 申请完成一个挑战下的某个习题集 challengeID 挑战ID problemsetID 习题集ID """ if not permission_manager.has_permission( session.get("uid"), f"challenge.access.{challengeID}"): return make_response(-1, message="你没有权限访问该挑战") challenge: Challenge = db.session.query(Challenge.problemset_list).filter( Challenge.id == challengeID).one_or_none() if not challenge: return make_response(-1, message="该挑战不存在") if problemsetID not in challenge.problemset_list: return make_response(-1, message="该习题集ID不在该挑战之下") problemset: ProblemSet = db.session.query( ProblemSet.problems).filter(ProblemSet.id == problemsetID).one() for problem in problemset.problems: submission = db.session.query(Submission.id).filter( expr.and_(Submission.uid == session.get("uid"), Submission.problem_id == problem, Submission.status == "accepted")).one_or_none() if not submission: return make_response(-1, message="在该习题集之下,你尚存题目未完成.") permission_manager.add_permission( session.get("uid"), f"challenge.finish.{challengeID}.{problemsetID}") return make_response(0, message="操作完成")
def problem_list(): """ 获取题目列表 参数: page:int 页数 search_keyword:str 题目名关键字 返回: { "code":0,//非0表示调用成功 "message":"qwq",//调用失败时的信息 "data":[ {"id":-1,"title":"qwqqwq","submission":233,"status":"accepted","public":false,"total_submit":123,"accepted_submit":123} ], "total_pages":总页数, "current_page":当前页(根据URL分析) } """ page = int(request.form.get("page", 1)) result = None if not session.get("uid"): result = db.session.query(Problem).filter(Problem.public == True) else: user: User = db.session.query(User).filter( User.id == session.get("uid")).one() # 有查看私有题的权限 if permission_manager.has_permission(user.id, "problem.manage"): result = db.session.query(Problem) else: result = db.session.query(Problem).filter( or_(Problem.public == True, Problem.uploader_id == user.id)) keyword = request.form.get("search_keyword", "") result = result.filter(Problem.title.like(f"%{keyword}%")) count = result.count() import math pages = int(math.ceil(count/config.PROBLEMS_PER_PAGE)) result = result.slice( (page-1)*config.PROBLEMS_PER_PAGE, (page)*config.PROBLEMS_PER_PAGE).all() ret = [] for item in result: obj = { "id": item.id, "title": item.title, "submission": -1, "status": None, "public": True, "total_submit": db.session.query(Submission).filter(Submission.problem_id == item.id).count(), "accepted_submit": db.session.query(Submission).filter(Submission.problem_id == item.id).filter(Submission.status == "accepted").count() } # accepted的字典序比其他三个状态都少,所以按照status升序排能优先排到ac submit = db.session.query(Submission).filter(Submission.uid == session.get( "uid")).filter(Submission.problem_id == item.id).order_by(Submission.status.asc()).filter(Submission.contest_id == -1).order_by(Submission.submit_time.desc()) if submit.count(): submit = submit.first() obj["submission"] = submit.id obj["status"] = submit.status obj["public"] = item.public ret.append(obj) return make_response(0, data=ret, page_count=pages, current_page=page)
def get_discussion_list(path: str, page: id, countLimit: int = 10**8): """ 获取讨论列表 参数: path:str 讨论路径 page:id 页面ID countLimit:int 数量限制 返回 { "code":0,//调用失败返回-1 "message":-1, "page_count":10,//总页数 "current_page":10,//当前页 "managable":"可否删除\编辑", "data":[ { "uid":"用户ID", "username":"******", "email":"电子邮件" "time":"发布时间", "title":"讨论题目", "comment_count":0,//评论数量 "last_comment_time":"最后评论时间", "id":-1//讨论ID } ] } """ page = int(page) result = db.session.query(Discussion).filter(or_( Discussion.path == path, Discussion.path.like(f"{path}.%"))) ret = { "page_count": int(math.ceil(result.count()/config.DISCUSSIONS_PER_PAGE)), "current_page": page, "data": [], "managable": permission_manager.has_permission(session.get("uid", None), "discussion.manage") } result = result.order_by(Discussion.id.desc()).order_by(Discussion.top.desc()).slice((page-1)*config.DISCUSSIONS_PER_PAGE, min(page*config.DISCUSSIONS_PER_PAGE, (page-1)*config.DISCUSSIONS_PER_PAGE+int(countLimit))) for item in result: user: User = User.by_id(item.uid) comments = db.session.query(Comment).filter( Comment.discussion_id == item.id).order_by(Comment.id.desc()) # import pdb # pdb.set_trace() ret["data"].append({ "uid": user.id, "username": user.username, "email": user.email, "time": str(item.time), "title": item.title, "comment_count": comments.count(), "last_comment_time": str(comments.first().time) if (comments.count() != 0) else None, "id": item.id }) return make_response(0, **ret)
def upload_file(id): """ 上传题目文件 参数: files: 上传列表 返回: { "code":0,//非0表示调用成功 "message":"qwq",//code非0的时候表示错误信息, "file_list":[{"name":"a.in","size":123456}]//现有的文件列表 } """ problem = db.session.query(Problem).filter( Problem.id == id) if problem.count() == 0: return make_response(-1, message="题目ID不存在") problem = problem.one() if not session.get("uid"): return make_response(-1, message="你没有权限执行此操作") user: User = db.session.query(User).filter( User.id == session.get("uid")).one() if not permission_manager.has_permission(user.id, "problem.manage") and user.id != problem.uploader_id: return make_response(-1, message="你没有权限执行此操作") import os import shutil import zipfile from io import BytesIO import pathlib upload_path = pathlib.Path(os.path.join( basedir, f"{config.UPLOAD_DIR}/%d" % id)) os.makedirs(upload_path, exist_ok=True) def handle_zipfile(fileobj): buf = BytesIO(fileobj.stream.read()) zipf = zipfile.ZipFile(buf) for f in zipf.filelist: if not f.is_dir() and "/" not in f.filename: zipf.extract(f, upload_path) new_file_name = secure_filename(f.filename) shutil.move(upload_path/f.filename, upload_path/new_file_name) with open(os.path.join(upload_path, new_file_name)+".lock", "w") as file: import time file.write(f"{time.time()}") for file in request.files: if request.files[file].filename.endswith(".zip"): handle_zipfile(request.files[file]) continue request.files[file].save(os.path.join( upload_path, secure_filename(file))) with open(os.path.join(upload_path, secure_filename(file))+".lock", "w") as file: import time file.write(f"{time.time()}") problem.files = generate_file_list(id) db.session.commit() return make_response(0, file_list=generate_file_list(id))
def contest_raw_data(contestID): """ contestID { "id": contest.id, "name": contest.name, "description": contest.description, "start_time": int(time.mktime(contest.start_time.timetuple())), "end_time": int(time.mktime(contest.end_time.timetuple())), "problems": contest.problems, "ranklist_visible": contest.ranklist_visible, "judge_result_visible": contest.judge_result_visible, "rank_criterion": contest.rank_criterion, "private_contest": contest.private, "invite_code":"邀请码" } """ if not session.get("uid"): return "你没有权限这样做", 403 user: User = User.by_id(session.get("uid")) contest: Contest = Contest.by_id(contestID) if contest.private_contest and not permission_manager.has_permission( session.get("uid", -1), f"contest.use.{contest.id}"): return "你没有权限查看该比赛", 403 if not permission_manager.has_permission( user.id, "contest.manage") and user.id != contest.owner_id: return "你没有权限这样做", 403 import time result = { "id": contest.id, "name": contest.name, "description": contest.description, "start_time": int(time.mktime(contest.start_time.timetuple())), "end_time": int(time.mktime(contest.end_time.timetuple())), "problems": contest.problems, "ranklist_visible": contest.ranklist_visible, "judge_result_visible": contest.judge_result_visible, "rank_criterion": contest.rank_criterion, "private_contest": contest.private_contest, "invite_code": contest.invite_code } return make_response(0, data=result)
def api_get_challenge_list(): """ 获取挑战列表 "managable":"是否可管理" [ { "id":挑战ID, "name":挑战名, "description":描述, "problemsetList":"习题集列表", "accessible":"是否有权访问", "level":"挑战等级", "hasFinished":"是否完成" } ] """ challenges: typing.Iterable[Challenge] = db.session.query( Challenge).order_by(Challenge.level.asc()).all() result = [] for item in challenges: result.append({ "id": item.id, "name": item.name, "description": item.description, "problemsetList": item.problemset_list, "accessible": permission_manager.has_permission(session.get("uid", None), f"challenge.access.{item.id}"), "hasFinished": permission_manager.has_permission( session.get("uid", None), f"challenge.finish.{item.id}.all"), "level": item.level, }) return make_response(0, data=result, managable=permission_manager.has_permission( session.get("uid"), "challenge.manage"))
def remove_file(): """ 删除题目文件 参数: id:int 题目ID file:str 文件名 返回: { "code":0,//非0表示调用成功 "message":"qwq",//code非0的时候表示错误信息, "file_list":[{"name":"a.in","size":123456}]//现有的文件列表 } """ problem = db.session.query(Problem).filter( Problem.id == request.form["id"]) if problem.count() == 0: return make_response(-1, message="题目ID不存在") problem = problem.one() # if not problem.public and not session.get("uid"): # return make_response(-1, message="你没有权限执行此操作") if not session.get("uid"): return make_response(-1, message="你没有权限执行此操作") user: User = db.session.query(User).filter( User.id == session.get("uid")).one() if not permission_manager.has_permission( user.id, "problem.manage") and user.id != problem.uploader_id: return make_response(-1, message="你没有权限执行此操作") if not any((x["name"] == request.form["file"] for x in problem.files)): return make_response(-1, message="此文件不存在!") import os upload_path = os.path.join(basedir, f"{config.UPLOAD_DIR}/{request.form['id']}") os.makedirs(upload_path, exist_ok=True) try: os.remove(os.path.join(upload_path, request.form["file"])) os.remove(os.path.join(upload_path, request.form["file"] + ".lock")) except Exception as ex: pass problem.files = generate_file_list(request.form["id"]) def remove_and_return(seq, val): seq = seq.copy() if val in seq: seq.remove(val) return seq problem.downloads = remove_and_return(problem.downloads, request.form["file"]) problem.provides = remove_and_return(problem.provides, request.form["file"]) db.session.commit() return make_response(0, file_list=generate_file_list(request.form["id"]))
def can_post_at(user: User, path: str): if not permission_manager.has_permission(user.id, "discussion.manage") and path.startswith("broadcast"): return False match_result = legal_paths.match(path) if not match_result: return False if match_result.groupdict().get("id", None): problem_id = int(match_result.groupdict()["id"]) if not Problem.has(problem_id): return False return True
def api_finish_challenge(challengeID: int): """ 申请完成一个挑战 challengeID 挑战ID """ if not permission_manager.has_permission( session.get("uid"), f"challenge.access.{challengeID}"): return make_response(-1, message="你没有权限访问该挑战") challenge: Challenge = db.session.query(Challenge.problemset_list).filter( Challenge.id == challengeID).one_or_none() if not challenge: return make_response(-1, message="该挑战不存在") for problemset in challenge.problemset_list: if not permission_manager.has_permission( session.get("uid"), f"challenge.finish.{challengeID}.{problemset}"): return make_response(-1, message="该挑战之下存在未完成的习题集") permission_manager.add_permission(session.get("uid"), f"challenge.finish.{challengeID}.all") return make_response(0, message="操作完成")
def api_refresh_cached_count(problem_id: int): """ 刷新题目AC数和提交数缓存 problem_id: 题目ID """ user: User = User.by_id(session.get("uid")) problem: Problem = Problem.by_id(problem_id) if not permission_manager.has_permission( user.id, "problem.manage") and user.id != problem.uploader_id: return make_response(-1, message="你没有权限执行此操作") refresh_cached_count(problem_id) return make_response(0, message="操作完成")
def api_problemtag_update_problem(problemID: int, tags: typing.List[int]): uid = int(session.get("uid", -1)) problem = db.session.query( Problem.uploader_id).filter_by(id=problemID).one() if not permission_manager.has_permission( uid, "problem.manage") and uid != problem.uploader_id: return make_response(-1, message="你没有权限执行此操作") db.session.query(ProblemTag).filter( ProblemTag.problem_id == problemID).delete() db.session.add_all( (ProblemTag(problem_id=problemID, tag_id=item) for item in tags)) db.session.commit() return make_response(0, message="操作完成")
def api_problemset_remove(id): problemset: ProblemSet = db.session.query(ProblemSet).filter( ProblemSet.id == id).one_or_none() if not problemset: return make_response(-1, message="非法ID") if not permission_manager.has_permission( session.get("uid"), "problemset.manage") and problemset.owner_uid != int( session.get("uid")): return make_response(-1, message="你没有权限进行此操作") db.session.delete(problemset) db.session.commit() return make_response(0, message="删除成功")
def query_login_state(): """ 查询登录状态。 参数: 无 返回: { "code":0,//0表示调用成功 "result": true,//表示是否已登录 "uid":-1//如果已登录则表示用户ID, "group":"用户组ID", "group_name":"用户组名", "backend_managable":"是否可以进行后台管理" "username":"******", "email":"电子邮件", "salt":"密码盐", "judgeStatus":{ "评测状态列表" }, "appName":"应用程序名", "usePolling":"是否使用轮询", "registerURL":"注册页面的URL", "gravatarURL":"gravatarURL前缀" } """ use_phone_auth = config.USE_PHONE_WHEN_REGISTER_AND_RESETPASSWD result = { "result": session.get("uid") is not None, "judgeStatus": config.JUDGE_STATUS, "salt": config.PASSWORD_SALT, "appName": config.APP_NAME, "usePolling": config.USE_POLLING, "usePhoneAuth": use_phone_auth, "registerURL": "/phone/register" if use_phone_auth else "/register", "gravatarURL": config.GRAVATAR_URL_PREFIX } if session.get("uid"): user: User = db.session.query( User.id, User.permission_group, User.email, User.username).filter(User.id == session.get("uid")).one() result["uid"] = user.id group: PermissionGroup = db.session.query(PermissionGroup.name).filter( PermissionGroup.id == user.permission_group).one() result.update(group=user.permission_group, group_name=group.name, backend_managable=permission_manager.has_permission( user.id, "backend.manage")) result.update(username=user.username, email=user.email) return make_response(0, **result)
def api_problemset_list(page: int): """ { "data":{ "items":[ { "id":"问题集ID", "name":"名称", "owner":{ "uid":"用户ID", "username":"******" }, "problemCount":"题目数量", "private":"是否私有", "accessible":"是否可访问(仅对私有习题集有效)", "createTime":"创建时间" } ], "pageCount":"总页数" } } """ query_object: BaseQuery = db.session.query( ProblemSet.id, ProblemSet.name, ProblemSet.owner_uid, ProblemSet.problems, ProblemSet.private, ProblemSet.create_time).order_by(ProblemSet.id.desc()) pages = int(math.ceil(query_object.count() / config.PROBLEMSETS_PER_PAGE)) query_object = query_object.slice((page - 1) * config.PROBLEMSETS_PER_PAGE, (page) * config.PROBLEMSETS_PER_PAGE) result = [] for item in query_object.all(): item: ProblemSet = item owner: User = db.session.query( User.username, User.id).filter(User.id == item.owner_uid).one() accessible = (not item.private) or permission_manager.has_permission( session.get("uid"), "problemset.use." + str(item.id)) result.append({ "id": item.id, "name": item.name, "owner": { "uid": owner.id, "username": owner.username }, "problemCount": len(item.problems) if accessible else -1, "private": item.private, "accessible": accessible, "createTime": str(item.create_time) }) return make_response(0, data={"items": result, "pageCount": pages})
def quit_team(): """ 退出团队并清空相应权限 参数 { "uid":"用户ID", "team_id":"团队ID" } 返回: { "code":0, "message":"" } """ if not session.get("uid"): return make_response(-1, message="请先登录") operator: User = User.by_id(session.get("uid")) user: User = User.by_id(request.form["uid"]) team: Team = Team.by_id(request.form["team_id"]) if user.id != operator.id and not permission_manager.has_permission( operator.id, "team.manage" ) and operator.id not in team.admins and operator.id != team.owner_id: return make_response(-1, message="你没有权限这样做") relation = db.session.query(TeamMember).filter_by( uid=user.id, team_id=team.id).one_or_none() if not relation: return make_response(-1, message="您不在此团队内") if user.id == team.owner_id: return make_response(-1, message="此用户不可被移出团队") # def remove_and_return(a, val): # a = a.copy() # a.remove(val) # return a # # print(team.members) # team.members = remove_and_return(team.members, user.id) # user.joined_teams = remove_and_return(user.joined_teams, team.id) # if user.id in team.admins: # team.admins = remove_and_return(team.admins, user.id) # print(team.members) db.session.delete(relation) db.session.commit() perms = set((f"contest.use.{item}" for item in team.team_contests)) | set( (f"problem.use.{item}" for item in team.team_problems)) | set( (f"problemset.use.{item}" for item in team.team_problemsets)) user.permissions = [item for item in user.permissions if item not in perms] db.session.commit() permission_manager.refresh_user(user.id) return make_response(0, message="操作完成")
def discussion_remove(discussionID: int): """ 删除讨论 discussionID:讨论ID """ if not session.get("uid"): return make_response(-1, message="请先登录") discussion: Discussion = Discussion.by_id(discussionID) if not discussion: return make_response(-1, message="讨论ID不存在") user: User = User.by_id(session.get("uid")) if not permission_manager.has_permission(user.id, "discussion.manage") and user.id != discussion.uid: return make_response(-1, message="你没有权限这样做") db.session.delete(discussion) db.session.commit() return make_response(0, message="操作成功")