Merge branch 'dev' of git.coding.net:virusdefender/qduoj into dev

Conflicts:
	template/src/oj/problem/problem.html
This commit is contained in:
sxw@401
2015-09-08 18:55:17 +08:00
30 changed files with 559 additions and 152 deletions

View File

@@ -1,13 +1,7 @@
FROM python:2.7
ENV PYTHONUNBUFFERED 1
ENV oj_env daocloud
RUN mkdir /var/oj
COPY . /var/oj/
WORKDIR /var/oj/
ENV PYTHONBUFFERED 1
RUN mkdir -p /code/log /code/test_case
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
EXPOSE 8080
RUN mkdir LOG
RUN mkdir test_case
RUN mkdir tmp
RUN python manage.py migrate
CMD python manage.py runserver 0.0.0.0:8080
EXPOSE 8010

View File

@@ -370,7 +370,7 @@ class UserLogoutTest(TestCase):
user.set_password("1")
user.save()
def logout_success(self):
def test_logout_success(self):
self.client = Client()
self.client.login(username="test", password="1")
response = self.client.get("/logout/")

9
contest/test_urls.py Normal file
View File

@@ -0,0 +1,9 @@
# coding=utf-8
from django.conf.urls import include, url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
]

View File

@@ -1,15 +1,18 @@
# coding=utf-8
import json
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test import TestCase, Client
from django.http import HttpResponse
from rest_framework.test import APITestCase, APIClient
from account.models import User
from group.models import Group
from contest.models import Contest, ContestProblem
from .models import ContestSubmission
from announcement.models import Announcement
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from decorators import check_user_contest_permission
class ContestAdminAPITest(APITestCase):
@@ -398,3 +401,181 @@ class ContestProblemAdminAPItEST(APITestCase):
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 1)
class ContestPasswordVerifyAPITest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse('contest_password_verify_api')
self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user.set_password("testaa")
self.user.save()
self.user2 = User.objects.create(username="test2", admin_type=ADMIN)
self.user2.set_password("testbb")
self.user2.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
def test_invalid_format(self):
self.client.login(username="test2", password="testbb")
data = {"contest_id": self.global_contest.id}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_contest_does_not_exist(self):
self.client.login(username="test2", password="testbb")
data = {"contest_id": self.global_contest.id + 1, "password": "aacc"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"比赛不存在"})
def test_contest_password_verify_unsuccessfully(self):
self.client.login(username="test2", password="testbb")
data = {"contest_id": self.global_contest.id, "password": "aabb"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"密码错误"})
def test_contest_password_verify_successfully(self):
self.client.login(username="test2", password="testbb")
data = {"contest_id": self.global_contest.id, "password": "aacc"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 0)
class ContestPageTest(TestCase):
# 单个比赛详情页的测试
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
def test_visit_contest_page_successfully(self):
response = self.client.get('/contest/1/')
self.assertEqual(response.status_code, 200)
def test_visit_contest_page_unsuccessfully(self):
response = self.client.get('/contest/10/')
self.assertTemplateUsed(response, "utils/error.html")
class ContestProblemPageTest(TestCase):
# 单个比赛题目详情页的测试
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
self.contest_problem = ContestProblem.objects.create(title="titlex",
description="descriptionx",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
hint="hint1",
created_by=User.objects.get(username="test1"),
contest=Contest.objects.get(title="titlex"),
sort_index="a")
def test_visit_contest_problem_page_successfully(self):
response = self.client.get('/contest/1/problem/1/')
self.assertEqual(response.status_code, 200)
def test_visit_contest_page_unsuccessfully(self):
response = self.client.get('/contest/10/')
self.assertTemplateUsed(response, "utils/error.html")
def test_visit_contest_submissions_page_successfully(self):
ContestSubmission.objects.create(user=self.user1,
contest=self.global_contest,
problem=self.contest_problem,
ac=True)
response = self.client.get('/contest/1/problem/1/submissions/')
self.assertEqual(response.status_code, 200)
class ContestProblemListPageTest(TestCase):
# 比赛题目列表的测试
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
self.contest_problem = ContestProblem.objects.create(title="titlex",
description="descriptionx",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
hint="hint1",
created_by=User.objects.get(username="test1"),
contest=Contest.objects.get(title="titlex"),
sort_index="a")
def test_visit_contest_problem_list_page_successfully(self):
response = self.client.get('/contest/1/problems/')
self.assertEqual(response.status_code, 200)
def test_visit_contest_problem_page_unsuccessfully(self):
response = self.client.get('/contest/1/problem/100/')
self.assertTemplateUsed(response, "utils/error.html")
class ContestListPageTest(TestCase):
# 以下是所有比赛列表页的测试
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.url = reverse('contest_list_page')
self.client.login(username="test1", password="testaa")
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
def test_visit_contest_list_page_successfully(self):
response = self.client.get('/contests/')
self.assertEqual(response.status_code, 200)
def test_visit_contest_list_page_unsuccessfully(self):
response = self.client.get('/contests/2/')
self.assertTemplateUsed(response, "utils/error.html")
def test_query_by_keyword(self):
response = self.client.get(self.url + "?keyword=title1")
self.assertEqual(response.status_code, 200)
def test_query_by_join_successfully(self):
response = self.client.get(self.url + "?join=True")
self.assertEqual(response.status_code, 200)

