Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
* dev: (32 commits)
  添加帮助页面包含: 1.关于判题系统
  添加后台到前台的链接
  为超级管理员添加前台到后台的链接
  添加后台超级管理员把比赛题目添加到题目列表的功能,利用problemAdminAPIView的post实现,默认隐藏题目
  修改problemAdminAPIView,添加新建问题时对问题可见/不可见的支持
  去掉没用的标签,因为修改了排名的显示方法,用不着引用自定义标签了
  修复参数错误(复制粘贴没看好) 轻微修改代码提交页面js对语言小错误的提示功能。 再次添加C语言的提示 添加c++判断条件  cstdio
  修改提交代码页面的js逻辑,判断语言 更加宽泛, 添加 对于 __int64和%I64d错误的提醒
  修改静态文件打包过程中的 bug
  修复ac_time的问题,添加first_achieved逻辑
  修改rank 页面的bug(对于没有有效时间的用户时间格式转换失败),添加mq对first_achieved的支持
  修复问题,比赛列表编辑密码无法正常提交,写错变量名
  修改配置文件方便区分不同的开发环境
  根据不同的环境使用不同的配置文件
  创建 docker 镜像的时候使用阿里云的源
  修复 avalon 执行 bug
  修复typo
  刚刚漏了一项~
  更新数据库
  修改rank页面时间格式 hh:mm:ss,修改rank页面时间格式 hh:mm:ss,ContestSubmission中时间以秒计
  ...
  • Loading branch information
