From d8966ed48af556a4234f54f4c6e637c84ed2830f Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sat, 28 Nov 2015 20:32:49 +0800 Subject: [PATCH 01/64] dev test --- judge/judger/__init__.py => db1.sqlite3 | 0 judge/__init__.py | 1 - judge/{judger => }/client.py | 0 judge/{judger => }/compiler.py | 0 judge/{judger => }/judge_exceptions.py | 0 judge/judger/run.py | 94 ------------------- judge/judger_controller/README.md | 1 - judge/judger_controller/celery.py | 9 -- judge/judger_controller/settings.py | 39 -------- judge/judger_controller/tasks.py | 45 --------- judge/{judger => }/language.py | 0 judge/{judger => }/logger.py | 0 judge/{judger => }/result.py | 0 judge/run.py | 52 ++++++++++ .../__init__.py => server.py} | 0 judge/{judger => }/settings.py | 0 judge/{judger => }/utils.py | 0 judge_dispatcher/__init__.py | 1 + judge_dispatcher/judge.py | 16 ++++ judge_dispatcher/models.py | 15 +++ judge_dispatcher/rpc_client.py | 24 +++++ judge_dispatcher/settings.py | 9 ++ 22 files changed, 117 insertions(+), 189 deletions(-) rename judge/judger/__init__.py => db1.sqlite3 (100%) rename judge/{judger => }/client.py (100%) rename judge/{judger => }/compiler.py (100%) rename judge/{judger => }/judge_exceptions.py (100%) delete mode 100644 judge/judger/run.py delete mode 100644 judge/judger_controller/README.md delete mode 100644 judge/judger_controller/celery.py delete mode 100644 judge/judger_controller/settings.py delete mode 100644 judge/judger_controller/tasks.py rename judge/{judger => }/language.py (100%) rename judge/{judger => }/logger.py (100%) rename judge/{judger => }/result.py (100%) create mode 100644 judge/run.py rename judge/{judger_controller/__init__.py => server.py} (100%) rename judge/{judger => }/settings.py (100%) rename judge/{judger => }/utils.py (100%) create mode 100644 judge_dispatcher/__init__.py create mode 100644 judge_dispatcher/judge.py create mode 100644 judge_dispatcher/models.py create mode 100644 judge_dispatcher/rpc_client.py create mode 100644 judge_dispatcher/settings.py diff --git a/judge/judger/__init__.py b/db1.sqlite3 similarity index 100% rename from judge/judger/__init__.py rename to db1.sqlite3 diff --git a/judge/__init__.py b/judge/__init__.py index 9bad5790a..e69de29bb 100644 --- a/judge/__init__.py +++ b/judge/__init__.py @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/judge/judger/client.py b/judge/client.py similarity index 100% rename from judge/judger/client.py rename to judge/client.py diff --git a/judge/judger/compiler.py b/judge/compiler.py similarity index 100% rename from judge/judger/compiler.py rename to judge/compiler.py diff --git a/judge/judger/judge_exceptions.py b/judge/judge_exceptions.py similarity index 100% rename from judge/judger/judge_exceptions.py rename to judge/judge_exceptions.py diff --git a/judge/judger/run.py b/judge/judger/run.py deleted file mode 100644 index 8aeb54767..000000000 --- a/judge/judger/run.py +++ /dev/null @@ -1,94 +0,0 @@ -# coding=utf-8 -import sys -import json -import MySQLdb - -from client import JudgeClient -from language import languages -from compiler import compile_ -from result import result -from settings import judger_workspace, submission_db -from logger import logger - - -# 简单的解析命令行参数 -# 参数有 -solution_id -time_limit -memory_limit -test_case_id -# 获取到的值是['xxx.py', '-solution_id', '1111', '-time_limit', '1000', '-memory_limit', '100', '-test_case_id', 'aaaa'] -args = sys.argv -submission_id = args[2] -time_limit = args[4] -memory_limit = args[6] -test_case_id = args[8] - - -def db_conn(): - return MySQLdb.connect(db=submission_db["db"], - user=submission_db["user"], - passwd=submission_db["password"], - host=submission_db["host"], - port=submission_db["port"], charset="utf8") - - -conn = db_conn() -cur = conn.cursor() -cur.execute("select language, code from submission where id = %s", (submission_id,)) -data = cur.fetchall() -if not data: - exit() -language_code = data[0][0] -code = data[0][1] - -conn.close() - -# 将代码写入文件 -language = languages[language_code] -src_path = judger_workspace + "run/" + language["src_name"] -f = open(src_path, "w") -f.write(code.encode("utf8")) -f.close() - -# 编译 -try: - exe_path = compile_(language, src_path, judger_workspace + "run/") -except Exception as e: - print e - conn = db_conn() - cur = conn.cursor() - cur.execute("update submission set result=%s, info=%s where id=%s", - (result["compile_error"], str(e), submission_id)) - conn.commit() - exit() - -# 运行 -try: - client = JudgeClient(language_code=language_code, - exe_path=exe_path, - max_cpu_time=int(time_limit), - max_real_time=int(time_limit) * 2, - max_memory=int(memory_limit), - test_case_dir=judger_workspace + "test_case/" + test_case_id + "/") - judge_result = {"result": result["accepted"], "info": client.run(), "accepted_answer_time": None} - - for item in judge_result["info"]: - if item["result"]: - judge_result["result"] = item["result"] - break - else: - l = sorted(judge_result["info"], key=lambda k: k["cpu_time"]) - judge_result["accepted_answer_time"] = l[-1]["cpu_time"] - -except Exception as e: - logger.error(e) - conn = db_conn() - cur = conn.cursor() - cur.execute("update submission set result=%s, info=%s where id=%s", (result["system_error"], str(e), submission_id)) - conn.commit() - exit() - -conn = db_conn() -cur = conn.cursor() -cur.execute("update submission set result=%s, info=%s, accepted_answer_time=%s where id=%s", - (judge_result["result"], json.dumps(judge_result["info"]), judge_result["accepted_answer_time"], - submission_id)) -conn.commit() -conn.close() diff --git a/judge/judger_controller/README.md b/judge/judger_controller/README.md deleted file mode 100644 index 9dd560320..000000000 --- a/judge/judger_controller/README.md +++ /dev/null @@ -1 +0,0 @@ -celery -A judge.controller worker -l DEBUG \ No newline at end of file diff --git a/judge/judger_controller/celery.py b/judge/judger_controller/celery.py deleted file mode 100644 index 4c64ab042..000000000 --- a/judge/judger_controller/celery.py +++ /dev/null @@ -1,9 +0,0 @@ -# coding=utf-8 -from __future__ import absolute_import -from celery import Celery, platforms -from .settings import redis_config - -app = Celery("judge", broker='redis://%s:%s/%s' % (redis_config["host"], redis_config["port"], redis_config["db"]), - include=["judge.judger_controller.tasks"]) - -platforms.C_FORCE_ROOT =True diff --git a/judge/judger_controller/settings.py b/judge/judger_controller/settings.py deleted file mode 100644 index 4d48340ea..000000000 --- a/judge/judger_controller/settings.py +++ /dev/null @@ -1,39 +0,0 @@ -# coding=utf-8 -""" -注意: -此文件包含 celery 的部分配置,但是 celery 并不是运行在docker 中的,所以本配置文件中的 redis和 MySQL 的地址就应该是 -运行 redis 和 MySQL 的 docker 容器的地址了。怎么获取这个地址见帮助文档。测试用例的路径和源代码路径同理。 -""" -import os -# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息 -redis_config = { - "host": os.environ.get("REDIS_PORT_6379_TCP_ADDR"), - "port": 6379, - "db": 0 -} - - -# 判题的 docker 容器的配置参数 -docker_config = { - "image_name": "judger", - "docker_path": "docker", - "shell": True -} - - -# 测试用例的路径,是主机上的实际路径 -test_case_dir = "/root/test_case/" -# 源代码路径,也就是 manage.py 所在的实际路径 -source_code_dir = "/root/qduoj/" -# 日志文件夹路径 -log_dir = "/root/log/" - - -# 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址 -submission_db = { - "host": os.environ.get("submission_db_host"), - "port": 3306, - "db": "oj_submission", - "user": "root", - "password": "root" -} diff --git a/judge/judger_controller/tasks.py b/judge/judger_controller/tasks.py deleted file mode 100644 index 2219d96eb..000000000 --- a/judge/judger_controller/tasks.py +++ /dev/null @@ -1,45 +0,0 @@ -# coding=utf-8 -import json -import redis -import MySQLdb -import subprocess -from ..judger.result import result -from ..judger_controller.celery import app -from settings import docker_config, source_code_dir, test_case_dir, log_dir, submission_db, redis_config - - -@app.task -def judge(submission_id, time_limit, memory_limit, test_case_id): - try: - command = "%s run --privileged --rm " \ - "--link mysql " \ - "-v %s:/var/judger/test_case/:ro " \ - "-v %s:/var/judger/code/:ro " \ - "-v %s:/var/judger/code/log/ " \ - "--device /dev/null:/dev/null " \ - "%s " \ - "python judge/judger/run.py " \ - "--solution_id %s --time_limit %s --memory_limit %s --test_case_id %s" % \ - (docker_config["docker_path"], - test_case_dir, - source_code_dir, - log_dir, - docker_config["image_name"], - submission_id, str(time_limit), str(memory_limit), test_case_id) - subprocess.call(command, shell=docker_config["shell"]) - except Exception as e: - conn = MySQLdb.connect(db=submission_db["db"], - user=submission_db["user"], - passwd=submission_db["password"], - host=submission_db["host"], - port=submission_db["port"], - charset="utf8") - - cur = conn.cursor() - cur.execute("update submission set result=%s, info=%s where id=%s", - (result["system_error"], str(e), submission_id)) - conn.commit() - conn.close() - r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) - r.decr("judge_queue_length") - r.lpush("queue", submission_id) diff --git a/judge/judger/language.py b/judge/language.py similarity index 100% rename from judge/judger/language.py rename to judge/language.py diff --git a/judge/judger/logger.py b/judge/logger.py similarity index 100% rename from judge/judger/logger.py rename to judge/logger.py diff --git a/judge/judger/result.py b/judge/result.py similarity index 100% rename from judge/judger/result.py rename to judge/result.py diff --git a/judge/run.py b/judge/run.py new file mode 100644 index 000000000..2118521a6 --- /dev/null +++ b/judge/run.py @@ -0,0 +1,52 @@ +# coding=utf-8 +import sys +import json +import MySQLdb + +from client import JudgeClient +from language import languages +from compiler import compile_ +from result import result +from settings import judger_workspace, submission_db +from logger import logger + + +class JudgeInstanceRunner(object): + def __init__(self): + pass + + def run(self, submission_id, language_code, code, time_limit, memory_limit, test_case_id): + language = languages[language_code] + # 将代码写入文件 + src_path = judger_workspace + "run/" + submission_id + "/" + language["src_name"] + f = open(src_path, "w") + f.write(code.encode("utf8")) + f.close() + + # 编译 + try: + exe_path = compile_(language, src_path, judger_workspace + "run/" + submission_id + "/") + except Exception as e: + return {"code": 1, "data": str(e)} + + # 运行 + try: + client = JudgeClient(language_code=language_code, + exe_path=exe_path, + max_cpu_time=int(time_limit), + max_real_time=int(time_limit) * 2, + max_memory=int(memory_limit), + test_case_dir=judger_workspace + "test_case/" + test_case_id + "/") + judge_result = {"result": result["accepted"], "info": client.run(), "accepted_answer_time": None} + + for item in judge_result["info"]: + if item["result"]: + judge_result["result"] = item["result"] + break + else: + l = sorted(judge_result["info"], key=lambda k: k["cpu_time"]) + judge_result["accepted_answer_time"] = l[-1]["cpu_time"] + return {"code": 0, "data": judge_result} + + except Exception as e: + return {"code": 1, "data": str(e)} \ No newline at end of file diff --git a/judge/judger_controller/__init__.py b/judge/server.py similarity index 100% rename from judge/judger_controller/__init__.py rename to judge/server.py diff --git a/judge/judger/settings.py b/judge/settings.py similarity index 100% rename from judge/judger/settings.py rename to judge/settings.py diff --git a/judge/judger/utils.py b/judge/utils.py similarity index 100% rename from judge/judger/utils.py rename to judge/utils.py diff --git a/judge_dispatcher/__init__.py b/judge_dispatcher/__init__.py new file mode 100644 index 000000000..9bad5790a --- /dev/null +++ b/judge_dispatcher/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 diff --git a/judge_dispatcher/judge.py b/judge_dispatcher/judge.py new file mode 100644 index 000000000..8e4e1dd86 --- /dev/null +++ b/judge_dispatcher/judge.py @@ -0,0 +1,16 @@ +# coding=utf-8 +import socket +import redis + +from .rpc_client import TimeoutServerProxy +from .settings import redis_config +from .models import JudgeServer + + +class JudgeDispatcher(object): + def __init__(self): + self.redis = redis.StrictRedis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) + + def judge(self): + pass + diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py new file mode 100644 index 000000000..29f522679 --- /dev/null +++ b/judge_dispatcher/models.py @@ -0,0 +1,15 @@ +# coding=utf-8 +from django.db import models + + +class JudgeServer(models.Model): + ip = models.IPAddressField() + port = models.IntegerField() + # 这个服务器最大可能运行的判题实例数量 + max_instance_number = models.IntegerField() + left_instance_number = models.IntegerField() + # status 为 false 的时候代表不使用这个服务器 + status = models.BooleanField(default=True) + + class Meta: + db_table = "judge_server" diff --git a/judge_dispatcher/rpc_client.py b/judge_dispatcher/rpc_client.py new file mode 100644 index 000000000..c095cb5e4 --- /dev/null +++ b/judge_dispatcher/rpc_client.py @@ -0,0 +1,24 @@ +# coding=utf-8 +import xmlrpclib +import httplib + + +class TimeoutHTTPConnection(httplib.HTTPConnection): + def __init__(self, host, timeout=10): + httplib.HTTPConnection.__init__(self, host, timeout=timeout) + + +class TimeoutTransport(xmlrpclib.Transport): + def __init__(self, timeout=10, *args, **kwargs): + xmlrpclib.Transport.__init__(self, *args, **kwargs) + self.timeout = timeout + + def make_connection(self, host): + conn = TimeoutHTTPConnection(host, self.timeout) + return conn + + +class TimeoutServerProxy(xmlrpclib.ServerProxy): + def __init__(self, uri, timeout=10, *args, **kwargs): + kwargs['transport'] = TimeoutTransport(timeout=timeout, use_datetime=kwargs.get('use_datetime', 0)) + xmlrpclib.ServerProxy.__init__(self, uri, *args, **kwargs) diff --git a/judge_dispatcher/settings.py b/judge_dispatcher/settings.py new file mode 100644 index 000000000..332cefe8e --- /dev/null +++ b/judge_dispatcher/settings.py @@ -0,0 +1,9 @@ +# coding=utf-8 +import os + + +redis_config = { + "host": os.environ.get("REDIS_PORT_6379_TCP_ADDR"), + "port": 6379, + "db": 0 +} \ No newline at end of file From 3e3770f6695ff14e7137371c3b9d9eea7ba587d8 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 29 Nov 2015 01:05:29 +0800 Subject: [PATCH 02/64] =?UTF-8?q?=E5=AE=8C=E5=96=84=20rpc=20=E9=80=9A?= =?UTF-8?q?=E4=BF=A1=20server=EF=BC=9B=E5=B0=86=E5=88=A4=E9=A2=98=E9=99=90?= =?UTF-8?q?=E5=88=B6=E5=9C=A8=E4=B8=80=E4=B8=AA=E5=AE=B9=E5=99=A8=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/{run.py => runner.py} | 35 ++++++++++++++++++++++------------- judge/server.py | 12 ++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) rename judge/{run.py => runner.py} (64%) diff --git a/judge/run.py b/judge/runner.py similarity index 64% rename from judge/run.py rename to judge/runner.py index 2118521a6..49b1ea9d2 100644 --- a/judge/run.py +++ b/judge/runner.py @@ -1,14 +1,12 @@ # coding=utf-8 -import sys -import json -import MySQLdb +import os +import shutil from client import JudgeClient from language import languages from compiler import compile_ from result import result -from settings import judger_workspace, submission_db -from logger import logger +from settings import judger_workspace class JudgeInstanceRunner(object): @@ -17,16 +15,26 @@ def __init__(self): def run(self, submission_id, language_code, code, time_limit, memory_limit, test_case_id): language = languages[language_code] - # 将代码写入文件 - src_path = judger_workspace + "run/" + submission_id + "/" + language["src_name"] - f = open(src_path, "w") - f.write(code.encode("utf8")) - f.close() + + judge_base_path = os.path.join(judger_workspace, "run", submission_id) + + try: + os.mkdir(judge_base_path) + + # 将代码写入文件 + src_path = os.path.join(judge_base_path, language["src_name"]) + f = open(src_path, "w") + f.write(code.encode("utf8")) + f.close() + except Exception as e: + shutil.rmtree(judge_base_path, ignore_errors=True) + return {"code": 2, "data": str(e)} # 编译 try: - exe_path = compile_(language, src_path, judger_workspace + "run/" + submission_id + "/") + exe_path = compile_(language, src_path, judge_base_path) except Exception as e: + shutil.rmtree(judge_base_path, ignore_errors=True) return {"code": 1, "data": str(e)} # 运行 @@ -47,6 +55,7 @@ def run(self, submission_id, language_code, code, time_limit, memory_limit, test l = sorted(judge_result["info"], key=lambda k: k["cpu_time"]) judge_result["accepted_answer_time"] = l[-1]["cpu_time"] return {"code": 0, "data": judge_result} - except Exception as e: - return {"code": 1, "data": str(e)} \ No newline at end of file + return {"code": 2, "data": str(e)} + finally: + shutil.rmtree(judge_base_path, ignore_errors=True) \ No newline at end of file diff --git a/judge/server.py b/judge/server.py index 9bad5790a..477cc1e4e 100644 --- a/judge/server.py +++ b/judge/server.py @@ -1 +1,13 @@ # coding=utf-8 +import SocketServer +from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler +from runner import JudgeInstanceRunner + + +class AsyncXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer): + pass + + +server = AsyncXMLRPCServer(('0.0.0.0', 8080), SimpleXMLRPCRequestHandler, allow_none=True) +server.register_instance(JudgeInstanceRunner()) +server.serve_forever() \ No newline at end of file From 236102b6accc56a80df1e81b03429c043a8446c3 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 29 Nov 2015 01:24:15 +0800 Subject: [PATCH 03/64] =?UTF-8?q?=E5=88=A4=E9=A2=98=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E4=B8=AD=E8=BF=94=E5=9B=9E=20server=20=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=EF=BC=8C=E4=BE=BF=E4=BA=8E=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/runner.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/judge/runner.py b/judge/runner.py index 49b1ea9d2..4b5349e4f 100644 --- a/judge/runner.py +++ b/judge/runner.py @@ -1,5 +1,6 @@ # coding=utf-8 import os +import socket import shutil from client import JudgeClient @@ -15,7 +16,7 @@ def __init__(self): def run(self, submission_id, language_code, code, time_limit, memory_limit, test_case_id): language = languages[language_code] - + host_name = socket.gethostname() judge_base_path = os.path.join(judger_workspace, "run", submission_id) try: @@ -28,14 +29,14 @@ def run(self, submission_id, language_code, code, time_limit, memory_limit, test f.close() except Exception as e: shutil.rmtree(judge_base_path, ignore_errors=True) - return {"code": 2, "data": str(e)} + return {"code": 2, "data": {"error": str(e), "server": host_name}} # 编译 try: exe_path = compile_(language, src_path, judge_base_path) except Exception as e: shutil.rmtree(judge_base_path, ignore_errors=True) - return {"code": 1, "data": str(e)} + return {"code": 1, "data": {"error": str(e), "server": host_name}} # 运行 try: @@ -45,7 +46,8 @@ def run(self, submission_id, language_code, code, time_limit, memory_limit, test max_real_time=int(time_limit) * 2, max_memory=int(memory_limit), test_case_dir=judger_workspace + "test_case/" + test_case_id + "/") - judge_result = {"result": result["accepted"], "info": client.run(), "accepted_answer_time": None} + judge_result = {"result": result["accepted"], "info": client.run(), + "accepted_answer_time": None, "server": host_name} for item in judge_result["info"]: if item["result"]: @@ -56,6 +58,6 @@ def run(self, submission_id, language_code, code, time_limit, memory_limit, test judge_result["accepted_answer_time"] = l[-1]["cpu_time"] return {"code": 0, "data": judge_result} except Exception as e: - return {"code": 2, "data": str(e)} + return {"code": 2, "data": {"error": str(e), "server": host_name}} finally: shutil.rmtree(judge_base_path, ignore_errors=True) \ No newline at end of file From 3311a4c8990faeab67241de2a8ab01d5a8f29a58 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 29 Nov 2015 21:29:26 +0800 Subject: [PATCH 04/64] =?UTF-8?q?rpc=20=E9=80=9A=E4=BF=A1=E5=92=8C?= =?UTF-8?q?=E5=88=A4=E9=A2=98=E5=88=9D=E6=AD=A5=E6=B5=8B=E8=AF=95=E9=80=9A?= =?UTF-8?q?=E8=BF=87=EF=BC=9B=E5=88=A4=E9=A2=98=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E4=BE=9D=E8=B5=96=20redis=20=E5=92=8C=20mysq?= =?UTF-8?q?l=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/models.py | 2 +- judge/language.py | 8 ++++---- judge/runner.py | 1 + judge_dispatcher/judge.py | 16 ---------------- judge_dispatcher/models.py | 2 +- judge_dispatcher/settings.py | 9 --------- judge_dispatcher/tasks.py | 34 ++++++++++++++++++++++++++++++++++ monitor/views.py | 6 +++--- oj/__init__.py | 7 ++++++- oj/celery.py | 17 +++++++++++++++++ oj/local_settings.py | 5 +++++ oj/server_settings.py | 5 +++++ oj/settings.py | 12 ++++++++++++ submission/models.py | 2 +- submission/views.py | 12 ++++++------ 15 files changed, 96 insertions(+), 42 deletions(-) delete mode 100644 judge_dispatcher/judge.py delete mode 100644 judge_dispatcher/settings.py create mode 100644 judge_dispatcher/tasks.py create mode 100644 oj/celery.py diff --git a/contest/models.py b/contest/models.py index 2213f43ea..4e3631ba5 100644 --- a/contest/models.py +++ b/contest/models.py @@ -7,7 +7,7 @@ from group.models import Group from utils.models import RichTextField from jsonfield import JSONField -from judge.judger.result import result +from judge.result import result GROUP_CONTEST = 0 diff --git a/judge/language.py b/judge/language.py index c7a14eb48..e6406566c 100644 --- a/judge/language.py +++ b/judge/language.py @@ -7,16 +7,16 @@ "src_name": "main.c", "code": 1, "syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k", - "compile_command": "gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main", - "execute_command": "{exe_path}main" + "compile_command": "gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}/main", + "execute_command": "{exe_path}/main" }, 2: { "name": "cpp", "src_name": "main.cpp", "code": 2, "syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k", - "compile_command": "g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main", - "execute_command": "{exe_path}main" + "compile_command": "g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}/main", + "execute_command": "{exe_path}/main" }, 3: { "name": "java", diff --git a/judge/runner.py b/judge/runner.py index 4b5349e4f..9eb78b0fd 100644 --- a/judge/runner.py +++ b/judge/runner.py @@ -21,6 +21,7 @@ def run(self, submission_id, language_code, code, time_limit, memory_limit, test try: os.mkdir(judge_base_path) + os.chmod(judge_base_path, 0777) # 将代码写入文件 src_path = os.path.join(judge_base_path, language["src_name"]) diff --git a/judge_dispatcher/judge.py b/judge_dispatcher/judge.py deleted file mode 100644 index 8e4e1dd86..000000000 --- a/judge_dispatcher/judge.py +++ /dev/null @@ -1,16 +0,0 @@ -# coding=utf-8 -import socket -import redis - -from .rpc_client import TimeoutServerProxy -from .settings import redis_config -from .models import JudgeServer - - -class JudgeDispatcher(object): - def __init__(self): - self.redis = redis.StrictRedis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) - - def judge(self): - pass - diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 29f522679..67401c2bc 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -3,7 +3,7 @@ class JudgeServer(models.Model): - ip = models.IPAddressField() + ip = models.GenericIPAddressField() port = models.IntegerField() # 这个服务器最大可能运行的判题实例数量 max_instance_number = models.IntegerField() diff --git a/judge_dispatcher/settings.py b/judge_dispatcher/settings.py deleted file mode 100644 index 332cefe8e..000000000 --- a/judge_dispatcher/settings.py +++ /dev/null @@ -1,9 +0,0 @@ -# coding=utf-8 -import os - - -redis_config = { - "host": os.environ.get("REDIS_PORT_6379_TCP_ADDR"), - "port": 6379, - "db": 0 -} \ No newline at end of file diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py new file mode 100644 index 000000000..b5bfcd4a2 --- /dev/null +++ b/judge_dispatcher/tasks.py @@ -0,0 +1,34 @@ +# coding=utf-8 +import json + +from celery import shared_task +from rpc_client import TimeoutServerProxy + +from judge.result import result +from submission.models import Submission + + +@shared_task +def create_judge_task(submission_id, code, language_code, time_limit, memory_limit, test_case_id): + submission = Submission.objects.get(id=submission_id) + try: + s = TimeoutServerProxy('http://121.42.198.156:8080', timeout=20) + data = s.run(submission_id, language_code, code, time_limit, memory_limit, test_case_id) + print data + # 编译错误 + if data["code"] == 1: + submission.result = result["compile_error"] + submission.info = data["data"]["error"] + # system error + elif data["code"] == 2: + submission.result = result["system_error"] + submission.info = data["data"]["error"] + elif data["code"] == 0: + submission.result = data["data"]["result"] + submission.info = json.dumps(data["data"]["info"]) + submission.accepted_answer_time = data["data"]["accepted_answer_time"] + except Exception as e: + submission.result = result["system_error"] + submission.info = str(e) + finally: + submission.save() diff --git a/monitor/views.py b/monitor/views.py index 15c62b4c7..f502579fa 100644 --- a/monitor/views.py +++ b/monitor/views.py @@ -2,15 +2,15 @@ import redis import datetime from rest_framework.views import APIView -from judge.judger.result import result -from judge.judger_controller.settings import redis_config +from judge.result import result +from django.conf import settings from utils.shortcuts import success_response from submission.models import Submission class QueueLengthMonitorAPIView(APIView): def get(self, request): - r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) + r = redis.Redis(host=settings.redis_config["host"], port=settings.redis_config["port"], db=settings.redis_config["db"]) waiting_number = r.get("judge_queue_length") if waiting_number is None: waiting_number = 0 diff --git a/oj/__init__.py b/oj/__init__.py index c19c07943..d22a84608 100644 --- a/oj/__init__.py +++ b/oj/__init__.py @@ -6,4 +6,9 @@ \___/ |_| |_||_||_||_| |_| \___| \___/ \__,_| \__,_| \__, | \___| |_.__/ \__, | \__, | \__,_| \__,_| |___/ |___/ |_| https://github.com/QingdaoU/OnlineJudge -""" \ No newline at end of file +""" +from __future__ import absolute_import + +# This will make sure the app is always imported when +# Django starts so that shared_task will use this app. +from .celery import app as celery_app diff --git a/oj/celery.py b/oj/celery.py new file mode 100644 index 000000000..2f53c0ca8 --- /dev/null +++ b/oj/celery.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import + +import os + +from celery import Celery + +# set the default Django settings module for the 'celery' program. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oj.settings') + +from django.conf import settings + +app = Celery('oj') + +# Using a string here means the worker will not have to +# pickle the object when using Windows. +app.config_from_object('django.conf:settings') +app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) \ No newline at end of file diff --git a/oj/local_settings.py b/oj/local_settings.py index a08ae7e2d..965fd6b82 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -22,6 +22,11 @@ "db": 1 } +# for celery +REDIS_HOST = "localhost" +REDIS_PORT = 6379 +REDIS_DB = 0 + DEBUG = True ALLOWED_HOSTS = [] diff --git a/oj/server_settings.py b/oj/server_settings.py index bba27c6f7..f8942a927 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -31,6 +31,11 @@ "db": 1 } +# for celery +REDIS_HOST = os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1") +REDIS_PORT = 6379 +REDIS_DB = 0 + DEBUG = False ALLOWED_HOSTS = ['*'] diff --git a/oj/settings.py b/oj/settings.py index 83d49ef7a..13fb8f9a0 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -22,6 +22,15 @@ elif ENV == "server": from .server_settings import * +import djcelery +djcelery.setup_loader() + +BROKER_BACKEND = "redis" +CELERY_ACCEPT_CONTENT = ['json'] +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' + + BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -51,9 +60,12 @@ 'mq', 'contest', 'mail', + 'judge', + 'judge_dispatcher', 'django_extensions', 'rest_framework', + 'djcelery', ) if DEBUG: diff --git a/submission/models.py b/submission/models.py index b28bd5ab6..660b6d834 100644 --- a/submission/models.py +++ b/submission/models.py @@ -1,7 +1,7 @@ # coding=utf-8 from django.db import models from utils.shortcuts import rand_str -from judge.judger.result import result +from judge.result import result class Submission(models.Model): diff --git a/submission/views.py b/submission/views.py index 1f2acb164..94043cf42 100644 --- a/submission/views.py +++ b/submission/views.py @@ -7,7 +7,7 @@ from django.core.paginator import Paginator from rest_framework.views import APIView -from judge.judger_controller.tasks import judge +from judge_dispatcher.tasks import create_judge_task from account.decorators import login_required, super_admin_required from account.models import SUPER_ADMIN, User from problem.models import Problem @@ -23,8 +23,8 @@ logger = logging.getLogger("app_info") -def _judge(submission_id, time_limit, memory_limit, test_case_id): - judge.delay(submission_id, time_limit, memory_limit, test_case_id) +def _judge(submission_id, code, language_code, time_limit, memory_limit, test_case_id): + create_judge_task.delay(submission_id, code, language_code, time_limit, memory_limit, test_case_id) get_cache_redis().incr("judge_queue_length") @@ -49,7 +49,7 @@ def post(self, request): problem_id=problem.id) try: - _judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") @@ -94,7 +94,7 @@ def post(self, request): code=data["code"], problem_id=problem.id) try: - _judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") @@ -279,7 +279,7 @@ def post(self, request): except Problem.DoesNotExist: return error_response(u"题目不存在") try: - _judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") From 89ceca862973d69165628c3d12df380658e92ef6 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 29 Nov 2015 22:02:46 +0800 Subject: [PATCH 05/64] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BA=86=20mq=20?= =?UTF-8?q?=E7=9A=84=20app=EF=BC=8C=E5=B0=86=E4=BB=A3=E7=A0=81=E7=A7=BB?= =?UTF-8?q?=E5=85=A5=20rpc=20=E9=80=9A=E4=BF=A1=E7=9A=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=B8=AD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/tasks.py | 78 +++++++++++++++++++++++++++- mq/__init__.py | 1 - mq/models.py | 1 - mq/scripts/__init__.py | 1 - mq/scripts/mq.py | 104 -------------------------------------- oj/settings.py | 1 - 6 files changed, 77 insertions(+), 109 deletions(-) delete mode 100644 mq/__init__.py delete mode 100644 mq/models.py delete mode 100644 mq/scripts/__init__.py delete mode 100644 mq/scripts/mq.py diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index b5bfcd4a2..23670e8b3 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -1,11 +1,20 @@ # coding=utf-8 import json +import logging + +from django.db import transaction from celery import shared_task from rpc_client import TimeoutServerProxy from judge.result import result +from contest.models import ContestProblem, ContestRank, Contest, CONTEST_UNDERWAY +from problem.models import Problem from submission.models import Submission +from account.models import User +from utils.cache import get_cache_redis + +logger = logging.getLogger("app_info") @shared_task @@ -14,7 +23,6 @@ def create_judge_task(submission_id, code, language_code, time_limit, memory_lim try: s = TimeoutServerProxy('http://121.42.198.156:8080', timeout=20) data = s.run(submission_id, language_code, code, time_limit, memory_limit, test_case_id) - print data # 编译错误 if data["code"] == 1: submission.result = result["compile_error"] @@ -32,3 +40,71 @@ def create_judge_task(submission_id, code, language_code, time_limit, memory_lim submission.info = str(e) finally: submission.save() + + # 更新该用户的解题状态用 + try: + user = User.objects.get(pk=submission.user_id) + except User.DoesNotExist: + logger.warning("Submission user does not exist, submission_id: " + submission_id) + return + + if not submission.contest_id: + try: + problem = Problem.objects.get(id=submission.problem_id) + except Problem.DoesNotExist: + logger.warning("Submission problem does not exist, submission_id: " + submission_id) + return + + problems_status = user.problems_status + + # 更新普通题目的计数器 + problem.add_submission_number() + if "problems" not in problems_status: + problems_status["problems"] = {} + if submission.result == result["accepted"]: + problem.add_ac_number() + problems_status["problems"][str(problem.id)] = 1 + else: + problems_status["problems"][str(problem.id)] = 2 + user.problems_status = problems_status + user.save() + # 普通题目的话,到这里就结束了 + return + + # 能运行到这里的都是比赛题目 + try: + contest = Contest.objects.get(id=submission.contest_id) + if contest.status != CONTEST_UNDERWAY: + logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + submission_id) + return + contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id) + except Contest.DoesNotExist: + logger.warning("Submission contest does not exist, submission_id: " + submission_id) + return + except ContestProblem.DoesNotExist: + logger.warning("Submission problem does not exist, submission_id: " + submission_id) + return + + # 如果比赛现在不是封榜状态,删除比赛的排名缓存 + if contest.real_time_rank: + get_cache_redis().delete(str(contest.id) + "_rank_cache") + + with transaction.atomic(): + try: + contest_rank = ContestRank.objects.get(contest=contest, user=user) + contest_rank.update_rank(submission) + except ContestRank.DoesNotExist: + ContestRank.objects.create(contest=contest, user=user).update_rank(submission) + + problems_status = user.problems_status + + contest_problem.add_submission_number() + if "contest_problems" not in problems_status: + problems_status["contest_problems"] = {} + if submission.result == result["accepted"]: + contest_problem.add_ac_number() + problems_status["contest_problems"][str(contest_problem.id)] = 1 + else: + problems_status["contest_problems"][str(contest_problem.id)] = 0 + user.problems_status = problems_status + user.save() diff --git a/mq/__init__.py b/mq/__init__.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mq/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mq/models.py b/mq/models.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mq/models.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mq/scripts/__init__.py b/mq/scripts/__init__.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mq/scripts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mq/scripts/mq.py b/mq/scripts/mq.py deleted file mode 100644 index a3b15e7ed..000000000 --- a/mq/scripts/mq.py +++ /dev/null @@ -1,104 +0,0 @@ -# coding=utf-8 -import logging - -import redis - -from django.db import transaction - -from judge.judger_controller.settings import redis_config -from judge.judger.result import result -from submission.models import Submission -from problem.models import Problem -from utils.cache import get_cache_redis -from contest.models import ContestProblem, Contest, CONTEST_UNDERWAY, ContestRank -from account.models import User - -logger = logging.getLogger("app_info") - - -class MessageQueue(object): - def __init__(self): - self.conn = redis.StrictRedis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) - self.queue = 'queue' - - def listen_task(self): - while True: - submission_id = self.conn.blpop(self.queue, 0)[1] - logger.debug("receive submission_id: " + submission_id) - - try: - submission = Submission.objects.get(id=submission_id) - except Submission.DoesNotExist: - logger.warning("Submission does not exist, submission_id: " + submission_id) - continue - - # 更新该用户的解题状态用 - try: - user = User.objects.get(pk=submission.user_id) - except User.DoesNotExist: - logger.warning("Submission user does not exist, submission_id: " + submission_id) - continue - - if not submission.contest_id: - try: - problem = Problem.objects.get(id=submission.problem_id) - except Problem.DoesNotExist: - logger.warning("Submission problem does not exist, submission_id: " + submission_id) - continue - - problems_status = user.problems_status - - # 更新普通题目的计数器 - problem.add_submission_number() - if "problems" not in problems_status: - problems_status["problems"] = {} - if submission.result == result["accepted"]: - problem.add_ac_number() - problems_status["problems"][str(problem.id)] = 1 - else: - problems_status["problems"][str(problem.id)] = 2 - user.problems_status = problems_status - user.save() - # 普通题目的话,到这里就结束了 - continue - - # 能运行到这里的都是比赛题目 - try: - contest = Contest.objects.get(id=submission.contest_id) - if contest.status != CONTEST_UNDERWAY: - logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + submission_id) - continue - contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id) - except Contest.DoesNotExist: - logger.warning("Submission contest does not exist, submission_id: " + submission_id) - continue - except ContestProblem.DoesNotExist: - logger.warning("Submission problem does not exist, submission_id: " + submission_id) - continue - - # 如果比赛现在不是封榜状态,删除比赛的排名缓存 - if contest.real_time_rank: - get_cache_redis().delete(str(contest.id) + "_rank_cache") - - with transaction.atomic(): - try: - contest_rank = ContestRank.objects.get(contest=contest, user=user) - contest_rank.update_rank(submission) - except ContestRank.DoesNotExist: - ContestRank.objects.create(contest=contest, user=user).update_rank(submission) - - problems_status = user.problems_status - - contest_problem.add_submission_number() - if "contest_problems" not in problems_status: - problems_status["contest_problems"] = {} - if submission.result == result["accepted"]: - contest_problem.add_ac_number() - problems_status["contest_problems"][str(contest_problem.id)] = 1 - else: - problems_status["contest_problems"][str(contest_problem.id)] = 0 - user.problems_status = problems_status - user.save() - -logger.debug("Start message queue") -MessageQueue().listen_task() diff --git a/oj/settings.py b/oj/settings.py index 13fb8f9a0..54fefa71b 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -57,7 +57,6 @@ 'problem', 'admin', 'submission', - 'mq', 'contest', 'mail', 'judge', From f2f124e462410025433fd0b5cfa80bf69a2dfd8b Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 13:22:21 +0800 Subject: [PATCH 06/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8A=A0=E5=B0=8F?= =?UTF-8?q?=E7=BB=84=E8=AF=B7=E6=B1=82=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E6=8A=8Agroup=3D[]=E6=94=B9=E6=88=90group=5F=5Fin=3D[],?= =?UTF-8?q?=E5=90=A6=E5=88=99=E6=97=A0=E6=B3=95=E8=BF=94=E5=9B=9E=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group/views.py b/group/views.py index a4a31236e..23e59ad3d 100644 --- a/group/views.py +++ b/group/views.py @@ -217,7 +217,7 @@ def get(self, request): --- response_serializer: JoinGroupRequestSerializer """ - requests = JoinGroupRequest.objects.filter(group=Group.objects.filter(admin=request.user, visible=True), + requests = JoinGroupRequest.objects.filter(group__in=Group.objects.filter(admin=request.user, visible=True), status=False) return paginate(request, requests, JoinGroupRequestSerializer) From c2597a6647eee6401d5e49851881c78396f5bd91 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 13:26:09 +0800 Subject: [PATCH 07/64] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E5=86=85?= =?UTF-8?q?=E5=AE=B9=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=96=B0=E5=BB=BA=E5=B0=8F?= =?UTF-8?q?=E7=BB=84UI=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=88=B0=E5=B0=8F?= =?UTF-8?q?=E7=BB=84=E8=AF=A6=E7=BB=86=E7=9A=84=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/admin/admin.js | 9 +---- static/src/js/app/admin/group/group.js | 35 +++++++++++++++++--- static/src/js/app/admin/group/groupDetail.js | 1 + static/src/js/app/oj/group/group.js | 3 +- template/src/admin/group/group.html | 29 ++++++++++++++++ template/src/admin/group/group_detail.html | 4 +-- 6 files changed, 66 insertions(+), 15 deletions(-) diff --git a/static/src/js/app/admin/admin.js b/static/src/js/app/admin/admin.js index 72c8fd6b1..2c527de7f 100644 --- a/static/src/js/app/admin/admin.js +++ b/static/src/js/app/admin/admin.js @@ -103,14 +103,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($, } }); - vm.$watch("showGroupDetailPage", function (groupId) { - vm.groupId = groupId; - vm.template_url = "template/group/group_detail.html"; - }); - - vm.$watch("showGroupListPage", function () { - vm.template_url = "template/group/group.html"; - }); + avalon.scan(); diff --git a/static/src/js/app/admin/group/group.js b/static/src/js/app/admin/group/group.js index 425e4bbf6..f97e809c2 100644 --- a/static/src/js/app/admin/group/group.js +++ b/static/src/js/app/admin/group/group.js @@ -1,7 +1,30 @@ -require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) { +require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) { avalon.ready(function () { - //avalon.vmodels.group = null; + $('#add-group-form').validator().on('submit', function (e) { + if (!e.isDefaultPrevented()) { + var name = vm.name; + var description = vm.description; + var join_group_setting = vm.group_type; + $.ajax({ + beforeSend: csrfTokenHeader, + url: "/api/admin/group/", + method: "post", + data: {name: name, description: description, join_group_setting: join_group_setting}, + dataType: "json", + success: function (data) { + if (!data.code) { + getPageData(1); + bsAlert("添加成功"); + } + else { + bsAlert(data.data); + } + } + }); + return false; + } + }) if (avalon.vmodels.group) { var vm = avalon.vmodels.group; } @@ -16,7 +39,9 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT page: 1, // 当前页数 totalPage: 1, // 总页数 keyword: "", - + name: "", + description: "", + group_type: 0, getNext: function () { if (!vm.nextPage) return; @@ -42,8 +67,10 @@ require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfT getGroupSettingString: function (setting) { return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting] }, + showGroupDetailPage: function (groupId) { - vm.$fire("up!showGroupDetailPage", groupId); + avalon.vmodels.admin.groupId = groupId; + avalon.vmodels.admin.template_url = "template/group/group_detail.html"; } }); } diff --git a/static/src/js/app/admin/group/groupDetail.js b/static/src/js/app/admin/group/groupDetail.js index de4a0ff57..7b7e3f388 100644 --- a/static/src/js/app/admin/group/groupDetail.js +++ b/static/src/js/app/admin/group/groupDetail.js @@ -53,6 +53,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, }) }, showGroupListPage: function () { + avalon.vmodels.admin.template_url = "template/group/group.html"; vm.$fire("up!showGroupListPage"); } }); diff --git a/static/src/js/app/oj/group/group.js b/static/src/js/app/oj/group/group.js index d9371427e..66bb73357 100644 --- a/static/src/js/app/oj/group/group.js +++ b/static/src/js/app/oj/group/group.js @@ -3,9 +3,10 @@ require(["jquery", "csrfToken", "bsAlert"], function ($, csrfTokenHeader, bsAler var message; if ($("#applyMessage").length) { message = $("#applyMessage").val(); - if (!message) + if (!message) { bsAlert("提交失败,请填写申请信息!"); return false; + } } var groupId = window.location.pathname.split("/")[2]; diff --git a/template/src/admin/group/group.html b/template/src/admin/group/group.html index 84614c9bc..3dcb7eaab 100644 --- a/template/src/admin/group/group.html +++ b/template/src/admin/group/group.html @@ -38,6 +38,35 @@