View File

@@ -320,7 +320,6 @@ def contest_problems_list_page(request, contest_id):
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
submissions = ContestSubmission.objects.filter(user=request.user, contest=contest)
state = {}
@@ -334,10 +333,8 @@ def contest_problems_list_page(request, contest_id):
item.state = 2
else:
item.state = 0
# 右侧的公告列表
announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time")
return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems,
"announcements": announcements,
"contest": {"id": contest_id}})
@@ -419,4 +416,5 @@ def contest_rank_page(request, contest_id):
return render(request, "oj/contest/contest_rank.html",
{"contest": contest, "contest_problems": contest_problems,
"result": sorted(result, cmp=_cmp, reverse=True)})
"result": sorted(result, cmp=_cmp, reverse=True),
"auto_refresh": request.GET.get("auto_refresh", None) == "true"})

View File

@@ -1,14 +1,97 @@
# coding=utf-8
import json
from django.test import TestCase, Client
from django.core.urlresolvers import reverse
from account.models import User, ADMIN, SUPER_ADMIN
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from problem.models import Problem
from contest.models import Contest, ContestProblem
from submission.models import Submission
from rest_framework.test import APITestCase, APIClient
# Create your tests here.
class ContestSubmissionAPITest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse('contest_submission_api')
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.user2 = User.objects.create(username="test2", admin_type=REGULAR_USER)
self.user2.set_password("testbb")
self.user2.save()
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=1, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-30T12:00:00.000Z",
created_by=User.objects.get(username="test1"))
self.contest_problem = ContestProblem.objects.create(title="titlex",
description="descriptionx",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
hint="hint1",
created_by=User.objects.get(username="test1"),
contest=Contest.objects.get(title="titlex"),
sort_index="a")
# 以下是创建比赛的提交
def test_invalid_format(self):
self.client.login(username="test1", password="testaa")
data = {"contest_id": self.global_contest.id, "language": 1}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_contest_submission_successfully(self):
self.client.login(username="test1", password="testaa")
data = {"contest_id": self.global_contest.id, "problem_id": self.contest_problem.id,
"language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}'}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 0)
def test_contest_problem_does_not_exist(self):
self.client.login(username="test1", password="testaa")
data = {"contest_id": self.global_contest.id, "problem_id": self.contest_problem.id + 10,
"language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}'}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"题目不存在"})
class ContestProblemMySubmissionListTest(TestCase):
# 以下是我比赛单个题目的提交列表的测试
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.user2 = User.objects.create(username="test2", admin_type=REGULAR_USER)
self.user2.set_password("testbb")
self.user2.save()
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=1, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-30T12:00:00.000Z",
created_by=User.objects.get(username="test1"))
self.contest_problem = ContestProblem.objects.create(title="titlex",
description="descriptionx",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
hint="hint1",
created_by=self.user1,
contest=self.global_contest,
sort_index="a")
def test_contestsList_page_not_exist(self):
self.client.login(username="test1", password="testaa")
response = self.client.get('/contest/1/submissions/999/')
self.assertTemplateUsed(response, "utils/error.html")
class SubmissionAPITest(APITestCase):
def setUp(self):

View File

@@ -1,6 +1,5 @@
# coding=utf-8
import json
import redis
from django.shortcuts import render
from django.core.paginator import Paginator
@@ -9,16 +8,15 @@ from rest_framework.views import APIView
from judge.judger_controller.tasks import judge
from judge.judger_controller.settings import redis_config
from account.decorators import login_required
from account.models import SUPER_ADMIN
from contest.decorators import check_user_contest_permission
from problem.models import Problem
from contest.models import Contest, ContestProblem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
from submission.models import Submission
from .serializers import CreateContestSubmissionSerializer
from submission.serializers import SubmissionSerializer
@@ -35,31 +33,24 @@ class ContestSubmissionAPIView(APIView):
serializer = CreateContestSubmissionSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
contest = Contest.objects.get(id=data["contest_id"])
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
try:
problem = ContestProblem.objects.get(contest=contest, id=data["problem_id"])
# 更新题目提交计数器
problem.total_submit_number += 1
problem.save()
except Problem.DoesNotExist:
except ContestProblem.DoesNotExist:
return error_response(u"题目不存在")
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
contest_id=contest.id, code=data["code"], problem_id=problem.id)
try:
judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception:
return error_response(u"提交判题任务失败")
# 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length")
return success_response({"submission_id": submission.id})
else:
return serializer_invalid_response(serializer)
@@ -75,7 +66,7 @@ def contest_problem_my_submissions_list_page(request, contest_id, contest_proble
return error_page(request, u"比赛不存在")
try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except Problem.DoesNotExist:
except ContestProblem.DoesNotExist:
return error_page(request, u"比赛问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by(
"-create_time"). \
@@ -95,8 +86,26 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
return error_page(request, u"比赛不存在")
# 以下是本场比赛中所有的提交
submissions = Submission.objects.filter(contest_id=contest_id). \
values("id", "result", "create_time", "accepted_answer_time", "language", "user_id").order_by("-create_time")
values("id", "contest_id", "problem_id", "result", "create_time", "accepted_answer_time", "language", "user_id").order_by("-create_time")
language = request.GET.get("language", None)
filter = None
if language:
submissions = submissions.filter(language=int(language))
filter = {"name": "language", "content": language}
result = request.GET.get("result", None)
if result:
submissions = submissions.filter(result=int(result))
filter = {"name": "result", "content": result}
paginator = Paginator(submissions, 20)
# 为查询题目标题创建新字典
title = {}
contest_problems = ContestProblem.objects.filter(contest=contest)
for item in contest_problems:
title[item.id] = item.title
for item in submissions:
item['title'] = title[item['problem_id']]
try:
current_page = paginator.page(int(page))
except Exception:
@@ -110,11 +119,10 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
next_page = current_page.next_page_number()
except Exception:
pass
return render(request, "oj/contest/submissions_list.html",
{"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest})
"contest": contest, "filter":filter})
class ContestSubmissionAdminAPIView(APIView):
@@ -147,5 +155,4 @@ class ContestSubmissionAdminAPIView(APIView):
return error_response(u"参数错误!")
if problem_id:
submissions = submissions.filter(problem_id=problem_id)
return paginate(request, submissions, SubmissionSerializer)

View File

@@ -4,9 +4,9 @@ services:
- mysql
env:
- oj_env="daocloud"
- oj_env="local"
script:
- pip install -r requirements.txt
- mkdir LOG
- mkdir log
- python manage.py test

19
judge/Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM ubuntu:14.04
MAINTAINER virusdefender<qduliyang@outlook.com>
RUN mkdir /var/install/
WORKDIR /var/install/
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get -y install software-properties-common python-software-properties
RUN add-apt-repository -y ppa:webupd8team/java
RUN apt-get update
RUN apt-get -y install python gcc g++ rake pkg-config git make autoconf automake libtool python-pip python2.7-mysqldb
RUN echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections
RUN echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections
RUN apt-get install -y oracle-java7-installer
RUN apt-get -y install libseccomp-dev
RUN git clone https://github.com/quark-zju/lrun.git
RUN cd lrun && make install
RUN mkdir -p /var/judger/run/ && mkdir /var/judger/test_case/ && mkdir /var/judger/code/
RUN chmod -R 777 /var/judger/run/
WORKDIR /var/judger/code/

View File

@@ -1,4 +1,5 @@
# coding=utf-8
# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息
redis_config = {
"host": "121.42.32.129",
"port": 6379,
@@ -6,17 +7,21 @@ redis_config = {
}
# 判题的 docker 容器的配置参数
docker_config = {
"image_name": " a7673b55d263",
"image_name": "3da0e526934e",
"docker_path": "docker",
"shell": True
}
test_case_dir = "/root/test_case/"
source_code_dir = "/root/"
# 测试用例的路径,是主机上的实际路径
test_case_dir = "/var/mnt/source/test_case/"
# 源代码路径,也就是 manage.py 所在的实际路径
source_code_dir = "/var/mnt/source/OnlineJudge/"
# 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址
submission_db = {
"host": "127.0.0.1",
"port": 3306,

View File

@@ -1,19 +0,0 @@
# coding=utf-8
import os
LOG_PATH = "LOG/"
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 1,
}
}
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

View File

@@ -12,15 +12,16 @@ DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 0.3,
},
# submission 的 name 和 engine 请勿修改,其他代码会用到
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'HOST': "121.42.32.129",
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'mypwd'
'PASSWORD': 'mypwd',
'CONN_MAX_AGE': 0.1,
}
}
@@ -30,4 +31,3 @@ DEBUG = True
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
ALLOWED_HOSTS = []

