From cbd9e448c51890b2307100507eaf141121a2746e Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Sat, 5 Sep 2015 19:55:51 +0800 Subject: [PATCH 001/195] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E9=A2=98=E7=9B=AE=E5=88=97=E8=A1=A8=E4=B8=AD=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E9=A2=98=E7=9B=AE=E7=8A=B6=E6=80=81=E7=9A=84=E6=A0=87?= =?UTF-8?q?=E8=AF=86(AC/=E6=AD=A3=E5=9C=A8=E8=BF=9B=E8=A1=8C/=E6=B2=A1?= =?UTF-8?q?=E5=BC=80=E5=A7=8B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 32 ++++++++++++------- .../src/oj/contest/contest_problems_list.html | 17 +++++++++- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/contest/views.py b/contest/views.py index a117672..ca93b67 100644 --- a/contest/views.py +++ b/contest/views.py @@ -323,11 +323,24 @@ def contest_problems_list_page(request, contest_id): 比赛所有题目的列表页 """ try: - contest_problems = ContestProblem.objects.filter(contest=Contest.objects.get(id=contest_id)).order_by("sort_index") + contest = Contest.objects.get(id=contest_id) except Contest.DoesNotExist: - return error_page(request, u"比赛题目不存在") + return error_page(request, u"比赛不存在") + + contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index") + submissions = ContestSubmission.objects.filter(user=request.user, contest=contest) + state = {} + for item in submissions: + state[item.problem_id] = item.ac + for item in contest_problems: + if item.id in state: + item.ac = state[item.id].ac + else: + item.ac = 0 + # 右侧的公告列表 announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time") + return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems, "announcements": announcements, "contest": {"id": contest_id}}) @@ -348,7 +361,7 @@ def contest_list_page(request, page=1): # 筛选我能参加的比赛 join = request.GET.get("join", None) if join: - contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())).\ + contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \ filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now()) paginator = Paginator(contests, 20) @@ -379,7 +392,6 @@ def contest_list_page(request, page=1): "join": join}) - def _cmp(x, y): if x["total_ac"] > y["total_ac"]: return 1 @@ -396,7 +408,8 @@ def _cmp(x, y): def contest_rank_page(request, contest_id): contest = Contest.objects.get(id=contest_id) contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index") - result = ContestSubmission.objects.filter(contest=contest).values("user_id").annotate(total_submit=Sum("total_submission_number")) + result = ContestSubmission.objects.filter(contest=contest).values("user_id").annotate( + total_submit=Sum("total_submission_number")) for i in range(0, len(result)): # 这个人所有的提交 submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id) @@ -407,11 +420,6 @@ def contest_rank_page(request, contest_id): result[i]["user"] = User.objects.get(id=result[i]["user_id"]) result[i]["total_time"] = submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"] - return render(request, "oj/contest/contest_rank.html", - {"contest": contest, "contest_problems": contest_problems, "result": sorted(result, cmp=_cmp, reverse=True)}) - - - - - + {"contest": contest, "contest_problems": contest_problems, + "result": sorted(result, cmp=_cmp, reverse=True)}) diff --git a/template/src/oj/contest/contest_problems_list.html b/template/src/oj/contest/contest_problems_list.html index 0289592..aae2a2b 100644 --- a/template/src/oj/contest/contest_problems_list.html +++ b/template/src/oj/contest/contest_problems_list.html @@ -40,7 +40,22 @@ {% for item in contest_problems %} - + + + + + {{ item.sort_index }} From 81bd998d8dba0ddd921400034220ce24c7eec9a3 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Sat, 5 Sep 2015 20:07:31 +0800 Subject: [PATCH 002/195] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=9A=E5=88=9A?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/contest/views.py b/contest/views.py index ca93b67..2542198 100644 --- a/contest/views.py +++ b/contest/views.py @@ -258,10 +258,10 @@ class ContestPasswordVerifyAPIView(APIView): try: contest = Contest.objects.get(id=data["contest_id"], contest_type=2) except Contest.DoesNotExist: - return error_response(u"密码错误") + return error_response(u"比赛不存在") if data["password"] != contest.password: - return error_response(u" 密码错误") + return error_response(u"密码错误") else: if "contests" not in request.session: request.session["contests"] = [] @@ -279,10 +279,7 @@ def contest_page(request, contest_id): """ 单个比赛的详情页 """ - try: - contest = Contest.objects.get(id=contest_id) - except Contest.DoesNotExist: - return error_page(request, u"比赛不存在") + contest = Contest.objects.get(id=contest_id) return render(request, "oj/contest/contest_index.html", {"contest": contest}) @@ -292,10 +289,7 @@ def contest_problem_page(request, contest_id, contest_problem_id): """ 单个比赛题目的详情页 """ - try: - contest = Contest.objects.get(id=contest_id) - except Contest.DoesNotExist: - return error_page(request, u"比赛不存在") + contest = Contest.objects.get(id=contest_id) try: contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True) except ContestProblem.DoesNotExist: @@ -334,7 +328,7 @@ def contest_problems_list_page(request, contest_id): state[item.problem_id] = item.ac for item in contest_problems: if item.id in state: - item.ac = state[item.id].ac + item.ac = state[item.id] else: item.ac = 0 From 1f50cd075182f1626698d3399187e91972549685 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Sat, 5 Sep 2015 20:17:15 +0800 Subject: [PATCH 003/195] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=AD=A3=E5=9C=A8?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=9B=BE=E6=A0=87=E4=B8=8D=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98,=E4=BF=AE=E6=94=B9view=E9=87=8Ccont?= =?UTF-8?q?est=5Fproblem=E7=8A=B6=E6=80=81=E7=9A=84=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=90=8D,=E4=BD=BF=E6=9B=B4=E7=A1=AE=E5=88=87,=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0dealing-falg=E7=9A=84css?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 7 +++++-- static/src/css/oj.css | 4 ++++ template/src/oj/contest/contest_problems_list.html | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/contest/views.py b/contest/views.py index 2542198..eaef55b 100644 --- a/contest/views.py +++ b/contest/views.py @@ -328,9 +328,12 @@ def contest_problems_list_page(request, contest_id): state[item.problem_id] = item.ac for item in contest_problems: if item.id in state: - item.ac = state[item.id] + if state[item.id]: + item.state = 1 + else: + item.state = 2 else: - item.ac = 0 + item.state = 0 # 右侧的公告列表 announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time") diff --git a/static/src/css/oj.css b/static/src/css/oj.css index e099835..9e9af55 100644 --- a/static/src/css/oj.css +++ b/static/src/css/oj.css @@ -73,6 +73,10 @@ li.list-group-item { color: green; } +.dealing-flag { + color: yellow; +} + .CodeMirror{ min-height: 250px; _height:250px; diff --git a/template/src/oj/contest/contest_problems_list.html b/template/src/oj/contest/contest_problems_list.html index aae2a2b..c7bdec0 100644 --- a/template/src/oj/contest/contest_problems_list.html +++ b/template/src/oj/contest/contest_problems_list.html @@ -43,11 +43,11 @@ Date: Sat, 5 Sep 2015 20:24:11 +0800 Subject: [PATCH 004/195] =?UTF-8?q?=E5=AF=B9=E6=AF=94=E8=B5=9B=E9=A2=98?= =?UTF-8?q?=E7=9B=AE=E5=88=97=E8=A1=A8=E9=87=8C=E7=8A=B6=E6=80=81=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E7=9A=84=E6=A0=B7=E5=BC=8F=E7=9A=84=E5=B0=8F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/css/oj.css | 2 +- template/src/oj/contest/contest_problems_list.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/static/src/css/oj.css b/static/src/css/oj.css index 9e9af55..a5dc892 100644 --- a/static/src/css/oj.css +++ b/static/src/css/oj.css @@ -74,7 +74,7 @@ li.list-group-item { } .dealing-flag { - color: yellow; + color: #FF9933; } .CodeMirror{ diff --git a/template/src/oj/contest/contest_problems_list.html b/template/src/oj/contest/contest_problems_list.html index c7bdec0..5118d3e 100644 --- a/template/src/oj/contest/contest_problems_list.html +++ b/template/src/oj/contest/contest_problems_list.html @@ -47,7 +47,7 @@ {% ifequal item.state 1%} glyphicon-ok ac-flag {% else %} - glyphicon-arrow-right dealing-flag + glyphicon-minus dealing-flag {% endifequal %} {% endif %} From 4d12914e8e21026b19026495b4a8d067d305be2a Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Sat, 5 Sep 2015 20:30:21 +0800 Subject: [PATCH 005/195] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=AA=E8=BE=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/contest_problem.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/src/oj/contest/contest_problem.html b/template/src/oj/contest/contest_problem.html index 8f55b10..4cf7e3b 100644 --- a/template/src/oj/contest/contest_problem.html +++ b/template/src/oj/contest/contest_problem.html @@ -9,7 +9,7 @@ href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/submissions/">我的提交
  • 返回题目列表 + href="/contest/{{ contest_problem.contest.id }}/problems/">返回
  • {{ contest_problem.title }}

    From 49643c661af28a7e1f8fa32d3189246ead3b25a0 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Sat, 5 Sep 2015 21:09:02 +0800 Subject: [PATCH 006/195] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=BD=E6=9D=BE?= =?UTF-8?q?=E5=88=A4=E9=A2=98=E7=9A=84client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/judger/loose_client.py | 163 +++++++++++++++++++++++++++++++++++ judge/judger/run.py | 9 +- 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 judge/judger/loose_client.py diff --git a/judge/judger/loose_client.py b/judge/judger/loose_client.py new file mode 100644 index 0000000..e3d2540 --- /dev/null +++ b/judge/judger/loose_client.py @@ -0,0 +1,163 @@ +# coding=utf-8 +import json +import commands +import hashlib +from multiprocessing import Pool + +from settings import max_running_number, lrun_gid, lrun_uid, judger_workspace +from language import languages +from result import result +from compiler import compile_ +from judge_exceptions import JudgeClientError, CompileError +from utils import parse_lrun_output + + +# 下面这个函数作为代理访问实例变量,否则Python2会报错,是Python2的已知问题 +# http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons-multiprocessing-pool-ma/7309686 +def _run(instance, test_case_id): + return instance._judge_one(test_case_id) + + +class JudgeClient(object): + def __init__(self, language_code, exe_path, max_cpu_time, + max_real_time, max_memory, test_case_dir): + """ + :param language_code: 语言编号 + :param exe_path: 可执行文件路径 + :param max_cpu_time: 最大cpu时间,单位ms + :param max_real_time: 最大执行时间,单位ms + :param max_memory: 最大内存,单位MB + :param test_case_dir: 测试用例文件夹路径 + :return:返回结果list + """ + self._language = languages[language_code] + self._exe_path = exe_path + self._max_cpu_time = max_cpu_time + self._max_real_time = max_real_time + self._max_memory = max_memory + self._test_case_dir = test_case_dir + # 进程池 + self._pool = Pool(processes=max_running_number) + + def _generate_command(self, test_case_id): + """ + 设置相关运行限制 进制访问网络 如果启用tmpfs 就把代码输出写入tmpfs,否则写入硬盘 + """ + # todo 系统调用白名单 chroot等参数 + command = "lrun" + \ + " --max-cpu-time " + str(self._max_cpu_time / 1000.0) + \ + " --max-real-time " + str(self._max_real_time / 1000.0 * 2) + \ + " --max-memory " + str(self._max_memory * 1000 * 1000) + \ + " --network false" + \ + " --uid " + str(lrun_uid) + \ + " --gid " + str(lrun_gid) + + execute_command = self._language["execute_command"].format(exe_path=self._exe_path) + + command += (" " + + execute_command + + # 0就是stdin + " 0<" + self._test_case_dir + str(test_case_id) + ".in" + + # 1就是stdout + " 1>" + judger_workspace + str(test_case_id) + ".out" + + # 3是stderr,包含lrun的输出和程序的异常输出 + " 3>&2") + return command + + def _parse_lrun_output(self, output): + # 要注意的是 lrun把结果输出到了stderr,所以有些情况下lrun的输出可能与程序的一些错误输出的混合的,要先分离一下 + error = None + # 倒序找到MEMORY的位置 + output_start = output.rfind("MEMORY") + if output_start == -1: + raise JudgeClientError("Lrun result parse error") + # 如果不是0,说明lrun输出前面有输出,也就是程序的stderr有内容 + if output_start != 0: + error = output[0:output_start] + # 分离出lrun的输出 + output = output[output_start:] + + return error, parse_lrun_output(output) + + def _compare_output(self, test_case_id): + + output_path = judger_workspace + str(test_case_id) + ".out" + + try: + f = open(output_path, "r") + except IOError: + # 文件不存在等引发的异常 返回结果错误 + return False + try: + std = open(self._test_case_dir+test_case_id+".out", "r") + except IOError: + # 文件不存在等引发的异常 返回结果错误 + return False + lines=std.readline() + line_conut = len(lines) + for i in range(0, line_conut-2): + if lines[i] + + + + + + + def _judge_one(self, test_case_id): + # 运行lrun程序 接收返回值 + command = self._generate_command(test_case_id) + status_code, output = commands.getstatusoutput(command) + if status_code: + raise JudgeClientError(output) + error, run_result = self._parse_lrun_output(output) + + run_result["test_case_id"] = test_case_id + + # 如果返回值非0 或者信号量不是0 或者程序的stderr有输出 代表非正常结束 + if run_result["exit_code"] or run_result["term_sig"] or run_result["siginaled"] or error: + run_result["result"] = result["runtime_error"] + return run_result + + # 代表内存或者时间超过限制了 + if run_result["exceed"]: + if run_result["exceed"] == "memory": + run_result["result"] = result["memory_limit_exceeded"] + elif run_result["exceed"] in ["cpu_time", "real_time"]: + run_result["result"] = result["time_limit_exceeded"] + else: + raise JudgeClientError("Error exceeded type: " + run_result["exceed"]) + return run_result + + # 下面就是代码正常运行了 需要判断代码的输出是否正确 + if self._compare_output(test_case_id): + run_result["result"] = result["accepted"] + else: + run_result["result"] = result["wrong_answer"] + + return run_result + + def run(self): + # 添加到任务队列 + _results = [] + results = [] + for i in range(self._test_case_info["test_case_number"]): + _results.append(self._pool.apply_async(_run, (self, i + 1))) + self._pool.close() + self._pool.join() + for item in _results: + # 注意多进程中的异常只有在get()的时候才会被引发 + # http://stackoverflow.com/questions/22094852/how-to-catch-exceptions-in-workers-in-multiprocessing + try: + results.append(item.get()) + except Exception as e: + # todo logging + print e + results.append({"result": result["system_error"]}) + return results + + def __getstate__(self): + # 不同的pool之间进行pickle的时候要排除自己,否则报错 + # http://stackoverflow.com/questions/25382455/python-notimplementederror-pool-objects-cannot-be-passed-between-processes + self_dict = self.__dict__.copy() + del self_dict['_pool'] + return self_dict diff --git a/judge/judger/run.py b/judge/judger/run.py index 6ecc2d3..08e01c8 100644 --- a/judge/judger/run.py +++ b/judge/judger/run.py @@ -2,8 +2,15 @@ import sys import json import MySQLdb +import os + +# 判断判题模式 +judge_model = os.environ.get("judge_model", "default") +if judge_model == "default": + from client import JudgeClient +elif judge_model == "loose": + from loose_client import JudgeClient -from client import JudgeClient from language import languages from compiler import compile_ from result import result From b13f487d530a761cf5a9399b4dda126f9d67c378 Mon Sep 17 00:00:00 2001 From: esp Date: Sat, 5 Sep 2015 22:04:40 +0800 Subject: [PATCH 007/195] update views.py --- contest/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contest/views.py b/contest/views.py index eaef55b..58fcf5d 100644 --- a/contest/views.py +++ b/contest/views.py @@ -357,7 +357,7 @@ def contest_list_page(request, page=1): # 筛选我能参加的比赛 join = request.GET.get("join", None) - if join: + if join and request.user.id: contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \ filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now()) From 51601c34d876c46f5211acbfe49478e0e5f7eba6 Mon Sep 17 00:00:00 2001 From: esp Date: Sat, 5 Sep 2015 22:15:34 +0800 Subject: [PATCH 008/195] =?UTF-8?q?update=20contest=5Flist.html=20?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=9C=AA=E7=99=BB=E5=BD=95=E6=97=B6=E5=B0=B1?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E5=AF=B9=E5=8F=AF=E4=BB=A5=E5=8F=82=E5=8A=A0?= =?UTF-8?q?=E7=9A=84=E6=AF=94=E8=B5=9B=E7=9A=84=E7=AD=9B=E9=80=89=EF=BC=8C?= =?UTF-8?q?=E5=9B=A0=E4=B8=BA=E8=BF=99=E6=B2=A1=E6=9C=89=E6=84=8F=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/contest_list.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/template/src/oj/contest/contest_list.html b/template/src/oj/contest/contest_list.html index 25b8eae..51e522d 100644 --- a/template/src/oj/contest/contest_list.html +++ b/template/src/oj/contest/contest_list.html @@ -48,12 +48,13 @@ {% endfor %} - + {% if request.user.is_authenticated %}
    + {% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/template/src/oj/problem/problem.html b/template/src/oj/problem/problem.html index b82fc01..affc520 100644 --- a/template/src/oj/problem/problem.html +++ b/template/src/oj/problem/problem.html @@ -4,8 +4,14 @@
    {% include "oj/problem/_problem_header.html" %} @@ -33,7 +39,6 @@
    -
     {{ item.output }}
    @@ -45,23 +50,19 @@ {% if problem.hint %}
    -

    {{ problem.hint|safe }}

    {% endif %}
    -

    {% for tag in problem.tags.all %} {{ tag.name }} {% endfor %}

    -
    -
    -
    @@ -85,9 +85,7 @@ 提交代码 -
    -

    diff --git a/template/src/oj/submission/my_submissions_list.html b/template/src/oj/submission/my_submissions_list.html index 1f91ce9..08cf17d 100644 --- a/template/src/oj/submission/my_submissions_list.html +++ b/template/src/oj/submission/my_submissions_list.html @@ -8,6 +8,7 @@ # + 题目名称 提交时间
    -{% endblock %} +{% endblock %} \ No newline at end of file From 13b7a84c8f295ca2682dfa5e6ef33db9ecbb2043 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 10:35:24 +0800 Subject: [PATCH 028/195] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A2=98=E7=9B=AE,?= =?UTF-8?q?=E6=AF=94=E8=B5=9B=E9=A2=98=E7=9B=AE=E5=88=97=E8=A1=A8=E9=87=8C?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E5=92=8C=E6=8F=90=E7=A4=BA=E7=9A=84=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E6=B2=A1=E6=9C=89=E5=8C=85=E8=A3=B9=E5=9C=A8=20proble?= =?UTF-8?q?m-detail=E9=87=8C=E7=9A=84=E9=97=AE=E9=A2=98,=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E4=B8=8A=E6=BA=90=E4=BB=A3=E7=A0=81=E9=87=8C=E4=BB=96=E4=BB=AC?= =?UTF-8?q?=E8=A2=AB=E5=8C=85=E8=A3=B9=E5=9C=A8=E9=87=8C=E4=BD=86=E6=98=AF=E5=AE=9E=E9=99=85=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=9A=84=E5=8D=B4=E6=98=AF=E5=9C=A8=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=A4=96=E9=83=A8,=E4=B8=8D=E7=90=86=E8=A7=A3.=E6=8A=8Ap?= =?UTF-8?q?=E6=94=B9=E6=88=90div=E5=B0=B1=E5=A5=BD=E4=BA=86~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/contest_problem.html | 4 ++-- template/src/oj/problem/problem.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/template/src/oj/contest/contest_problem.html b/template/src/oj/contest/contest_problem.html index 4cf7e3b..a42b8ad 100644 --- a/template/src/oj/contest/contest_problem.html +++ b/template/src/oj/contest/contest_problem.html @@ -23,7 +23,7 @@
    -

    {{ contest_problem.description|safe }}

    +
    {{ contest_problem.description|safe }}
    @@ -62,7 +62,7 @@
    -

    {{ contest_problem.hint|safe }}

    +
    {{ contest_problem.hint|safe }}
    {% endif %} diff --git a/template/src/oj/problem/problem.html b/template/src/oj/problem/problem.html index 2efd86a..00b4ce7 100644 --- a/template/src/oj/problem/problem.html +++ b/template/src/oj/problem/problem.html @@ -13,7 +13,7 @@
    -

    {{ problem.description|safe }}

    +
    {{ problem.description|safe }}
    @@ -46,7 +46,7 @@
    -

    {{ problem.hint|safe }}

    +
    {{ problem.hint|safe }}
    {% endif %}
    From e219ff890d25a4798a21e6a481f69384ab379e89 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 11:03:59 +0800 Subject: [PATCH 029/195] =?UTF-8?q?=E5=90=88=E5=B9=B6dev,=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=AE=A1=E7=90=86=E5=91=98=E5=9C=A8=E5=89=8D=E5=8F=B0?= =?UTF-8?q?=E5=8F=AF=E8=A7=81=E6=AF=94=E8=B5=9B=E6=89=80=E6=9C=89=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E8=AF=A6=E6=83=85,=E4=BF=AE=E6=94=B9=E6=8E=AA?= =?UTF-8?q?=E8=BE=9E,=E4=BF=AE=E6=94=B9=E6=8F=90=E7=A4=BA=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F,=E4=BB=A5=E4=BE=BF=E4=BA=8E=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=AD=9B=E9=80=89=E5=8A=9F=E8=83=BD=E7=9A=84?= =?UTF-8?q?=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 16 +- account/tests.py | 2 +- contest/test_urls.py | 9 + contest/tests.py | 183 +++++++++++++++++- contest/views.py | 3 - contest_submission/tests.py | 91 ++++++++- contest_submission/views.py | 46 +++-- judge/Dockerfile | 19 ++ judge/judger_controller/settings.py | 11 +- oj/daocloud_settings.py | 19 -- oj/local_settings.py | 6 +- oj/server_settings.py | 4 +- oj/settings.py | 4 - problem/serizalizers.py | 8 +- problem/tests.py | 14 ++ requirements.txt | 3 +- static/release/fis-conf.js | 10 + static/src/js/app/admin/problem/addProblem.js | 4 - static/src/js/app/oj/problem/problem.js | 2 +- static/src/js/build.js | 11 +- submission/tests.py | 81 ++++++-- submission/views.py | 2 +- .../src/oj/contest/my_submissions_list.html | 14 +- template/src/oj/contest/submissions_list.html | 72 +++++-- .../oj/contest/submissions_list_admin.html | 78 ++++++++ template/src/oj/problem/problem.html | 20 +- .../oj/submission/my_submissions_list.html | 12 +- template/src/oj_base.html | 4 +- utils/templatetags/problem.py | 2 +- 29 files changed, 610 insertions(+), 140 deletions(-) create mode 100644 contest/test_urls.py create mode 100644 judge/Dockerfile delete mode 100644 oj/daocloud_settings.py create mode 100644 template/src/oj/contest/submissions_list_admin.html diff --git a/Dockerfile b/Dockerfile index f10b84c..2e10830 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,7 @@ FROM python:2.7 -ENV PYTHONUNBUFFERED 1 -ENV oj_env daocloud -RUN mkdir /var/oj -COPY . /var/oj/ -WORKDIR /var/oj/ +ENV PYTHONBUFFERED 1 +RUN mkdir -p /code/log /code/test_case +WORKDIR /code +ADD requirements.txt /code/ RUN pip install -r requirements.txt -EXPOSE 8080 -RUN mkdir LOG -RUN mkdir test_case -RUN mkdir tmp -RUN python manage.py migrate -CMD python manage.py runserver 0.0.0.0:8080 +EXPOSE 8010 \ No newline at end of file diff --git a/account/tests.py b/account/tests.py index e868f62..d0adf8a 100644 --- a/account/tests.py +++ b/account/tests.py @@ -370,7 +370,7 @@ class UserLogoutTest(TestCase): user.set_password("1") user.save() - def logout_success(self): + def test_logout_success(self): self.client = Client() self.client.login(username="test", password="1") response = self.client.get("/logout/") diff --git a/contest/test_urls.py b/contest/test_urls.py new file mode 100644 index 0000000..234c600 --- /dev/null +++ b/contest/test_urls.py @@ -0,0 +1,9 @@ +# coding=utf-8 +from django.conf.urls import include, url +from django.views.generic import TemplateView + + +urlpatterns = [ + + url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), +] diff --git a/contest/tests.py b/contest/tests.py index adbf00b..626a3ab 100644 --- a/contest/tests.py +++ b/contest/tests.py @@ -1,15 +1,18 @@ # coding=utf-8 import json from django.core.urlresolvers import reverse -from django.test import TestCase +from django.test import TestCase, Client +from django.http import HttpResponse from rest_framework.test import APITestCase, APIClient from account.models import User from group.models import Group from contest.models import Contest, ContestProblem +from .models import ContestSubmission from announcement.models import Announcement from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN +from decorators import check_user_contest_permission class ContestAdminAPITest(APITestCase): @@ -398,3 +401,181 @@ class ContestProblemAdminAPItEST(APITestCase): response = self.client.put(self.url, data=data) self.assertEqual(response.data["code"], 1) + +class ContestPasswordVerifyAPITest(APITestCase): + def setUp(self): + self.client = APIClient() + self.url = reverse('contest_password_verify_api') + self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user.set_password("testaa") + self.user.save() + self.user2 = User.objects.create(username="test2", admin_type=ADMIN) + self.user2.set_password("testbb") + self.user2.save() + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + + def test_invalid_format(self): + self.client.login(username="test2", password="testbb") + data = {"contest_id": self.global_contest.id} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 1) + + def test_contest_does_not_exist(self): + self.client.login(username="test2", password="testbb") + data = {"contest_id": self.global_contest.id + 1, "password": "aacc"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 1, "data": u"比赛不存在"}) + + def test_contest_password_verify_unsuccessfully(self): + self.client.login(username="test2", password="testbb") + data = {"contest_id": self.global_contest.id, "password": "aabb"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 1, "data": u"密码错误"}) + + def test_contest_password_verify_successfully(self): + self.client.login(username="test2", password="testbb") + data = {"contest_id": self.global_contest.id, "password": "aacc"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 0) + + +class ContestPageTest(TestCase): + # 单个比赛详情页的测试 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + + def test_visit_contest_page_successfully(self): + response = self.client.get('/contest/1/') + self.assertEqual(response.status_code, 200) + + def test_visit_contest_page_unsuccessfully(self): + response = self.client.get('/contest/10/') + self.assertTemplateUsed(response, "utils/error.html") + + +class ContestProblemPageTest(TestCase): + # 单个比赛题目详情页的测试 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + self.contest_problem = ContestProblem.objects.create(title="titlex", + description="descriptionx", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + hint="hint1", + created_by=User.objects.get(username="test1"), + contest=Contest.objects.get(title="titlex"), + sort_index="a") + + def test_visit_contest_problem_page_successfully(self): + response = self.client.get('/contest/1/problem/1/') + self.assertEqual(response.status_code, 200) + + def test_visit_contest_page_unsuccessfully(self): + response = self.client.get('/contest/10/') + self.assertTemplateUsed(response, "utils/error.html") + + def test_visit_contest_submissions_page_successfully(self): + ContestSubmission.objects.create(user=self.user1, + contest=self.global_contest, + problem=self.contest_problem, + ac=True) + response = self.client.get('/contest/1/problem/1/submissions/') + self.assertEqual(response.status_code, 200) + + +class ContestProblemListPageTest(TestCase): + # 比赛题目列表的测试 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + self.contest_problem = ContestProblem.objects.create(title="titlex", + description="descriptionx", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + hint="hint1", + created_by=User.objects.get(username="test1"), + contest=Contest.objects.get(title="titlex"), + sort_index="a") + + def test_visit_contest_problem_list_page_successfully(self): + response = self.client.get('/contest/1/problems/') + self.assertEqual(response.status_code, 200) + + def test_visit_contest_problem_page_unsuccessfully(self): + response = self.client.get('/contest/1/problem/100/') + self.assertTemplateUsed(response, "utils/error.html") + + +class ContestListPageTest(TestCase): + # 以下是所有比赛列表页的测试 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.url = reverse('contest_list_page') + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + + def test_visit_contest_list_page_successfully(self): + response = self.client.get('/contests/') + self.assertEqual(response.status_code, 200) + + def test_visit_contest_list_page_unsuccessfully(self): + response = self.client.get('/contests/2/') + self.assertTemplateUsed(response, "utils/error.html") + + def test_query_by_keyword(self): + response = self.client.get(self.url + "?keyword=title1") + self.assertEqual(response.status_code, 200) + + def test_query_by_join_successfully(self): + response = self.client.get(self.url + "?join=True") + self.assertEqual(response.status_code, 200) + + + + diff --git a/contest/views.py b/contest/views.py index 2c03f75..39d0f0f 100644 --- a/contest/views.py +++ b/contest/views.py @@ -320,7 +320,6 @@ def contest_problems_list_page(request, contest_id): contest = Contest.objects.get(id=contest_id) except Contest.DoesNotExist: return error_page(request, u"比赛不存在") - contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index") submissions = ContestSubmission.objects.filter(user=request.user, contest=contest) state = {} @@ -334,10 +333,8 @@ def contest_problems_list_page(request, contest_id): item.state = 2 else: item.state = 0 - # 右侧的公告列表 announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time") - return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems, "announcements": announcements, "contest": {"id": contest_id}}) diff --git a/contest_submission/tests.py b/contest_submission/tests.py index b1eace1..975d11c 100644 --- a/contest_submission/tests.py +++ b/contest_submission/tests.py @@ -1,14 +1,97 @@ +# coding=utf-8 import json - +from django.test import TestCase, Client from django.core.urlresolvers import reverse -from account.models import User, ADMIN, SUPER_ADMIN - +from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN +from problem.models import Problem from contest.models import Contest, ContestProblem from submission.models import Submission from rest_framework.test import APITestCase, APIClient -# Create your tests here. +class ContestSubmissionAPITest(APITestCase): + def setUp(self): + self.client = APIClient() + self.url = reverse('contest_submission_api') + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.user2 = User.objects.create(username="test2", admin_type=REGULAR_USER) + self.user2.set_password("testbb") + self.user2.save() + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=1, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-30T12:00:00.000Z", + created_by=User.objects.get(username="test1")) + self.contest_problem = ContestProblem.objects.create(title="titlex", + description="descriptionx", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + hint="hint1", + created_by=User.objects.get(username="test1"), + contest=Contest.objects.get(title="titlex"), + sort_index="a") + + # 以下是创建比赛的提交 + def test_invalid_format(self): + self.client.login(username="test1", password="testaa") + data = {"contest_id": self.global_contest.id, "language": 1} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 1) + + def test_contest_submission_successfully(self): + self.client.login(username="test1", password="testaa") + data = {"contest_id": self.global_contest.id, "problem_id": self.contest_problem.id, + "language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}'} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 0) + + def test_contest_problem_does_not_exist(self): + self.client.login(username="test1", password="testaa") + data = {"contest_id": self.global_contest.id, "problem_id": self.contest_problem.id + 10, + "language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}'} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 1, "data": u"题目不存在"}) + + +class ContestProblemMySubmissionListTest(TestCase): + # 以下是我比赛单个题目的提交列表的测试 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.user2 = User.objects.create(username="test2", admin_type=REGULAR_USER) + self.user2.set_password("testbb") + self.user2.save() + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=1, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-30T12:00:00.000Z", + created_by=User.objects.get(username="test1")) + self.contest_problem = ContestProblem.objects.create(title="titlex", + description="descriptionx", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + hint="hint1", + created_by=self.user1, + contest=self.global_contest, + sort_index="a") + + def test_contestsList_page_not_exist(self): + self.client.login(username="test1", password="testaa") + response = self.client.get('/contest/1/submissions/999/') + self.assertTemplateUsed(response, "utils/error.html") + class SubmissionAPITest(APITestCase): def setUp(self): diff --git a/contest_submission/views.py b/contest_submission/views.py index 003ad8a..538d03b 100644 --- a/contest_submission/views.py +++ b/contest_submission/views.py @@ -1,6 +1,5 @@ # coding=utf-8 import json - import redis from django.shortcuts import render from django.core.paginator import Paginator @@ -9,16 +8,15 @@ from rest_framework.views import APIView from judge.judger_controller.tasks import judge from judge.judger_controller.settings import redis_config + from account.decorators import login_required from account.models import SUPER_ADMIN from contest.decorators import check_user_contest_permission - from problem.models import Problem from contest.models import Contest, ContestProblem from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate - from submission.models import Submission from .serializers import CreateContestSubmissionSerializer from submission.serializers import SubmissionSerializer @@ -35,31 +33,24 @@ class ContestSubmissionAPIView(APIView): serializer = CreateContestSubmissionSerializer(data=request.data) if serializer.is_valid(): data = serializer.data - try: - contest = Contest.objects.get(id=data["contest_id"]) - except Contest.DoesNotExist: - return error_response(u"比赛不存在") + contest = Contest.objects.get(id=data["contest_id"]) try: problem = ContestProblem.objects.get(contest=contest, id=data["problem_id"]) # 更新题目提交计数器 problem.total_submit_number += 1 problem.save() - except Problem.DoesNotExist: + except ContestProblem.DoesNotExist: return error_response(u"题目不存在") - submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]), contest_id=contest.id, code=data["code"], problem_id=problem.id) try: judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception: return error_response(u"提交判题任务失败") - # 增加redis 中判题队列长度的计数器 r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) r.incr("judge_queue_length") - return success_response({"submission_id": submission.id}) - else: return serializer_invalid_response(serializer) @@ -75,7 +66,7 @@ def contest_problem_my_submissions_list_page(request, contest_id, contest_proble return error_page(request, u"比赛不存在") try: contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True) - except Problem.DoesNotExist: + except ContestProblem.DoesNotExist: return error_page(request, u"比赛问题不存在") submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by( "-create_time"). \ @@ -95,8 +86,26 @@ def contest_problem_submissions_list_page(request, contest_id, page=1): return error_page(request, u"比赛不存在") # 以下是本场比赛中所有的提交 submissions = Submission.objects.filter(contest_id=contest_id). \ - values("id", "result", "create_time", "accepted_answer_time", "language", "user_id").order_by("-create_time") + values("id", "contest_id", "problem_id", "result", "create_time", "accepted_answer_time", "language", "user_id").order_by("-create_time") + language = request.GET.get("language", None) + filter = None + if language: + submissions = submissions.filter(language=int(language)) + filter = {"name": "language", "content": language} + result = request.GET.get("result", None) + if result: + submissions = submissions.filter(result=int(result)) + filter = {"name": "result", "content": result} paginator = Paginator(submissions, 20) + + # 为查询题目标题创建新字典 + title = {} + contest_problems = ContestProblem.objects.filter(contest=contest) + for item in contest_problems: + title[item.id] = item.title + for item in submissions: + item['title'] = title[item['problem_id']] + try: current_page = paginator.page(int(page)) except Exception: @@ -111,10 +120,16 @@ def contest_problem_submissions_list_page(request, contest_id, page=1): except Exception: pass + # 如果该用户是超级管理员那么他可以查看所有的提交记录详情 + if request.user.admin_type > 1: + return render(request, "oj/contest/submissions_list_admin.html", + {"submissions": current_page, "page": int(page), + "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20, + "contest": contest}) return render(request, "oj/contest/submissions_list.html", {"submissions": current_page, "page": int(page), "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20, - "contest": contest}) + "contest": contest, "filter":filter}) class ContestSubmissionAdminAPIView(APIView): @@ -147,5 +162,4 @@ class ContestSubmissionAdminAPIView(APIView): return error_response(u"参数错误!") if problem_id: submissions = submissions.filter(problem_id=problem_id) - return paginate(request, submissions, SubmissionSerializer) diff --git a/judge/Dockerfile b/judge/Dockerfile new file mode 100644 index 0000000..c2ca1b1 --- /dev/null +++ b/judge/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:14.04 +MAINTAINER virusdefender +RUN mkdir /var/install/ +WORKDIR /var/install/ +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get update +RUN apt-get -y install software-properties-common python-software-properties +RUN add-apt-repository -y ppa:webupd8team/java +RUN apt-get update +RUN apt-get -y install python gcc g++ rake pkg-config git make autoconf automake libtool python-pip python2.7-mysqldb +RUN echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections +RUN echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections +RUN apt-get install -y oracle-java7-installer +RUN apt-get -y install libseccomp-dev +RUN git clone https://github.com/quark-zju/lrun.git +RUN cd lrun && make install +RUN mkdir -p /var/judger/run/ && mkdir /var/judger/test_case/ && mkdir /var/judger/code/ +RUN chmod -R 777 /var/judger/run/ +WORKDIR /var/judger/code/ \ No newline at end of file diff --git a/judge/judger_controller/settings.py b/judge/judger_controller/settings.py index a0d3e66..aff08b1 100644 --- a/judge/judger_controller/settings.py +++ b/judge/judger_controller/settings.py @@ -1,4 +1,5 @@ # coding=utf-8 +# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息 redis_config = { "host": "121.42.32.129", "port": 6379, @@ -6,17 +7,21 @@ redis_config = { } +# 判题的 docker 容器的配置参数 docker_config = { - "image_name": " a7673b55d263", + "image_name": "3da0e526934e", "docker_path": "docker", "shell": True } -test_case_dir = "/root/test_case/" -source_code_dir = "/root/" +# 测试用例的路径,是主机上的实际路径 +test_case_dir = "/var/mnt/source/test_case/" +# 源代码路径,也就是 manage.py 所在的实际路径 +source_code_dir = "/var/mnt/source/OnlineJudge/" +# 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址 submission_db = { "host": "127.0.0.1", "port": 3306, diff --git a/oj/daocloud_settings.py b/oj/daocloud_settings.py deleted file mode 100644 index a99e009..0000000 --- a/oj/daocloud_settings.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding=utf-8 -import os - -LOG_PATH = "LOG/" - -# Database -# https://docs.djangoproject.com/en/1.8/ref/settings/#databases -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - 'CONN_MAX_AGE': 1, - } -} - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True \ No newline at end of file diff --git a/oj/local_settings.py b/oj/local_settings.py index 0b7f642..b923291 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -12,15 +12,16 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - 'CONN_MAX_AGE': 0.3, }, + # submission 的 name 和 engine 请勿修改,其他代码会用到 'submission': { 'NAME': 'oj_submission', 'ENGINE': 'django.db.backends.mysql', 'HOST': "121.42.32.129", 'PORT': 3306, 'USER': 'root', - 'PASSWORD': 'mypwd' + 'PASSWORD': 'mypwd', + 'CONN_MAX_AGE': 0.1, } } @@ -30,4 +31,3 @@ DEBUG = True TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/') ALLOWED_HOSTS = [] - diff --git a/oj/server_settings.py b/oj/server_settings.py index badfef6..185bf6b 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -12,7 +12,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': "oj", - 'CONN_MAX_AGE': 0.3, + 'CONN_MAX_AGE': 0.1, 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', @@ -21,6 +21,7 @@ DATABASES = { 'submission': { 'NAME': 'oj_submission', 'ENGINE': 'django.db.backends.mysql', + 'CONN_MAX_AGE': 0.1, 'HOST': "127.0.0.1", 'PORT': 3306, 'USER': 'root', @@ -34,4 +35,3 @@ DEBUG = True TEST_CASE_DIR = '/root/test_case/' ALLOWED_HOSTS = ['*'] - diff --git a/oj/settings.py b/oj/settings.py index 376060f..097a4c2 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -113,10 +113,6 @@ STATIC_URL = '/static/' STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),) -TEMPLATE_DIRS = ( - os.path.join(BASE_DIR, "template/src"), -) - AUTH_USER_MODEL = 'account.User' LOGGING = { diff --git a/problem/serizalizers.py b/problem/serizalizers.py index 1fb61cc..f9c5caa 100644 --- a/problem/serizalizers.py +++ b/problem/serizalizers.py @@ -26,8 +26,8 @@ class CreateProblemSerializer(serializers.Serializer): samples = ProblemSampleSerializer() test_case_id = serializers.CharField(max_length=40) source = serializers.CharField(max_length=30, required=False, default=None) - time_limit = serializers.IntegerField() - memory_limit = serializers.IntegerField() + time_limit = serializers.IntegerField(min_value=1) + memory_limit = serializers.IntegerField(min_value=1) difficulty = serializers.IntegerField() tags = serializers.ListField(child=serializers.CharField(max_length=10)) hint = serializers.CharField(max_length=3000, allow_blank=True) @@ -61,8 +61,8 @@ class EditProblemSerializer(serializers.Serializer): output_description = serializers.CharField(max_length=10000) test_case_id = serializers.CharField(max_length=40) source = serializers.CharField(max_length=30) - time_limit = serializers.IntegerField() - memory_limit = serializers.IntegerField() + time_limit = serializers.IntegerField(min_value=1) + memory_limit = serializers.IntegerField(min_value=1) difficulty = serializers.IntegerField() tags = serializers.ListField(child=serializers.CharField(max_length=20)) samples = ProblemSampleSerializer() diff --git a/problem/tests.py b/problem/tests.py index 2a7aecc..9819486 100644 --- a/problem/tests.py +++ b/problem/tests.py @@ -187,5 +187,19 @@ class ProblemListPageTest(TestCase): hint="hint1", created_by=User.objects.get(username="test")) + def test_problemListPage_not_exist(self): + response = self.client.get('/problems/999/') + self.assertTemplateUsed(response, "utils/error.html") + def test_query_by_keyword(self): + response = self.client.get(self.url + "?keyword=title1") + self.assertEqual(response.status_code, 200) + + def test_query_by_tag_successfully(self): + response = self.client.get(self.url + "?tag=") + self.assertEqual(response.status_code, 200) + + def test_tag_does_not_exists(self): + response = self.client.get(self.url + "?tag=xxxxxx") + self.assertTemplateUsed(response, "utils/error.html") diff --git a/requirements.txt b/requirements.txt index 9ad8f3f..3a706b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ django-rest-swagger celery gunicorn coverage -django-extensions \ No newline at end of file +django-extensions +supervisor \ No newline at end of file diff --git a/static/release/fis-conf.js b/static/release/fis-conf.js index ce128cd..f0935c3 100644 --- a/static/release/fis-conf.js +++ b/static/release/fis-conf.js @@ -1,3 +1,13 @@ /** * Created by virusdefender on 8/25/15. */ + +fis.match('*.{js,css,png,gif}', { + useHash: true // 开启 md5 戳 +}); + +fis.config.set( +'roadmap.path', +[{reg:'*.html',isHtmlLike : true} +]) +; \ No newline at end of file diff --git a/static/src/js/app/admin/problem/addProblem.js b/static/src/js/app/admin/problem/addProblem.js index d34cd9a..c6e49ca 100644 --- a/static/src/js/app/admin/problem/addProblem.js +++ b/static/src/js/app/admin/problem/addProblem.js @@ -13,10 +13,6 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE bsAlert("题目描述不能为空!"); return false; } - if (vm.timeLimit < 1000 || vm.timeLimit > 5000) { - bsAlert("保证时间限制是一个1000-5000的合法整数"); - return false; - } if (vm.samples.length == 0) { bsAlert("请至少添加一组样例!"); return false; diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js index d936e0f..1faeb6d 100644 --- a/static/src/js/app/oj/problem/problem.js +++ b/static/src/js/app/oj/problem/problem.js @@ -48,7 +48,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro if (!data.result) { html += "CPU time: " + data.accepted_answer_time + "ms   "; } - html += ('查看详情
    '); + html += ('查看详情
    '); return html; } diff --git a/static/src/js/build.js b/static/src/js/build.js index 9927a1b..ddd9bb3 100644 --- a/static/src/js/build.js +++ b/static/src/js/build.js @@ -1,8 +1,9 @@ ({ // RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。 - baseUrl: "js/", + baseUrl: "/static/js/", // 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了; paths: { + jquery: "lib/jquery/jquery", avalon: "lib/avalon/avalon", editor: "utils/editor", @@ -37,12 +38,12 @@ webUploader: "lib/webuploader/webuploader", "_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker" - }, shim: { - "bootstrap": {"deps": ['jquery']}, - "_datetimepicker": {"deps": ["jquery"]}, - "datetimepicker": {"deps": ["_datetimepicker"]} + bootstrap: {deps: ["jquery"]}, + _datetimePicker: {dep: ["jquery"]}, + datetimePicker: {deps: ["_datetimePicker"]}, + validator: ["jquery"] }, findNestedDependencies: true, appDir: "../", diff --git a/submission/tests.py b/submission/tests.py index 0d374ee..ad3b85a 100644 --- a/submission/tests.py +++ b/submission/tests.py @@ -1,6 +1,6 @@ # coding=utf-8 import json -from django.test import TestCase +from django.test import TestCase, Client from django.core.urlresolvers import reverse from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN from problem.models import Problem @@ -11,7 +11,7 @@ from rest_framework.test import APITestCase, APIClient class SubmissionsListPageTest(TestCase): def setUp(self): - self.client = APIClient() + self.client = Client() self.user = User.objects.create(username="gogoing", admin_type=REGULAR_USER) self.user2 = User.objects.create(username="cool", admin_type=REGULAR_USER) self.user2.set_password("666666") @@ -124,25 +124,78 @@ class SubmissionAPITest(APITestCase): response = self.client.get(self.url, data=data) self.assertEqual(response.data["code"], 0) + def test_parameter_error(self): + self.client.login(username="test1", password="testaa") + response = self.client.get(self.url) + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) -class ContestSubmissionAPITest(APITestCase): + +class SubmissionAdminAPITest(APITestCase): def setUp(self): self.client = APIClient() - self.url = reverse('contest_submission_api') - self.user1 = User.objects.create(username="test1", admin_type=REGULAR_USER) - self.user1.set_password("testaa") - self.user1.save() - self.user2 = User.objects.create(username="test2", admin_type=SUPER_ADMIN) - self.user2.set_password("testbb") - self.user2.save() + self.url = reverse('submission_admin_api_view') + self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user.set_password("testaa") + self.user.save() + self.client.login(username="test1", password="testaa") + self.problem = Problem.objects.create(title="title1", + description="description1", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + source="source1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + difficulty=1, + hint="hint1", + created_by=self.user) self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, contest_type=2, show_rank=True, show_user_submission=True, start_time="2015-08-15T10:00:00.000Z", end_time="2015-08-15T12:00:00.000Z", - password="aacc", created_by=User.objects.get(username="test2")) + password="aacc", created_by=self.user) + + self.submission = Submission.objects.create(user_id=self.user.id, + language=1, + code='#include "stdio.h"\nint main(){\n\treturn 0;\n}', + problem_id=self.problem.id) def test_invalid_format(self): + response = self.client.get(self.url) + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + +class SubmissionPageTest(TestCase): + # 单个题目的提交详情页 + def setUp(self): + self.client = Client() + self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN) + self.user1.set_password("testaa") + self.user1.save() + self.user2 = User.objects.create(username="test2", admin_type=ADMIN) + self.user2.set_password("testbb") + self.user2.save() self.client.login(username="test1", password="testaa") - data = {"language": 1} - response = self.client.post(self.url, data=data) - pass + self.problem = Problem.objects.create(title="title1", + description="description1", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + source="source1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + difficulty=1, + hint="hint1", + created_by=User.objects.get(username="test1")) + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + + self.submission = Submission.objects.create(user_id=self.user1.id, + language=1, + code='#include "stdio.h"\nint main(){\n\treturn 0;\n}', + problem_id=self.problem.id) diff --git a/submission/views.py b/submission/views.py index 0925e13..6180f8e 100644 --- a/submission/views.py +++ b/submission/views.py @@ -139,7 +139,7 @@ def my_submission_list_page(request, page=1): 我的所有提交的列表页 """ submissions = Submission.objects.filter(user_id=request.user.id, contest_id__isnull=True). \ - values("id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time") + values("id", "problem_id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time") language = request.GET.get("language", None) filter = None if language: diff --git a/template/src/oj/contest/my_submissions_list.html b/template/src/oj/contest/my_submissions_list.html index fb24bef..8c8aa5a 100644 --- a/template/src/oj/contest/my_submissions_list.html +++ b/template/src/oj/contest/my_submissions_list.html @@ -18,17 +18,19 @@ # 提交时间 - 结果 - 运行时间 语言 + 运行时间 + 结果 {% for item in submissions %} - + {{ forloop.counter }} {{ item.create_time }} - {{ item.result|translate_result }} + + {{ item.language|translate_language }} + {% if item.accepted_answer_time %} {{ item.accepted_answer_time }}ms @@ -36,8 +38,8 @@ -- {% endif %} - - {{ item.language|translate_language }} + + {{ item.result|translate_result }} {% endfor %} diff --git a/template/src/oj/contest/submissions_list.html b/template/src/oj/contest/submissions_list.html index 336e9c3..7141585 100644 --- a/template/src/oj/contest/submissions_list.html +++ b/template/src/oj/contest/submissions_list.html @@ -21,33 +21,67 @@ - {% if submissions %} - + + - + - + + {% if submissions %} - {% for item in submissions %} - + {% for item in submissions %} + {% ifequal item.user_id request.user.id %} - {% else %} {% endifequal %} - + - - + - {% endfor %} - + {% else %} +

    本场比赛还没有提交记录

    + {% endif %}
    #用户题目名称用户 提交时间结果 + + 运行时间语言 + +
    + {{ forloop.counter |add:start_id }}{{ forloop.counter |add:start_id }} + {{ item.title }} + {{ item.user_id|get_username }}{{ item.create_time }}{{ item.result|translate_result }} + {{ item.language|translate_language }} + {% if item.accepted_answer_time %} {{ item.accepted_answer_time }}ms @@ -55,28 +89,28 @@ -- {% endif %} - {{ item.language|translate_language }} + + {{ item.result|translate_result }}
    - {% else %} -

    你还没有提交记录!

    - {% endif %} + diff --git a/template/src/oj/contest/submissions_list_admin.html b/template/src/oj/contest/submissions_list_admin.html new file mode 100644 index 0000000..c8a6745 --- /dev/null +++ b/template/src/oj/contest/submissions_list_admin.html @@ -0,0 +1,78 @@ +{% extends 'oj_base.html' %} + +{% block body %} + + {% load submission %} + {% load user %} +
    +
    + +
    + + + + + + + + + + + + + {% if submissions %} + + {% for item in submissions %} + + + + + + + + + + {% endfor %} + + {% else %} +

    本场比赛还没有提交记录!

    + {% endif %} +
    #用户提交时间结果运行时间语言
    + {{ forloop.counter |add:start_id }}{{ item.user_id|get_username }}{{ item.create_time }}{{ item.result|translate_result }} + {% if item.accepted_answer_time %} + {{ item.accepted_answer_time }}ms + {% else %} + -- + {% endif %} + + {{ item.language|translate_language }} +
    + +
    +{% endblock %} diff --git a/template/src/oj/problem/problem.html b/template/src/oj/problem/problem.html index 00b4ce7..515c6a2 100644 --- a/template/src/oj/problem/problem.html +++ b/template/src/oj/problem/problem.html @@ -4,8 +4,14 @@
    {% include "oj/problem/_problem_header.html" %} @@ -23,7 +29,7 @@
    -

    {{ problem.output_description }}k

    +

    {{ problem.output_description }}

    {% for item in samples %}
    @@ -33,7 +39,6 @@
    -
     {{ item.output }}
    @@ -45,23 +50,19 @@ {% if problem.hint %}
    -
    {{ problem.hint|safe }}
    {% endif %}
    -

    {% for tag in problem.tags.all %} {{ tag.name }} {% endfor %}

    -
    -
    -
    @@ -85,9 +85,7 @@ 提交代码 -
    -

    diff --git a/template/src/oj/submission/my_submissions_list.html b/template/src/oj/submission/my_submissions_list.html index e5eb554..08cf17d 100644 --- a/template/src/oj/submission/my_submissions_list.html +++ b/template/src/oj/submission/my_submissions_list.html @@ -1,7 +1,6 @@ {% extends 'oj_base.html' %} {% block body %} - {% load submission %}
    @@ -9,6 +8,7 @@ # + 题目名称 提交时间
    -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/template/src/oj_base.html b/template/src/oj_base.html index 534c4db..56ba614 100644 --- a/template/src/oj_base.html +++ b/template/src/oj_base.html @@ -56,7 +56,7 @@ {{ request.user.username }}
    - \ No newline at end of file + diff --git a/utils/templatetags/problem.py b/utils/templatetags/problem.py index 78ee4ea..412c91d 100644 --- a/utils/templatetags/problem.py +++ b/utils/templatetags/problem.py @@ -4,7 +4,7 @@ def get_problem_accepted_radio(problem): if problem.total_submit_number: return str(int((problem.total_accepted_number * 100) / problem.total_submit_number)) \ - + "% (" + str(problem.total_accepted_number) + "/" + str(problem.total_submit_number) + ")" + + "% (" + str(problem.total_accepted_number) + " / " + str(problem.total_submit_number) + ")" return "0%" From 8287a722ec7eeafe0348982e37f5fc60e8298cbe Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 11:31:30 +0800 Subject: [PATCH 030/195] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B6=85=E7=BA=A7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E6=AF=94=E8=B5=9B=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=9A=84=E6=A0=B7=E5=BC=8F=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oj/contest/submissions_list_admin.html | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/template/src/oj/contest/submissions_list_admin.html b/template/src/oj/contest/submissions_list_admin.html index c8a6745..f65f141 100644 --- a/template/src/oj/contest/submissions_list_admin.html +++ b/template/src/oj/contest/submissions_list_admin.html @@ -1,5 +1,119 @@ {% extends 'oj_base.html' %} +{% block body %} + + {% load submission %} + {% load user %} +
    +
    + +
    + + + + + + + + + + + + + {% if submissions %} + + + {% for item in submissions %} + + + + + + + + + + {% endfor %} + + {% else %} +

    本场比赛还没有提交记录

    + {% endif %} +
    #题目名称用户提交时间 + + 运行时间 + +
    + {{ forloop.counter |add:start_id }} + {{ item.title }} + {{ item.user_id|get_username }}{{ item.create_time }} + {{ item.language|translate_language }} + + {% if item.accepted_answer_time %} + {{ item.accepted_answer_time }}ms + {% else %} + -- + {% endif %} + + {{ item.result|translate_result }} +
    + + +
    +{% endblock %} +{% extends 'oj_base.html' %} + {% block body %} {% load submission %} From bd014b5c40af09bbf16b8a225646f421e13fc6cd Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 11:38:11 +0800 Subject: [PATCH 031/195] =?UTF-8?q?=E5=88=9A=E5=88=9A=E4=B8=8D=E5=B0=8F?= =?UTF-8?q?=E5=BF=83=E6=8A=8A=E4=B8=A4=E4=B8=AA=E6=96=87=E4=BB=B6=E7=B2=98?= =?UTF-8?q?=E4=B8=80=E8=B5=B7=E4=BA=86=EF=BC=8C=E5=8E=9F=E6=9D=A5=E7=9A=84?= =?UTF-8?q?=E5=BF=98=E6=B8=85=E4=BA=86=E3=80=82=E3=80=82=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oj/contest/submissions_list_admin.html | 86 ++----------------- 1 file changed, 6 insertions(+), 80 deletions(-) diff --git a/template/src/oj/contest/submissions_list_admin.html b/template/src/oj/contest/submissions_list_admin.html index f65f141..5f1b719 100644 --- a/template/src/oj/contest/submissions_list_admin.html +++ b/template/src/oj/contest/submissions_list_admin.html @@ -68,8 +68,12 @@ {% for item in submissions %} - + {% ifequal item.user_id request.user.id %} + {{ forloop.counter |add:start_id }} + {% else %} + {{ forloop.counter |add:start_id }} + {% endifequal %} {{ item.title }} @@ -111,82 +115,4 @@
    -{% endblock %} -{% extends 'oj_base.html' %} - -{% block body %} - - {% load submission %} - {% load user %} -
    -
    - -
    - - - - - - - - - - - - - {% if submissions %} - - {% for item in submissions %} - - - - - - - - - - {% endfor %} - - {% else %} -

    本场比赛还没有提交记录!

    - {% endif %} -
    #用户提交时间结果运行时间语言
    - {{ forloop.counter |add:start_id }}{{ item.user_id|get_username }}{{ item.create_time }}{{ item.result|translate_result }} - {% if item.accepted_answer_time %} - {{ item.accepted_answer_time }}ms - {% else %} - -- - {% endif %} - - {{ item.language|translate_language }} -
    - -
    -{% endblock %} +{% endblock %} \ No newline at end of file From 4be960093941a1b707dc7c9b0e3dab27aacd2f0b Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 11:42:20 +0800 Subject: [PATCH 032/195] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=89=8D=E5=8F=B0?= =?UTF-8?q?=E6=AF=94=E8=B5=9B=E6=8F=90=E4=BA=A4=E5=88=97=E8=A1=A8=E4=B8=AD?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E5=8F=AF=E8=A7=81=E6=AF=94=E8=B5=9B?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/submissions_list_admin.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/template/src/oj/contest/submissions_list_admin.html b/template/src/oj/contest/submissions_list_admin.html index 5f1b719..8f1660b 100644 --- a/template/src/oj/contest/submissions_list_admin.html +++ b/template/src/oj/contest/submissions_list_admin.html @@ -68,12 +68,8 @@ {% for item in submissions %} - {% ifequal item.user_id request.user.id %} - + {{ forloop.counter |add:start_id }} - {% else %} - {{ forloop.counter |add:start_id }} - {% endifequal %} {{ item.title }} From 78f7f2bb314e5033c206c8a308b1553c65439463 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:05:26 +0800 Subject: [PATCH 033/195] =?UTF-8?q?=E5=B0=86=E7=BC=96=E8=AF=91=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BF=A1=E6=81=AF=E5=8C=85=E8=A3=B9=E5=9C=A8=20pre=20?= =?UTF-8?q?=E9=87=8C=E9=9D=A2=EF=BC=8C=E5=90=A6=E5=88=99=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E6=8D=A2=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/problem/my_submission.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/src/oj/problem/my_submission.html b/template/src/oj/problem/my_submission.html index fdfcec2..c60c146 100644 --- a/template/src/oj/problem/my_submission.html +++ b/template/src/oj/problem/my_submission.html @@ -43,7 +43,7 @@

    {% endifequal %} {% ifequal submission.result 4 %} -

    {{ submission.info }}

    +
    {{ submission.info }}
    {% endifequal %}

    提交时间 : {{ submission.create_time }}

    From 6cd898d2c0836710afc508c29bb22600f30eca0e Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:12:45 +0800 Subject: [PATCH 034/195] =?UTF-8?q?=E5=88=9B=E5=BB=BA=20codeMirror=20?= =?UTF-8?q?=E4=B9=8B=E5=89=8D=E5=85=88=E5=88=A4=E6=96=AD=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/problem/problem.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js index 1faeb6d..4612a94 100644 --- a/static/src/js/app/oj/problem/problem.js +++ b/static/src/js/app/oj/problem/problem.js @@ -1,5 +1,10 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirror, csrfTokenHeader, bsAlert) { - var codeEditor = codeMirror($("#code-editor")[0], "text/x-csrc"); + var codeEditorSelector = $("#code-editor")[0]; + // 部分界面逻辑会隐藏代码输入框,先判断有没有。 + if (codeEditorSelector == undefined){ + return; + } + var codeEditor = codeMirror(codeEditorSelector, "text/x-csrc"); var language = $("input[name='language'][checked]").val(); var submissionId; From 4529ce191c71f745454111a2d6693c9ea895b309 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:15:25 +0800 Subject: [PATCH 035/195] =?UTF-8?q?=E5=88=A0=E9=99=A4=20daocloud=20?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daocloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daocloud.yml b/daocloud.yml index e5c5724..1f763d8 100644 --- a/daocloud.yml +++ b/daocloud.yml @@ -4,7 +4,7 @@ services: - mysql env: - - oj_env="daocloud" + - oj_env="local" script: - pip install -r requirements.txt From 2334982f31aa0e3297d5541db81fc3dfe6a864e4 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:34:21 +0800 Subject: [PATCH 036/195] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=AF=94=E8=B5=9B?= =?UTF-8?q?=E6=8E=92=E5=90=8D=E9=A1=B5=E9=9D=A2=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 3 ++- template/src/oj/contest/contest_rank.html | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/contest/views.py b/contest/views.py index af8d469..e68b81f 100644 --- a/contest/views.py +++ b/contest/views.py @@ -416,4 +416,5 @@ def contest_rank_page(request, contest_id): return render(request, "oj/contest/contest_rank.html", {"contest": contest, "contest_problems": contest_problems, - "result": sorted(result, cmp=_cmp, reverse=True)}) + "result": sorted(result, cmp=_cmp, reverse=True), + "auto_refresh": request.GET.get("auto_refresh", None) == "true"}) diff --git a/template/src/oj/contest/contest_rank.html b/template/src/oj/contest/contest_rank.html index 7d17134..ac2bb15 100644 --- a/template/src/oj/contest/contest_rank.html +++ b/template/src/oj/contest/contest_rank.html @@ -50,6 +50,7 @@ {% endfor %} + 自动刷新 {% else %}

    还没有结果

    {% endif %} @@ -60,4 +61,11 @@ {% block js_block %} +{% if auto_refresh %} + + {% endif %} {% endblock %} \ No newline at end of file From fbd99450ec42837cda9cd417e56591a0d5db8fd2 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:36:07 +0800 Subject: [PATCH 037/195] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20ci=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daocloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daocloud.yml b/daocloud.yml index 1f763d8..5e9f6ff 100644 --- a/daocloud.yml +++ b/daocloud.yml @@ -8,5 +8,5 @@ env: script: - pip install -r requirements.txt - - mkdir LOG + - mkdir log - python manage.py test \ No newline at end of file From cd5ce220da35b2ef4aa1db86ee5ce22e10ad3983 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:48:46 +0800 Subject: [PATCH 038/195] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=8C=9C=E6=B5=8B=E4=BB=A3=E7=A0=81=E8=AF=AD=E8=A8=80=E5=92=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=AF=AD=E8=A8=80=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/problem/problem.js | 37 +++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js index 4612a94..823afc8 100644 --- a/static/src/js/app/oj/problem/problem.js +++ b/static/src/js/app/oj/problem/problem.js @@ -1,7 +1,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirror, csrfTokenHeader, bsAlert) { var codeEditorSelector = $("#code-editor")[0]; // 部分界面逻辑会隐藏代码输入框,先判断有没有。 - if (codeEditorSelector == undefined){ + if (codeEditorSelector == undefined) { return; } var codeEditor = codeMirror(codeEditorSelector, "text/x-csrc"); @@ -92,9 +92,37 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro }) } + function guessLanguage(code) { + //cpp + if (code.indexOf("using namespace std") > -1) { + return "2"; + } + //c + if (code.indexOf("printf") > -1) { + return "1"; + } + //java + if (code.indexOf("public class Main")) { + return "3"; + } + } + $("#submit-code-button").click(function () { var code = codeEditor.getValue(); + + if (!code.trim()) { + bsAlert("请填写代码!"); + hideLoading(); + return false; + } + + if(guessLanguage(code) != language){ + if(!confirm("您选择的代码语言可能存在错误,是否继续提交?")){ + return; + } + } + if (location.href.indexOf("contest") > -1) { var problemId = location.pathname.split("/")[4]; var contestId = location.pathname.split("/")[2]; @@ -118,15 +146,8 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro showLoading(); - if (!code.trim()) { - bsAlert("请填写代码!"); - hideLoading(); - return false; - } - $("#result").html(""); - $.ajax({ beforeSend: csrfTokenHeader, url: url, From e357dd293f3cb2d2293872727af2310f29ae7965 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Sep 2015 17:50:56 +0800 Subject: [PATCH 039/195] =?UTF-8?q?=E8=A7=84=E8=8C=83=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E5=99=A8=E5=A4=A7=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/contest_problem.html | 6 +++--- template/src/oj/problem/problem.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/template/src/oj/contest/contest_problem.html b/template/src/oj/contest/contest_problem.html index 4cf7e3b..0dc4918 100644 --- a/template/src/oj/contest/contest_problem.html +++ b/template/src/oj/contest/contest_problem.html @@ -72,13 +72,13 @@
    diff --git a/template/src/oj/problem/problem.html b/template/src/oj/problem/problem.html index affc520..0c82bc6 100644 --- a/template/src/oj/problem/problem.html +++ b/template/src/oj/problem/problem.html @@ -65,13 +65,13 @@
    From 254427ef7c6101452afc2bcc47f1b264be1ae550 Mon Sep 17 00:00:00 2001 From: "sxw@401" Date: Tue, 8 Sep 2015 18:52:13 +0800 Subject: [PATCH 040/195] =?UTF-8?q?[=E5=90=8E=E5=8F=B0-=E5=89=8D=E7=AB=AF]?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=BA=86=E6=AF=94=E8=B5=9B=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=BC=80=E6=94=BE=E6=8E=92=E5=90=8D=E9=80=89?= =?UTF-8?q?=20=E9=A1=B9,=E5=A4=A9=E5=8A=A0=E5=B0=81=E6=A6=9C=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E5=AD=97=E6=AE=B5[CI=20SKIP]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/admin/contest/add_contest.html | 28 ++++++++------------ template/src/admin/contest/contest_list.html | 19 +++++-------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/template/src/admin/contest/add_contest.html b/template/src/admin/contest/add_contest.html index b374ec8..4dd8c96 100644 --- a/template/src/admin/contest/add_contest.html +++ b/template/src/admin/contest/add_contest.html @@ -57,36 +57,30 @@
    {{el.name}}
    -
    +
    + +
    +
    -
    - -
    -
    +
    -
    +
    + +
    +
    +
    -
    -
    -
    - -
    -
    -
    +