小组管理

+

创建小组

+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ + 允许任何人加入 + 提交请求后管理员审核 + 不允许任何人加入 + +
+ +
+
\ No newline at end of file diff --git a/template/src/admin/group/group_detail.html b/template/src/admin/group/group_detail.html index b75f0efae..a6e0a3b0b 100644 --- a/template/src/admin/group/group_detail.html +++ b/template/src/admin/group/group_detail.html @@ -5,7 +5,7 @@ aria-hidden="true">← 返回 -

小组成员管理

+

小组成员管理

@@ -31,7 +31,7 @@

小组成员管理

-

修改小组信息

+

修改小组信息

From 42a289d656f30be0de725f27536d4155c8824a23 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 13:26:51 +0800 Subject: [PATCH 08/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=80=E7=82=B9=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/group/group.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/template/src/oj/group/group.html b/template/src/oj/group/group.html index c860fdf89..3d9fa23c7 100644 --- a/template/src/oj/group/group.html +++ b/template/src/oj/group/group.html @@ -35,11 +35,7 @@

{{ group.name }}

{% endif %}
- +
From ddb609ae6bd8c53d7d90194bb3ada567d586db72 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 15:46:54 +0800 Subject: [PATCH 09/64] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E6=9C=89?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E7=9A=84=E5=B0=8F=E7=BB=84=E8=B5=9B=E7=9A=84?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/decorators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contest/decorators.py b/contest/decorators.py index 01297f675..63884119c 100644 --- a/contest/decorators.py +++ b/contest/decorators.py @@ -9,7 +9,7 @@ from utils.shortcuts import error_response, error_page from account.models import SUPER_ADMIN -from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, +from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY) @@ -66,7 +66,7 @@ def _check_user_contest_permission(*args, **kwargs): return error_page(request, u"比赛不存在") # 有密码的公开赛 - if contest.contest_type == PASSWORD_PROTECTED_CONTEST: + if contest.contest_type == PASSWORD_PROTECTED_CONTEST or contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST: # 没有输入过密码 if contest.id not in request.session.get("contests", []): if request.is_ajax(): From e6af2734adfd387f5ef6c5eacc0c7c2e600b0edc Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 15:47:25 +0800 Subject: [PATCH 10/64] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E6=AF=94=E8=B5=9B=E7=B1=BB=E5=9E=8B=E2=80=94=E2=80=94=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=9C=89=E5=AF=86=E7=A0=81=E7=9A=84=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E8=B5=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/contest/models.py b/contest/models.py index 2213f43ea..51f5ea505 100644 --- a/contest/models.py +++ b/contest/models.py @@ -13,6 +13,7 @@ GROUP_CONTEST = 0 PUBLIC_CONTEST = 1 PASSWORD_PROTECTED_CONTEST = 2 +PASSWORD_PROTECTED_GROUP_CONTEST = 3 CONTEST_NOT_START = 1 CONTEST_ENDED = -1 From f7f2a327ea21e99dd1a55f5f4cd272da4200b687 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 15:48:02 +0800 Subject: [PATCH 11/64] =?UTF-8?q?=E5=AF=B9=E6=96=B0=E7=9A=84=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E7=B1=BB=E5=9E=8B=EF=BC=8C=E6=9C=89=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E5=B0=8F=E7=BB=84=E8=B5=9B=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contest/views.py b/contest/views.py index 87378db5f..be6630e53 100644 --- a/contest/views.py +++ b/contest/views.py @@ -23,7 +23,7 @@ from problem.models import Problem from .models import (Contest, ContestProblem, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank) -from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST +from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST from .decorators import check_user_contest_permission from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer, CreateContestProblemSerializer, ContestProblemSerializer, @@ -50,11 +50,11 @@ def post(self, request): if request.user.admin_type != SUPER_ADMIN: return error_response(u"只有超级管理员才可创建公开赛") - if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: + if data["contest_type"] in [PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]: if not data["password"]: - return error_response(u"此比赛为有密码的公开赛,密码不可为空") + return error_response(u"此比赛为有密码的比赛,密码不可为空") # 没有密码的公开赛 没有密码的小组赛 - elif data["contest_type"] == GROUP_CONTEST: + if data["contest_type"] == GROUP_CONTEST or data["contest_type"] == PASSWORD_PROTECTED_GROUP_CONTEST: if request.user.admin_type == SUPER_ADMIN: groups = Group.objects.filter(id__in=data["groups"]) else: @@ -107,7 +107,7 @@ def put(self, request): if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: if not data["password"]: return error_response(u"此比赛为有密码的公开赛,密码不可为空") - elif data["contest_type"] == GROUP_CONTEST: + elif data["contest_type"] == GROUP_CONTEST or data["contest_type"] == PASSWORD_PROTECTED_GROUP_CONTEST: if request.user.admin_type == SUPER_ADMIN: groups = Group.objects.filter(id__in=data["groups"]) else: From bbf3b42edc24d1b5f37f528bd222bd4230873021 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 15:49:54 +0800 Subject: [PATCH 12/64] =?UTF-8?q?=E5=AF=B9=E5=90=8E=E5=8F=B0=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E7=9A=84=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E5=AF=B9=E6=9C=89=E5=AF=86=E7=A0=81=E7=9A=84?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E8=B5=9B=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/admin/contest/addContest.js | 4 ++++ .../src/js/app/admin/contest/editContest.js | 6 +++++- template/src/admin/contest/add_contest.html | 20 +++++++++++++------ template/src/admin/contest/edit_contest.html | 20 +++++++++++++------ 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/static/src/js/app/admin/contest/addContest.js b/static/src/js/app/admin/contest/addContest.js index e84f6b08d..0fd6f9ff1 100644 --- a/static/src/js/app/admin/contest/addContest.js +++ b/static/src/js/app/admin/contest/addContest.js @@ -22,6 +22,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date selectedGroups.push(vm.allGroups[i].id); } } + if (vm.password) { + ajaxData.password = vm.password; + ajaxData.contest_type = 3; + } ajaxData.groups = selectedGroups; } else { diff --git a/static/src/js/app/admin/contest/editContest.js b/static/src/js/app/admin/contest/editContest.js index 67a027c35..a49781776 100644 --- a/static/src/js/app/admin/contest/editContest.js +++ b/static/src/js/app/admin/contest/editContest.js @@ -23,6 +23,10 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date selectedGroups.push(vm.allGroups[i].id); } } + if (vm.password) { + ajaxData.password = vm.password; + ajaxData.contest_type = 3; + } ajaxData.groups = selectedGroups; } else { @@ -131,7 +135,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date vm.startTime = contest.start_time.substring(0, 16).replace("T", " "); vm.endTime = contest.end_time.substring(0, 16).replace("T", " "); vm.password = contest.password; - if (contest.contest_type == 0) { //contest_type == 0, 小组内比赛 + if (contest.contest_type == 0 || contest.contest_type == 3) { //contest_type == 0, 小组内比赛 vm.isGlobal = false; for (var i = 0; i < vm.allGroups.length; i++) { vm.allGroups[i].isSelected = false; diff --git a/template/src/admin/contest/add_contest.html b/template/src/admin/contest/add_contest.html index 010b73ebc..e97331612 100644 --- a/template/src/admin/contest/add_contest.html +++ b/template/src/admin/contest/add_contest.html @@ -46,13 +46,13 @@
@@ -60,10 +60,18 @@
-
- -
- +
+
+ +
+ +
+
+
+ +
+ +
diff --git a/template/src/admin/contest/edit_contest.html b/template/src/admin/contest/edit_contest.html index 08f7c09dd..3e5060362 100644 --- a/template/src/admin/contest/edit_contest.html +++ b/template/src/admin/contest/edit_contest.html @@ -55,13 +55,13 @@
@@ -69,11 +69,19 @@
-
- +
+
+ -
- +
+ +
+
+
+ +
+ +
From 13c74797c418c8ae642f984a42103e8dbc05a957 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 16:03:05 +0800 Subject: [PATCH 13/64] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E9=82=80=E8=AF=B7=E8=B5=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/_contest_header.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template/src/oj/contest/_contest_header.html b/template/src/oj/contest/_contest_header.html index 3fcac4470..2e1fdf3c7 100644 --- a/template/src/oj/contest/_contest_header.html +++ b/template/src/oj/contest/_contest_header.html @@ -21,7 +21,7 @@

