Пример #1
0
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
Пример #2
0
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="完成")
Пример #3
0
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="操作成功")
Пример #4
0
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)
Пример #5
0
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)
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
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="更新成功")
Пример #9
0
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="操作完成")
Пример #10
0
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)
Пример #11
0
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)
Пример #12
0
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)
Пример #13
0
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})
Пример #14
0
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)
Пример #15
0
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="操作完成")
Пример #16
0
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)
Пример #17
0
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)
Пример #18
0
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))
Пример #19
0
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)
Пример #20
0
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"))
Пример #21
0
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"]))
Пример #22
0
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
Пример #23
0
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="操作完成")
Пример #24
0
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="操作完成")
Пример #25
0
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="操作完成")
Пример #26
0
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="删除成功")
Пример #27
0
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)
Пример #28
0
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})
Пример #29
0
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="操作完成")
Пример #30
0
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="操作成功")