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/
|
||||
test_case/
|
||||
release/
|
||||
upload/
|
@ -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
|
||||
|
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)
|
||||
# 这道题是 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"
|
||||
|
@ -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()
|
||||
@ -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()
|
||||
|
@ -21,6 +21,8 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
|
||||
CreateContestProblemSerializer, ContestProblemSerializer,
|
||||
ContestPasswordVerifySerializer,
|
||||
EditContestProblemSerializer)
|
||||
from oj.settings import REDIS_CACHE
|
||||
import redis
|
||||
|
||||
|
||||
class ContestAdminAPIView(APIView):
|
||||
@ -58,7 +60,7 @@ class ContestAdminAPIView(APIView):
|
||||
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"]),
|
||||
@ -112,7 +114,7 @@ class ContestAdminAPIView(APIView):
|
||||
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"])
|
||||
@ -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))
|
||||
@ -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")
|
||||
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"] = {}
|
||||
for item in submissions:
|
||||
result[i]["submissions"][item.problem_id] = item
|
||||
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]["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"]
|
||||
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})
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,5 @@
|
||||
# coding=utf-8
|
||||
import os
|
||||
# 单个判题端最多同时运行的程序个数,因为判题端会同时运行多组测试数据,比如一共有5组测试数据
|
||||
# 如果MAX_RUNNING_NUMBER大于等于5,那么这5组数据就会同时进行评测,然后返回结果。
|
||||
# 如果MAX_RUNNING_NUMBER小于5,为3,那么就会同时运行前三组测试数据,然后再运行后两组数据
|
||||
@ -14,12 +15,10 @@ lrun_gid = 1002
|
||||
# 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
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 problem.models import Problem
|
||||
from contest.models import ContestProblem, Contest, ContestSubmission
|
||||
|
||||
from account.models import User
|
||||
logger = logging.getLogger("app_info")
|
||||
|
||||
|
||||
@ -53,10 +53,8 @@ class MessageQueue(object):
|
||||
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:
|
||||
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
|
||||
@ -64,30 +62,40 @@ class MessageQueue(object):
|
||||
# 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")
|
||||
|
@ -3,10 +3,6 @@ import os
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# 下面是需要自己修改的
|
||||
LOG_PATH = "log/"
|
||||
|
||||
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@ -17,11 +13,11 @@ DATABASES = {
|
||||
'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',
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,9 +29,11 @@ REDIS_CACHE = {
|
||||
|
||||
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/')]
|
@ -3,43 +3,41 @@ import os
|
||||
|
||||
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/')]
|
||||
|
@ -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'
|
||||
|
||||
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = (
|
||||
@ -76,7 +74,7 @@ ROOT_URLCONF = 'oj.urls'
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'template/src')],
|
||||
'DIRS': TEMPLATE_DIRS,
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
@ -91,7 +89,6 @@ TEMPLATES = [
|
||||
|
||||
WSGI_APPLICATION = 'oj.wsgi.application'
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
||||
@ -111,10 +108,11 @@ USE_TZ = True
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),)
|
||||
|
||||
AUTH_USER_MODEL = 'account.User'
|
||||
|
||||
LOG_PATH = "log/"
|
||||
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
@ -167,3 +165,7 @@ REST_FRAMEWORK = {
|
||||
}
|
||||
|
||||
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()
|
||||
tags = serializers.ListField(child=serializers.CharField(max_length=10))
|
||||
hint = serializers.CharField(max_length=3000, allow_blank=True)
|
||||
visible = visible = serializers.BooleanField()
|
||||
|
||||
|
||||
class ProblemTagSerializer(serializers.ModelSerializer):
|
||||
|
@ -13,13 +13,16 @@ from rest_framework.views import APIView
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
from announcement.models import Announcement
|
||||
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||
success_response, paginate, rand_str, error_page)
|
||||
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
|
||||
ProblemTagSerializer, CreateProblemTagSerializer)
|
||||
from .models import Problem, ProblemTag
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("app_info")
|
||||
|
||||
def problem_page(request, problem_id):
|
||||
try:
|
||||
@ -56,7 +59,8 @@ class ProblemAdminAPIView(APIView):
|
||||
memory_limit=data["memory_limit"],
|
||||
difficulty=data["difficulty"],
|
||||
created_by=request.user,
|
||||
hint=data["hint"])
|
||||
hint=data["hint"],
|
||||
visible=data["visible"])
|
||||
for tag in data["tags"]:
|
||||
try:
|
||||
tag = ProblemTag.objects.get(name=tag)
|
||||
@ -151,8 +155,9 @@ class TestCaseUploadAPIView(APIView):
|
||||
with open(tmp_zip, "wb") as test_case_zip:
|
||||
for chunk in f:
|
||||
test_case_zip.write(chunk)
|
||||
except IOError:
|
||||
return error_response(u"上传错误,写入临时目录失败")
|
||||
except IOError as e:
|
||||
logger.error(e)
|
||||
return error_response(u"上传失败")
|
||||
|
||||
test_case_file = zipfile.ZipFile(tmp_zip, 'r')
|
||||
name_list = test_case_file.namelist()
|
||||
|
@ -108,3 +108,8 @@ li.list-group-item {
|
||||
#about-acm-logo{
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.rank .first-achieved{
|
||||
background: #33CC99;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
ajaxData.groups = selectedGroups;
|
||||
}
|
||||
else {
|
||||
if (vm.password) {
|
||||
if (vm.editPassword) {
|
||||
ajaxData.password = vm.editPassword;
|
||||
ajaxData.contest_type = 2;
|
||||
}
|
||||
@ -114,7 +114,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
isGlobal: true,
|
||||
allGroups: [],
|
||||
showGlobalViewRadio: true,
|
||||
|
||||
admin_type: 1,
|
||||
getNext: function () {
|
||||
if (!vm.nextPage)
|
||||
return;
|
||||
@ -211,6 +211,39 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
if (el)
|
||||
problemId = el.id;
|
||||
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 () {
|
||||
@ -266,6 +299,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
var admin_type = data.data.admin_type;
|
||||
vm.admin_type = admin_type;
|
||||
if (data.data.admin_type == 1) {
|
||||
vm.isGlobal = false;
|
||||
vm.showGlobalViewRadio = false;
|
||||
@ -278,6 +312,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
if (!data.data.length) {
|
||||
|
||||
if (admin_type != 2)
|
||||
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
||||
return;
|
||||
|
@ -117,11 +117,11 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
|
||||
|
||||
function guessLanguage(code) {
|
||||
//cpp
|
||||
if (code.indexOf("using namespace std") > -1) {
|
||||
if (code.indexOf("using namespace std") > -1||code.indexOf("<cstdio>") > -1) {
|
||||
return "2";
|
||||
}
|
||||
//c
|
||||
if (code.indexOf("printf") > -1) {
|
||||
if (code.indexOf("printf"))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
//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) {
|
||||
var problemId = location.pathname.split("/")[4];
|
||||
var contestId = location.pathname.split("/")[2];
|
||||
|
@ -4,7 +4,7 @@
|
||||
// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了;
|
||||
paths: {
|
||||
jquery: "empty:",
|
||||
avalon: "lib/avalon/avalon",
|
||||
avalon: "empty:",
|
||||
editor: "utils/editor",
|
||||
uploader: "utils/uploader",
|
||||
formValidation: "utils/formValidation",
|
||||
@ -70,9 +70,71 @@
|
||||
appDir: "../",
|
||||
dir: "../../release/",
|
||||
modules: [
|
||||
|
||||
{
|
||||
name: "bootstrap",
|
||||
},
|
||||
{
|
||||
name: "addProblem_0_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",
|
||||
|
@ -21,7 +21,6 @@ from .models import Submission
|
||||
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer
|
||||
|
||||
|
||||
|
||||
class SubmissionAPIView(APIView):
|
||||
@login_required
|
||||
def post(self, request):
|
||||
@ -81,7 +80,8 @@ def problem_my_submissions_list_page(request, problem_id):
|
||||
except Problem.DoesNotExist:
|
||||
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")
|
||||
|
||||
return render(request, "oj/problem/my_submissions_list.html",
|
||||
|
@ -31,9 +31,9 @@
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#">主页</a></li>
|
||||
<li><a href="#about">题目</a></li>
|
||||
<li><a href="#contact">提交</a></li>
|
||||
<li class="active"><a href="/" target="_blank">主页</a></li>
|
||||
<li><a href="#problem">题目</a></li>
|
||||
<li><a href="#">提交</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
|
@ -178,6 +178,8 @@
|
||||
ms-click="showProblemEditPage(el)">编辑</a>
|
||||
<a href="javascript:void(0)" class="btn-sm btn-info"
|
||||
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>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,6 +1,5 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
{% load submission %}
|
||||
<div class="container main">
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-google contest-tab">
|
||||
@ -19,31 +18,43 @@
|
||||
</ul>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12">
|
||||
<h2 class="text-center">排名(
|
||||
{% if real_time_rank %}
|
||||
实时
|
||||
{% else %}
|
||||
已封榜
|
||||
{% endif %})
|
||||
</h2>
|
||||
{% if result %}
|
||||
<table class="table table-bordered">
|
||||
<table class="table table-bordered text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>用户名</th>
|
||||
<th>AC / 总提交</th>
|
||||
<th>用时 + 罚时</th>
|
||||
<th class="text-center">用户名</th>
|
||||
<th class="text-center">AC / 总提交</th>
|
||||
<th class="text-center">用时 + 罚时</th>
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="rank">
|
||||
{% for item in result %}
|
||||
<tr>
|
||||
<th scope="row">{{ forloop.counter }}</th>
|
||||
<td>{{ item.user.username }}</td>
|
||||
<td>{{ item.username }}</td>
|
||||
<td>{{ item.total_ac }} / {{ item.total_submit }}</td>
|
||||
<td>{% if item.total_time %}{{ item.total_time }} min{% else %}--{% endif %}</td>
|
||||
{% for problem in contest_problems %}
|
||||
<td class="{% submission_problem_result_class problem item.submissions %}">
|
||||
{% submission_problem problem item.submissions %}
|
||||
<td>{% if item.total_time %}{{ item.total_time }}{% else %}--{% endif %}</td>
|
||||
{% for problem in item.problems %}
|
||||
<td class="
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@ -59,6 +70,7 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -57,6 +57,9 @@
|
||||
{{ request.user.username }}
|
||||
<span class="caret"></span></a>
|
||||
<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="#">我的资料</a></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_release_path = "static/release/"
|
||||
|
||||
try:
|
||||
# 删除模板的 release 文件夹
|
||||
shutil.rmtree(template_release_path)
|
||||
except Exception:
|
||||
pass
|
||||
# 复制一份模板文件夹到 release
|
||||
shutil.copytree(template_src_path, template_release_path)
|
||||
|
||||
|
@ -29,33 +29,7 @@ def translate_result_class(value):
|
||||
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.filter("translate_result", translate_result)
|
||||
register.filter("translate_language", translate_language)
|
||||
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 utils.shortcuts import rand_str
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("app_info")
|
||||
|
||||
class SimditorImageUploadAPIView(APIView):
|
||||
def post(self, request):
|
||||
@ -22,12 +24,13 @@ class SimditorImageUploadAPIView(APIView):
|
||||
with open(image_dir, "wb") as imageFile:
|
||||
for chunk in img:
|
||||
imageFile.write(chunk)
|
||||
except IOError:
|
||||
except IOError as e:
|
||||
logger.error(e)
|
||||
return Response(data={
|
||||
"success": True,
|
||||
"msg": "上传错误",
|
||||
"file_path": "/static/upload_image/" + image_name})
|
||||
"file_path": "/static/upload/" + image_name})
|
||||
return Response(data={
|
||||
"success": True,
|
||||
"msg": "",
|
||||
"file_path": "/static/upload_image/" + image_name})
|
||||
"file_path": "/static/upload/" + image_name})
|
||||
|
Loading…
Reference in New Issue
Block a user