def download_file(id: int, filename: str):
    """
    下载题目文件 
    参数:
        无
    返回:
        无
    """
    # print(id,filename)
    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)
    public_file = filename in problem.downloads
    # if not problem.public and not permission_manager.has_any_permission(session.get("uid", None), f"problem.use.{problem.id}"):
    # 用户未登录
    ok = False
    if not session.get("uid", None):
        # 只能下载公开题目的公开文件
        if not problem.public or not public_file:
            flask.abort(403)
    else:
        # 用户已登录
        # 区分是否有题目管理权限
        # 题目创建者或者有管理权限,那么任何时候都行
        if session.get(
                "uid", -1
        ) == problem.uploader_id or permission_manager.has_any_permission(
                session.get("uid", None), f"problem.manage"):
            ok = True
        # 其他情况,如果是公开题或者有权限的私有题,则任何时候都允许下公开文件
        else:
            if problem.public or permission_manager.has_any_permission(
                    session.get("uid", -1), f"problem.use.{problem.id}"):
                if public_file:
                    ok = True
    # if not problem.public and not permission_manager.has_any_permission(session.get("uid", None), f"problem.manage") and not public_file:
    #     flask.abort(403)
    # if session.get("uid"):
    #     user: User = db.session.query(User).filter(
    #         User.id == session.get("uid")).one()
    #     if not permission_manager.has_permission(user.id, f"problem.manage") and user.id != problem.uploader_id and not public_file:
    #         flask.abort(403)
    # else:
    #     if not problem.public or not public_file:
    #         flask.abort(403)
    if not ok:
        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)
Beispiel #2
0
def rejudge():
    """
    重测提交
    参数:
    submission_id:int 提交ID
    {
        "code","message"
    }
    """
    # user: User = User.by_id(session.get("uid"))
    if not permission_manager.has_any_permission(session.get(
            "uid", None), "submission.manage", "submission.rejudge"):
        return make_response(-1, message="你没有权限这样做")
    submit: Submission = Submission.by_id(request.form["submission_id"])
    problem: Problem = db.session.query(
        Problem.problem_type).filter_by(id=submit.problem_id).one()
    if problem.problem_type == "submit_answer":
        return make_response(-1, message="提交答案题不能重测")
    if not submit:
        return make_response(-1, message="提交不存在")
    from api.judge import push_to_queue
    submit.status = "waiting"
    db.session.commit()
    push_to_queue(submit.id)
    return make_response(0, message="ok")
def create_problem():
    """
    创建空题目
    参数:
        无
    返回:
        {
            "code":0,//非0表示调用成功
            "message":"qwq"//code非0的时候表示错误信息
            "problem_id":-1//成功时表示题目ID
        }
    """
    if session.get("uid") is None:
        return make_response(-1, message="你尚未登录!")
    user: User = db.session.query(User).filter(
        User.id == session.get("uid")).one()
    if not permission_manager.has_any_permission(user.id, "problem.manage",
                                                 "problem.create"):
        return make_response(-1, message="你没有权限进行此操作")
    from datetime import datetime
    problem = Problem(uploader_id=user.id,
                      create_time=datetime.now(),
                      public=False)
    db.session.add(problem)
    db.session.commit()
    return make_response(0, problem_id=problem.id)