View File

@@ -12,7 +12,7 @@ DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "oj",
'CONN_MAX_AGE': 0.3,
'CONN_MAX_AGE': 0.1,
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
@@ -21,6 +21,7 @@ DATABASES = {
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'CONN_MAX_AGE': 0.1,
'HOST': "127.0.0.1",
'PORT': 3306,
'USER': 'root',
@@ -34,4 +35,3 @@ DEBUG = True
TEST_CASE_DIR = '/root/test_case/'
ALLOWED_HOSTS = ['*']

View File

@@ -113,10 +113,6 @@ STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),)
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, "template/src"),
)
AUTH_USER_MODEL = 'account.User'
LOGGING = {

View File

@@ -26,8 +26,8 @@ class CreateProblemSerializer(serializers.Serializer):
samples = ProblemSampleSerializer()
test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30, required=False, default=None)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField(min_value=1)
difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=10))
hint = serializers.CharField(max_length=3000, allow_blank=True)
@@ -61,8 +61,8 @@ class EditProblemSerializer(serializers.Serializer):
output_description = serializers.CharField(max_length=10000)
test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField(min_value=1)
difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer()

View File

@@ -187,5 +187,19 @@ class ProblemListPageTest(TestCase):
hint="hint1",
created_by=User.objects.get(username="test"))
def test_problemListPage_not_exist(self):
response = self.client.get('/problems/999/')
self.assertTemplateUsed(response, "utils/error.html")
def test_query_by_keyword(self):
response = self.client.get(self.url + "?keyword=title1")
self.assertEqual(response.status_code, 200)
def test_query_by_tag_successfully(self):
response = self.client.get(self.url + "?tag=")
self.assertEqual(response.status_code, 200)
def test_tag_does_not_exists(self):
response = self.client.get(self.url + "?tag=xxxxxx")
self.assertTemplateUsed(response, "utils/error.html")