{{ contest.title }}

{% ifequal contest.contest_type 0 %} - + {% endifequal %} {% ifequal contest.contest_type 1 %} @@ -29,6 +29,9 @@

{{ contest.title }}

{% ifequal contest.contest_type 2 %}
{% endifequal %} + {% ifequal contest.contest_type 3 %} + + {% endifequal %} From 8ae485a35cd51cdbf2b874ded9ca5981a98b3005 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 16:13:55 +0800 Subject: [PATCH 14/64] =?UTF-8?q?contest=20list=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E9=82=80=E8=AF=B7=E8=B5=9B=E5=92=8C=E7=A7=81?= =?UTF-8?q?=E6=9C=89=E5=B0=8F=E7=BB=84=E8=B5=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/contest/contest_list.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template/src/oj/contest/contest_list.html b/template/src/oj/contest/contest_list.html index 92a59d87f..00fde88bb 100644 --- a/template/src/oj/contest/contest_list.html +++ b/template/src/oj/contest/contest_list.html @@ -37,7 +37,7 @@ {% ifequal item.contest_type 0 %} - + {% endifequal %} {% ifequal item.contest_type 1 %} @@ -45,6 +45,9 @@ {% ifequal item.contest_type 2 %} {% endifequal %} + {% ifequal item.contest_type 3 %} + + {% endifequal %} From 85b2fef22dc07e29119ec4757a660c1b5bd323f7 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 16:19:22 +0800 Subject: [PATCH 15/64] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E9=82=80=E8=AF=B7=E8=B5=9B=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/decorators.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/contest/decorators.py b/contest/decorators.py index 63884119c..ebee48232 100644 --- a/contest/decorators.py +++ b/contest/decorators.py @@ -66,7 +66,7 @@ def _check_user_contest_permission(*args, **kwargs): return error_page(request, u"比赛不存在") # 有密码的公开赛 - if contest.contest_type == PASSWORD_PROTECTED_CONTEST or contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST: + if contest.contest_type == PASSWORD_PROTECTED_CONTEST: # 没有输入过密码 if contest.id not in request.session.get("contests", []): if request.is_ajax(): @@ -83,7 +83,15 @@ def _check_user_contest_permission(*args, **kwargs): else: return render(request, "oj/contest/no_contest_permission.html", {"reason": "group_limited", "show_tab": False, "contest": contest}) - + + if contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST: + if not contest.groups.filter(id__in=request.user.group_set.all()).exists(): + if contest.id not in request.session.get("contests", []): + if request.is_ajax(): + return error_response(u"请先输入密码") + else: + return render(request, "oj/contest/no_contest_permission.html", + {"reason": "password_protect", "show_tab": False, "contest": contest}) # 比赛没有开始 if contest.status == CONTEST_NOT_START: if request.is_ajax(): From 7af2c433c4a62b1b6c260d4fa78fea7e4115c992 Mon Sep 17 00:00:00 2001 From: sxw Date: Sat, 5 Dec 2015 16:29:07 +0800 Subject: [PATCH 16/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/decorators.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contest/decorators.py b/contest/decorators.py index ebee48232..0dad16fde 100644 --- a/contest/decorators.py +++ b/contest/decorators.py @@ -87,11 +87,12 @@ def _check_user_contest_permission(*args, **kwargs): if contest.contest_type == PASSWORD_PROTECTED_GROUP_CONTEST: if not contest.groups.filter(id__in=request.user.group_set.all()).exists(): if contest.id not in request.session.get("contests", []): - if request.is_ajax(): - return error_response(u"请先输入密码") - else: - return render(request, "oj/contest/no_contest_permission.html", - {"reason": "password_protect", "show_tab": False, "contest": contest}) + if request.is_ajax(): + return error_response(u"请先输入密码") + else: + return render(request, "oj/contest/no_contest_permission.html", + {"reason": "password_protect", "show_tab": False, "contest": contest}) + # 比赛没有开始 if contest.status == CONTEST_NOT_START: if request.is_ajax(): From 1381797183caa2db8c13ec328cc4686dc99ab51e Mon Sep 17 00:00:00 2001 From: sxw Date: Sun, 6 Dec 2015 10:23:01 +0800 Subject: [PATCH 17/64] =?UTF-8?q?=E5=90=A7if=20=E3=80=82=E3=80=82=E3=80=82?= =?UTF-8?q?or...=E6=94=B9=E6=88=90=20if=20in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contest/views.py b/contest/views.py index be6630e53..225395587 100644 --- a/contest/views.py +++ b/contest/views.py @@ -107,7 +107,7 @@ def put(self, request): if data["contest_type"] == PASSWORD_PROTECTED_CONTEST: if not data["password"]: return error_response(u"此比赛为有密码的公开赛,密码不可为空") - elif data["contest_type"] == GROUP_CONTEST or data["contest_type"] == PASSWORD_PROTECTED_GROUP_CONTEST: + elif data["contest_type"] in [GROUP_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST]: if request.user.admin_type == SUPER_ADMIN: groups = Group.objects.filter(id__in=data["groups"]) else: From 02a0a123725e43ba4a4c42d419a43dab8e23ba0d Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 6 Dec 2015 18:44:58 +0800 Subject: [PATCH 18/64] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=A4=E9=A2=98?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E6=97=B6=E9=97=B4=E5=92=8C=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E6=97=B6=E9=97=B4=EF=BC=8C=E4=BE=BF=E4=BA=8E=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- submission/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/submission/models.py b/submission/models.py index 660b6d834..a0db4b3d9 100644 --- a/submission/models.py +++ b/submission/models.py @@ -8,6 +8,10 @@ class Submission(models.Model): id = models.CharField(max_length=32, default=rand_str, primary_key=True, db_index=True) user_id = models.IntegerField(db_index=True) create_time = models.DateTimeField(auto_now_add=True) + # 判题开始时间 + judge_start_time = models.IntegerField(blank=True, null=True) + # 判题结束时间 + judge_end_time = models.IntegerField(blank=True, null=True) result = models.IntegerField(default=result["waiting"]) language = models.IntegerField() code = models.TextField() From 7661f99d36c85411124eb348d0556c792830d5ce Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 6 Dec 2015 18:45:21 +0800 Subject: [PATCH 19/64] =?UTF-8?q?=E5=B0=86=E4=BB=A5=E5=89=8D=E7=9A=84=20mq?= =?UTF-8?q?=20=E4=BD=BF=E7=94=A8=E7=B1=BB=E6=94=B9=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/tasks.py | 141 ++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index 23670e8b3..4ad333d3d 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -1,6 +1,7 @@ # coding=utf-8 import json import logging +import time from django.db import transaction @@ -17,94 +18,98 @@ logger = logging.getLogger("app_info") -@shared_task -def create_judge_task(submission_id, code, language_code, time_limit, memory_limit, test_case_id): - submission = Submission.objects.get(id=submission_id) - try: - s = TimeoutServerProxy('http://121.42.198.156:8080', timeout=20) - data = s.run(submission_id, language_code, code, time_limit, memory_limit, test_case_id) - # 编译错误 - if data["code"] == 1: - submission.result = result["compile_error"] - submission.info = data["data"]["error"] - # system error - elif data["code"] == 2: - submission.result = result["system_error"] - submission.info = data["data"]["error"] - elif data["code"] == 0: - submission.result = data["data"]["result"] - submission.info = json.dumps(data["data"]["info"]) - submission.accepted_answer_time = data["data"]["accepted_answer_time"] - except Exception as e: - submission.result = result["system_error"] - submission.info = str(e) - finally: - submission.save() - - # 更新该用户的解题状态用 - try: - user = User.objects.get(pk=submission.user_id) - except User.DoesNotExist: - logger.warning("Submission user does not exist, submission_id: " + submission_id) - return - - if not submission.contest_id: +class JudgeDispatcher(object): + def __init__(self, submission, time_limit, memory_limit, test_case_id): + self.submission = submission + self.time_limit = time_limit + self.memory_limit = memory_limit + self.test_case_id = test_case_id + self.user = User.objects.get(id=submission.user_id) + + def choose_judge_server(self): + pass + + def judge(self): + self.submission.judge_start_time = int(time.time() * 1000) try: - problem = Problem.objects.get(id=submission.problem_id) - except Problem.DoesNotExist: - logger.warning("Submission problem does not exist, submission_id: " + submission_id) - return + judge_server = self.choose_judge_server() - problems_status = user.problems_status + s = TimeoutServerProxy(judge_server.ip + ":" + judge_server.port, timeout=20) + data = s.run(self.submission.id, self.submission.language_code, + self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) + # 编译错误 + if data["code"] == 1: + self.submission.result = result["compile_error"] + self.submission.info = data["data"]["error"] + # system error + elif data["code"] == 2: + self.submission.result = result["system_error"] + self.submission.info = data["data"]["error"] + elif data["code"] == 0: + self.submission.result = data["data"]["result"] + self.submission.info = json.dumps(data["data"]["info"]) + self.submission.accepted_answer_time = data["data"]["accepted_answer_time"] + except Exception as e: + self.submission.result = result["system_error"] + self.submission.info = str(e) + finally: + self.submission.judge_end_time = int(time.time() * 1000) + self.submission.save() + + if self.submission.contest_id: + self.update_contest_problem_status() + else: + self.update_problem_status() + + def update_problem_status(self): + problem = Problem.objects.get(id=self.submission.problem_id) # 更新普通题目的计数器 problem.add_submission_number() + + # 更新用户做题状态 + problems_status = self.user.problems_status if "problems" not in problems_status: problems_status["problems"] = {} - if submission.result == result["accepted"]: + if self.submission.result == result["accepted"]: problem.add_ac_number() problems_status["problems"][str(problem.id)] = 1 else: problems_status["problems"][str(problem.id)] = 2 - user.problems_status = problems_status - user.save() + self.user.problems_status = problems_status + self.user.save() # 普通题目的话,到这里就结束了 - return - # 能运行到这里的都是比赛题目 - try: - contest = Contest.objects.get(id=submission.contest_id) + def update_contest_problem_status(self): + # 能运行到这里的都是比赛题目 + contest = Contest.objects.get(id=self.submission.contest_id) if contest.status != CONTEST_UNDERWAY: - logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + submission_id) + logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + self.submission.id) return - contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id) - except Contest.DoesNotExist: - logger.warning("Submission contest does not exist, submission_id: " + submission_id) - return - except ContestProblem.DoesNotExist: - logger.warning("Submission problem does not exist, submission_id: " + submission_id) - return - - # 如果比赛现在不是封榜状态,删除比赛的排名缓存 - if contest.real_time_rank: - get_cache_redis().delete(str(contest.id) + "_rank_cache") - - with transaction.atomic(): - try: - contest_rank = ContestRank.objects.get(contest=contest, user=user) - contest_rank.update_rank(submission) - except ContestRank.DoesNotExist: - ContestRank.objects.create(contest=contest, user=user).update_rank(submission) - - problems_status = user.problems_status + contest_problem = ContestProblem.objects.get(contest=contest, id=self.submission.problem_id) contest_problem.add_submission_number() + + problems_status = self.user.problems_status if "contest_problems" not in problems_status: problems_status["contest_problems"] = {} - if submission.result == result["accepted"]: + if self.submission.result == result["accepted"]: contest_problem.add_ac_number() problems_status["contest_problems"][str(contest_problem.id)] = 1 else: problems_status["contest_problems"][str(contest_problem.id)] = 0 - user.problems_status = problems_status - user.save() + self.user.problems_status = problems_status + self.user.save() + + self.update_contest_rank(contest) + + def update_contest_rank(self, contest): + if contest.real_time_rank: + get_cache_redis().delete(str(contest.id) + "_rank_cache") + + with transaction.atomic(): + try: + contest_rank = ContestRank.objects.get(contest=contest, user=self.user) + contest_rank.update_rank(self.submission) + except ContestRank.DoesNotExist: + ContestRank.objects.create(contest=contest, user=self.user).update_rank(self.submission) From b542d7c5c512d6b3daff8ac8762d015626b8e668 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 6 Dec 2015 18:45:53 +0800 Subject: [PATCH 20/64] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=A4=E9=A2=98?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E8=AE=A4=E8=AF=81=20token=E5=92=8C?= =?UTF-8?q?=E9=94=81=EF=BC=9B=E5=A2=9E=E5=8A=A0=E5=88=A4=E9=A2=98=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/models.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 67401c2bc..20fbc1b32 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -8,8 +8,19 @@ class JudgeServer(models.Model): # 这个服务器最大可能运行的判题实例数量 max_instance_number = models.IntegerField() left_instance_number = models.IntegerField() + token = models.CharField(max_length=30) + # 进行测试用例同步的时候加锁 + lock = models.BooleanField(default=False) # status 为 false 的时候代表不使用这个服务器 status = models.BooleanField(default=True) class Meta: db_table = "judge_server" + + +class JudgeWaitingQueue(models.Model): + submission_id = models.CharField(max_length=40) + create_time = models.DateTimeField(auto_now_add=True) + + class Meta: + db_table = "judge_waiting_queue" From e85c5b6b4a1c97db5c378378f2d3959ae66520f8 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 16:54:29 +0800 Subject: [PATCH 21/64] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/migrations/0001_initial.py | 41 +++++++++++++++++++ judge_dispatcher/migrations/__init__.py | 0 .../migrations/0007_auto_20151207_1645.py | 24 +++++++++++ 3 files changed, 65 insertions(+) create mode 100644 judge_dispatcher/migrations/0001_initial.py create mode 100644 judge_dispatcher/migrations/__init__.py create mode 100644 submission/migrations/0007_auto_20151207_1645.py diff --git a/judge_dispatcher/migrations/0001_initial.py b/judge_dispatcher/migrations/0001_initial.py new file mode 100644 index 000000000..e85330ed7 --- /dev/null +++ b/judge_dispatcher/migrations/0001_initial.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='JudgeServer', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('ip', models.GenericIPAddressField()), + ('port', models.IntegerField()), + ('max_instance_number', models.IntegerField()), + ('left_instance_number', models.IntegerField()), + ('workload', models.IntegerField(default=0)), + ('token', models.CharField(max_length=30)), + ('lock', models.BooleanField(default=False)), + ('status', models.BooleanField(default=True)), + ], + options={ + 'db_table': 'judge_server', + }, + ), + migrations.CreateModel( + name='JudgeWaitingQueue', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('submission_id', models.CharField(max_length=40)), + ('create_time', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'db_table': 'judge_waiting_queue', + }, + ), + ] diff --git a/judge_dispatcher/migrations/__init__.py b/judge_dispatcher/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/submission/migrations/0007_auto_20151207_1645.py b/submission/migrations/0007_auto_20151207_1645.py new file mode 100644 index 000000000..a053d98c7 --- /dev/null +++ b/submission/migrations/0007_auto_20151207_1645.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('submission', '0006_submission_shared'), + ] + + operations = [ + migrations.AddField( + model_name='submission', + name='judge_end_time', + field=models.IntegerField(null=True, blank=True), + ), + migrations.AddField( + model_name='submission', + name='judge_start_time', + field=models.IntegerField(null=True, blank=True), + ), + ] From df0d69ae31b4c1126cabf69af5b484d8fd569519 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 16:54:49 +0800 Subject: [PATCH 22/64] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=88=A4=E9=A2=98?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/models.py | 6 ++++++ judge_dispatcher/tasks.py | 10 ++++++++-- submission/views.py | 13 ++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 20fbc1b32..68ef60dc4 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -8,12 +8,18 @@ class JudgeServer(models.Model): # 这个服务器最大可能运行的判题实例数量 max_instance_number = models.IntegerField() left_instance_number = models.IntegerField() + workload = models.IntegerField(default=0) token = models.CharField(max_length=30) # 进行测试用例同步的时候加锁 lock = models.BooleanField(default=False) # status 为 false 的时候代表不使用这个服务器 status = models.BooleanField(default=True) + def use_judge_instance(self): + self.left_instance_number -= 1 + self.workload = 100 - int(self.left_instance_number / self.max_instance_number) + self.save() + class Meta: db_table = "judge_server" diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index 4ad333d3d..68e26ce2c 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -5,7 +5,6 @@ from django.db import transaction -from celery import shared_task from rpc_client import TimeoutServerProxy from judge.result import result @@ -14,6 +13,7 @@ from submission.models import Submission from account.models import User from utils.cache import get_cache_redis +from .models import JudgeServer,JudgeWaitingQueue logger = logging.getLogger("app_info") @@ -27,12 +27,18 @@ def __init__(self, submission, time_limit, memory_limit, test_case_id): self.user = User.objects.get(id=submission.user_id) def choose_judge_server(self): - pass + servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload") + if servers.exists(): + return servers[0] def judge(self): self.submission.judge_start_time = int(time.time() * 1000) try: judge_server = self.choose_judge_server() + # 如果没有合适的判题服务器,就放入等待队列中等待判题 + if not judge_server: + JudgeWaitingQueue.objects.create(submission_id=self.submission.id) + return s = TimeoutServerProxy(judge_server.ip + ":" + judge_server.port, timeout=20) data = s.run(self.submission.id, self.submission.language_code, diff --git a/submission/views.py b/submission/views.py index 94043cf42..3a54bc921 100644 --- a/submission/views.py +++ b/submission/views.py @@ -7,7 +7,7 @@ from django.core.paginator import Paginator from rest_framework.views import APIView -from judge_dispatcher.tasks import create_judge_task +from judge_dispatcher.tasks import JudgeDispatcher from account.decorators import login_required, super_admin_required from account.models import SUPER_ADMIN, User from problem.models import Problem @@ -23,9 +23,8 @@ logger = logging.getLogger("app_info") -def _judge(submission_id, code, language_code, time_limit, memory_limit, test_case_id): - create_judge_task.delay(submission_id, code, language_code, time_limit, memory_limit, test_case_id) - get_cache_redis().incr("judge_queue_length") +def _judge(submission, time_limit, memory_limit, test_case_id): + JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge() class SubmissionAPIView(APIView): @@ -49,7 +48,7 @@ def post(self, request): problem_id=problem.id) try: - _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") @@ -94,7 +93,7 @@ def post(self, request): code=data["code"], problem_id=problem.id) try: - _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") @@ -279,7 +278,7 @@ def post(self, request): except Problem.DoesNotExist: return error_response(u"题目不存在") try: - _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id) + _judge(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) except Exception as e: logger.error(e) return error_response(u"提交判题任务失败") From d61dae9be063e843975d8e9cca713663e93e63ec Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 17:18:55 +0800 Subject: [PATCH 23/64] =?UTF-8?q?fix=20typo=EF=BC=8C=E5=BA=94=E8=AF=A5?= =?UTF-8?q?=E6=98=AF=20http=20=E5=BC=80=E5=A4=B4=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/tasks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index 68e26ce2c..9e20cc874 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -40,8 +40,9 @@ def judge(self): JudgeWaitingQueue.objects.create(submission_id=self.submission.id) return - s = TimeoutServerProxy(judge_server.ip + ":" + judge_server.port, timeout=20) - data = s.run(self.submission.id, self.submission.language_code, + s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) + + data = s.run(self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) # 编译错误 if data["code"] == 1: From efee635173c3cb6e6e22b7140675dc38017c3164 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 17:35:03 +0800 Subject: [PATCH 24/64] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=A4=E9=A2=98?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=20token=20=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/runner.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/judge/runner.py b/judge/runner.py index 9eb78b0fd..5ca5c2056 100644 --- a/judge/runner.py +++ b/judge/runner.py @@ -11,14 +11,15 @@ class JudgeInstanceRunner(object): - def __init__(self): - pass - def run(self, submission_id, language_code, code, time_limit, memory_limit, test_case_id): + def run(self, token, submission_id, language_code, code, time_limit, memory_limit, test_case_id): language = languages[language_code] host_name = socket.gethostname() judge_base_path = os.path.join(judger_workspace, "run", submission_id) + if not token or token != os.environ.get("rpc_token"): + return {"code": 2, "data": {"error": "Invalid token", "server": host_name}} + try: os.mkdir(judge_base_path) os.chmod(judge_base_path, 0777) From f1449962e4c450e87a164274020a234385783664 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 17:35:28 +0800 Subject: [PATCH 25/64] =?UTF-8?q?=E5=90=91=E5=88=A4=E9=A2=98=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E4=BC=A0=E9=80=92=E6=8E=88=E6=9D=83=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index 9e20cc874..ba4070786 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -42,7 +42,7 @@ def judge(self): s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) - data = s.run(self.submission.id, self.submission.language, + data = s.run(judge_server.token, self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) # 编译错误 if data["code"] == 1: From 3996647f68ac11843b9483dda75ff024e7877793 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 18:05:44 +0800 Subject: [PATCH 26/64] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20js=20=E7=9A=84?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/build.js | 94 ++++++++++++++++++++++------------------- static/src/js/config.js | 41 +++++++++--------- 2 files changed, 72 insertions(+), 63 deletions(-) diff --git a/static/src/js/build.js b/static/src/js/build.js index beb891e0a..8c8de627d 100644 --- a/static/src/js/build.js +++ b/static/src/js/build.js @@ -57,25 +57,28 @@ problem_2_pack: "app/oj/problem/problem", submissionList_3_pack: "app/admin/problem/submissionList", contestCountdown_4_pack: "app/oj/contest/contestCountdown", - addProblem_5_pack: "app/admin/problem/addProblem", - problem_6_pack: "app/admin/problem/problem", - contestList_7_pack: "app/admin/contest/contestList", - admin_8_pack: "app/admin/admin", - login_9_pack: "app/oj/account/login", - addContest_10_pack: "app/admin/contest/addContest", - contestPassword_11_pack: "app/oj/contest/contestPassword", - changePassword_12_pack: "app/oj/account/changePassword", - monitor_13_pack: "app/admin/monitor/monitor", - editProblem_14_pack: "app/admin/contest/editProblem", - joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList", - group_16_pack: "app/oj/group/group", - contestProblemList_17_pack: "app/admin/contest/contestProblemList", - editProblem_18_pack: "app/admin/problem/editProblem", - register_19_pack: "app/oj/account/register", - groupDetail_20_pack: "app/admin/group/groupDetail", - editContest_21_pack: "app/admin/contest/editContest", - group_22_pack: "app/admin/group/group", - settings_23_pack: "app/oj/account/settings" + avatar_5_pack: "app/oj/account/avatar", + addProblem_6_pack: "app/admin/problem/addProblem", + problem_7_pack: "app/admin/problem/problem", + contestList_8_pack: "app/admin/contest/contestList", + admin_9_pack: "app/admin/admin", + login_10_pack: "app/oj/account/login", + applyResetPassword_11_pack: "app/oj/account/applyResetPassword", + addContest_12_pack: "app/admin/contest/addContest", + contestPassword_13_pack: "app/oj/contest/contestPassword", + changePassword_14_pack: "app/oj/account/changePassword", + monitor_15_pack: "app/admin/monitor/monitor", + editProblem_16_pack: "app/admin/contest/editProblem", + joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList", + group_18_pack: "app/oj/group/group", + contestProblemList_19_pack: "app/admin/contest/contestProblemList", + editProblem_20_pack: "app/admin/problem/editProblem", + register_21_pack: "app/oj/account/register", + groupDetail_22_pack: "app/admin/group/groupDetail", + editContest_23_pack: "app/admin/contest/editContest", + resetPassword_24_pack: "app/oj/account/resetPassword", + group_25_pack: "app/admin/group/group", + settings_26_pack: "app/oj/account/settings" }, shim: { avalon: { @@ -86,12 +89,6 @@ appDir: "../", dir: "../../release/", modules: [ - { - name: "bootstrap", - }, - { - name: "codeMirror" - }, { name: "announcement_0_pack" }, @@ -108,62 +105,71 @@ name: "contestCountdown_4_pack" }, { - name: "addProblem_5_pack" + name: "avatar_5_pack" }, { - name: "problem_6_pack" + name: "addProblem_6_pack" }, { - name: "contestList_7_pack" + name: "problem_7_pack" }, { - name: "admin_8_pack" + name: "contestList_8_pack" }, { - name: "login_9_pack" + name: "admin_9_pack" }, { - name: "addContest_10_pack" + name: "login_10_pack" }, { - name: "contestPassword_11_pack" + name: "applyResetPassword_11_pack" }, { - name: "changePassword_12_pack" + name: "addContest_12_pack" }, { - name: "monitor_13_pack" + name: "contestPassword_13_pack" }, { - name: "editProblem_14_pack" + name: "changePassword_14_pack" }, { - name: "joinGroupRequestList_15_pack" + name: "monitor_15_pack" }, { - name: "group_16_pack" + name: "editProblem_16_pack" }, { - name: "contestProblemList_17_pack" + name: "joinGroupRequestList_17_pack" }, { - name: "editProblem_18_pack" + name: "group_18_pack" }, { - name: "register_19_pack" + name: "contestProblemList_19_pack" }, { - name: "groupDetail_20_pack" + name: "editProblem_20_pack" }, { - name: "editContest_21_pack" + name: "register_21_pack" }, { - name: "group_22_pack" + name: "groupDetail_22_pack" }, { - name: "settings_23_pack" + name: "editContest_23_pack" }, + { + name: "resetPassword_24_pack" + }, + { + name: "group_25_pack" + }, + { + name: "settings_26_pack" + } ], optimizeCss: "standard", }) \ No newline at end of file diff --git a/static/src/js/config.js b/static/src/js/config.js index e2856f654..ee6f52b25 100644 --- a/static/src/js/config.js +++ b/static/src/js/config.js @@ -59,25 +59,28 @@ var require = { problem_2_pack: "app/oj/problem/problem", submissionList_3_pack: "app/admin/problem/submissionList", contestCountdown_4_pack: "app/oj/contest/contestCountdown", - addProblem_5_pack: "app/admin/problem/addProblem", - problem_6_pack: "app/admin/problem/problem", - contestList_7_pack: "app/admin/contest/contestList", - admin_8_pack: "app/admin/admin", - login_9_pack: "app/oj/account/login", - addContest_10_pack: "app/admin/contest/addContest", - contestPassword_11_pack: "app/oj/contest/contestPassword", - changePassword_12_pack: "app/oj/account/changePassword", - monitor_13_pack: "app/admin/monitor/monitor", - editProblem_14_pack: "app/admin/contest/editProblem", - joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList", - group_16_pack: "app/oj/group/group", - contestProblemList_17_pack: "app/admin/contest/contestProblemList", - editProblem_18_pack: "app/admin/problem/editProblem", - register_19_pack: "app/oj/account/register", - groupDetail_20_pack: "app/admin/group/groupDetail", - editContest_21_pack: "app/admin/contest/editContest", - group_22_pack: "app/admin/group/group", - settings_23_pack: "app/oj/account/settings" + avatar_5_pack: "app/oj/account/avatar", + addProblem_6_pack: "app/admin/problem/addProblem", + problem_7_pack: "app/admin/problem/problem", + contestList_8_pack: "app/admin/contest/contestList", + admin_9_pack: "app/admin/admin", + login_10_pack: "app/oj/account/login", + applyResetPassword_11_pack: "app/oj/account/applyResetPassword", + addContest_12_pack: "app/admin/contest/addContest", + contestPassword_13_pack: "app/oj/contest/contestPassword", + changePassword_14_pack: "app/oj/account/changePassword", + monitor_15_pack: "app/admin/monitor/monitor", + editProblem_16_pack: "app/admin/contest/editProblem", + joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList", + group_18_pack: "app/oj/group/group", + contestProblemList_19_pack: "app/admin/contest/contestProblemList", + editProblem_20_pack: "app/admin/problem/editProblem", + register_21_pack: "app/oj/account/register", + groupDetail_22_pack: "app/admin/group/groupDetail", + editContest_23_pack: "app/admin/contest/editContest", + resetPassword_24_pack: "app/oj/account/resetPassword", + group_25_pack: "app/admin/group/group", + settings_26_pack: "app/oj/account/settings", }, shim: { avalon: { From 3dd19cf654728e4ad5f1ff1ba7eb7f384342a3c1 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 19:14:43 +0800 Subject: [PATCH 27/64] =?UTF-8?q?mail=20=E6=8B=86=E5=88=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/views.py | 2 +- mail/__init__.py | 1 - mail/celery.py | 1 - mail/tasks.py | 19 ------------------- oj/settings.py | 7 +++++-- utils/mail.py | 15 +++++++++++++++ 6 files changed, 21 insertions(+), 24 deletions(-) delete mode 100644 mail/__init__.py delete mode 100644 mail/celery.py delete mode 100644 mail/tasks.py create mode 100644 utils/mail.py diff --git a/account/views.py b/account/views.py index 2ba5739c6..d6eb77d52 100644 --- a/account/views.py +++ b/account/views.py @@ -14,7 +14,7 @@ from utils.shortcuts import (serializer_invalid_response, error_response, success_response, error_page, paginate, rand_str) from utils.captcha import Captcha -from mail.tasks import send_email +from utils.mail import send_email from .decorators import login_required from .models import User, UserProfile diff --git a/mail/__init__.py b/mail/__init__.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mail/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mail/celery.py b/mail/celery.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mail/celery.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mail/tasks.py b/mail/tasks.py deleted file mode 100644 index 490472baf..000000000 --- a/mail/tasks.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding=utf-8 -import os -from envelopes import Envelope - -SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com", - "email": "noreply@qduoj.com", - "password": os.environ.get("smtp_password", "111111"), - "tls": False} - - -def send_email(from_name, to_email, to_name, subject, content): - envelope = Envelope(from_addr=(SMTP_CONFIG["email"], from_name), - to_addr=(to_email, to_name), - subject=subject, - html_body=content) - envelope.send(SMTP_CONFIG["smtp_server"], - login=SMTP_CONFIG["email"], - password=SMTP_CONFIG["password"], - tls=SMTP_CONFIG["tls"]) diff --git a/oj/settings.py b/oj/settings.py index ceed0fe53..e20499e20 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -50,7 +50,6 @@ 'submission', 'mq', 'contest', - 'mail', 'django_extensions', 'rest_framework', @@ -118,7 +117,6 @@ LOG_PATH = "log/" - LOGGING = { 'version': 1, 'disable_existing_loggers': True, @@ -186,3 +184,8 @@ WEBSITE_INFO = {"website_name": "qduoj", "website_footer": u"青岛大学信息工程学院 创新实验室 京ICP备15062075号-1", "url": "https://qduoj.com"} + +SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com", + "email": "noreply@qduoj.com", + "password": os.environ.get("smtp_password", "111111"), + "tls": False} diff --git a/utils/mail.py b/utils/mail.py new file mode 100644 index 000000000..5d4e1c3ce --- /dev/null +++ b/utils/mail.py @@ -0,0 +1,15 @@ +# coding=utf-8 +from envelopes import Envelope + +from django.conf import settings + + +def send_email(from_name, to_email, to_name, subject, content): + envelope = Envelope(from_addr=(settings.SMTP_CONFIG["email"], from_name), + to_addr=(to_email, to_name), + subject=subject, + html_body=content) + envelope.send(settings.SMTP_CONFIG["smtp_server"], + login=settings.SMTP_CONFIG["email"], + password=settings.SMTP_CONFIG["password"], + tls=settings.SMTP_CONFIG["tls"]) From 43e8ec2d90a3f14b3da385bf679c3287f837ab71 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 19:15:28 +0800 Subject: [PATCH 28/64] =?UTF-8?q?=E5=88=A0=E9=99=A4=20celery=20=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockerfiles/oj_web_server/requirements.txt | 5 +++-- oj/__init__.py | 5 ----- oj/celery.py | 17 ----------------- oj/local_settings.py | 9 +++++---- oj/server_settings.py | 10 ++++++---- oj/settings.py | 6 +----- runJudge.sh | 1 - 7 files changed, 15 insertions(+), 38 deletions(-) delete mode 100644 oj/celery.py delete mode 100755 runJudge.sh diff --git a/dockerfiles/oj_web_server/requirements.txt b/dockerfiles/oj_web_server/requirements.txt index 7ad8718e1..a0582be32 100644 --- a/dockerfiles/oj_web_server/requirements.txt +++ b/dockerfiles/oj_web_server/requirements.txt @@ -4,11 +4,12 @@ redis django-redis-sessions djangorestframework django-rest-swagger -celery gunicorn coverage django-extensions supervisor pillow jsonfield -Envelopes \ No newline at end of file +Envelopes +rq +django-rq \ No newline at end of file diff --git a/oj/__init__.py b/oj/__init__.py index d22a84608..f4206374b 100644 --- a/oj/__init__.py +++ b/oj/__init__.py @@ -7,8 +7,3 @@ |___/ |___/ |_| https://github.com/QingdaoU/OnlineJudge """ -from __future__ import absolute_import - -# This will make sure the app is always imported when -# Django starts so that shared_task will use this app. -from .celery import app as celery_app diff --git a/oj/celery.py b/oj/celery.py deleted file mode 100644 index 2f53c0ca8..000000000 --- a/oj/celery.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import absolute_import - -import os - -from celery import Celery - -# set the default Django settings module for the 'celery' program. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oj.settings') - -from django.conf import settings - -app = Celery('oj') - -# Using a string here means the worker will not have to -# pickle the object when using Windows. -app.config_from_object('django.conf:settings') -app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) \ No newline at end of file diff --git a/oj/local_settings.py b/oj/local_settings.py index 965fd6b82..82bfe2edd 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -22,10 +22,11 @@ "db": 1 } -# for celery -REDIS_HOST = "localhost" -REDIS_PORT = 6379 -REDIS_DB = 0 +REDIS_QUEUE = { + "host": "127.0.0.1", + "port": 6379, + "db": 2 +} DEBUG = True diff --git a/oj/server_settings.py b/oj/server_settings.py index f8942a927..cd86c16ff 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -31,10 +31,12 @@ "db": 1 } -# for celery -REDIS_HOST = os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1") -REDIS_PORT = 6379 -REDIS_DB = 0 +REDIS_QUEUE = { + "host": os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1"), + "port": 6379, + "db": 2 +} + DEBUG = False diff --git a/oj/settings.py b/oj/settings.py index 54fefa71b..65462e64d 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -22,9 +22,6 @@ elif ENV == "server": from .server_settings import * -import djcelery -djcelery.setup_loader() - BROKER_BACKEND = "redis" CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' @@ -63,8 +60,7 @@ 'judge_dispatcher', 'django_extensions', - 'rest_framework', - 'djcelery', + 'rest_framework' ) if DEBUG: diff --git a/runJudge.sh b/runJudge.sh deleted file mode 100755 index ba25da83a..000000000 --- a/runJudge.sh +++ /dev/null @@ -1 +0,0 @@ -nohup celery -A judge.judger_controller worker -l DEBUG & From bf6a42b5b115565cb9d9d52376cfe8c1c5b2336a Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 20:07:52 +0800 Subject: [PATCH 29/64] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20rq=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/settings.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/oj/settings.py b/oj/settings.py index 65462e64d..02b081695 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -60,7 +60,8 @@ 'judge_dispatcher', 'django_extensions', - 'rest_framework' + 'rest_framework', + 'django_rq', ) if DEBUG: @@ -193,3 +194,18 @@ WEBSITE_INFO = {"website_name": "qduoj", "website_footer": u"青岛大学信息工程学院 创新实验室", "url": "https://qduoj.com"} + +RQ_QUEUES = { + 'judge': { + 'HOST': REDIS_QUEUE["host"], + 'PORT': REDIS_QUEUE["port"], + 'DB': 2, + 'DEFAULT_TIMEOUT': 60, + }, + 'mail': { + 'HOST': REDIS_QUEUE["host"], + 'PORT': REDIS_QUEUE["port"], + 'DB': 3, + 'DEFAULT_TIMEOUT': 60, + } +} \ No newline at end of file From 2f557994574a352699b5a9e51acace717e009b22 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 21:19:55 +0800 Subject: [PATCH 30/64] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20huey=20=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E9=98=9F=E5=88=97=E3=80=82=20ps=20=E7=9C=9F=E6=83=B3?= =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=86=99=E4=B8=80=E4=B8=AA=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E9=98=9F=E5=88=97=EF=BC=8Crq=20=E4=B8=8D=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=20worker=EF=BC=8Ccelery=20=E5=A4=AA=E5=A4=8D=E6=9D=82?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockerfiles/oj_web_server/requirements.txt | 3 +-- oj/settings.py | 22 ++++++++-------------- submission/tasks.py | 9 +++++++++ submission/views.py | 7 +------ 4 files changed, 19 insertions(+), 22 deletions(-) create mode 100644 submission/tasks.py diff --git a/dockerfiles/oj_web_server/requirements.txt b/dockerfiles/oj_web_server/requirements.txt index a0582be32..56676a92d 100644 --- a/dockerfiles/oj_web_server/requirements.txt +++ b/dockerfiles/oj_web_server/requirements.txt @@ -11,5 +11,4 @@ supervisor pillow jsonfield Envelopes -rq -django-rq \ No newline at end of file +huey \ No newline at end of file diff --git a/oj/settings.py b/oj/settings.py index 02b081695..391c8b091 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -61,7 +61,7 @@ 'django_extensions', 'rest_framework', - 'django_rq', + 'huey.djhuey', ) if DEBUG: @@ -195,17 +195,11 @@ "website_footer": u"青岛大学信息工程学院 创新实验室", "url": "https://qduoj.com"} -RQ_QUEUES = { - 'judge': { - 'HOST': REDIS_QUEUE["host"], - 'PORT': REDIS_QUEUE["port"], - 'DB': 2, - 'DEFAULT_TIMEOUT': 60, - }, - 'mail': { - 'HOST': REDIS_QUEUE["host"], - 'PORT': REDIS_QUEUE["port"], - 'DB': 3, - 'DEFAULT_TIMEOUT': 60, - } +HUEY = { + 'backend': 'huey.backends.redis_backend', + 'name': 'task_queue', + 'connection': {'host': REDIS_QUEUE["host"], 'port': REDIS_QUEUE["port"], 'db': REDIS_QUEUE["db"]}, + 'always_eager': False, # Defaults to False when running via manage.py run_huey + # Options to pass into the consumer when running ``manage.py run_huey`` + 'consumer_options': {'workers': 50}, } \ No newline at end of file diff --git a/submission/tasks.py b/submission/tasks.py new file mode 100644 index 000000000..67719c47f --- /dev/null +++ b/submission/tasks.py @@ -0,0 +1,9 @@ +# coding=utf-8 +from huey.djhuey import task + +from judge_dispatcher.tasks import JudgeDispatcher + + +@task() +def _judge(submission, time_limit, memory_limit, test_case_id): + JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge() \ No newline at end of file diff --git a/submission/views.py b/submission/views.py index 3a54bc921..6a16eaf6d 100644 --- a/submission/views.py +++ b/submission/views.py @@ -7,14 +7,13 @@ from django.core.paginator import Paginator from rest_framework.views import APIView -from judge_dispatcher.tasks import JudgeDispatcher from account.decorators import login_required, super_admin_required from account.models import SUPER_ADMIN, User from problem.models import Problem from contest.models import ContestProblem, Contest from contest.decorators import check_user_contest_permission from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate -from utils.cache import get_cache_redis +from .task import _judge from .models import Submission from .serializers import (CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer, SubmissionRejudgeSerializer, @@ -23,10 +22,6 @@ logger = logging.getLogger("app_info") -def _judge(submission, time_limit, memory_limit, test_case_id): - JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge() - - class SubmissionAPIView(APIView): @login_required def post(self, request): From 4ef9f9f01b93446c3c10b4e7529d00fb71c147d6 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 21:39:13 +0800 Subject: [PATCH 31/64] =?UTF-8?q?=E4=B8=BA=E5=BC=82=E6=AD=A5=E9=98=9F?= =?UTF-8?q?=E5=88=97=E4=BF=AE=E6=94=B9=20supervisor=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockerfiles/oj_web_server/supervisord.conf | 2 +- dockerfiles/oj_web_server/{mq.conf => task_queue.conf} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dockerfiles/oj_web_server/{mq.conf => task_queue.conf} (100%) diff --git a/dockerfiles/oj_web_server/supervisord.conf b/dockerfiles/oj_web_server/supervisord.conf index 420b65f4b..dec4bf49d 100644 --- a/dockerfiles/oj_web_server/supervisord.conf +++ b/dockerfiles/oj_web_server/supervisord.conf @@ -23,4 +23,4 @@ serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets. [include] -files=gunicorn.conf mq.conf \ No newline at end of file +files=gunicorn.conf task_queue.conf \ No newline at end of file diff --git a/dockerfiles/oj_web_server/mq.conf b/dockerfiles/oj_web_server/task_queue.conf similarity index 100% rename from dockerfiles/oj_web_server/mq.conf rename to dockerfiles/oj_web_server/task_queue.conf From 6bce16b8530d4c6dfe5606164aba01f49f38e540 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 21:39:58 +0800 Subject: [PATCH 32/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockerfiles/oj_web_server/task_queue.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dockerfiles/oj_web_server/task_queue.conf b/dockerfiles/oj_web_server/task_queue.conf index ae1797c67..39f837e03 100644 --- a/dockerfiles/oj_web_server/task_queue.conf +++ b/dockerfiles/oj_web_server/task_queue.conf @@ -1,12 +1,12 @@ [program:mq] -command=python manage.py runscript mq +command=python manage.py run_huey directory=/code/ user=root numprocs=1 -stdout_logfile=/code/log/mq.log -stderr_logfile=/code/log/mq.log +stdout_logfile=/code/log/task_queue.log +stderr_logfile=/code/log/task_queue.log autostart=true autorestart=true startsecs=5 From 1337b26d504dea52b2a1c84dad36f9a61b2430ff Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 23:20:27 +0800 Subject: [PATCH 33/64] =?UTF-8?q?=E6=AF=8F=E6=AC=A1=E6=9C=89=E5=88=A4?= =?UTF-8?q?=E9=A2=98=E4=BB=BB=E5=8A=A1=E5=AE=8C=E6=88=90=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E5=80=99=EF=BC=8C=E9=80=92=E5=BD=92=E8=B0=83=E7=94=A8=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E5=88=A4=E6=96=AD=E8=BF=98=E6=9C=89=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E7=9A=84=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0002_auto_20151207_2310.py | 32 +++++++++++++++++ judge_dispatcher/models.py | 12 ++++++- judge_dispatcher/tasks.py | 35 ++++++++++++++----- submission/tasks.py | 4 +-- submission/views.py | 2 +- 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 judge_dispatcher/migrations/0002_auto_20151207_2310.py diff --git a/judge_dispatcher/migrations/0002_auto_20151207_2310.py b/judge_dispatcher/migrations/0002_auto_20151207_2310.py new file mode 100644 index 000000000..1597919ce --- /dev/null +++ b/judge_dispatcher/migrations/0002_auto_20151207_2310.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('judge_dispatcher', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='judgewaitingqueue', + name='memory_limit', + field=models.IntegerField(default=1), + preserve_default=False, + ), + migrations.AddField( + model_name='judgewaitingqueue', + name='test_case_id', + field=models.CharField(default=1, max_length=40), + preserve_default=False, + ), + migrations.AddField( + model_name='judgewaitingqueue', + name='time_limit', + field=models.IntegerField(default=1), + preserve_default=False, + ), + ] diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 68ef60dc4..4e75bca90 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -17,7 +17,14 @@ class JudgeServer(models.Model): def use_judge_instance(self): self.left_instance_number -= 1 - self.workload = 100 - int(self.left_instance_number / self.max_instance_number) + self.workload = 100 - int(float(self.left_instance_number) / self.max_instance_number * 100) + print self.left_instance_number, self.workload + self.save() + + def release_judge_instance(self): + self.left_instance_number += 1 + self.workload = 100 - int(float(self.left_instance_number) / self.max_instance_number * 100) + print self.left_instance_number, self.workload self.save() class Meta: @@ -26,6 +33,9 @@ class Meta: class JudgeWaitingQueue(models.Model): submission_id = models.CharField(max_length=40) + time_limit = models.IntegerField() + memory_limit = models.IntegerField() + test_case_id = models.CharField(max_length=40) create_time = models.DateTimeField(auto_now_add=True) class Meta: diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index ba4070786..38d9ef1f4 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -13,7 +13,8 @@ from submission.models import Submission from account.models import User from utils.cache import get_cache_redis -from .models import JudgeServer,JudgeWaitingQueue + +from .models import JudgeServer, JudgeWaitingQueue logger = logging.getLogger("app_info") @@ -25,25 +26,31 @@ def __init__(self, submission, time_limit, memory_limit, test_case_id): self.memory_limit = memory_limit self.test_case_id = test_case_id self.user = User.objects.get(id=submission.user_id) - + def choose_judge_server(self): servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload") if servers.exists(): - return servers[0] - - def judge(self): + server = servers[0] + server.use_judge_instance() + return server + + def judge(self, is_waiting_task=False): self.submission.judge_start_time = int(time.time() * 1000) try: judge_server = self.choose_judge_server() # 如果没有合适的判题服务器,就放入等待队列中等待判题 if not judge_server: - JudgeWaitingQueue.objects.create(submission_id=self.submission.id) + if not is_waiting_task: + JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, + memory_limit=self.memory_limit, test_case_id=self.test_case_id) return s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) data = s.run(judge_server.token, self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) + + judge_server.release_judge_instance() # 编译错误 if data["code"] == 1: self.submission.result = result["compile_error"] @@ -67,7 +74,19 @@ def judge(self): self.update_contest_problem_status() else: self.update_problem_status() - + + if is_waiting_task: + JudgeWaitingQueue.objects.filter(submission_id=self.submission.id).delete() + + waiting_submissions = JudgeWaitingQueue.objects.all() + if waiting_submissions.exists(): + submission = waiting_submissions.first() + # 防止循环依赖 + from submission.tasks import _judge + _judge(Submission.objects.get(id=submission.submission_id), time_limit=submission.time_limit, + memory_limit=submission.memory_limit, test_case_id=submission.test_case_id, + is_waiting_task=True) + def update_problem_status(self): problem = Problem.objects.get(id=self.submission.problem_id) @@ -109,7 +128,7 @@ def update_contest_problem_status(self): self.user.save() self.update_contest_rank(contest) - + def update_contest_rank(self, contest): if contest.real_time_rank: get_cache_redis().delete(str(contest.id) + "_rank_cache") diff --git a/submission/tasks.py b/submission/tasks.py index 67719c47f..25476e36e 100644 --- a/submission/tasks.py +++ b/submission/tasks.py @@ -5,5 +5,5 @@ @task() -def _judge(submission, time_limit, memory_limit, test_case_id): - JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge() \ No newline at end of file +def _judge(submission, time_limit, memory_limit, test_case_id, is_waiting_task=False): + JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge(is_waiting_task) \ No newline at end of file diff --git a/submission/views.py b/submission/views.py index 6a16eaf6d..ccda8acb2 100644 --- a/submission/views.py +++ b/submission/views.py @@ -13,7 +13,7 @@ from contest.models import ContestProblem, Contest from contest.decorators import check_user_contest_permission from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate -from .task import _judge +from .tasks import _judge from .models import Submission from .serializers import (CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer, SubmissionRejudgeSerializer, From 7d358c9e4c4b24930f0667fdfd8726021e84db99 Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 14:31:43 +0800 Subject: [PATCH 34/64] =?UTF-8?q?=E5=9C=A8UserProfile=E4=B8=AD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AD=A6=E5=8F=B7=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0015_userprofile_student_id.py | 20 +++++++++++++++++++ account/models.py | 1 + 2 files changed, 21 insertions(+) create mode 100644 account/migrations/0015_userprofile_student_id.py diff --git a/account/migrations/0015_userprofile_student_id.py b/account/migrations/0015_userprofile_student_id.py new file mode 100644 index 000000000..cb8991bf1 --- /dev/null +++ b/account/migrations/0015_userprofile_student_id.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-08 06:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0014_auto_20151110_1037'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='student_id', + field=models.CharField(blank=True, max_length=15, null=True), + ), + ] diff --git a/account/models.py b/account/models.py index e08ff6c8e..395fc2750 100644 --- a/account/models.py +++ b/account/models.py @@ -70,6 +70,7 @@ class UserProfile(models.Model): problems_status = JSONField(default={}) phone_number = models.CharField(max_length=15, blank=True, null=True) school = models.CharField(max_length=200, blank=True, null=True) + student_id = models.CharField(max_length=15, blank=True, null=True) class Meta: From 2d6be12a2f355fe55a206a761e5974e5d6070f6e Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 14:33:40 +0800 Subject: [PATCH 35/64] =?UTF-8?q?=E9=92=88=E5=AF=B9=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AD=A6=E5=8F=B7=E5=AD=97=E6=AE=B5=E5=AF=B9=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=9A=84=E4=B8=80=E4=BA=9B=E4=BF=AE=E6=94=B9=EF=BC=8C=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=98=AF=E5=AD=A6=E6=A0=A1=E4=B8=BA=E9=9D=92=E5=B2=9B?= =?UTF-8?q?=E5=A4=A7=E5=AD=A6=E5=88=99=E6=98=BE=E7=A4=BA=E5=AD=A6=E5=8F=B7?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=9C=A8user=20settings=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=98=BE=E7=A4=BA=E5=AD=A6=E5=8F=B7=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/serializers.py | 4 +++- account/views.py | 3 ++- static/src/js/app/oj/account/register.js | 14 +++++++++++++- static/src/js/app/oj/account/settings.js | 5 +++-- template/src/oj/account/register.html | 6 +++++- template/src/oj/account/settings.html | 9 ++++++++- 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/account/serializers.py b/account/serializers.py index 0aac07aed..0d92ae7ed 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -25,6 +25,7 @@ class UserRegisterSerializer(serializers.Serializer): password = serializers.CharField(max_length=30, min_length=6) email = serializers.EmailField(max_length=254) captcha = serializers.CharField(max_length=4, min_length=4) + student_id = serializers.CharField(max_length=15, required=False, default=None) class UserChangePasswordSerializer(serializers.Serializer): @@ -74,6 +75,7 @@ class EditUserProfileSerializer(serializers.Serializer): codeforces_username = serializers.CharField(max_length=30, required=False, allow_blank=True, default='') school = serializers.CharField(max_length=200, required=False, allow_blank=True, default='') phone_number = serializers.CharField(max_length=15, required=False, allow_blank=True, default='') + student_id = serializers.CharField(max_length=15, required=False, default="") class UserProfileSerializer(serializers.ModelSerializer): @@ -81,4 +83,4 @@ class UserProfileSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ["avatar", "blog", "mood", "hduoj_username", "bestcoder_username", "codeforces_username", - "rank", "accepted_number", "submissions_number", "problems_status", "phone_number", "school"] + "rank", "accepted_number", "submissions_number", "problems_status", "phone_number", "school", "student_id"] diff --git a/account/views.py b/account/views.py index 2ba5739c6..d1e6b2a6a 100644 --- a/account/views.py +++ b/account/views.py @@ -97,7 +97,7 @@ def post(self, request): email=data["email"]) user.set_password(data["password"]) user.save() - UserProfile.objects.create(user=user, school=data["school"]) + UserProfile.objects.create(user=user, school=data["school"], student_id=data["student_id"]) return success_response(u"注册成功!") else: return serializer_invalid_response(serializer) @@ -262,6 +262,7 @@ def put(self, request): user_profile.codeforces_username = data["codeforces_username"] user_profile.blog = data["blog"] user_profile.school = data["school"] + user_profile.student_id = data["student_id"] user_profile.phone_number = data["phone_number"] user_profile.save() return success_response(u"修改成功") diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index ef23a38c3..0557cfbd5 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -1,16 +1,18 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) { + $("#stu_id").hide(); $('form').validator().on('submit', function (e) { if (!e.isDefaultPrevented()) { var username = $("#username").val(); var realName = $("#real_name").val(); var school = $('#school').val(); + var student_id = $('#student_id').val(); var password = $("#password").val(); var email = $("#email").val(); var captcha = $("#captcha").val(); $.ajax({ beforeSend: csrfTokenHeader, url: "/api/register/", - data: {username: username, school: school, real_name: realName, password: password, email: email, captcha:captcha}, + data: {username: username, school: school, student_id: student_id, real_name: realName, password: password, email: email, captcha:captcha}, dataType: "json", method: "post", success: function (data) { @@ -29,6 +31,16 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c return false; } }); + + $("#school").blur(function () { + if ($("#school").val() == "青岛大学") { + $("#stu_id").show(); + } + if ($("#school").val() == "qdu") { + $("#stu_id").show(); + $("#school").val("青岛大学"); + } + }); function refresh_captcha() { $("#captcha-img")[0].src = "/captcha/?" + Math.random(); $("#captcha")[0].value = ""; diff --git a/static/src/js/app/oj/account/settings.js b/static/src/js/app/oj/account/settings.js index b4538ee54..2c485300b 100644 --- a/static/src/js/app/oj/account/settings.js +++ b/static/src/js/app/oj/account/settings.js @@ -8,7 +8,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c var blog = $("#blog").val(); var mood = $("#mood").val(); var school = $("#school").val(); - + var student_id = $("#student_id").val(); $.ajax({ beforeSend: csrfTokenHeader, url: "/api/account/userprofile/", @@ -19,7 +19,8 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c codeforces_username: codeforces_username, blog: blog, mood: mood, - school: school + school: school, + student_id: student_id }, dataType: "json", method: "put", diff --git a/template/src/oj/account/register.html b/template/src/oj/account/register.html index f3b990b30..504361111 100644 --- a/template/src/oj/account/register.html +++ b/template/src/oj/account/register.html @@ -19,10 +19,14 @@