virusdefender committed Sep 15, 2015
2 parents 74f9c29 + 5e88e62 commit bd412dc
Show file tree
Hide file tree
Showing 28 changed files with 427 additions and 171 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ static/src/upload_image/*
build.txt
tmp/
test_case/
release/
release/
upload/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM python:2.7
ENV PYTHONBUFFERED 1
RUN mkdir -p /code/log /code/test_case
RUN mkdir -p /code/log /code/test_case /code/upload
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
Expand Down
19 changes: 19 additions & 0 deletions contest/migrations/0009_contestsubmission_first_achieved.py
Original file line number Diff line number Diff line change
@@ -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),
),
]
4 changes: 3 additions & 1 deletion contest/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ class ContestSubmission(models.Model):
total_submission_number = models.IntegerField(default=1)
# 这道题是 AC 还是没过
ac = models.BooleanField()
# ac 用时
# ac 用时以秒计
ac_time = models.IntegerField(default=0)
# 总的时间,用于acm 类型的,也需要保存罚时
total_time = models.IntegerField(default=0)
# 第一个解出此题目
first_achieved = models.BooleanField(default=False)

class Meta:
db_table = "contest_submission"
4 changes: 2 additions & 2 deletions contest/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CreateContestSerializer(serializers.Serializer):
description = serializers.CharField(max_length=5000)
mode = serializers.IntegerField()
contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
real_time_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
Expand Down Expand Up @@ -47,7 +47,7 @@ class EditContestSerializer(serializers.Serializer):
description = serializers.CharField(max_length=10000)
mode = serializers.IntegerField()
contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
real_time_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
Expand Down
72 changes: 56 additions & 16 deletions contest/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
CreateContestProblemSerializer, ContestProblemSerializer,
ContestPasswordVerifySerializer,
EditContestProblemSerializer)
from oj.settings import REDIS_CACHE
import redis


class ContestAdminAPIView(APIView):
Expand Down Expand Up @@ -58,7 +60,7 @@ def post(self, request):
try:
contest = Contest.objects.create(title=data["title"], description=data["description"],
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"],
start_time=dateparse.parse_datetime(data["start_time"]),
end_time=dateparse.parse_datetime(data["end_time"]),
Expand Down Expand Up @@ -112,7 +114,7 @@ def put(self, request):
contest.description = data["description"]
contest.mode = data["mode"]
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.start_time = dateparse.parse_datetime(data["start_time"])
contest.end_time = dateparse.parse_datetime(data["end_time"])
Expand Down Expand Up @@ -353,7 +355,6 @@ def contest_list_page(request, page=1):
if request.user.is_authenticated and join:
contests = contests.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all())). \
filter(end_time__gt=datetime.datetime.now(), start_time__lt=datetime.datetime.now())

paginator = Paginator(contests, 20)
try:
current_page = paginator.page(int(page))
Expand Down Expand Up @@ -390,23 +391,62 @@ def _cmp(x, y):
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
def contest_rank_page(request, contest_id):
contest = Contest.objects.get(id=contest_id)
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
result = ContestSubmission.objects.filter(contest=contest).values("user_id").\
annotate(total_submit=Sum("total_submission_number"))
for i in range(0, len(result)):
# 这个人所有的提交
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
result[i]["submissions"] = {}
for item in submissions:
result[i]["submissions"][item.problem_id] = item
result[i]["total_ac"] = submissions.filter(ac=True).count()
result[i]["user"] = User.objects.get(id=result[i]["user_id"])
result[i]["total_time"] = submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]
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"). \
annotate(total_submit=Sum("total_submission_number"))
for i in range(0, len(result)):
# 这个人所有的提交
submissions = ContestSubmission.objects.filter(user_id=result[i]["user_id"], contest_id=contest_id)
result[i]["submissions"] = {}
result[i]["problems"] = []
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]["username"] = User.objects.get(id=result[i]["user_id"]).username
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",
{"contest": contest, "contest_problems": contest_problems,
"result": sorted(result, cmp=_cmp, reverse=True),
"auto_refresh": request.GET.get("auto_refresh", None) == "true"})
"result": result,
"auto_refresh": request.GET.get("auto_refresh", None) == "true",
"real_time_rank": contest.real_time_rank})
2 changes: 2 additions & 0 deletions judge/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ MAINTAINER virusdefender<qduliyang@outlook.com>
RUN mkdir /var/install/
WORKDIR /var/install/
ENV DEBIAN_FRONTEND noninteractive
RUN rm /etc/apt/sources.list
COPY sources.list /etc/apt/
RUN apt-get update
RUN apt-get -y install software-properties-common python-software-properties
RUN add-apt-repository -y ppa:webupd8team/java
Expand Down
7 changes: 3 additions & 4 deletions judge/judger/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# coding=utf-8
import os
# 单个判题端最多同时运行的程序个数,因为判题端会同时运行多组测试数据,比如一共有5组测试数据
# 如果MAX_RUNNING_NUMBER大于等于5,那么这5组数据就会同时进行评测,然后返回结果。
# 如果MAX_RUNNING_NUMBER小于5,为3,那么就会同时运行前三组测试数据,然后再运行后两组数据
Expand All @@ -14,12 +15,10 @@
# judger工作目录
judger_workspace = "/var/judger/"


# 这个是在docker 中访问数据库 ip 不一定和web服务器还有celery的一样
submission_db = {
"host": "192.168.42.1",
"host": os.environ.get("MYSQL_PORT_3306_TCP_ADDR", "127.0.0.1"),
"port": 3306,
"db": "oj_submission",
"user": "root",
"password": "mypwd"
"password": os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
}
10 changes: 10 additions & 0 deletions judge/sources.list
Original file line number Diff line number Diff line change
@@ -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
24 changes: 16 additions & 8 deletions mq/scripts/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from submission.models import Submission
from problem.models import Problem
from contest.models import ContestProblem, Contest, ContestSubmission

from account.models import User
logger = logging.getLogger("app_info")


Expand Down Expand Up @@ -53,41 +53,49 @@ def listen_task(self):
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
problem_id=contest_problem.id)
# 提交次数加1
contest_submission.total_submission_number += 1

if submission.result == result["accepted"]:

# 避免这道题已经 ac 了,但是又重新提交了一遍
if not contest_submission.ac:
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
# logger.debug(contest.start_time)
# logger.debug(submission.create_time)
# logger.debug((submission.create_time - contest.start_time).total_seconds())
# 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_submission_number += 1
# 标记为已经通过
if contest_problem.total_accepted_number == 0:
contest_submission.first_achieved = True
contest_submission.ac = True
# contest problem ac 计数器加1
contest_problem.total_accepted_number += 1
else:
# 如果这个提交是错误的,就罚时20分钟
contest_submission.total_time += 20
contest_submission.total_time += 1200
contest_submission.total_submission_number += 1
contest_submission.save()
contest_problem.save()
except ContestSubmission.DoesNotExist:
# 第一次提交
is_ac = submission.result == result["accepted"]
first_achieved = False
ac_time = 0
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数计数器
if contest_problem.total_accepted_number == 0:
first_achieved = True
contest_problem.total_accepted_number += 1
contest_problem.save()
else:
# 没过罚时20分钟
total_time = 20
total_time = 1200
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")
Expand Down
20 changes: 9 additions & 11 deletions oj/local_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# 下面是需要自己修改的
LOG_PATH = "log/"

# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
DATABASES = {
'default': {
Expand All @@ -17,11 +13,11 @@
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'HOST': "121.42.32.129",
'CONN_MAX_AGE': 0.1,
'HOST': "127.0.0.1",
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'mypwd',
'CONN_MAX_AGE': 0.1,
'PASSWORD': 'root',
}
}

Expand All @@ -33,9 +29,11 @@

DEBUG = True

# 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')

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/')]
26 changes: 12 additions & 14 deletions oj/server_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,41 @@

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# 下面是需要自己修改的
LOG_PATH = "/var/log/oj/"

# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "oj",
'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,
'USER': 'root',
'PASSWORD': 'mypwd'
'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
},
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'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,
'USER': 'root',
'PASSWORD': 'mypwd'
'PASSWORD': os.environ.get("MYSQL_ENV_MYSQL_ROOT_PASSWORD", "root")
}
}

REDIS_CACHE = {
"host": "127.0.0.1",
"host": os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1"),
"port": 6379,
"db": 1
}

DEBUG = True

# 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = '/root/test_case/'
DEBUG = False

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/')]
Loading

0 comments on commit bd412dc

Please sign in to comment.