Beispiel #4
0
def import_from_syzoj(url: str, willPublic: bool):
    """
    从SYZOJ导入题目
    参数:
    url:str SYZOJ题目URL
    willPublic:int 新题目是否公开
    返回
    {
        "code":0,
        "uuid":'用于websocket的uuid',
        "message":""
    }
    """
    import urllib
    import tempfile
    import pathlib
    import traceback
    import zipfile
    import shutil
    import os
    import yaml
    import requests
    from io import BytesIO
    from utils import decode_json
    if not session.get("uid"):
        return make_response(-1, message="请先登录")
    user: User = User.by_id(session.get("uid"))
    if not permission_manager.has_any_permission(user.id, "problem.create", "problem.manage"):
        return make_response(-1, message="你没有权限执行此操作")
    try:

        with requests.get(f"{url}/export") as urlf:
            data = decode_json(urlf.content.decode())["obj"]
        print("JSON data: {}".format(data))
        import datetime
        problem = Problem(uploader_id=user.id,
                          title=data["title"],
                          content=data["description"],
                          input_format=data["input_format"],
                          output_format=data["output_format"],
                          hint=data["limit_and_hint"],
                          using_file_io=data["file_io"],
                          input_file_name=data["file_io_input_name"],
                          output_file_name=data["file_io_output_name"],
                          create_time=datetime.datetime.now()
                          )
        if willPublic:
            if not permission_manager.has_any_permission(user.id, "problem.publicize", "problem.manage"):
                return make_response(-1, message="你没有权限公开题目")
            problem.public = True
        problem.example = []
        problem.hint = "### 样例\n" + \
            data["example"]+"\n\n### Hint\n"+problem.hint
        time_limit = int(data["time_limit"])
        memory_limit = int(data["memory_limit"])
        db.session.add(problem)
        db.session.commit()

        work_dir = pathlib.PurePath(tempfile.mkdtemp())
        with requests.get(f"{url}/testdata/download") as urlf:
            pack = zipfile.ZipFile(BytesIO(urlf.content))
            pack.extractall(work_dir)
            pack.close()
        problem_data_dir = pathlib.PurePath(
            f"{config.UPLOAD_DIR}/{problem.id}")
        shutil.rmtree(problem_data_dir, ignore_errors=True)
        shutil.copytree(work_dir, problem_data_dir)
        shutil.rmtree(work_dir)
        # 更换新的word_dir
        work_dir = problem_data_dir
        for file in filter(lambda x: x.endswith(".lock"), os.listdir(work_dir)):
            os.remove(work_dir/file)
        file_list = []
        for file in filter(lambda x: not x.endswith(".lock"), os.listdir(work_dir)):
            with open(work_dir/(file+".lock"), "w") as f:
                import time
                last_modified_time = time.time()
                f.write(str(last_modified_time))
            file_list.append({
                "name": file, "size": os.path.getsize(work_dir/file), "last_modified_time": last_modified_time
            })
        problem.files = file_list
        pure_file_list = list(map(lambda x: x["name"], file_list))

        for x in pure_file_list:
            if x.startswith("spj_"):
                problem.spj_filename = x
                break
        auto_generate = True
        subtasks = []
        if os.path.exists(work_dir/"data.yml"):
            # 存在data.yml
            with open(work_dir/"data.yml", "r", encoding="utf-8") as f:
                data_obj = yaml.safe_load(f)
                # data.yml中钦定spj

                if "specialJudge" in data_obj:
                    new_spj_filename = work_dir/(
                        "spj_"+data_obj["specialJudge"]["language"]+"."+data_obj["specialJudge"]["fileName"].split(".")[-1])
                    print(new_spj_filename)
                    print(work_dir/data_obj["specialJudge"]["fileName"])
                    shutil.move(
                        work_dir/data_obj["specialJudge"]["fileName"], new_spj_filename)
                    problem.spj_filename = new_spj_filename.name
                if "subtasks" in data_obj:
                    auto_generate = False

                    def make_input(x):
                        return data_obj["inputFile"].replace("#", str(x))

                    def make_output(x):
                        return data_obj["outputFile"].replace("#", str(x))

                    for i, subtask in enumerate(data_obj["subtasks"]):
                        print(subtask)
                        subtasks.append({
                            "name": f"Subtask{i+1}",
                            "score": int(subtask["score"]),
                            "method": subtask["type"],
                            "time_limit": time_limit,
                            "memory_limit": memory_limit,
                            "testcases": []
                        })
                        testcases = subtasks[-1]["testcases"]
                        score = subtasks[-1]["score"]//len(subtask["cases"])
                        for testcase in subtask["cases"]:
                            testcases.append({
                                "input": make_input(testcase),
                                "output": make_output(testcase),
                                "full_score": score
                            })
                        testcases[-1]["full_score"] = subtasks[-1]["score"] - \
                            score*(len(testcases)-1)
        if auto_generate:
            # 不存在data.yml,直接生成子任务
            input_files = list(
                filter(lambda x: x.endswith(".in"), pure_file_list))
            output_files = list(
                filter(lambda x: x.endswith(".out") or x.endswith(".ans"), pure_file_list))
            if len(input_files) == len(output_files):
                pass
            for i, file in enumerate(input_files):
                pure_file_name = file[:file.rindex(".")]
                subtasks.append({
                    "name": f"Subtask{i+1}",
                    "score": 100//len(input_files),
                    "method": "sum",
                    "time_limit": time_limit,
                    "memory_limit": memory_limit,
                    "testcases": [{"full_score": 100//len(input_files), "input": file, "output": f"{pure_file_name}.ans" if f"{pure_file_name}.ans" in output_files else f"{pure_file_name}.out"}],
                    "comment": ""
                })
            diff = 100-sum(map(lambda x: x["score"], subtasks))
            subtasks[-1]["score"] += diff
            subtasks[-1]["testcases"][0]["full_score"] += diff
        for file in filter(lambda x: x.endswith(".lock"), os.listdir(work_dir)):
            os.remove(work_dir/file)
        for file in filter(lambda x: not x.endswith(".lock"), os.listdir(work_dir)):
            with open(work_dir/(file+".lock"), "w") as f:
                import time
                last_modified_time = time.time()
                f.write(str(last_modified_time))
        problem.files = generate_file_list(problem.id)
        problem.subtasks = subtasks
        db.session.commit()
    except Exception:
        print(traceback.format_exc())
        return make_response(-1, message=traceback.format_exc())
    return make_response(0, problem_id=problem.id)
Beispiel #5
0
def update_problem():
    """
    更新题目
    参数:
        id:int 题目ID
        data:dict 题目数据
    返回:
        {
            "code":0,//非0表示调用成功
            "message":"qwq",//code非0的时候表示错误信息
        }
    """
    problem: 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 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="你没有权限执行此操作")
    data = decode_json(request.form["data"])
    for subtask in data["subtasks"]:
        try:
            subtask["score"] = int(subtask["score"])
        except Exception as ex:
            return make_response(-1, message=f"子任务{subtask['name']}的分数非整数")
    for subtask in data["subtasks"]:
        if len(subtask["testcases"]) == 0:
            return make_response(-1, message=f"子任务{subtask['name']}的测试点个数为0!")
        if subtask["score"] < len(subtask["testcases"]):
            return make_response(-1, message="测试点个数不得多于分数")
        if subtask["method"] == "min":
            list(map(lambda x: x.__setitem__(
                "full_score", 1), subtask["testcases"]))
        else:
            score = subtask["score"]//len(subtask["testcases"])
            for i in range(0, len(subtask["testcases"])-1):
                subtask["testcases"][i]["full_score"] = score
            subtask["testcases"][-1]["full_score"] = subtask["score"] - \
                score*(len(subtask["testcases"])-1)
    if not permission_manager.has_any_permission(user.id, "problem.manage", "problem.publicize") and problem.public == False and data["public"] == True:
        return make_response(-1, message="你没有权限公开题目")
    # 更改题目ID
    if data["newProblemID"] != problem.id:
        old_id: int = int(problem.id)
        new_id: int = int(data["newProblemID"])
        if db.session.query(Problem.id).filter(Problem.id == new_id).one_or_none():
            return make_response(-1, message="题目ID已存在!")

        # 移动题目数据文件夹
        import shutil
        import pathlib
        path = pathlib.Path(config.UPLOAD_DIR)
        try:
            shutil.move(path/str(old_id), path/str(new_id))
        except Exception as ex:
            pass
        # 修改提交中涉及的题目ID
        db.session.query(Submission).filter(
            Submission.problem_id == old_id).update({Submission.problem_id: new_id})
        # 至于比赛...不管了
        problem.id = new_id
    for k, v in data.items():
        if k in {"create_time", "id", "newProblemID"}:
            continue
        setattr(problem, k, v)

    db.session.commit()
    return make_response(0)
Beispiel #6
0
def submit():
    """
    提交代码/答案
    参数:
        problem_id:int 题目ID
        code:str 代码
        language:str 语言ID
        contest_id:int 比赛ID,设置为-1表示非比赛提交,如果非-1,那么problem_id为比赛中的题目ID
        usedParameters:str [1,2,3] 使用到了的附加编译选项ID
        virtualID: 虚拟比赛ID
        answerData: 提交答案题答案数据
    返回:
        {
            "code":0,//非0表示调用成功
            "message":"qwq",//调用失败时的信息
            "submission_id":-1//调用成功时的提交ID
        }
    """
    if not session.get("uid"):
        return make_response(-1, message="请先登录")
    user: User = db.session.query(User).filter(
        User.id == session.get("uid")).one()

    using_contest = int(request.form["contest_id"]) != -1
    virtual_id = int(request.form.get("virtualID", -1))
    using_virtual = (virtual_id != -1)
    virtual_contest: VirtualContest = db.session.query(
        VirtualContest).filter_by(id=virtual_id).one_or_none()
    if using_contest:
        contest: Contest = Contest.by_id(request.form["contest_id"])
        if using_virtual:
            if (not virtual_contest
                ) or virtual_contest.contest_id != contest.id:
                return make_response(-1, message="此虚拟比赛不对应于此实际比赛")
            if not virtual_contest.running():
                return make_response(-1, message="虚拟比赛未在进行")
            problem: Problem = Problem.by_id(contest.problems[int(
                request.form["problem_id"])]["id"])
        else:

            if not contest.running():
                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(
                request.form["problem_id"])]["id"])

    else:
        problem = db.session.query(Problem).filter(
            Problem.id == request.form["problem_id"])
        if problem.count() == 0:
            return make_response(-1, message="题目ID不存在")
        problem: Problem = problem.one()
        if not problem.public:
            if not permission_manager.has_any_permission(
                    user.id, f"problem.use.{problem.id}"
            ) and user.id != problem.uploader_id:
                return make_response(-1, message="你没有权限执行此操作")
    from typing import Set
    if problem.problem_type != "submit_answer":
        parameters: Set[int] = set(decode_json(request.form["usedParameters"]))
        import importlib
        import re

        for i, item in enumerate(problem.extra_parameter):
            if re.compile(item["lang"]).match(
                    request.form["language"]
            ) and item["force"] and i not in parameters:
                parameters.add(i)

        try:
            importlib.import_module("langs." + request.form["language"])
        except:
            return make_response(-1, message="不支持的语言ID")
        parameter_string = " ".join(
            (problem.extra_parameter[i]["parameter"] for i in parameters
             if i < len(problem.extra_parameter)
             and re.compile(problem.extra_parameter[i]["lang"]).match(
                 request.form["language"])))

        import datetime
        submit = Submission(
            uid=user.id,
            language=request.form["language"],
            problem_id=problem.id,
            submit_time=datetime.datetime.now(),
            public=problem.public,
            contest_id=request.form["contest_id"],
            virtual_contest_id=virtual_id if using_virtual else None,
            code=request.form["code"],
            status="waiting",
            extra_compile_parameter=parameter_string,
            selected_compile_parameters=list(parameters))
    else:
        import base64
        import datetime
        encoded = base64.encodebytes(
            request.files["answerData"].stream.read()).decode().replace(
                "\n", "")

        submit = Submission(
            uid=user.id,
            language="cpp",
            problem_id=problem.id,
            submit_time=datetime.datetime.now(),
            public=problem.public,
            contest_id=request.form["contest_id"],
            virtual_contest_id=virtual_id if using_virtual else None,
            code=encoded,
            status="waiting",
            extra_compile_parameter="",
            selected_compile_parameters=[])
    db.session.add(submit)
    db.session.commit()
    from api.judge import push_to_queue
    push_to_queue(submit.id)
    return make_response(0, submission_id=submit.id)