View File

@@ -8,3 +8,4 @@ celery
gunicorn
coverage
django-extensions
supervisor

View File

@@ -13,10 +13,6 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
bsAlert("题目描述不能为空!");
return false;
}
if (vm.timeLimit < 1000 || vm.timeLimit > 5000) {
bsAlert("保证时间限制是一个1000-5000的合法整数");
return false;
}
if (vm.samples.length == 0) {
bsAlert("请至少添加一组样例!");
return false;

View File

@@ -1,5 +1,10 @@
require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirror, csrfTokenHeader, bsAlert) {
var codeEditor = codeMirror($("#code-editor")[0], "text/x-csrc");
var codeEditorSelector = $("#code-editor")[0];
// 部分界面逻辑会隐藏代码输入框,先判断有没有。
if (codeEditorSelector == undefined) {
return;
}
var codeEditor = codeMirror(codeEditorSelector, "text/x-csrc");
var language = $("input[name='language'][checked]").val();
var submissionId;
@@ -48,7 +53,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
if (!data.result) {
html += "CPU time: " + data.accepted_answer_time + "ms &nbsp;&nbsp;";
}
html += ('<a href="/my_submission/' + submissionId + '/" target="_blank">查看详情</a></div> </div>');
html += ('<a href="/submission/' + submissionId + '/" target="_blank">查看详情</a></div> </div>');
return html;
}
@@ -87,9 +92,37 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
})
}
function guessLanguage(code) {
//cpp
if (code.indexOf("using namespace std") > -1) {
return "2";
}
//c
if (code.indexOf("printf") > -1) {
return "1";
}
//java
if (code.indexOf("public class Main")) {
return "3";
}
}
$("#submit-code-button").click(function () {
var code = codeEditor.getValue();
if (!code.trim()) {
bsAlert("请填写代码!");
hideLoading();
return false;
}
if(guessLanguage(code) != language){
if(!confirm("您选择的代码语言可能存在错误,是否继续提交?")){
return;
}
}
if (location.href.indexOf("contest") > -1) {
var problemId = location.pathname.split("/")[4];
var contestId = location.pathname.split("/")[2];
@@ -113,15 +146,8 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
showLoading();
if (!code.trim()) {
bsAlert("请填写代码!");
hideLoading();
return false;
}
$("#result").html("");
$.ajax({
beforeSend: csrfTokenHeader,
url: url,

View File

@@ -1,6 +1,6 @@
# coding=utf-8
import json
from django.test import TestCase
from django.test import TestCase, Client
from django.core.urlresolvers import reverse
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from problem.models import Problem
@@ -11,7 +11,7 @@ from rest_framework.test import APITestCase, APIClient
class SubmissionsListPageTest(TestCase):
def setUp(self):
self.client = APIClient()
self.client = Client()
self.user = User.objects.create(username="gogoing", admin_type=REGULAR_USER)
self.user2 = User.objects.create(username="cool", admin_type=REGULAR_USER)
self.user2.set_password("666666")
@@ -124,25 +124,78 @@ class SubmissionAPITest(APITestCase):
response = self.client.get(self.url, data=data)
self.assertEqual(response.data["code"], 0)
def test_parameter_error(self):
self.client.login(username="test1", password="testaa")
response = self.client.get(self.url)
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
class ContestSubmissionAPITest(APITestCase):
class SubmissionAdminAPITest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse('contest_submission_api')
self.user1 = User.objects.create(username="test1", admin_type=REGULAR_USER)
self.user1.set_password("testaa")
self.user1.save()
self.user2 = User.objects.create(username="test2", admin_type=SUPER_ADMIN)
self.user2.set_password("testbb")
self.user2.save()
self.url = reverse('submission_admin_api_view')
self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user.set_password("testaa")
self.user.save()
self.client.login(username="test1", password="testaa")
self.problem = Problem.objects.create(title="title1",
description="description1",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
source="source1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
difficulty=1,
hint="hint1",
created_by=self.user)
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test2"))
password="aacc", created_by=self.user)
self.submission = Submission.objects.create(user_id=self.user.id,
language=1,
code='#include "stdio.h"\nint main(){\n\treturn 0;\n}',
problem_id=self.problem.id)
def test_invalid_format(self):
response = self.client.get(self.url)
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
class SubmissionPageTest(TestCase):
# 单个题目的提交详情页
def setUp(self):
self.client = Client()
self.user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa")
self.user1.save()
self.user2 = User.objects.create(username="test2", admin_type=ADMIN)
self.user2.set_password("testbb")
self.user2.save()
self.client.login(username="test1", password="testaa")
data = {"language": 1}
response = self.client.post(self.url, data=data)
pass
self.problem = Problem.objects.create(title="title1",
description="description1",
input_description="input1_description",
output_description="output1_description",
test_case_id="1",
source="source1",
samples=json.dumps([{"input": "1 1", "output": "2"}]),
time_limit=100,
memory_limit=1000,
difficulty=1,
hint="hint1",
created_by=User.objects.get(username="test1"))
self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12:00:00.000Z",
password="aacc", created_by=User.objects.get(username="test1"))
self.submission = Submission.objects.create(user_id=self.user1.id,
language=1,
code='#include "stdio.h"\nint main(){\n\treturn 0;\n}',
problem_id=self.problem.id)

View File

@@ -139,7 +139,7 @@ def my_submission_list_page(request, page=1):
我的所有提交的列表页
"""
submissions = Submission.objects.filter(user_id=request.user.id, contest_id__isnull=True). \
values("id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time")
values("id", "problem_id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time")
language = request.GET.get("language", None)
filter = None
if language:

View File

@@ -72,13 +72,13 @@
<div>
<label class="radio-inline">
<input type="radio" name="language" value="1" checked> C (gcc 4.8)
<input type="radio" name="language" value="1" checked> C (GCC 4.8)
</label>
<label class="radio-inline">
<input type="radio" name="language" value="2"> C++ (g++ 4.3)
<input type="radio" name="language" value="2"> C++ (G++ 4.3)
</label>
<label class="radio-inline">
<input type="radio" name="language" value="3"> Java (jre 1.7)
<input type="radio" name="language" value="3"> Java (Oracle JDK 1.7)
</label>
</div>
</div>

View File

@@ -50,6 +50,7 @@
{% endfor %}
</tbody>
</table>
<input type="checkbox" id="auto-refresh" {% if auto_refresh %}checked{% endif %} onchange="if(this.checked){location.href='?auto_refresh=true'}else{location.href=location.href.split('?')[0]}"> 自动刷新
{% else %}
<p>还没有结果</p>
{% endif %}
@@ -60,4 +61,11 @@
{% block js_block %}
{% if auto_refresh %}
<script>
setTimeout(function(){
location.reload();
}, 5000);
</script>
{% endif %}
{% endblock %}

View File

@@ -18,17 +18,19 @@
<tr class="" success>
<th>#</th>
<th>提交时间</th>
<th>结果</th>
<th>运行时间</th>
<th>语言</th>
<th>运行时间</th>
<th>结果</th>
</tr>
</thead>
<tbody>
{% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}">
<tr>
<th scope="row"><a href="/submission/{{ item.id }}/">{{ forloop.counter }}</a></th>
<td>{{ item.create_time }}</td>
<td>{{ item.result|translate_result }}</td>
<td>
{{ item.language|translate_language }}
</td>
<td>
{% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms
@@ -36,8 +38,8 @@
--
{% endif %}
</td>
<td>
{{ item.language|translate_language }}
<td class="alert-{{ item.result|translate_result_class }}">
<strong>{{ item.result|translate_result }}</strong>
</td>
</tr>
{% endfor %}

View File

@@ -26,28 +26,61 @@
<thead>
<tr class="" success>
<th>#</th>
<td>用户</td>
<th>题目名称</th>
<th>用户</th>
<th>提交时间</th>
<th>结果</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="languageFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
语言<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="languageFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?language=1">C</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=2">C++</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?language=3">Java</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
<th>运行时间</th>
<th>语言</th>
<th>
<div class="dropdown">
<a href="#" class="dropdown-toggle" id="resultFilter" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
结果<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="resultFilter">
<li><a href="/contest/{{ contest.id }}/submissions/?result=0">Accepted</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=6">Wrong Answer</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=1">Runtime Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=2">Time Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=3">Memory Limit Exceeded</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=4">Compile Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/?result=5">Format Error</a></li>
<li><a href="/contest/{{ contest.id }}/submissions/">取消筛选</a></li>
</ul>
</div>
</th>
</tr>
</thead>
<tbody>
{% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}">
<tr>
{% ifequal item.user_id request.user.id %}
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
<th scope="row"><a href="/submission/{{ item.id }}/">
{{ forloop.counter |add:start_id }}</a></th>
{% else %}
<th scope="row">{{ forloop.counter |add:start_id }}</th>
{% endifequal %}
<th scope="row">
<a href="/contest/{{ item.contest_id }}/problem/{{ item.problem_id }}/">{{ item.title }}</a>
</th>
<td>{{ item.user_id|get_username }}</td>
<td>{{ item.create_time }}</td>
<td>{{ item.result|translate_result }}</td>
<td>
{{ item.language|translate_language }}
</td>
<td>
{% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms
@@ -55,12 +88,11 @@
--
{% endif %}
</td>
<td>
{{ item.language|translate_language }}
<td class="alert-{{ item.result|translate_result_class }}">
<strong>{{ item.result|translate_result }}</strong>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
@@ -70,13 +102,13 @@
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/">
href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %}
{% if next_page %}
<li class="next">
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/">下一页 <span
aria-hidden="true">&rarr;</span></a></li>
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
下一页 <span aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>

View File

@@ -43,7 +43,7 @@
</p>
{% endifequal %}
{% ifequal submission.result 4 %}
<p>{{ submission.info }}</p>
<pre>{{ submission.info }}</pre>
{% endifequal %}
<p>提交时间 : {{ submission.create_time }}</p>
</div>

View File

@@ -4,8 +4,14 @@
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active">
<a href="/problem/{{ problem.id }}/">题目</a></li>
<li role="presentation"><a href="/problem/{{ problem.id }}/submissions/">我的提交</a></li>
<a href="/problem/{{ problem.id }}/">题目</a>
</li>
<li role="presentation">
<a href="/problem/{{ problem.id }}/submissions/">我的提交</a>
</li>
<li role="presentation">
<a href="/problems/">返回</a>
</li>
</ul>
{% include "oj/problem/_problem_header.html" %}
@@ -23,7 +29,7 @@
<div class="problem-section">
<label class="problem-label">输出</label>
<p class="problem-detail">{{ problem.output_description }}k</p>
<p class="problem-detail">{{ problem.output_description }}</p>
</div>
{% for item in samples %}
<div class="problem-section">
@@ -33,7 +39,6 @@
</div>
<div class="problem-section">
<label class="problem-label">样例输出{{ forloop.counter }}</label>
<pre>
{{ item.output }}</pre>
@@ -45,36 +50,31 @@
{% if problem.hint %}
<div class="problem-section hide">
<label class="problem-label">提示</label>
<div class="problem-detail">{{ problem.hint|safe }}</div>
</div>
{% endif %}
<div class="problem-section hide">
<label class="problem-label">标签</label>
<p class="problem-detail">
{% for tag in problem.tags.all %}
<span class="label label-success">{{ tag.name }}</span>
{% endfor %}
</p>
</div>
<div>
<label>选择语言</label>
<div>
<label class="radio-inline">
<input type="radio" name="language" value="1" checked> C (gcc 4.8)
<input type="radio" name="language" value="1" checked> C (GCC 4.8)
</label>
<label class="radio-inline">
<input type="radio" name="language" value="2"> C++ (g++ 4.3)
<input type="radio" name="language" value="2"> C++ (G++ 4.3)
</label>
<label class="radio-inline">
<input type="radio" name="language" value="3"> Java (jre 1.7)
<input type="radio" name="language" value="3"> Java (Oracle JDK 1.7)
</label>
</div>
</div>
<div id="code-field">
<label class="problem-label">提交代码</label>
<textarea id="code-editor"></textarea>
@@ -85,9 +85,7 @@
提交代码
</button>
<img src="/static/img/loading.gif" id="loading-gif">
</div>
<div id="result">
</div>
<hr>

View File

@@ -1,7 +1,6 @@
{% extends 'oj_base.html' %}
{% block body %}
{% load submission %}
<div class="container main">
<div class="col-md-9 col-lg-9">
@@ -9,6 +8,7 @@
<thead>
<tr>
<th>#</th>
<th>题目名称</th>
<th>提交时间</th>
<th>
<div class="dropdown">
@@ -48,8 +48,12 @@
<tbody>
{% for item in submissions %}
<tr>
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
{{ forloop.counter |add:start_id }}</a></th>
<th scope="row">
<a href="/submission/{{ item.id }}/">{{ forloop.counter |add:start_id }}</a>
</th>
<td>
<a href="/problem/{{ item.problem_id }}/">{{ item.problem_id }}</a>
</td>
<td>{{ item.create_time }}</td>
<td>
{{ item.language|translate_language }}

View File

@@ -56,7 +56,7 @@
{{ request.user.username }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/submission/">我的提交</a></li>
<li><a href="/submissions/">我的提交</a></li>
<li><a href="#">我的资料</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">退出</a></li>