用户注册

- +
+
+ + +
diff --git a/template/src/oj/account/settings.html b/template/src/oj/account/settings.html index ebfee385a..d15411df4 100644 --- a/template/src/oj/account/settings.html +++ b/template/src/oj/account/settings.html @@ -69,9 +69,16 @@
+
+ + +
+ +
+ value="{% if request.user.userprofile.school %}{{ request.user.userprofile.blog }}{% endif %}">
From 124a402ade3fd37e1e3218c1bce6c463c48e5886 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Dec 2015 14:51:50 +0800 Subject: [PATCH 36/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=AB=9E=E6=80=81?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=AF=BC=E8=87=B4=E7=9A=84=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E5=99=A8=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/models.py | 20 ++++++++++++-------- judge_dispatcher/tasks.py | 27 +++++++++++++++------------ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 4e75bca90..6b2a4dee0 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -16,16 +16,20 @@ class JudgeServer(models.Model): status = models.BooleanField(default=True) def use_judge_instance(self): - self.left_instance_number -= 1 - self.workload = 100 - int(float(self.left_instance_number) / self.max_instance_number * 100) - print self.left_instance_number, self.workload - self.save() + # 因为use 和 release 中间是判题时间,可能这个 model 的数据已经被修改了,所以不能直接使用self.xxx,否则取到的是旧数据 + server = JudgeServer.objects.select_for_update().get(id=self.id) + server.left_instance_number -= 1 + server.workload = 100 - int(float(server.left_instance_number) / server.max_instance_number * 100) + print "\n ---- use", server.left_instance_number, server.workload + server.save() def release_judge_instance(self): - self.left_instance_number += 1 - self.workload = 100 - int(float(self.left_instance_number) / self.max_instance_number * 100) - print self.left_instance_number, self.workload - self.save() + # 使用原子操作 + server = JudgeServer.objects.select_for_update().get(id=self.id) + server.left_instance_number += 1 + server.workload = 100 - int(float(server.left_instance_number) / server.max_instance_number * 100) + print "\n ---- release", server.left_instance_number, server.workload + server.save() class Meta: db_table = "judge_server" diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index 38d9ef1f4..c487eefae 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -26,31 +26,32 @@ def __init__(self, submission, time_limit, memory_limit, test_case_id): self.memory_limit = memory_limit self.test_case_id = test_case_id self.user = User.objects.get(id=submission.user_id) + print "init init" def choose_judge_server(self): servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload") if servers.exists(): - server = servers[0] - server.use_judge_instance() - return server + return servers.first() def judge(self, is_waiting_task=False): self.submission.judge_start_time = int(time.time() * 1000) - try: - judge_server = self.choose_judge_server() - # 如果没有合适的判题服务器,就放入等待队列中等待判题 - if not judge_server: - if not is_waiting_task: - JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, - memory_limit=self.memory_limit, test_case_id=self.test_case_id) - return + judge_server = self.choose_judge_server() + + # 如果没有合适的判题服务器,就放入等待队列中等待判题 + if not judge_server: + if not is_waiting_task: + JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, + memory_limit=self.memory_limit, test_case_id=self.test_case_id) + return + + judge_server.use_judge_instance() + try: s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) data = s.run(judge_server.token, self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) - judge_server.release_judge_instance() # 编译错误 if data["code"] == 1: self.submission.result = result["compile_error"] @@ -67,6 +68,8 @@ def judge(self, is_waiting_task=False): self.submission.result = result["system_error"] self.submission.info = str(e) finally: + judge_server.release_judge_instance() + self.submission.judge_end_time = int(time.time() * 1000) self.submission.save() From e86f9e59d99bd3d9a2a6ec0ca071282954b55d49 Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 16:11:14 +0800 Subject: [PATCH 37/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9settings=E4=B8=AD?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E4=B8=BA=E6=96=B0=E7=89=88=E6=9C=AC=E7=9A=84?= =?UTF-8?q?'zh-hans'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oj/settings.py b/oj/settings.py index 83d49ef7a..f2c3f2408 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -98,7 +98,7 @@ # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ -LANGUAGE_CODE = 'zh-cn' +LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' From 7cd012af4835f81e374a73e055cf4adb4293fa84 Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 16:14:01 +0800 Subject: [PATCH 38/64] =?UTF-8?q?=E7=BB=9F=E4=B8=80userprofile=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=9A=84=E5=A4=84=E7=90=86=E6=96=B9=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E9=83=BD=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E4=B8=BAnone,?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtypo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/account/settings.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/template/src/oj/account/settings.html b/template/src/oj/account/settings.html index d15411df4..f97e66db0 100644 --- a/template/src/oj/account/settings.html +++ b/template/src/oj/account/settings.html @@ -34,7 +34,7 @@ value="{{ request.user.email }}" readonly>
-
@@ -50,35 +50,35 @@
- +
- +
- +
+ value="{% if request.user.userprofile.student_id %}{{ request.user.userprofile.student_id }}{% endif %}">
+ value="{% if request.user.userprofile.blog %}{{ request.user.userprofile.blog }}{% endif %}">
From 4d975b98fb0c7f7a293e065fed54afab2c0f5bd8 Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 16:29:27 +0800 Subject: [PATCH 39/64] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=B8=BB=E9=A1=B5=E9=87=8C=E8=BF=98=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=90=8E=E7=AB=AF=E9=85=8D=E5=A5=97=E7=9A=84submissio?= =?UTF-8?q?n=E9=83=A8=E5=88=86=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=AD=A6?= =?UTF-8?q?=E6=A0=A1=E6=98=BE=E7=A4=BA=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?settings=E9=87=8Ccodeforces=E7=94=A8=E6=88=B7=E5=90=8D=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=BC=96=E8=BE=91=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=8E=9F=E6=9D=A5=E6=98=AFhtml=E9=87=8C=E8=BE=B9=E6=8B=BC?= =?UTF-8?q?=E9=94=99=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/account/settings.html | 4 ++-- template/src/oj/account/user_index.html | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/template/src/oj/account/settings.html b/template/src/oj/account/settings.html index f97e66db0..53560240f 100644 --- a/template/src/oj/account/settings.html +++ b/template/src/oj/account/settings.html @@ -64,8 +64,8 @@
- +
diff --git a/template/src/oj/account/user_index.html b/template/src/oj/account/user_index.html index a829a25d9..9ae7178ea 100644 --- a/template/src/oj/account/user_index.html +++ b/template/src/oj/account/user_index.html @@ -22,6 +22,9 @@

{% if user.userprofile.mood %}

{{ user.userprofile.mood }}

{% endif %} + {% if user.userprofile.school %} +

{{ user.userprofile.school }}

+ {% endif %}
@@ -57,7 +60,7 @@

{% endif %} - +

{{ user.create_time }} @@ -68,7 +71,7 @@

{{ user.userprofile.rank }} Rank

- --> +
{{ user.userprofile.accepted_number }} AC @@ -77,6 +80,7 @@

{{ user.userprofile.submissions_number }} Submissions

+ --> From 8e232a90bd30efdfc969881b145f8d3ce986d25d Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 8 Dec 2015 16:52:47 +0800 Subject: [PATCH 40/64] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/account/register.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index 0557cfbd5..c6780992b 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -12,7 +12,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c $.ajax({ beforeSend: csrfTokenHeader, url: "/api/register/", - data: {username: username, school: school, student_id: student_id, real_name: realName, password: password, email: email, captcha:captcha}, + data: {username: username, school: school, student_id: student_id, real_name: realName, password: password, email: email, captcha: captcha}, dataType: "json", method: "post", success: function (data) { From cb64ece6ee3237129bb7815649cd67b9413c2926 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Dec 2015 19:04:31 +0800 Subject: [PATCH 41/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/tasks.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index c487eefae..f9920e6f1 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -39,9 +39,9 @@ def judge(self, is_waiting_task=False): # 如果没有合适的判题服务器,就放入等待队列中等待判题 if not judge_server: - if not is_waiting_task: - JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, - memory_limit=self.memory_limit, test_case_id=self.test_case_id) + print self.submission.id, "waiting" + JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, + memory_limit=self.memory_limit, test_case_id=self.test_case_id) return judge_server.use_judge_instance() @@ -51,6 +51,7 @@ def judge(self, is_waiting_task=False): data = s.run(judge_server.token, self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) + print self.submission.id, "finished" # 编译错误 if data["code"] == 1: @@ -78,18 +79,18 @@ def judge(self, is_waiting_task=False): else: self.update_problem_status() - if is_waiting_task: - JudgeWaitingQueue.objects.filter(submission_id=self.submission.id).delete() - waiting_submissions = JudgeWaitingQueue.objects.all() if waiting_submissions.exists(): - submission = waiting_submissions.first() # 防止循环依赖 from submission.tasks import _judge - _judge(Submission.objects.get(id=submission.submission_id), time_limit=submission.time_limit, - memory_limit=submission.memory_limit, test_case_id=submission.test_case_id, + waiting_submission = waiting_submissions.first() + print self.submission.id, "left queue" + _judge(Submission.objects.get(id=waiting_submission.submission_id), time_limit=waiting_submission.time_limit, + memory_limit=waiting_submission.memory_limit, test_case_id=waiting_submission.test_case_id, is_waiting_task=True) + waiting_submission.delete() + def update_problem_status(self): problem = Problem.objects.get(id=self.submission.problem_id) From bd5caa8f280792c5719f902c6cd9932d5beb19b6 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Dec 2015 19:04:56 +0800 Subject: [PATCH 42/64] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=9B=E5=88=A0=E9=99=A4=E4=B8=8D=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/models.py | 1 - oj/settings.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/account/models.py b/account/models.py index e08ff6c8e..2988addf0 100644 --- a/account/models.py +++ b/account/models.py @@ -71,6 +71,5 @@ class UserProfile(models.Model): phone_number = models.CharField(max_length=15, blank=True, null=True) school = models.CharField(max_length=200, blank=True, null=True) - class Meta: db_table = "user_profile" diff --git a/oj/settings.py b/oj/settings.py index 391c8b091..153c1af45 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -59,7 +59,6 @@ 'judge', 'judge_dispatcher', - 'django_extensions', 'rest_framework', 'huey.djhuey', ) @@ -106,7 +105,7 @@ # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ -LANGUAGE_CODE = 'zh-cn' +LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' From 3afdc1a58b98b8a22d2f78f9caff2709d292086d Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Dec 2015 22:39:26 +0800 Subject: [PATCH 43/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20MySQL=20=E4=B8=8A?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=88=B3=E5=AD=97=E6=AE=B5=E6=BA=A2=E5=87=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0008_auto_20151208_2106.py | 25 +++++++++++++++++++ submission/models.py | 7 ++++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 submission/migrations/0008_auto_20151208_2106.py diff --git a/submission/migrations/0008_auto_20151208_2106.py b/submission/migrations/0008_auto_20151208_2106.py new file mode 100644 index 000000000..b3a85763c --- /dev/null +++ b/submission/migrations/0008_auto_20151208_2106.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-08 13:06 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('submission', '0007_auto_20151207_1645'), + ] + + operations = [ + migrations.AlterField( + model_name='submission', + name='judge_end_time', + field=models.BigIntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='submission', + name='judge_start_time', + field=models.BigIntegerField(blank=True, null=True), + ), + ] diff --git a/submission/models.py b/submission/models.py index a0db4b3d9..fc1a0708a 100644 --- a/submission/models.py +++ b/submission/models.py @@ -9,9 +9,9 @@ class Submission(models.Model): user_id = models.IntegerField(db_index=True) create_time = models.DateTimeField(auto_now_add=True) # 判题开始时间 - judge_start_time = models.IntegerField(blank=True, null=True) + judge_start_time = models.BigIntegerField(blank=True, null=True) # 判题结束时间 - judge_end_time = models.IntegerField(blank=True, null=True) + judge_end_time = models.BigIntegerField(blank=True, null=True) result = models.IntegerField(default=result["waiting"]) language = models.IntegerField() code = models.TextField() @@ -28,3 +28,6 @@ class Submission(models.Model): class Meta: db_table = "submission" + + def __unicode__(self): + return self.id From 89cb788d0a8fc6a4810491ffa5656f4da9c9349a Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 8 Dec 2015 22:49:05 +0800 Subject: [PATCH 44/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E5=A4=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E6=B2=A1=E6=9C=89=E5=8A=A0=E9=94=81?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E9=AB=98=E5=B9=B6=E5=8F=91=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E7=AB=9E=E6=80=81=E6=9D=A1=E4=BB=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge_dispatcher/models.py | 2 -- judge_dispatcher/tasks.py | 54 ++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/judge_dispatcher/models.py b/judge_dispatcher/models.py index 6b2a4dee0..7ec5af8f5 100644 --- a/judge_dispatcher/models.py +++ b/judge_dispatcher/models.py @@ -20,7 +20,6 @@ def use_judge_instance(self): server = JudgeServer.objects.select_for_update().get(id=self.id) server.left_instance_number -= 1 server.workload = 100 - int(float(server.left_instance_number) / server.max_instance_number * 100) - print "\n ---- use", server.left_instance_number, server.workload server.save() def release_judge_instance(self): @@ -28,7 +27,6 @@ def release_judge_instance(self): server = JudgeServer.objects.select_for_update().get(id=self.id) server.left_instance_number += 1 server.workload = 100 - int(float(server.left_instance_number) / server.max_instance_number * 100) - print "\n ---- release", server.left_instance_number, server.workload server.save() class Meta: diff --git a/judge_dispatcher/tasks.py b/judge_dispatcher/tasks.py index f9920e6f1..244c9074b 100644 --- a/judge_dispatcher/tasks.py +++ b/judge_dispatcher/tasks.py @@ -26,7 +26,6 @@ def __init__(self, submission, time_limit, memory_limit, test_case_id): self.memory_limit = memory_limit self.test_case_id = test_case_id self.user = User.objects.get(id=submission.user_id) - print "init init" def choose_judge_server(self): servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload") @@ -35,24 +34,23 @@ def choose_judge_server(self): def judge(self, is_waiting_task=False): self.submission.judge_start_time = int(time.time() * 1000) - judge_server = self.choose_judge_server() - # 如果没有合适的判题服务器,就放入等待队列中等待判题 - if not judge_server: - print self.submission.id, "waiting" - JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, - memory_limit=self.memory_limit, test_case_id=self.test_case_id) - return + with transaction.atomic(): + judge_server = self.choose_judge_server() - judge_server.use_judge_instance() + # 如果没有合适的判题服务器,就放入等待队列中等待判题 + if not judge_server: + JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, + memory_limit=self.memory_limit, test_case_id=self.test_case_id) + return + + judge_server.use_judge_instance() try: s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) data = s.run(judge_server.token, self.submission.id, self.submission.language, self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) - print self.submission.id, "finished" - # 编译错误 if data["code"] == 1: self.submission.result = result["compile_error"] @@ -69,7 +67,8 @@ def judge(self, is_waiting_task=False): self.submission.result = result["system_error"] self.submission.info = str(e) finally: - judge_server.release_judge_instance() + with transaction.atomic(): + judge_server.release_judge_instance() self.submission.judge_end_time = int(time.time() * 1000) self.submission.save() @@ -79,17 +78,20 @@ def judge(self, is_waiting_task=False): else: self.update_problem_status() - waiting_submissions = JudgeWaitingQueue.objects.all() - if waiting_submissions.exists(): - # 防止循环依赖 - from submission.tasks import _judge - waiting_submission = waiting_submissions.first() - print self.submission.id, "left queue" - _judge(Submission.objects.get(id=waiting_submission.submission_id), time_limit=waiting_submission.time_limit, - memory_limit=waiting_submission.memory_limit, test_case_id=waiting_submission.test_case_id, - is_waiting_task=True) + with transaction.atomic(): + waiting_submissions = JudgeWaitingQueue.objects.select_for_update().all() + if waiting_submissions.exists(): + # 防止循环依赖 + from submission.tasks import _judge + + waiting_submission = waiting_submissions.first() - waiting_submission.delete() + submission = Submission.objects.get(id=waiting_submission.submission_id) + waiting_submission.delete() + + _judge(submission, time_limit=waiting_submission.time_limit, + memory_limit=waiting_submission.memory_limit, test_case_id=waiting_submission.test_case_id, + is_waiting_task=True) def update_problem_status(self): problem = Problem.objects.get(id=self.submission.problem_id) @@ -116,10 +118,12 @@ def update_contest_problem_status(self): if contest.status != CONTEST_UNDERWAY: logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + self.submission.id) return - contest_problem = ContestProblem.objects.get(contest=contest, id=self.submission.problem_id) + with transaction.atomic(): + contest_problem = ContestProblem.objects.select_for_update().get(contest=contest, id=self.submission.problem_id) - contest_problem.add_submission_number() + contest_problem.add_submission_number() + # todo 事务 problems_status = self.user.problems_status if "contest_problems" not in problems_status: problems_status["contest_problems"] = {} @@ -139,7 +143,7 @@ def update_contest_rank(self, contest): with transaction.atomic(): try: - contest_rank = ContestRank.objects.get(contest=contest, user=self.user) + contest_rank = ContestRank.objects.select_for_update().get(contest=contest, user=self.user) contest_rank.update_rank(self.submission) except ContestRank.DoesNotExist: ContestRank.objects.create(contest=contest, user=self.user).update_rank(self.submission) From 350890669118f5c0d0bd5a7c0a1410d2f97845a1 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 09:45:31 +0800 Subject: [PATCH 45/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AD=A6=E6=A0=A1?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E5=92=8C=E8=87=AA=E5=8A=A8=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E9=98=9F=E5=BD=A2=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/account/register.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index c6780992b..d5b9a5433 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -33,10 +33,10 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c }); $("#school").blur(function () { - if ($("#school").val() == "青岛大学") { - $("#stu_id").show(); - } - if ($("#school").val() == "qdu") { + var school = $("#school").val(); + school = $.trim(school).toLowerCase(); + console.log(school); + if (school == "青岛大学" || school == "qdu" || school == "qdu" || school == "青大") { $("#stu_id").show(); $("#school").val("青岛大学"); } From 492e7446b1d43cb703cbd625a952aeab712f2654 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 7 Dec 2015 19:14:43 +0800 Subject: [PATCH 46/64] =?UTF-8?q?mail=20=E6=8B=86=E5=88=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加 js 的压缩配置 修改设置,增加备案号 Squash from 3dd19cf to bfc4123 by virusdefender --- account/views.py | 2 +- mail/__init__.py | 1 - mail/celery.py | 1 - mail/tasks.py | 19 --------- oj/settings.py | 11 +++-- static/src/js/build.js | 94 ++++++++++++++++++++++------------------- static/src/js/config.js | 41 +++++++++--------- utils/mail.py | 15 +++++++ 8 files changed, 95 insertions(+), 89 deletions(-) delete mode 100644 mail/__init__.py delete mode 100644 mail/celery.py delete mode 100644 mail/tasks.py create mode 100644 utils/mail.py diff --git a/account/views.py b/account/views.py index 2ba5739c6..d6eb77d52 100644 --- a/account/views.py +++ b/account/views.py @@ -14,7 +14,7 @@ from utils.shortcuts import (serializer_invalid_response, error_response, success_response, error_page, paginate, rand_str) from utils.captcha import Captcha -from mail.tasks import send_email +from utils.mail import send_email from .decorators import login_required from .models import User, UserProfile diff --git a/mail/__init__.py b/mail/__init__.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mail/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mail/celery.py b/mail/celery.py deleted file mode 100644 index 9bad5790a..000000000 --- a/mail/celery.py +++ /dev/null @@ -1 +0,0 @@ -# coding=utf-8 diff --git a/mail/tasks.py b/mail/tasks.py deleted file mode 100644 index 490472baf..000000000 --- a/mail/tasks.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding=utf-8 -import os -from envelopes import Envelope - -SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com", - "email": "noreply@qduoj.com", - "password": os.environ.get("smtp_password", "111111"), - "tls": False} - - -def send_email(from_name, to_email, to_name, subject, content): - envelope = Envelope(from_addr=(SMTP_CONFIG["email"], from_name), - to_addr=(to_email, to_name), - subject=subject, - html_body=content) - envelope.send(SMTP_CONFIG["smtp_server"], - login=SMTP_CONFIG["email"], - password=SMTP_CONFIG["password"], - tls=SMTP_CONFIG["tls"]) diff --git a/oj/settings.py b/oj/settings.py index 83d49ef7a..e20499e20 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -50,7 +50,6 @@ 'submission', 'mq', 'contest', - 'mail', 'django_extensions', 'rest_framework', @@ -102,7 +101,7 @@ TIME_ZONE = 'Asia/Shanghai' -USE_I18N = True +USE_I18N = False USE_L10N = True @@ -118,7 +117,6 @@ LOG_PATH = "log/" - LOGGING = { 'version': 1, 'disable_existing_loggers': True, @@ -184,5 +182,10 @@ IMAGE_UPLOAD_DIR = os.path.join(BASE_DIR, 'upload/') WEBSITE_INFO = {"website_name": "qduoj", - "website_footer": u"青岛大学信息工程学院 创新实验室", + "website_footer": u"青岛大学信息工程学院 创新实验室 京ICP备15062075号-1", "url": "https://qduoj.com"} + +SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com", + "email": "noreply@qduoj.com", + "password": os.environ.get("smtp_password", "111111"), + "tls": False} diff --git a/static/src/js/build.js b/static/src/js/build.js index beb891e0a..8c8de627d 100644 --- a/static/src/js/build.js +++ b/static/src/js/build.js @@ -57,25 +57,28 @@ problem_2_pack: "app/oj/problem/problem", submissionList_3_pack: "app/admin/problem/submissionList", contestCountdown_4_pack: "app/oj/contest/contestCountdown", - addProblem_5_pack: "app/admin/problem/addProblem", - problem_6_pack: "app/admin/problem/problem", - contestList_7_pack: "app/admin/contest/contestList", - admin_8_pack: "app/admin/admin", - login_9_pack: "app/oj/account/login", - addContest_10_pack: "app/admin/contest/addContest", - contestPassword_11_pack: "app/oj/contest/contestPassword", - changePassword_12_pack: "app/oj/account/changePassword", - monitor_13_pack: "app/admin/monitor/monitor", - editProblem_14_pack: "app/admin/contest/editProblem", - joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList", - group_16_pack: "app/oj/group/group", - contestProblemList_17_pack: "app/admin/contest/contestProblemList", - editProblem_18_pack: "app/admin/problem/editProblem", - register_19_pack: "app/oj/account/register", - groupDetail_20_pack: "app/admin/group/groupDetail", - editContest_21_pack: "app/admin/contest/editContest", - group_22_pack: "app/admin/group/group", - settings_23_pack: "app/oj/account/settings" + avatar_5_pack: "app/oj/account/avatar", + addProblem_6_pack: "app/admin/problem/addProblem", + problem_7_pack: "app/admin/problem/problem", + contestList_8_pack: "app/admin/contest/contestList", + admin_9_pack: "app/admin/admin", + login_10_pack: "app/oj/account/login", + applyResetPassword_11_pack: "app/oj/account/applyResetPassword", + addContest_12_pack: "app/admin/contest/addContest", + contestPassword_13_pack: "app/oj/contest/contestPassword", + changePassword_14_pack: "app/oj/account/changePassword", + monitor_15_pack: "app/admin/monitor/monitor", + editProblem_16_pack: "app/admin/contest/editProblem", + joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList", + group_18_pack: "app/oj/group/group", + contestProblemList_19_pack: "app/admin/contest/contestProblemList", + editProblem_20_pack: "app/admin/problem/editProblem", + register_21_pack: "app/oj/account/register", + groupDetail_22_pack: "app/admin/group/groupDetail", + editContest_23_pack: "app/admin/contest/editContest", + resetPassword_24_pack: "app/oj/account/resetPassword", + group_25_pack: "app/admin/group/group", + settings_26_pack: "app/oj/account/settings" }, shim: { avalon: { @@ -86,12 +89,6 @@ appDir: "../", dir: "../../release/", modules: [ - { - name: "bootstrap", - }, - { - name: "codeMirror" - }, { name: "announcement_0_pack" }, @@ -108,62 +105,71 @@ name: "contestCountdown_4_pack" }, { - name: "addProblem_5_pack" + name: "avatar_5_pack" }, { - name: "problem_6_pack" + name: "addProblem_6_pack" }, { - name: "contestList_7_pack" + name: "problem_7_pack" }, { - name: "admin_8_pack" + name: "contestList_8_pack" }, { - name: "login_9_pack" + name: "admin_9_pack" }, { - name: "addContest_10_pack" + name: "login_10_pack" }, { - name: "contestPassword_11_pack" + name: "applyResetPassword_11_pack" }, { - name: "changePassword_12_pack" + name: "addContest_12_pack" }, { - name: "monitor_13_pack" + name: "contestPassword_13_pack" }, { - name: "editProblem_14_pack" + name: "changePassword_14_pack" }, { - name: "joinGroupRequestList_15_pack" + name: "monitor_15_pack" }, { - name: "group_16_pack" + name: "editProblem_16_pack" }, { - name: "contestProblemList_17_pack" + name: "joinGroupRequestList_17_pack" }, { - name: "editProblem_18_pack" + name: "group_18_pack" }, { - name: "register_19_pack" + name: "contestProblemList_19_pack" }, { - name: "groupDetail_20_pack" + name: "editProblem_20_pack" }, { - name: "editContest_21_pack" + name: "register_21_pack" }, { - name: "group_22_pack" + name: "groupDetail_22_pack" }, { - name: "settings_23_pack" + name: "editContest_23_pack" }, + { + name: "resetPassword_24_pack" + }, + { + name: "group_25_pack" + }, + { + name: "settings_26_pack" + } ], optimizeCss: "standard", }) \ No newline at end of file diff --git a/static/src/js/config.js b/static/src/js/config.js index e2856f654..ee6f52b25 100644 --- a/static/src/js/config.js +++ b/static/src/js/config.js @@ -59,25 +59,28 @@ var require = { problem_2_pack: "app/oj/problem/problem", submissionList_3_pack: "app/admin/problem/submissionList", contestCountdown_4_pack: "app/oj/contest/contestCountdown", - addProblem_5_pack: "app/admin/problem/addProblem", - problem_6_pack: "app/admin/problem/problem", - contestList_7_pack: "app/admin/contest/contestList", - admin_8_pack: "app/admin/admin", - login_9_pack: "app/oj/account/login", - addContest_10_pack: "app/admin/contest/addContest", - contestPassword_11_pack: "app/oj/contest/contestPassword", - changePassword_12_pack: "app/oj/account/changePassword", - monitor_13_pack: "app/admin/monitor/monitor", - editProblem_14_pack: "app/admin/contest/editProblem", - joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList", - group_16_pack: "app/oj/group/group", - contestProblemList_17_pack: "app/admin/contest/contestProblemList", - editProblem_18_pack: "app/admin/problem/editProblem", - register_19_pack: "app/oj/account/register", - groupDetail_20_pack: "app/admin/group/groupDetail", - editContest_21_pack: "app/admin/contest/editContest", - group_22_pack: "app/admin/group/group", - settings_23_pack: "app/oj/account/settings" + avatar_5_pack: "app/oj/account/avatar", + addProblem_6_pack: "app/admin/problem/addProblem", + problem_7_pack: "app/admin/problem/problem", + contestList_8_pack: "app/admin/contest/contestList", + admin_9_pack: "app/admin/admin", + login_10_pack: "app/oj/account/login", + applyResetPassword_11_pack: "app/oj/account/applyResetPassword", + addContest_12_pack: "app/admin/contest/addContest", + contestPassword_13_pack: "app/oj/contest/contestPassword", + changePassword_14_pack: "app/oj/account/changePassword", + monitor_15_pack: "app/admin/monitor/monitor", + editProblem_16_pack: "app/admin/contest/editProblem", + joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList", + group_18_pack: "app/oj/group/group", + contestProblemList_19_pack: "app/admin/contest/contestProblemList", + editProblem_20_pack: "app/admin/problem/editProblem", + register_21_pack: "app/oj/account/register", + groupDetail_22_pack: "app/admin/group/groupDetail", + editContest_23_pack: "app/admin/contest/editContest", + resetPassword_24_pack: "app/oj/account/resetPassword", + group_25_pack: "app/admin/group/group", + settings_26_pack: "app/oj/account/settings", }, shim: { avalon: { diff --git a/utils/mail.py b/utils/mail.py new file mode 100644 index 000000000..5d4e1c3ce --- /dev/null +++ b/utils/mail.py @@ -0,0 +1,15 @@ +# coding=utf-8 +from envelopes import Envelope + +from django.conf import settings + + +def send_email(from_name, to_email, to_name, subject, content): + envelope = Envelope(from_addr=(settings.SMTP_CONFIG["email"], from_name), + to_addr=(to_email, to_name), + subject=subject, + html_body=content) + envelope.send(settings.SMTP_CONFIG["smtp_server"], + login=settings.SMTP_CONFIG["email"], + password=settings.SMTP_CONFIG["password"], + tls=settings.SMTP_CONFIG["tls"]) From 09de27667ddbcc2db501bd6e67e60f58ecfe939a Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 19:48:58 +0800 Subject: [PATCH 47/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9group=E7=9A=84models?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E7=9A=84=E5=A4=9A=E5=AF=B9=E5=A4=9A=E5=AD=97=E6=AE=B5=EF=BC=8C?= =?UTF-8?q?=E6=8A=8A=E5=8E=9F=E6=9D=A5=E7=9A=84=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BA=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/migrations/0006_auto_20151209_1834.py | 20 +++++++++++ group/migrations/0007_auto_20151209_1836.py | 38 +++++++++++++++++++++ group/models.py | 13 ++++++- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 group/migrations/0006_auto_20151209_1834.py create mode 100644 group/migrations/0007_auto_20151209_1836.py diff --git a/group/migrations/0006_auto_20151209_1834.py b/group/migrations/0006_auto_20151209_1834.py new file mode 100644 index 000000000..3e5a6e955 --- /dev/null +++ b/group/migrations/0006_auto_20151209_1834.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-09 10:34 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('group', '0005_joingrouprequest_accepted'), + ] + + operations = [ + migrations.RenameField( + model_name='group', + old_name='admin', + new_name='created_by', + ), + ] diff --git a/group/migrations/0007_auto_20151209_1836.py b/group/migrations/0007_auto_20151209_1836.py new file mode 100644 index 000000000..937d6f071 --- /dev/null +++ b/group/migrations/0007_auto_20151209_1836.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2015-12-09 10:36 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('group', '0006_auto_20151209_1834'), + ] + + operations = [ + migrations.CreateModel( + name='AdminGroupRelation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='group.Group')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'admin_group_relation', + }, + ), + migrations.AddField( + model_name='group', + name='admin', + field=models.ManyToManyField(related_name='managed_groups', through='group.AdminGroupRelation', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='admingrouprelation', + unique_together=set([('user', 'group')]), + ), + ] diff --git a/group/models.py b/group/models.py index a2db074a9..26059f7e5 100644 --- a/group/models.py +++ b/group/models.py @@ -8,10 +8,11 @@ class Group(models.Model): name = models.CharField(max_length=30, unique=True) description = models.TextField() create_time = models.DateTimeField(auto_now_add=True) - admin = models.ForeignKey(User, related_name="my_groups") + created_by = models.ForeignKey(User, related_name="my_groups") # 0是公开 1是需要申请后加入 2是不允许任何人加入 join_group_setting = models.IntegerField(default=1) members = models.ManyToManyField(User, through="UserGroupRelation") + admin = models.ManyToManyField(User, through="AdminGroupRelation", related_name="managed_groups") # 解散小组后,这一项改为False visible = models.BooleanField(default=True) @@ -29,6 +30,16 @@ class Meta: unique_together = ("group", "user") + +class AdminGroupRelation(models.Model): + user = models.ForeignKey(User) + group = models.ForeignKey(Group) + + class Meta: + db_table = "admin_group_relation" + unique_together = ("user", "group") + + class JoinGroupRequest(models.Model): group = models.ForeignKey(Group) user = models.ForeignKey(User, related_name="my_join_group_requests") From c12ee66c51ddc9b1bd9111acdb56e44d29db851c Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 19:50:48 +0800 Subject: [PATCH 48/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=AE=BE=E4=B8=BA=E7=AE=A1=E7=90=86=E5=91=98=E6=8C=89?= =?UTF-8?q?=E9=92=AE=EF=BC=8C=E6=96=B9=E4=BE=BF=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/admin/group/groupDetail.js | 13 ++++++++++++- template/src/admin/group/group_detail.html | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/static/src/js/app/admin/group/groupDetail.js b/static/src/js/app/admin/group/groupDetail.js index 7b7e3f388..9edc23559 100644 --- a/static/src/js/app/admin/group/groupDetail.js +++ b/static/src/js/app/admin/group/groupDetail.js @@ -1,6 +1,5 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, avalon, csrfTokenHeader, bsAlert) { - // avalon:定义模式 group_list avalon.ready(function () { @@ -55,6 +54,18 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, showGroupListPage: function () { avalon.vmodels.admin.template_url = "template/group/group.html"; vm.$fire("up!showGroupListPage"); + }, + promotAsAdmin: function (relation) { + $.ajax({ + beforeSend: csrfTokenHeader, + url: "/api/admin/group/promot_as_admin/", + method: "post", + data: JSON.stringify({group_id: relation.group, user_id: relation.user.id}), + contentType: "application/json;charset=UTF-8", + success: function (data) { + bsAlert(data.data); + } + }) } }); } diff --git a/template/src/admin/group/group_detail.html b/template/src/admin/group/group_detail.html index a6e0a3b0b..cb1be1fec 100644 --- a/template/src/admin/group/group_detail.html +++ b/template/src/admin/group/group_detail.html @@ -19,13 +19,13 @@

小组成员管理

- +
ID
{{ contest.end_time }} {{ contest|contest_status }}小组赛私有小组赛公开赛公开赛(密码保护)小组邀请赛{{ contest.created_by.username }}
{{ item.start_time }}小组赛私有小组赛公开赛公开赛(密码保护)小组邀请赛{{ item|contest_status }}
{{ el.user.username }} {{ el.user.real_name }} {{ el.join_time|date("yyyy-MM-dd HH:mm:ss")}} +
-
页数:{{ page }}/{{ totalPage }}   From f924843ef173dbd78980316726ecd370bd38d772 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 19:51:59 +0800 Subject: [PATCH 49/64] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86=E5=91=98=E7=9A=84api?= =?UTF-8?q?=EF=BC=8C=E8=B0=83=E6=95=B4=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=9A=84=E8=AE=A4=E8=AF=81=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 45 +++++++++++++++++++++++++++++++++++++++------ oj/urls.py | 5 ++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/group/views.py b/group/views.py index 23e59ad3d..527486e68 100644 --- a/group/views.py +++ b/group/views.py @@ -5,14 +5,14 @@ from rest_framework.views import APIView from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate, error_page -from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN +from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN, User from account.decorators import login_required -from .models import Group, JoinGroupRequest, UserGroupRelation +from .models import Group, JoinGroupRequest, UserGroupRelation, AdminGroupRelation from .serializers import (CreateGroupSerializer, EditGroupSerializer, CreateJoinGroupRequestSerializer, GroupSerializer, GroupMemberSerializer, EditGroupMemberSerializer, - JoinGroupRequestSerializer, PutJoinGroupRequestSerializer) + JoinGroupRequestSerializer, PutJoinGroupRequestSerializer, GroupPromoteAdminSerializer) from announcement.models import Announcement from django.core.paginator import Paginator from django.db.models import Q @@ -57,9 +57,10 @@ def post(self, request): group = Group.objects.create(name=data["name"], description=data["description"], join_group_setting=data["join_group_setting"], - admin=request.user) + created_by=request.user) except IntegrityError: return error_response(u"小组名已经存在") + AdminGroupRelation.objects.create(group=group, user=request.user) return success_response(GroupSerializer(group).data) else: return serializer_invalid_response(serializer) @@ -132,8 +133,13 @@ def get(self, request): group = self.get_group(request, group_id) except Group.DoesNotExist: return error_response(u"小组不存在") - - return paginate(request, UserGroupRelation.objects.filter(group=group), GroupMemberSerializer) + adminOnly = request.GET.get("adminOnly", None) + if adminOnly: + members = AdminGroupRelation.objects.filter(group=group) + else: + members = UserGroupRelation.objects.filter(group=group) + + return paginate(request, members, GroupMemberSerializer) def put(self, request): """ @@ -314,3 +320,30 @@ def application_page(request, request_id): return error_page(request, u"申请不存在") return render(request, "oj/group/my_application.html", {"application": application}) + + +class GroupPrometAdminAPIView(APIView): + def post(self, request): + """ + 创建小组管理员的api + --- + request_serializer: GroupPromoteAdminSerializer + """ + serializer = GroupPromoteAdminSerializer(data=request.data) + if serializer.is_valid(): + data = serializer.data + try: + group = Group.objects.get(id=data["group_id"]) + except Group.DoesNotExist: + return error_response(u"小组不存在") + try: + user = User.objects.get(id=data["user_id"]) + except User.DoesNotExist: + return error_response(u"用户不存在") + try: + AdminGroupRelation.objects.create(user=user, group=group) + except IntegrityError: + return error_response(u"该用户已经是管理员了") + return success_response(u"操作成功") + else: + return serializer_invalid_response(serializer) diff --git a/oj/urls.py b/oj/urls.py index d2beba16d..77a92b666 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -15,7 +15,7 @@ MakeContestProblemPublicAPIView) from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, - JoinGroupAPIView, JoinGroupRequestAdminAPIView) + JoinGroupAPIView, JoinGroupRequestAdminAPIView, GroupPrometAdminAPIView) from admin.views import AdminTemplateView @@ -55,6 +55,7 @@ url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"), url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"), url(r'^api/group_join/$', JoinGroupAPIView.as_view(), name="group_join_api"), + url(r'^api/admin/upload_image/$', SimditorImageUploadAPIView.as_view(), name="simditor_upload_image"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), @@ -62,6 +63,8 @@ url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"), + url(r'^api/admin/group/promot_as_admin/$', GroupPrometAdminAPIView.as_view(), name="group_promote_admin_api"), + url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"), url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"), From 1dcfe0bc102196d7315e745dbaaf7bbfc25f8a1b Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 19:52:42 +0800 Subject: [PATCH 50/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=A8=A1=E6=9D=BF=EF=BC=8C=E9=80=82=E5=BA=94?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9A=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/group/group_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/src/oj/group/group_list.html b/template/src/oj/group/group_list.html index 500257a02..03e425cb5 100644 --- a/template/src/oj/group/group_list.html +++ b/template/src/oj/group/group_list.html @@ -40,7 +40,7 @@ 无需申请 {% endif %} - {{ item.admin }} + {{ item.created_by }} {{ item.create_time }} {% endfor %} From 96b409d1f064c04b18316fa344de2aaa436e9fb2 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 20:02:47 +0800 Subject: [PATCH 51/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BE=83=E5=A4=9A?= =?UTF-8?q?=EF=BC=8C=E6=B6=89=E5=8F=8A=E5=88=B0=E5=B0=8F=E7=BB=84=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E5=AF=B9=E6=AF=94=E8=B5=9B=E7=9A=84=E7=AE=A1?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E5=B0=8F=E7=BB=84=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E7=9C=8B=E5=88=B0=E4=BB=96=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E7=9A=84=E5=B0=8F=E7=BB=84=E7=9A=84=E5=85=B6=E4=BB=96=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E5=88=9B=E5=BB=BA=E7=9A=84=E6=AF=94=E8=B5=9B?= =?UTF-8?q?=EF=BC=8C=E4=BD=86=E7=9C=8B=E4=B8=8D=E5=88=B0=E5=88=AB=E4=BA=BA?= =?UTF-8?q?=E7=9A=84=E9=A2=98=E7=9B=AE=EF=BC=8C=E4=BD=86=E6=98=AF=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=BB=8E=E5=89=8D=E5=8F=B0=E7=9C=8B=E5=88=B0=E6=AF=94?= =?UTF-8?q?=E8=B5=9B=E7=9A=84=E9=A2=98=E7=9B=AE=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E5=9C=A8=E6=AF=94=E8=B5=9B=E5=BC=80=E5=A7=8B=E5=89=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=A2=98=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contest/decorators.py | 7 +++++-- contest/views.py | 29 +++++++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/contest/decorators.py b/contest/decorators.py index 0dad16fde..663f8fbe6 100644 --- a/contest/decorators.py +++ b/contest/decorators.py @@ -8,7 +8,7 @@ from utils.shortcuts import error_response, error_page -from account.models import SUPER_ADMIN +from account.models import SUPER_ADMIN, ADMIN from .models import (Contest, PASSWORD_PROTECTED_CONTEST, PASSWORD_PROTECTED_GROUP_CONTEST, PUBLIC_CONTEST, GROUP_CONTEST, CONTEST_ENDED, CONTEST_NOT_START, CONTEST_UNDERWAY) @@ -57,7 +57,10 @@ def _check_user_contest_permission(*args, **kwargs): if request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by: return func(*args, **kwargs) - + if request.user.admin_type == ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest in contest_set: + return func(*args, **kwargs) # 管理员可见隐藏的比赛,已经先判断了身份 if not contest.visible: if request.is_ajax(): diff --git a/contest/views.py b/contest/views.py index 225395587..cfc2049bb 100644 --- a/contest/views.py +++ b/contest/views.py @@ -17,7 +17,7 @@ success_response, paginate, error_page, paginate_data) from account.models import SUPER_ADMIN, User from account.decorators import login_required, super_admin_required -from group.models import Group +from group.models import Group, AdminGroupRelation, UserGroupRelation from utils.cache import get_cache_redis from submission.models import Submission from problem.models import Problem @@ -91,8 +91,10 @@ def put(self, request): try: # 超级管理员可以编辑所有的 contest = Contest.objects.get(id=data["id"]) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"无权访问!") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"无权访问!") except Contest.DoesNotExist: return error_response(u"该比赛不存在!") try: @@ -151,16 +153,18 @@ def get(self, request): # 普通管理员只能获取自己创建的题目 # 超级管理员可以获取全部的题目 contest = Contest.objects.get(id=contest_id) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"题目不存在") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"比赛不存在") return success_response(ContestSerializer(contest).data) except Contest.DoesNotExist: - return error_response(u"题目不存在") + return error_response(u"比赛不存在") if request.user.admin_type == SUPER_ADMIN: contest = Contest.objects.all().order_by("-create_time") else: - contest = Contest.objects.filter(created_by=request.user).order_by("-create_time") + contest = Contest.objects.filter(groups__in=request.user.managed_groups.all()).distinct().order_by("-create_time") visible = request.GET.get("visible", None) if visible: contest = contest.filter(visible=(visible == "true")) @@ -184,8 +188,10 @@ def post(self, request): data = serializer.data try: contest = Contest.objects.get(id=data["contest_id"]) - if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: - return error_response(u"比赛不存在") + if request.user.admin_type != SUPER_ADMIN: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest not in contest_set: + return error_response(u"比赛不存在") except Contest.DoesNotExist: return error_response(u"比赛不存在") contest_problem = ContestProblem.objects.create(title=data["title"], @@ -362,7 +368,10 @@ def contest_problem_page(request, contest_id, contest_problem_id): request.user.admin_type == SUPER_ADMIN or \ request.user == contest.created_by: show_submit_code_area = True - + else: + contest_set = Contest.objects.filter(groups__in=request.user.managed_groups.all()) + if contest in contest_set: + show_submit_code_area = True return render(request, "oj/problem/contest_problem.html", {"problem": problem, "contest": contest, "samples": json.loads(problem.samples), From 023f4ab82fab90f6536c176ea5700af6e904a668 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 20:04:11 +0800 Subject: [PATCH 52/64] =?UTF-8?q?=E8=BF=99=E4=B8=AA=E6=98=AF=E5=88=9A?= =?UTF-8?q?=E6=89=8Dapi=E5=9C=B0=E6=96=B9=E7=9A=84=EF=BC=8C=E5=BF=98?= =?UTF-8?q?=E4=BA=86add=E4=B8=8A=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/serializers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/group/serializers.py b/group/serializers.py index 402ea5b94..27490d879 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -73,4 +73,8 @@ class EditGroupMemberSerializer(serializers.Serializer): class PutJoinGroupRequestSerializer(serializers.Serializer): request_id = serializers.IntegerField() - status = serializers.BooleanField() \ No newline at end of file + status = serializers.BooleanField() + +class GroupPromoteAdminSerializer(serializers.Serializer): + user_id = serializers.IntegerField() + group_id = serializers.IntegerField() From 82b17b1c0487672bac89e748442949818854d9a1 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 20:10:31 +0800 Subject: [PATCH 53/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/account/register.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index d5b9a5433..9c2109e33 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -33,10 +33,8 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c }); $("#school").blur(function () { - var school = $("#school").val(); - school = $.trim(school).toLowerCase(); - console.log(school); - if (school == "青岛大学" || school == "qdu" || school == "qdu" || school == "青大") { + var school = $("#school").val().trim(school).toLowerCase(); + if (school == "青岛大学" || school == "qdu" || school == "青大") { $("#stu_id").show(); $("#school").val("青岛大学"); } From 15d7179cae91adb58b44e886dda14fa27b414f04 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 20:23:30 +0800 Subject: [PATCH 54/64] =?UTF-8?q?=E7=BB=9F=E4=B8=80get=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group/views.py b/group/views.py index 527486e68..29f0a49c4 100644 --- a/group/views.py +++ b/group/views.py @@ -133,8 +133,8 @@ def get(self, request): group = self.get_group(request, group_id) except Group.DoesNotExist: return error_response(u"小组不存在") - adminOnly = request.GET.get("adminOnly", None) - if adminOnly: + admin_only = request.GET.get("admin_only", None) + if admin_only: members = AdminGroupRelation.objects.filter(group=group) else: members = UserGroupRelation.objects.filter(group=group) From 2e4379c1b9480f38fc875fa9c42d16c698e70a66 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 21:08:58 +0800 Subject: [PATCH 55/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=80=85=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/group/group.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/src/oj/group/group.html b/template/src/oj/group/group.html index 3d9fa23c7..704d886b6 100644 --- a/template/src/oj/group/group.html +++ b/template/src/oj/group/group.html @@ -15,7 +15,7 @@

{{ group.name }}

发布时间 : {{ group.create_time }}   - 创建者 : {{ group.admin }} + 创建者 : {{ group.created_by }}

From 7f38db660c14c288b4c529bc4929c9030ba90ee7 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 21:18:16 +0800 Subject: [PATCH 56/64] =?UTF-8?q?=E5=AF=B9=E4=BA=8E=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E7=9A=84=E5=B0=8F=E7=BB=84=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8A=A0=E5=85=A5=E5=B0=8F=E7=BB=84=E9=83=A8?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/group/group.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/template/src/oj/group/group.html b/template/src/oj/group/group.html index 704d886b6..003dd80cc 100644 --- a/template/src/oj/group/group.html +++ b/template/src/oj/group/group.html @@ -25,6 +25,7 @@

{{ group.name }}

{{ group.description|safe }}

+ {% if not joined %}
{% if group.join_group_setting %} @@ -34,10 +35,13 @@

{{ group.name }}

{% endif %} +
+ + {% endif %} {% endblock %} {% block js_block %} From 804add6a03ade3a176ce1d833f7bb6290d6524f2 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 21:18:31 +0800 Subject: [PATCH 57/64] =?UTF-8?q?=E5=AF=B9=E4=BA=8E=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E7=9A=84=E5=B0=8F=E7=BB=84=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8A=A0=E5=85=A5=E5=B0=8F=E7=BB=84=E9=83=A8?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/group/views.py b/group/views.py index 29f0a49c4..fd639de72 100644 --- a/group/views.py +++ b/group/views.py @@ -298,7 +298,12 @@ def group_page(request, group_id): group = Group.objects.get(id=group_id, visible=True) except Group.DoesNotExist: return error_page(request, u"小组不存在") - return render(request, "oj/group/group.html", {"group": group}) + joined = True + try: + UserGroupRelation.objects.get(user=request.user, group=group) + except UserGroupRelation.DoesNotExist: + joined = False + return render(request, "oj/group/group.html", {"group": group, "joined": joined}) @login_required From 541c3bb792c69d07076ae2ed81ebd9822691b4c6 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 9 Dec 2015 21:23:19 +0800 Subject: [PATCH 58/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E4=B9=8B=E5=89=8D=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E6=89=BE=E5=88=B0=20django=20=E6=8A=A5=E9=94=99=E7=9A=84?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=EF=BC=8C=E5=90=8E=E6=9D=A5=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=20django=20=E6=96=B0=E7=89=88=E6=9C=AC=E4=B8=8D=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B9=8B=E5=89=8D=20zh-cn=20=E7=9A=84=E5=86=99?= =?UTF-8?q?=E6=B3=95=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oj/settings.py b/oj/settings.py index 3f3ea8865..de88dfbc8 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -101,7 +101,7 @@ TIME_ZONE = 'Asia/Shanghai' -USE_I18N = False +USE_I18N = True USE_L10N = True From eacb26eed0528e5db021168008f392fb85411158 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 21:48:24 +0800 Subject: [PATCH 59/64] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BD=86=E6=98=AF?= =?UTF-8?q?=E5=8F=AA=E6=9C=89=E8=B6=85=E7=BA=A7=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E6=89=8D=E8=83=BD=E7=9C=8B=E5=88=B0=E9=9A=90=E8=97=8F=E5=B0=8F?= =?UTF-8?q?=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/serializers.py | 1 + group/views.py | 5 +++-- static/src/js/app/admin/group/groupDetail.js | 5 +++-- template/src/admin/group/group_detail.html | 22 +++++++++++++------- template/src/oj/account/user_index.html | 12 ++++++----- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/group/serializers.py b/group/serializers.py index 27490d879..377d56d6d 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -17,6 +17,7 @@ class EditGroupSerializer(serializers.Serializer): name = serializers.CharField(max_length=20) description = serializers.CharField(max_length=300) join_group_setting = serializers.IntegerField() + visible = serializers.BooleanField() class CreateJoinGroupRequestSerializer(serializers.Serializer): diff --git a/group/views.py b/group/views.py index fd639de72..5c2797b16 100644 --- a/group/views.py +++ b/group/views.py @@ -25,7 +25,7 @@ def get_group(self, request, group_id): 管理员可以查询所有的小组,其他用户查询自己创建的自傲组 """ if request.user.admin_type == SUPER_ADMIN: - group = Group.objects.get(id=group_id, visible=True) + group = Group.objects.get(id=group_id) else: group = Group.objects.get(id=group_id, visible=True, admin=request.user) return group @@ -36,7 +36,7 @@ def get_groups(self, request): 如果是管理员,就返回他创建的全部小组 """ if request.user.admin_type == SUPER_ADMIN: - groups = Group.objects.filter(visible=True) + groups = Group.objects.filter() else: groups = Group.objects.filter(admin=request.user, visible=True) return groups @@ -83,6 +83,7 @@ def put(self, request): group.name = data["name"] group.description = data["description"] group.join_group_setting = data["join_group_setting"] + group.visible = data["visible"] group.save() except IntegrityError: return error_response(u"小组名已经存在") diff --git a/static/src/js/app/admin/group/groupDetail.js b/static/src/js/app/admin/group/groupDetail.js index 9edc23559..6df05afaf 100644 --- a/static/src/js/app/admin/group/groupDetail.js +++ b/static/src/js/app/admin/group/groupDetail.js @@ -18,7 +18,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, name: "", description: "", checkedSetting: "0", - + visible: true, getNext: function () { if (!vm.nextPage) return; @@ -103,6 +103,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, vm.name = data.data.name; vm.description = data.data.description; vm.checkedSetting = data.data.join_group_setting.toString(); + vm.visible = data.data.visible; } else { bsAlert(data.data); @@ -123,7 +124,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "validator"], function ($, url: "/api/admin/group/", method: "put", data: {group_id: group_id, name: name, description: description, - join_group_setting: join_group_setting}, + join_group_setting: join_group_setting, visible:vm.visible}, dataType: "json", success: function (data) { if (!data.code) { diff --git a/template/src/admin/group/group_detail.html b/template/src/admin/group/group_detail.html index cb1be1fec..71e54b5cb 100644 --- a/template/src/admin/group/group_detail.html +++ b/template/src/admin/group/group_detail.html @@ -49,18 +49,24 @@

修改小组信息

-
+
- - - 允许任何人加入 - 提交请求后管理员审核 - 不允许任何人加入 - +
+ + +
+ +
+
+
+ +
+
-
diff --git a/template/src/oj/account/user_index.html b/template/src/oj/account/user_index.html index 9ae7178ea..7a481aa6d 100644 --- a/template/src/oj/account/user_index.html +++ b/template/src/oj/account/user_index.html @@ -22,14 +22,16 @@

{% if user.userprofile.mood %}

{{ user.userprofile.mood }}

{% endif %} - {% if user.userprofile.school %} -

{{ user.userprofile.school }}

- {% endif %} +
- + {% if user.userprofile.school %} +

+ {{ user.userprofile.school }} +

+ {% endif %} {% if user.userprofile.blog %} -

+

{{ blog_link }}

{% endif %} From 299d2a48e0994b5fba0c0e1489315194b301afd3 Mon Sep 17 00:00:00 2001 From: sxw Date: Wed, 9 Dec 2015 21:57:22 +0800 Subject: [PATCH 60/64] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E4=BB=BB=E4=BD=95=E4=BA=BA=E5=8A=A0=E5=85=A5=E7=9A=84=E5=B0=8F?= =?UTF-8?q?=E7=BB=84=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj/group/group.html | 4 ++-- template/src/oj/group/group_list.html | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/template/src/oj/group/group.html b/template/src/oj/group/group.html index 003dd80cc..bbf6c32ba 100644 --- a/template/src/oj/group/group.html +++ b/template/src/oj/group/group.html @@ -28,13 +28,13 @@

{{ group.name }}

{% if not joined %}
- {% if group.join_group_setting %} + {% ifequal group.join_group_setting 1 %}
- {% endif %} + {% endifequal %}
diff --git a/template/src/oj/group/group_list.html b/template/src/oj/group/group_list.html index 03e425cb5..575102bda 100644 --- a/template/src/oj/group/group_list.html +++ b/template/src/oj/group/group_list.html @@ -34,11 +34,15 @@ {{ item.id }} {{ item.name }} - {% if item.join_group_setting %} + {% ifequal item.join_group_setting 1 %} 需要申请 - {% else %} + {% endifequal %} + {% ifequal item.join_group_setting 0 %} 无需申请 - {% endif %} + {% endifequal %} + {% ifequal item.join_group_setting 2 %} + 不允许加入 + {% endifequal %} {{ item.created_by }} {{ item.create_time }} From 0a62b6ab4bae533dd294339eccd641f6d218aab4 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 9 Dec 2015 22:28:55 +0800 Subject: [PATCH 61/64] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squash from 1612a4d to 12f96c6 by virusdefender --- dockerfiles/judger/Dockerfile | 3 ++- oj/settings.py | 5 ----- tools/celeryd.conf | 15 --------------- tools/runserver.cmd | 5 ----- tools/runtest.cmd | 12 ------------ tools/supervisord.conf | 26 -------------------------- 6 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 tools/celeryd.conf delete mode 100644 tools/runserver.cmd delete mode 100644 tools/runtest.cmd delete mode 100644 tools/supervisord.conf diff --git a/dockerfiles/judger/Dockerfile b/dockerfiles/judger/Dockerfile index 6090728e8..f13a9a5dd 100644 --- a/dockerfiles/judger/Dockerfile +++ b/dockerfiles/judger/Dockerfile @@ -19,4 +19,5 @@ 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/ COPY policy /var/judger/run/ -WORKDIR /var/judger/code/ \ No newline at end of file +WORKDIR /var/judger/code/judge/ +CMD python server.py \ No newline at end of file diff --git a/oj/settings.py b/oj/settings.py index 1d3cc3781..ac766975d 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -22,11 +22,6 @@ elif ENV == "server": from .server_settings import * -BROKER_BACKEND = "redis" -CELERY_ACCEPT_CONTENT = ['json'] -CELERY_TASK_SERIALIZER = 'json' -CELERY_RESULT_SERIALIZER = 'json' - BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/tools/celeryd.conf b/tools/celeryd.conf deleted file mode 100644 index 60e3fc215..000000000 --- a/tools/celeryd.conf +++ /dev/null @@ -1,15 +0,0 @@ -[program:celery] -command=celery worker -A judge.judger_controller --loglevel=DEBUG - -directory=/root/qduoj/ -user=root -numprocs=1 -stdout_logfile=/root/log/celery_worker.log -stderr_logfile=/root/log/celery_worker.log -autostart=true -autorestart=true -startsecs=5 - -stopwaitsecs = 6 - -killasgroup=true diff --git a/tools/runserver.cmd b/tools/runserver.cmd deleted file mode 100644 index b458e559f..000000000 --- a/tools/runserver.cmd +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -python manage.py runserver -cls -cd.. -python manage.py runserver \ No newline at end of file diff --git a/tools/runtest.cmd b/tools/runtest.cmd deleted file mode 100644 index e6d9ad7b6..000000000 --- a/tools/runtest.cmd +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -coverage run --source='.' manage.py test -coverage html -cd htmlcov -index.html -cls -cd.. -coverage run --source='.' manage.py test -coverage html -cd htmlcov -index.html - diff --git a/tools/supervisord.conf b/tools/supervisord.conf deleted file mode 100644 index 1494d7cd4..000000000 --- a/tools/supervisord.conf +++ /dev/null @@ -1,26 +0,0 @@ -[unix_http_server] -file=/tmp/supervisor.sock ; path to your socket file - -[supervisord] -logfile=/root/log/supervisord.log ; supervisord log file -logfile_maxbytes=50MB ; maximum size of logfile before rotation -logfile_backups=10 ; number of backed up logfiles -loglevel=info ; info, debug, warn, trace -pidfile=/root/log/supervisord.pid ; pidfile location -nodaemon=false ; run supervisord as a daemon -minfds=1024 ; number of startup file descriptors -minprocs=200 ; number of process descriptors -user=root ; default user -childlogdir=/root/log/ ; where child log files will live - - -[rpcinterface:supervisor] -supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface - -[supervisorctl] -serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets. - - -[include] - -files=*.conf \ No newline at end of file From 3dbcf4951637b17e0b708c6bec740f7dbfa70d84 Mon Sep 17 00:00:00 2001 From: sxw Date: Thu, 10 Dec 2015 09:41:00 +0800 Subject: [PATCH 62/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A1=B5=E8=84=9A?= =?UTF-8?q?=E5=A4=87=E6=A1=88=E4=BF=A1=E6=81=AF=E6=98=BE=E7=A4=BA=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E8=A2=ABdjango?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=BD=AC=E4=B9=89=E4=BA=86=EF=BC=8C=E6=9C=AC?= =?UTF-8?q?=E6=9D=A5=E6=83=B3=E7=94=A8|safe=E5=91=A2=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=A5=BD=E5=83=8F=E4=B8=8D=E5=A5=BD=E4=BD=BF=EF=BC=8C=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E7=94=A8autoescape=20off=E6=A0=87=E7=AD=BE=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/src/oj_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/src/oj_base.html b/template/src/oj_base.html index 692bce1f2..725461e98 100644 --- a/template/src/oj_base.html +++ b/template/src/oj_base.html @@ -97,7 +97,7 @@ {% block js_block %}{% endblock %} From 52f62df3831f721b2a78f235baeebf36ec6b2432 Mon Sep 17 00:00:00 2001 From: sxw Date: Thu, 10 Dec 2015 13:09:03 +0800 Subject: [PATCH 63/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=BE=E5=9B=9E?= =?UTF-8?q?=E5=AF=86=E7=A0=81token=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=8E=9F=E6=9D=A5=E5=86=99=E7=9A=84=E6=97=B6=E5=80=99=E6=9C=AC?= =?UTF-8?q?=E6=9D=A5=E6=98=AF=E6=83=B3=E7=94=A8index=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E7=A1=AE=E5=AE=9Atoken=E7=9A=84=E4=BD=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E4=B8=80=E4=B8=8D=E5=B0=8F=E5=BF=83=E5=86=99?= =?UTF-8?q?=E6=AD=BB=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/account/resetPassword.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/src/js/app/oj/account/resetPassword.js b/static/src/js/app/oj/account/resetPassword.js index 0f0bb4bc5..ef1128d0e 100644 --- a/static/src/js/app/oj/account/resetPassword.js +++ b/static/src/js/app/oj/account/resetPassword.js @@ -2,8 +2,8 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c var applied_captcha = false; $('form').validator().on('submit', function (e) { if (!e.isDefaultPrevented()) { - var index = location.href.indexOf("/t/"); - var token = location.href.substr(36+3, 32); + var loca = location.href.split("/"); + var token = loca[loca.length-2]; var captcha = $("#captcha").val(); var password = $("#new_password").val(); $.ajax({ From 1eb1248cba04f47efccfd85d7762f91b5ec08624 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Thu, 10 Dec 2015 19:29:21 +0800 Subject: [PATCH 64/64] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=B0=8F=E9=97=AE=E9=A2=98=20Squash=20from=20b973dfd=20to=2012?= =?UTF-8?q?f96c6=20by=20virusdefender?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/local_settings.py | 2 +- oj/server_settings.py | 5 ++--- oj/settings.py | 6 +----- template/src/oj/account/user_index.html | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/oj/local_settings.py b/oj/local_settings.py index 82bfe2edd..794a7b633 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -39,4 +39,4 @@ # 模板文件夹 TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/src/')] -SSO = {"callback": "http://localhost:8765/login"} \ No newline at end of file +SSO = {"callback": "http://localhost:8765/login"} diff --git a/oj/server_settings.py b/oj/server_settings.py index cd86c16ff..afec6d194 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -11,7 +11,7 @@ 'CONN_MAX_AGE': 0.1, 'HOST': os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"), 'PORT': 3306, - 'USER': 'root', + 'USER': os.environ.get("MYSQL_ENV_MYSQL_USER", "root"), 'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root") }, 'submission': { @@ -20,7 +20,7 @@ 'CONN_MAX_AGE': 0.1, 'HOST': os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"), 'PORT': 3306, - 'USER': 'root', + 'USER': os.environ.get("MYSQL_ENV_MYSQL_USER", "root"), 'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root") } } @@ -37,7 +37,6 @@ "db": 2 } - DEBUG = False ALLOWED_HOSTS = ['*'] diff --git a/oj/settings.py b/oj/settings.py index ac766975d..f58570338 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -22,7 +22,6 @@ elif ENV == "server": from .server_settings import * - BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -187,19 +186,16 @@ "website_footer": u"青岛大学信息工程学院 创新实验室 京ICP备15062075号-1", "url": "https://qduoj.com"} - HUEY = { 'backend': 'huey.backends.redis_backend', 'name': 'task_queue', 'connection': {'host': REDIS_QUEUE["host"], 'port': REDIS_QUEUE["port"], 'db': REDIS_QUEUE["db"]}, - 'always_eager': False, # Defaults to False when running via manage.py run_huey + 'always_eager': False, # Defaults to False when running via manage.py run_huey # Options to pass into the consumer when running ``manage.py run_huey`` 'consumer_options': {'workers': 50}, } - SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com", "email": "noreply@qduoj.com", "password": os.environ.get("smtp_password", "111111"), "tls": False} - diff --git a/template/src/oj/account/user_index.html b/template/src/oj/account/user_index.html index 7a481aa6d..6d34593d5 100644 --- a/template/src/oj/account/user_index.html +++ b/template/src/oj/account/user_index.html @@ -31,7 +31,7 @@

{% endif %} {% if user.userprofile.blog %} -

+

{{ blog_link }}

{% endif %}