mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 16:33:22 +00:00
Merge branch 'dev' into hohoTT-dev
This commit is contained in:
commit
66b9b1a8f2
1
.gitignore
vendored
1
.gitignore
vendored
@ -63,3 +63,4 @@ build.txt
|
|||||||
tmp/
|
tmp/
|
||||||
test_case/
|
test_case/
|
||||||
release/
|
release/
|
||||||
|
upload/
|
@ -1,6 +1,6 @@
|
|||||||
FROM python:2.7
|
FROM python:2.7
|
||||||
ENV PYTHONBUFFERED 1
|
ENV PYTHONBUFFERED 1
|
||||||
RUN mkdir -p /code/log /code/test_case
|
RUN mkdir -p /code/log /code/test_case /code/upload
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
ADD requirements.txt /code/
|
ADD requirements.txt /code/
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
|
19
contest/migrations/0009_contestsubmission_first_achieved.py
Normal file
19
contest/migrations/0009_contestsubmission_first_achieved.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contest', '0008_auto_20150912_1912'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='contestsubmission',
|
||||||
|
name='first_achieved',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
@ -89,10 +89,12 @@ class ContestSubmission(models.Model):
|
|||||||
total_submission_number = models.IntegerField(default=1)
|
total_submission_number = models.IntegerField(default=1)
|
||||||
# 这道题是 AC 还是没过
|
# 这道题是 AC 还是没过
|
||||||
ac = models.BooleanField()
|
ac = models.BooleanField()
|
||||||
# ac 用时
|
# ac 用时以秒计
|
||||||
ac_time = models.IntegerField(default=0)
|
ac_time = models.IntegerField(default=0)
|
||||||
# 总的时间,用于acm 类型的,也需要保存罚时
|
# 总的时间,用于acm 类型的,也需要保存罚时
|
||||||
total_time = models.IntegerField(default=0)
|
total_time = models.IntegerField(default=0)
|
||||||
|
# 第一个解出此题目
|
||||||
|
first_achieved = models.BooleanField(default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "contest_submission"
|
db_table = "contest_submission"
|
||||||
|
@ -13,7 +13,7 @@ class CreateContestSerializer(serializers.Serializer):
|
|||||||
description = serializers.CharField(max_length=5000)
|
description = serializers.CharField(max_length=5000)
|
||||||
mode = serializers.IntegerField()
|
mode = serializers.IntegerField()
|
||||||
contest_type = serializers.IntegerField()
|
contest_type = serializers.IntegerField()
|
||||||
show_rank = serializers.BooleanField()
|
real_time_rank = serializers.BooleanField()
|
||||||
show_user_submission = serializers.BooleanField()
|
show_user_submission = serializers.BooleanField()
|
||||||
password = serializers.CharField(max_length=30, required=False, default=None)
|
password = serializers.CharField(max_length=30, required=False, default=None)
|
||||||
start_time = serializers.DateTimeField()
|
start_time = serializers.DateTimeField()
|
||||||
@ -47,7 +47,7 @@ class EditContestSerializer(serializers.Serializer):
|
|||||||
description = serializers.CharField(max_length=10000)
|
description = serializers.CharField(max_length=10000)
|
||||||
mode = serializers.IntegerField()
|
mode = serializers.IntegerField()
|
||||||
contest_type = serializers.IntegerField()
|
contest_type = serializers.IntegerField()
|
||||||
show_rank = serializers.BooleanField()
|
real_time_rank = serializers.BooleanField()
|
||||||
show_user_submission = serializers.BooleanField()
|
show_user_submission = serializers.BooleanField()
|
||||||
password = serializers.CharField(max_length=30, required=False, default=None)
|
password = serializers.CharField(max_length=30, required=False, default=None)
|
||||||
start_time = serializers.DateTimeField()
|
start_time = serializers.DateTimeField()
|
||||||
|
@ -21,6 +21,8 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
|
|||||||
CreateContestProblemSerializer, ContestProblemSerializer,
|
CreateContestProblemSerializer, ContestProblemSerializer,
|
||||||
ContestPasswordVerifySerializer,
|
ContestPasswordVerifySerializer,
|
||||||
EditContestProblemSerializer)
|
EditContestProblemSerializer)
|
||||||
|
from oj.settings import REDIS_CACHE
|
||||||
|
import redis
|
||||||
|
|
||||||
|
|
||||||
class ContestAdminAPIView(APIView):
|
class ContestAdminAPIView(APIView):
|
||||||
@ -58,7 +60,7 @@ class ContestAdminAPIView(APIView):
|
|||||||
try:
|
try:
|
||||||
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
contest = Contest.objects.create(title=data["title"], description=data["description"],
|
||||||
mode=data["mode"], contest_type=data["contest_type"],
|
mode=data["mode"], contest_type=data["contest_type"],
|
||||||
show_rank=data["show_rank"], password=data["password"],
|
real_time_rank=data["real_time_rank"], password=data["password"],
|
||||||
show_user_submission=data["show_user_submission"],
|
show_user_submission=data["show_user_submission"],
|
||||||
start_time=dateparse.parse_datetime(data["start_time"]),
|
start_time=dateparse.parse_datetime(data["start_time"]),
|
||||||
end_time=dateparse.parse_datetime(data["end_time"]),
|
end_time=dateparse.parse_datetime(data["end_time"]),
|
||||||
@ -112,7 +114,7 @@ class ContestAdminAPIView(APIView):
|
|||||||
contest.description = data["description"]
|
contest.description = data["description"]
|
||||||
contest.mode = data["mode"]
|
contest.mode = data["mode"]
|
||||||
contest.contest_type = data["contest_type"]
|
contest.contest_type = data["contest_type"]
|
||||||
contest.show_rank = data["show_rank"]
|
contest.real_time_rank = data["real_time_rank"]
|
||||||
contest.show_user_submission = data["show_user_submission"]
|
contest.show_user_submission = data["show_user_submission"]
|
||||||
contest.start_time = dateparse.parse_datetime(data["start_time"])
|
contest.start_time = dateparse.parse_datetime(data["start_time"])
|
||||||
contest.end_time = dateparse.parse_datetime(data["end_time"])
|
contest.end_time = dateparse.parse_datetime(data["end_time"])
|
||||||
@ -353,7 +355,6 @@ def contest_list_page(request, page=1):
|
|||||||
if request.user.is_authenticated and join:
|
if request.user.is_authenticated and join:
|
||||||
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
|
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
|
||||||
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
|
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())
|
||||||
|
|
||||||
paginator = Paginator(contests, 20)
|
paginator = Paginator(contests, 20)
|
||||||
try:
|
try:
|
||||||
current_page = paginator.page(int(page))
|
current_page = paginator.page(int(page))
|
||||||
@ -390,23 +391,62 @@ def _cmp(x, y):
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
def get_the_time_format(seconds):
|
||||||
|
if not seconds:
|
||||||
|
return ""
|
||||||
|
result = str(seconds % 60)
|
||||||
|
if seconds % 60 < 10:
|
||||||
|
result = "0" + result
|
||||||
|
result = str((seconds % 3600) / 60) + ":" + result
|
||||||
|
if (seconds % 3600) / 60 < 10:
|
||||||
|
result = "0" + result
|
||||||
|
result = str(seconds / 3600) + ":" + result
|
||||||
|
if seconds / 3600 < 10:
|
||||||
|
result = "0" + result
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@check_user_contest_permission
|
@check_user_contest_permission
|
||||||
def contest_rank_page(request, contest_id):
|
def contest_rank_page(request, contest_id):
|
||||||
contest = Contest.objects.get(id=contest_id)
|
contest = Contest.objects.get(id=contest_id)
|
||||||
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
|
||||||
|
r = redis.Redis(host=REDIS_CACHE["host"], port=REDIS_CACHE["port"], db=REDIS_CACHE["db"])
|
||||||
|
if contest.real_time_rank:
|
||||||
|
# 更新rank
|
||||||
result = ContestSubmission.objects.filter(contest=contest).values("user_id"). \
|
result = ContestSubmission.objects.filter(contest=contest).values("user_id"). \
|
||||||
annotate(total_submit=Sum("total_submission_number"))
|
annotate(total_submit=Sum("total_submission_number"))
|
||||||
for i in range(0, len(result)):
|
for i in range(0, len(result)):
|
||||||
# 这个人所有的提交
|
# 这个人所有的提交
|
||||||
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
|
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
|
||||||
result[i]["submissions"] = {}
|
result[i]["submissions"] = {}
|
||||||
for item in submissions:
|
result[i]["problems"] = []
|
||||||
result[i]["submissions"][item.problem_id] = item
|
for problem in contest_problems:
|
||||||
|
try:
|
||||||
|
status = submissions.get(problem=problem)
|
||||||
|
result[i]["problems"].append({
|
||||||
|
"first_achieved": status.first_achieved,
|
||||||
|
"ac": status.ac,
|
||||||
|
"failed_number": status.total_submission_number,
|
||||||
|
"ac_time": get_the_time_format(status.ac_time)})
|
||||||
|
if status.ac:
|
||||||
|
result[i]["problems"][-1]["failed_number"] -= 1
|
||||||
|
except ContestSubmission.DoesNotExist:
|
||||||
|
result[i]["problems"].append({})
|
||||||
result[i]["total_ac"] = submissions.filter(ac=True).count()
|
result[i]["total_ac"] = submissions.filter(ac=True).count()
|
||||||
result[i]["user"] = User.objects.get(id=result[i]["user_id"])
|
result[i]["username"] = User.objects.get(id=result[i]["user_id"]).username
|
||||||
result[i]["total_time"] = submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]
|
result[i]["total_time"] = get_the_time_format(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"])
|
||||||
|
result = sorted(result, cmp=_cmp, reverse=True)
|
||||||
|
r.set("contest_rank_" + contest_id, json.dumps(list(result)))
|
||||||
|
else:
|
||||||
|
# 从缓存读取排名信息
|
||||||
|
result = r.get("contest_rank_" + contest_id)
|
||||||
|
if result:
|
||||||
|
result = json.loads(result)
|
||||||
|
else:
|
||||||
|
result = []
|
||||||
|
|
||||||
return render(request, "oj/contest/contest_rank.html",
|
return render(request, "oj/contest/contest_rank.html",
|
||||||
{"contest": contest, "contest_problems": contest_problems,
|
{"contest": contest, "contest_problems": contest_problems,
|
||||||
"result": sorted(result, cmp=_cmp, reverse=True),
|
"result": result,
|
||||||
"auto_refresh": request.GET.get("auto_refresh", None) == "true"})
|
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
|
||||||
|
"real_time_rank": contest.real_time_rank})
|
||||||
|
@ -3,6 +3,8 @@ MAINTAINER virusdefender<qduliyang@outlook.com>
|
|||||||
RUN mkdir /var/install/
|
RUN mkdir /var/install/
|
||||||
WORKDIR /var/install/
|
WORKDIR /var/install/
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
RUN rm /etc/apt/sources.list
|
||||||
|
COPY sources.list /etc/apt/
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get -y install software-properties-common python-software-properties
|
RUN apt-get -y install software-properties-common python-software-properties
|
||||||
RUN add-apt-repository -y ppa:webupd8team/java
|
RUN add-apt-repository -y ppa:webupd8team/java
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
|
import os
|
||||||
# 单个判题端最多同时运行的程序个数,因为判题端会同时运行多组测试数据,比如一共有5组测试数据
|
# 单个判题端最多同时运行的程序个数,因为判题端会同时运行多组测试数据,比如一共有5组测试数据
|
||||||
# 如果MAX_RUNNING_NUMBER大于等于5,那么这5组数据就会同时进行评测,然后返回结果。
|
# 如果MAX_RUNNING_NUMBER大于等于5,那么这5组数据就会同时进行评测,然后返回结果。
|
||||||
# 如果MAX_RUNNING_NUMBER小于5,为3,那么就会同时运行前三组测试数据,然后再运行后两组数据
|
# 如果MAX_RUNNING_NUMBER小于5,为3,那么就会同时运行前三组测试数据,然后再运行后两组数据
|
||||||
@ -14,12 +15,10 @@ lrun_gid = 1002
|
|||||||
# judger工作目录
|
# judger工作目录
|
||||||
judger_workspace = "/var/judger/"
|
judger_workspace = "/var/judger/"
|
||||||
|
|
||||||
|
|
||||||
# 这个是在docker 中访问数据库 ip 不一定和web服务器还有celery的一样
|
|
||||||
submission_db = {
|
submission_db = {
|
||||||
"host": "192.168.42.1",
|
"host": os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"),
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"db": "oj_submission",
|
"db": "oj_submission",
|
||||||
"user": "root",
|
"user": "root",
|
||||||
"password": "mypwd"
|
"password": os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
|
||||||
}
|
}
|
||||||
|
10
judge/sources.list
Normal file
10
judge/sources.list
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
|
||||||
|
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
|
||||||
|
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
|
||||||
|
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
|
||||||
|
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
|
||||||
|
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
|
||||||
|
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
|
||||||
|
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
|
||||||
|
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
|
||||||
|
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
|
@ -8,7 +8,7 @@ from judge.judger.result import result
|
|||||||
from submission.models import Submission
|
from submission.models import Submission
|
||||||
from problem.models import Problem
|
from problem.models import Problem
|
||||||
from contest.models import ContestProblem, Contest, ContestSubmission
|
from contest.models import ContestProblem, Contest, ContestSubmission
|
||||||
|
from account.models import User
|
||||||
logger = logging.getLogger("app_info")
|
logger = logging.getLogger("app_info")
|
||||||
|
|
||||||
|
|
||||||
@ -53,10 +53,8 @@ class MessageQueue(object):
|
|||||||
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
|
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
|
||||||
problem_id=contest_problem.id)
|
problem_id=contest_problem.id)
|
||||||
# 提交次数加1
|
# 提交次数加1
|
||||||
contest_submission.total_submission_number += 1
|
|
||||||
|
|
||||||
if submission.result == result["accepted"]:
|
if submission.result == result["accepted"]:
|
||||||
|
|
||||||
# 避免这道题已经 ac 了,但是又重新提交了一遍
|
# 避免这道题已经 ac 了,但是又重新提交了一遍
|
||||||
if not contest_submission.ac:
|
if not contest_submission.ac:
|
||||||
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
|
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
|
||||||
@ -64,30 +62,40 @@ class MessageQueue(object):
|
|||||||
# logger.debug(submission.create_time)
|
# logger.debug(submission.create_time)
|
||||||
# logger.debug((submission.create_time - contest.start_time).total_seconds())
|
# logger.debug((submission.create_time - contest.start_time).total_seconds())
|
||||||
# logger.debug(int((submission.create_time - contest.start_time).total_seconds() / 60))
|
# logger.debug(int((submission.create_time - contest.start_time).total_seconds() / 60))
|
||||||
contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds() / 60)
|
contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds())
|
||||||
contest_submission.total_time += contest_submission.ac_time
|
contest_submission.total_time += contest_submission.ac_time
|
||||||
|
contest_submission.total_submission_number += 1
|
||||||
# 标记为已经通过
|
# 标记为已经通过
|
||||||
|
if contest_problem.total_accepted_number == 0:
|
||||||
|
contest_submission.first_achieved = True
|
||||||
contest_submission.ac = True
|
contest_submission.ac = True
|
||||||
# contest problem ac 计数器加1
|
# contest problem ac 计数器加1
|
||||||
contest_problem.total_accepted_number += 1
|
contest_problem.total_accepted_number += 1
|
||||||
else:
|
else:
|
||||||
# 如果这个提交是错误的,就罚时20分钟
|
# 如果这个提交是错误的,就罚时20分钟
|
||||||
contest_submission.total_time += 20
|
contest_submission.total_time += 1200
|
||||||
|
contest_submission.total_submission_number += 1
|
||||||
contest_submission.save()
|
contest_submission.save()
|
||||||
contest_problem.save()
|
contest_problem.save()
|
||||||
except ContestSubmission.DoesNotExist:
|
except ContestSubmission.DoesNotExist:
|
||||||
# 第一次提交
|
# 第一次提交
|
||||||
is_ac = submission.result == result["accepted"]
|
is_ac = submission.result == result["accepted"]
|
||||||
|
first_achieved = False
|
||||||
|
ac_time = 0
|
||||||
if is_ac:
|
if is_ac:
|
||||||
total_time = int((submission.create_time - contest.start_time).total_seconds() / 60)
|
ac_time = int((submission.create_time - contest.start_time).total_seconds())
|
||||||
|
total_time = int((submission.create_time - contest.start_time).total_seconds())
|
||||||
# 增加题目总的ac数计数器
|
# 增加题目总的ac数计数器
|
||||||
|
if contest_problem.total_accepted_number == 0:
|
||||||
|
first_achieved = True
|
||||||
contest_problem.total_accepted_number += 1
|
contest_problem.total_accepted_number += 1
|
||||||
contest_problem.save()
|
contest_problem.save()
|
||||||
else:
|
else:
|
||||||
# 没过罚时20分钟
|
# 没过罚时20分钟
|
||||||
total_time = 20
|
total_time = 1200
|
||||||
ContestSubmission.objects.create(user_id=submission.user_id, contest=contest, problem=contest_problem,
|
ContestSubmission.objects.create(user_id=submission.user_id, contest=contest, problem=contest_problem,
|
||||||
ac=is_ac, total_time=total_time)
|
ac=is_ac, total_time=total_time, first_achieved=first_achieved,
|
||||||
|
ac_time=ac_time)
|
||||||
|
|
||||||
|
|
||||||
logger.debug("Start message queue")
|
logger.debug("Start message queue")
|
||||||
|
@ -3,10 +3,6 @@ import os
|
|||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
# 下面是需要自己修改的
|
|
||||||
LOG_PATH = "log/"
|
|
||||||
|
|
||||||
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
|
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
@ -17,11 +13,11 @@ DATABASES = {
|
|||||||
'submission': {
|
'submission': {
|
||||||
'NAME': 'oj_submission',
|
'NAME': 'oj_submission',
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'HOST': "121.42.32.129",
|
'CONN_MAX_AGE': 0.1,
|
||||||
|
'HOST': "127.0.0.1",
|
||||||
'PORT': 3306,
|
'PORT': 3306,
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'mypwd',
|
'PASSWORD': 'root',
|
||||||
'CONN_MAX_AGE': 0.1,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +29,11 @@ REDIS_CACHE = {
|
|||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
# 同理 这是 web 服务器的上传路径
|
|
||||||
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
IMAGE_UPLOAD_DIR = os.path.join(BASE_DIR, 'static/src/upload_image/')
|
# 在 debug 关闭的情况下,静态文件不是有 django runserver 来处理的,应该由 nginx 返回
|
||||||
|
# 在 debug 开启的情况下,django 会在下面两个文件夹中寻找对应的静态文件。
|
||||||
|
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/src/"), BASE_DIR]
|
||||||
|
|
||||||
|
# 模板文件夹
|
||||||
|
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/src/')]
|
@ -3,43 +3,41 @@ import os
|
|||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
# 下面是需要自己修改的
|
|
||||||
LOG_PATH = "/var/log/oj/"
|
|
||||||
|
|
||||||
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
|
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': "oj",
|
'NAME': "oj",
|
||||||
'CONN_MAX_AGE': 0.1,
|
'CONN_MAX_AGE': 0.1,
|
||||||
'HOST': '127.0.0.1',
|
'HOST': os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"),
|
||||||
'PORT': 3306,
|
'PORT': 3306,
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'mypwd'
|
'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
|
||||||
},
|
},
|
||||||
'submission': {
|
'submission': {
|
||||||
'NAME': 'oj_submission',
|
'NAME': 'oj_submission',
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'CONN_MAX_AGE': 0.1,
|
'CONN_MAX_AGE': 0.1,
|
||||||
'HOST': "127.0.0.1",
|
'HOST': os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"),
|
||||||
'PORT': 3306,
|
'PORT': 3306,
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'mypwd'
|
'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
REDIS_CACHE = {
|
REDIS_CACHE = {
|
||||||
"host": "127.0.0.1",
|
"host": os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1"),
|
||||||
"port": 6379,
|
"port": 6379,
|
||||||
"db": 1
|
"db": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
|
|
||||||
# 同理 这是 web 服务器的上传路径
|
|
||||||
TEST_CASE_DIR = '/root/test_case/'
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
IMAGE_UPLOAD_DIR = '/var/mnt/source/OnlineJudge/static/src/upload_image/'
|
# 在 debug 关闭的情况下,静态文件不是有 django runserver 来处理的,应该由 nginx 返回
|
||||||
|
# 在 debug 开启的情况下,django 会在下面两个文件夹中寻找对应的静态文件。
|
||||||
|
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/release/"), os.path.join(BASE_DIR, "static/release/")]
|
||||||
|
|
||||||
|
# 模板文件夹
|
||||||
|
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/release/')]
|
||||||
|
@ -32,8 +32,6 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
SECRET_KEY = 'hzfp^8mbgapc&x%$#xv)0=t8s7_ilingw(q3!@h&2fty6v6fxz'
|
SECRET_KEY = 'hzfp^8mbgapc&x%$#xv)0=t8s7_ilingw(q3!@h&2fty6v6fxz'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
@ -76,7 +74,7 @@ ROOT_URLCONF = 'oj.urls'
|
|||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [os.path.join(BASE_DIR, 'template/src')],
|
'DIRS': TEMPLATE_DIRS,
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
@ -91,7 +89,6 @@ TEMPLATES = [
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'oj.wsgi.application'
|
WSGI_APPLICATION = 'oj.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||||
|
|
||||||
@ -111,10 +108,11 @@ USE_TZ = True
|
|||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),)
|
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'account.User'
|
AUTH_USER_MODEL = 'account.User'
|
||||||
|
|
||||||
|
LOG_PATH = "log/"
|
||||||
|
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': True,
|
'disable_existing_loggers': True,
|
||||||
@ -167,3 +165,7 @@ REST_FRAMEWORK = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DATABASE_ROUTERS = ['oj.db_router.DBRouter']
|
DATABASE_ROUTERS = ['oj.db_router.DBRouter']
|
||||||
|
|
||||||
|
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
|
||||||
|
|
||||||
|
IMAGE_UPLOAD_DIR = os.path.join(BASE_DIR, 'upload/')
|
@ -31,6 +31,7 @@ class CreateProblemSerializer(serializers.Serializer):
|
|||||||
difficulty = serializers.IntegerField()
|
difficulty = serializers.IntegerField()
|
||||||
tags = serializers.ListField(child=serializers.CharField(max_length=10))
|
tags = serializers.ListField(child=serializers.CharField(max_length=10))
|
||||||
hint = serializers.CharField(max_length=3000, allow_blank=True)
|
hint = serializers.CharField(max_length=3000, allow_blank=True)
|
||||||
|
visible = visible = serializers.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
class ProblemTagSerializer(serializers.ModelSerializer):
|
class ProblemTagSerializer(serializers.ModelSerializer):
|
||||||
|
@ -13,13 +13,16 @@ from rest_framework.views import APIView
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
from announcement.models import Announcement
|
from announcement.models import Announcement
|
||||||
from utils.shortcuts import (serializer_invalid_response, error_response,
|
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||||
success_response, paginate, rand_str, error_page)
|
success_response, paginate, rand_str, error_page)
|
||||||
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
|
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
|
||||||
ProblemTagSerializer, CreateProblemTagSerializer)
|
ProblemTagSerializer, CreateProblemTagSerializer)
|
||||||
from .models import Problem, ProblemTag
|
from .models import Problem, ProblemTag
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger("app_info")
|
||||||
|
|
||||||
def problem_page(request, problem_id):
|
def problem_page(request, problem_id):
|
||||||
try:
|
try:
|
||||||
@ -56,7 +59,8 @@ class ProblemAdminAPIView(APIView):
|
|||||||
memory_limit=data["memory_limit"],
|
memory_limit=data["memory_limit"],
|
||||||
difficulty=data["difficulty"],
|
difficulty=data["difficulty"],
|
||||||
created_by=request.user,
|
created_by=request.user,
|
||||||
hint=data["hint"])
|
hint=data["hint"],
|
||||||
|
visible=data["visible"])
|
||||||
for tag in data["tags"]:
|
for tag in data["tags"]:
|
||||||
try:
|
try:
|
||||||
tag = ProblemTag.objects.get(name=tag)
|
tag = ProblemTag.objects.get(name=tag)
|
||||||
@ -151,8 +155,9 @@ class TestCaseUploadAPIView(APIView):
|
|||||||
with open(tmp_zip, "wb") as test_case_zip:
|
with open(tmp_zip, "wb") as test_case_zip:
|
||||||
for chunk in f:
|
for chunk in f:
|
||||||
test_case_zip.write(chunk)
|
test_case_zip.write(chunk)
|
||||||
except IOError:
|
except IOError as e:
|
||||||
return error_response(u"上传错误,写入临时目录失败")
|
logger.error(e)
|
||||||
|
return error_response(u"上传失败")
|
||||||
|
|
||||||
test_case_file = zipfile.ZipFile(tmp_zip, 'r')
|
test_case_file = zipfile.ZipFile(tmp_zip, 'r')
|
||||||
name_list = test_case_file.namelist()
|
name_list = test_case_file.namelist()
|
||||||
|
@ -108,3 +108,8 @@ li.list-group-item {
|
|||||||
#about-acm-logo{
|
#about-acm-logo{
|
||||||
width: 40%;
|
width: 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rank .first-achieved{
|
||||||
|
background: #33CC99;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
ajaxData.groups = selectedGroups;
|
ajaxData.groups = selectedGroups;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (vm.password) {
|
if (vm.editPassword) {
|
||||||
ajaxData.password = vm.editPassword;
|
ajaxData.password = vm.editPassword;
|
||||||
ajaxData.contest_type = 2;
|
ajaxData.contest_type = 2;
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
allGroups: [],
|
allGroups: [],
|
||||||
showGlobalViewRadio: true,
|
showGlobalViewRadio: true,
|
||||||
|
admin_type: 1,
|
||||||
getNext: function () {
|
getNext: function () {
|
||||||
if (!vm.nextPage)
|
if (!vm.nextPage)
|
||||||
return;
|
return;
|
||||||
@ -211,6 +211,39 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
if (el)
|
if (el)
|
||||||
problemId = el.id;
|
problemId = el.id;
|
||||||
vm.$fire("up!showContestSubmissionPage", problemId, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
|
vm.$fire("up!showContestSubmissionPage", problemId, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
|
||||||
|
},
|
||||||
|
addToProblemList: function (problem) {
|
||||||
|
var ajaxData = {
|
||||||
|
title: problem.title,
|
||||||
|
description: problem.description,
|
||||||
|
time_limit: problem.time_limit,
|
||||||
|
memory_limit: problem.memory_limit,
|
||||||
|
samples: problem.samples,
|
||||||
|
test_case_id: problem.test_case_id,
|
||||||
|
hint: problem.hint,
|
||||||
|
source: problem.contest.title,
|
||||||
|
visible: false,
|
||||||
|
tags: [],
|
||||||
|
input_description: problem.input_description,
|
||||||
|
output_description: problem.output_description,
|
||||||
|
difficulty: 0
|
||||||
|
};
|
||||||
|
$.ajax({
|
||||||
|
beforeSend: csrfTokenHeader,
|
||||||
|
url: "/api/admin/problem/",
|
||||||
|
dataType: "json",
|
||||||
|
data: JSON.stringify(ajaxData),
|
||||||
|
method: "post",
|
||||||
|
contentType: "application/json",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
bsAlert("题目添加成功!题目现在处于隐藏状态,请到题目列表手动修改,并添加分类和难度信息!");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bsAlert(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
vm.$watch("showVisibleOnly", function () {
|
vm.$watch("showVisibleOnly", function () {
|
||||||
@ -266,6 +299,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (!data.code) {
|
if (!data.code) {
|
||||||
var admin_type = data.data.admin_type;
|
var admin_type = data.data.admin_type;
|
||||||
|
vm.admin_type = admin_type;
|
||||||
if (data.data.admin_type == 1) {
|
if (data.data.admin_type == 1) {
|
||||||
vm.isGlobal = false;
|
vm.isGlobal = false;
|
||||||
vm.showGlobalViewRadio = false;
|
vm.showGlobalViewRadio = false;
|
||||||
@ -278,6 +312,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (!data.code) {
|
if (!data.code) {
|
||||||
if (!data.data.length) {
|
if (!data.data.length) {
|
||||||
|
|
||||||
if (admin_type != 2)
|
if (admin_type != 2)
|
||||||
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
||||||
return;
|
return;
|
||||||
|
@ -117,11 +117,11 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
|
|||||||
|
|
||||||
function guessLanguage(code) {
|
function guessLanguage(code) {
|
||||||
//cpp
|
//cpp
|
||||||
if (code.indexOf("using namespace std") > -1) {
|
if (code.indexOf("using namespace std") > -1||code.indexOf("<cstdio>") > -1) {
|
||||||
return "2";
|
return "2";
|
||||||
}
|
}
|
||||||
//c
|
if (code.indexOf("printf"))
|
||||||
if (code.indexOf("printf") > -1) {
|
{
|
||||||
return "1";
|
return "1";
|
||||||
}
|
}
|
||||||
//java
|
//java
|
||||||
@ -146,6 +146,19 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (language < 3) {
|
||||||
|
if (code.indexOf("__int64") > -1) {
|
||||||
|
if (!confirm("您是否在尝试使用'__int64'类型? 这不是 c/c++ 标准并将引发编译错误可以使用 'long long' 代替(详见 关于->帮助),是否仍然提交?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (code.indexOf("%I64d") > -1) {
|
||||||
|
if (!confirm("您是否在尝试将'%I64d'用于long long类型的I/O? 这不被支持,并可能会导致程序输出异常,可以使用 '%lld' 代替(详见 关于->帮助),是否仍然提交?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (location.href.indexOf("contest") > -1) {
|
if (location.href.indexOf("contest") > -1) {
|
||||||
var problemId = location.pathname.split("/")[4];
|
var problemId = location.pathname.split("/")[4];
|
||||||
var contestId = location.pathname.split("/")[2];
|
var contestId = location.pathname.split("/")[2];
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了;
|
// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了;
|
||||||
paths: {
|
paths: {
|
||||||
jquery: "empty:",
|
jquery: "empty:",
|
||||||
avalon: "lib/avalon/avalon",
|
avalon: "empty:",
|
||||||
editor: "utils/editor",
|
editor: "utils/editor",
|
||||||
uploader: "utils/uploader",
|
uploader: "utils/uploader",
|
||||||
formValidation: "utils/formValidation",
|
formValidation: "utils/formValidation",
|
||||||
@ -70,9 +70,71 @@
|
|||||||
appDir: "../",
|
appDir: "../",
|
||||||
dir: "../../release/",
|
dir: "../../release/",
|
||||||
modules: [
|
modules: [
|
||||||
|
{
|
||||||
|
name: "bootstrap",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "addProblem_0_pack"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "addContest_1_pack"
|
name: "addContest_1_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "problem_2_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "register_3_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "contestList_4_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "group_5_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "editProblem_6_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "announcement_7_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "monitor_8_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "groupDetail_9_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "admin_10_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "problem_11_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "submissionList_12_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "editProblem_13_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "joinGroupRequestList_14_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "changePassword_15_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "group_16_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "submissionList_17_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "login_18_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "contestPassword_19_pack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "userList_20_pack"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
optimizeCss: "standard",
|
optimizeCss: "standard",
|
||||||
|
@ -21,7 +21,6 @@ from .models import Submission
|
|||||||
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer
|
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SubmissionAPIView(APIView):
|
class SubmissionAPIView(APIView):
|
||||||
@login_required
|
@login_required
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
@ -81,7 +80,8 @@ def problem_my_submissions_list_page(request, problem_id):
|
|||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
return error_page(request, u"问题不存在")
|
return error_page(request, u"问题不存在")
|
||||||
|
|
||||||
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id, contest_id__isnull=True).order_by("-create_time"). \
|
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id,
|
||||||
|
contest_id__isnull=True).order_by("-create_time"). \
|
||||||
values("id", "result", "create_time", "accepted_answer_time", "language")
|
values("id", "result", "create_time", "accepted_answer_time", "language")
|
||||||
|
|
||||||
return render(request, "oj/problem/my_submissions_list.html",
|
return render(request, "oj/problem/my_submissions_list.html",
|
||||||
|
@ -31,9 +31,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="active"><a href="#">主页</a></li>
|
<li class="active"><a href="/" target="_blank">主页</a></li>
|
||||||
<li><a href="#about">题目</a></li>
|
<li><a href="#problem">题目</a></li>
|
||||||
<li><a href="#contact">提交</a></li>
|
<li><a href="#">提交</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
|
@ -178,6 +178,8 @@
|
|||||||
ms-click="showProblemEditPage(el)">编辑</a>
|
ms-click="showProblemEditPage(el)">编辑</a>
|
||||||
<a href="javascript:void(0)" class="btn-sm btn-info"
|
<a href="javascript:void(0)" class="btn-sm btn-info"
|
||||||
ms-click="showSubmissionPage(el)">提交</a>
|
ms-click="showSubmissionPage(el)">提交</a>
|
||||||
|
<a href="javascript:void(0)" class="btn-sm btn-info"
|
||||||
|
ms-click="addToProblemList(el)" ms-visible="admin_type=='2'">添加到前台</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{% extends "oj_base.html" %}
|
{% extends "oj_base.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% load submission %}
|
|
||||||
<div class="container main">
|
<div class="container main">
|
||||||
|
|
||||||
<ul class="nav nav-tabs nav-tabs-google contest-tab">
|
<ul class="nav nav-tabs nav-tabs-google contest-tab">
|
||||||
@ -19,31 +18,43 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<h2 class="text-center">排名(
|
||||||
|
{% if real_time_rank %}
|
||||||
|
实时
|
||||||
|
{% else %}
|
||||||
|
已封榜
|
||||||
|
{% endif %})
|
||||||
|
</h2>
|
||||||
{% if result %}
|
{% if result %}
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered text-center">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>用户名</th>
|
<th class="text-center">用户名</th>
|
||||||
<th>AC / 总提交</th>
|
<th class="text-center">AC / 总提交</th>
|
||||||
<th>用时 + 罚时</th>
|
<th class="text-center">用时 + 罚时</th>
|
||||||
{% for item in contest_problems %}
|
{% for item in contest_problems %}
|
||||||
<th><a href="/contest/{{ contest.id }}/problem/{{ item.id }}/">{{ item.sort_index }}</a>
|
<th class="text-center"><a
|
||||||
|
href="/contest/{{ contest.id }}/problem/{{ item.id }}/">{{ item.sort_index }}</a>
|
||||||
</th>
|
</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody class="rank">
|
||||||
{% for item in result %}
|
{% for item in result %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{{ forloop.counter }}</th>
|
<th scope="row">{{ forloop.counter }}</th>
|
||||||
<td>{{ item.user.username }}</td>
|
<td>{{ item.username }}</td>
|
||||||
<td>{{ item.total_ac }} / {{ item.total_submit }}</td>
|
<td>{{ item.total_ac }} / {{ item.total_submit }}</td>
|
||||||
<td>{% if item.total_time %}{{ item.total_time }} min{% else %}--{% endif %}</td>
|
<td>{% if item.total_time %}{{ item.total_time }}{% else %}--{% endif %}</td>
|
||||||
{% for problem in contest_problems %}
|
{% for problem in item.problems %}
|
||||||
<td class="{% submission_problem_result_class problem item.submissions %}">
|
<td class="
|
||||||
{% submission_problem problem item.submissions %}
|
{% if problem %}{% if problem.ac %}{% if problem.first_achieved %}first-achieved{% else %}alert-success{% endif %}{% else %}alert-danger{% endif %}{% endif %}">
|
||||||
|
{% if problem.ac %}{{ problem.ac_time }}{% endif %}
|
||||||
|
{% if problem.failed_number %}
|
||||||
|
(-{{ problem.failed_number }})
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
@ -59,6 +70,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@
|
|||||||
{{ request.user.username }}
|
{{ request.user.username }}
|
||||||
<span class="caret"></span></a>
|
<span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
{% if request.user.admin_type == 2 %}
|
||||||
|
<li><a href="/admin/">后台管理</a></li>
|
||||||
|
{% endif %}
|
||||||
<li><a href="/submissions/">我的提交</a></li>
|
<li><a href="/submissions/">我的提交</a></li>
|
||||||
<li><a href="#">我的资料</a></li>
|
<li><a href="#">我的资料</a></li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
{% extends "oj_base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="container main">
|
||||||
|
<ul class="nav nav-tabs nav-tabs-google">
|
||||||
|
<li role="presentation" class="active">
|
||||||
|
<a href="/help/">帮助</a>
|
||||||
|
</li>
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="/about/">关于</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div>
|
||||||
|
<h2 class="text-center">判题系统</h2>
|
||||||
|
<h4>判题结果</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Accepted: 你的答案符合判题标准</li>
|
||||||
|
<li>Runtime Error: 你的程序运行时出现错误(指针越界,栈溢出,有未处理的异常,主函数返回值非零等)</li>
|
||||||
|
<li>Time Limit Exceeded: 你的程序执行时间超出题目要求</li>
|
||||||
|
<li>Memory Limit Exceeded: 你的程序内存使用超出题目要求</li>
|
||||||
|
<li>Compile Error: 你的程序在编译(包括链接)时出现错误</li>
|
||||||
|
<li>Wrong Answer: 你的程序输出的答案不符合判题标准</li>
|
||||||
|
<li>System Error: 判题系统发生故障,请等待重判</li>
|
||||||
|
<li>Waiting: 你的提交正在等待处理</li>
|
||||||
|
</ul>
|
||||||
|
<h4>支持的语言</h4>
|
||||||
|
<ul>
|
||||||
|
<li>C (GCC 4.8)</li>
|
||||||
|
|
||||||
|
<li>C++ (G++ 4.3)</li>
|
||||||
|
|
||||||
|
<li>Java (Oracle JDK 1.7)</li>
|
||||||
|
</ul>
|
||||||
|
<h4>编译参数</h4>
|
||||||
|
<ul>
|
||||||
|
<li>C</li>
|
||||||
|
<p>gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main</p>
|
||||||
|
<li>C++</li>
|
||||||
|
<p>g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main</p>
|
||||||
|
<li>Java</li>
|
||||||
|
<p>javac {src_path} -d {exe_path}</p>
|
||||||
|
<p>java -cp {exe_path} Main</p>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 class="text-center">常见问题</h2>
|
||||||
|
<ul>
|
||||||
|
<li>输入输出</li>
|
||||||
|
<p>无特殊说明,请使用标准输入输出</p>
|
||||||
|
<li>C/C++的64位整数类型</li>
|
||||||
|
<p>请使用long long声明,使用cin/cout或 %lld输入输出</p>
|
||||||
|
<li>判题结果与本地执行结果不一致</li>
|
||||||
|
<p>是否使用了不同版本的编译器(VC和TC并不完全符合C/C++标准)</p>
|
||||||
|
<p>判题时可能使用了与您测试时不同的测试数据(不仅限于样例中展示的数据)</p>
|
||||||
|
<li>程序执行时间和占用的内存如何计算</li>
|
||||||
|
<p>执行时间指CPU时间,占用内存按执行过程中内存消耗的峰值计,有多组测试数据时以最大的时间和内存消耗为准</p>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -9,9 +9,11 @@ template_release_path = "template/release/"
|
|||||||
|
|
||||||
static_src_path = "static/src/"
|
static_src_path = "static/src/"
|
||||||
static_release_path = "static/release/"
|
static_release_path = "static/release/"
|
||||||
|
try:
|
||||||
# 删除模板的 release 文件夹
|
# 删除模板的 release 文件夹
|
||||||
shutil.rmtree(template_release_path)
|
shutil.rmtree(template_release_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
# 复制一份模板文件夹到 release
|
# 复制一份模板文件夹到 release
|
||||||
shutil.copytree(template_src_path, template_release_path)
|
shutil.copytree(template_src_path, template_release_path)
|
||||||
|
|
||||||
|
@ -29,33 +29,7 @@ def translate_result_class(value):
|
|||||||
return "danger"
|
return "danger"
|
||||||
|
|
||||||
|
|
||||||
def get_contest_submission_problem_detail(contest_problem, my_submission):
|
|
||||||
if contest_problem.id in my_submission:
|
|
||||||
submission = my_submission[contest_problem.id]
|
|
||||||
if submission.ac:
|
|
||||||
# 只提交了一次就AC
|
|
||||||
if submission.total_submission_number == 1:
|
|
||||||
return str(submission.ac_time) + " min"
|
|
||||||
else:
|
|
||||||
return "20 min × " + str(submission.total_submission_number - 1) + " WA + " + str(submission.ac_time) + " min"
|
|
||||||
return str(submission.total_submission_number) + " WA"
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def get_submission_problem_result_class(contest_problem, my_submission):
|
|
||||||
if contest_problem.id in my_submission:
|
|
||||||
submission = my_submission[contest_problem.id]
|
|
||||||
if submission.ac:
|
|
||||||
return "success"
|
|
||||||
else:
|
|
||||||
return "danger"
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter("translate_result", translate_result)
|
register.filter("translate_result", translate_result)
|
||||||
register.filter("translate_language", translate_language)
|
register.filter("translate_language", translate_language)
|
||||||
register.filter("translate_result_class", translate_result_class)
|
register.filter("translate_result_class", translate_result_class)
|
||||||
register.simple_tag(get_contest_submission_problem_detail, name="submission_problem")
|
|
||||||
register.simple_tag(get_submission_problem_result_class, name="submission_problem_result_class")
|
|
@ -5,7 +5,9 @@ from rest_framework.response import Response
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from utils.shortcuts import rand_str
|
from utils.shortcuts import rand_str
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger("app_info")
|
||||||
|
|
||||||
class SimditorImageUploadAPIView(APIView):
|
class SimditorImageUploadAPIView(APIView):
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
@ -22,12 +24,13 @@ class SimditorImageUploadAPIView(APIView):
|
|||||||
with open(image_dir, "wb") as imageFile:
|
with open(image_dir, "wb") as imageFile:
|
||||||
for chunk in img:
|
for chunk in img:
|
||||||
imageFile.write(chunk)
|
imageFile.write(chunk)
|
||||||
except IOError:
|
except IOError as e:
|
||||||
|
logger.error(e)
|
||||||
return Response(data={
|
return Response(data={
|
||||||
"success": True,
|
"success": True,
|
||||||
"msg": "上传错误",
|
"msg": "上传错误",
|
||||||
"file_path": "/static/upload_image/" + image_name})
|
"file_path": "/static/upload/" + image_name})
|
||||||
return Response(data={
|
return Response(data={
|
||||||
"success": True,
|
"success": True,
|
||||||
"msg": "",
|
"msg": "",
|
||||||
"file_path": "/static/upload_image/" + image_name})
|
"file_path": "/static/upload/" + image_name})
|
||||||
|
Loading…
Reference in New Issue
Block a user