def update_problem():
    """
    更新题目
    参数:
        id:int 题目ID
        data:dict 题目数据
    返回:
        {
            "code":0,//非0表示调用成功
            "message":"qwq",//code非0的时候表示错误信息
        }
    """
    problem: 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 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="你没有权限执行此操作")
    data = decode_json(request.form["data"])
    for subtask in data["subtasks"]:
        try:
            subtask["score"] = int(subtask["score"])
        except Exception as ex:
            return make_response(-1, message=f"子任务{subtask['name']}的分数非整数")
    for subtask in data["subtasks"]:
        if len(subtask["testcases"]) == 0:
            return make_response(-1, message=f"子任务{subtask['name']}的测试点个数为0!")
        if subtask["score"] < len(subtask["testcases"]):
            return make_response(-1, message="测试点个数不得多于分数")
        if subtask["method"] == "min":
            list(
                map(lambda x: x.__setitem__("full_score", 1),
                    subtask["testcases"]))
        else:
            score = subtask["score"] // len(subtask["testcases"])
            for i in range(0, len(subtask["testcases"]) - 1):
                subtask["testcases"][i]["full_score"] = score
            subtask["testcases"][-1]["full_score"] = subtask["score"] - \
                score*(len(subtask["testcases"])-1)
    if not permission_manager.has_any_permission(
            user.id, "problem.manage", "problem.publicize"
    ) and problem.public == False and data["public"] == True:
        return make_response(-1, message="你没有权限公开题目")
    # 更改题目ID
    if data["newProblemID"] != problem.id:
        old_id: int = int(problem.id)
        new_id: int = int(data["newProblemID"])
        if db.session.query(
                Problem.id).filter(Problem.id == new_id).one_or_none():
            return make_response(-1, message="题目ID已存在!")

        # 移动题目数据文件夹
        import shutil
        import pathlib
        path = pathlib.Path(config.UPLOAD_DIR)
        try:
            shutil.move(path / str(old_id), path / str(new_id))
        except Exception as ex:
            pass
        # 修改提交中涉及的题目ID
        db.session.query(Submission).filter(
            Submission.problem_id == old_id).update(
                {Submission.problem_id: new_id})
        # 至于比赛...不管了
        problem.id = new_id
    AVAILABLE_KEYS = [
        "background", "extra_parameter", "subtasks", "content",
        "can_see_results", "public", "input_format", "spj_filename",
        "output_format", "using_file_io", "hint", "input_file_name", "example",
        "output_file_name", "title", "downloads", "provides", "invite_code"
    ]
    submit_answer = (request.form["submitAnswer"] == "true")
    if problem.problem_type == "remote_judge":
        return make_response(-1, message="远程评测题目不得更改题目类型")
    problem.problem_type = "submit_answer" if submit_answer else "traditional"
    for key in AVAILABLE_KEYS:
        setattr(problem, key, data[key])
    problem.submission_visible = data["submissionVisible"]
    db.session.commit()
    return make_response(0)