合并dev,添加管理员在前台可见比赛所有提交详情,修改措辞,修改提示形式,以便于提交列表筛选功能的使用

This commit is contained in:
sxw@401 2015-09-08 11:03:59 +08:00
parent 13b7a84c8f
commit e219ff890d
29 changed files with 610 additions and 140 deletions

View File

@ -1,13 +1,7 @@
FROM python:2.7 FROM python:2.7
ENV PYTHONUNBUFFERED 1 ENV PYTHONBUFFERED 1
ENV oj_env daocloud RUN mkdir -p /code/log /code/test_case
RUN mkdir /var/oj WORKDIR /code
COPY . /var/oj/ ADD requirements.txt /code/
WORKDIR /var/oj/
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
EXPOSE 8080 EXPOSE 8010
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

View File

@ -370,7 +370,7 @@ class UserLogoutTest(TestCase):
user.set_password("1") user.set_password("1")
user.save() user.save()
def logout_success(self): def test_logout_success(self):
self.client = Client() self.client = Client()
self.client.login(username="test", password="1") self.client.login(username="test", password="1")
response = self.client.get("/logout/") 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 # coding=utf-8
import json import json
from django.core.urlresolvers import reverse 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 rest_framework.test import APITestCase, APIClient
from account.models import User from account.models import User
from group.models import Group from group.models import Group
from contest.models import Contest, ContestProblem from contest.models import Contest, ContestProblem
from .models import ContestSubmission
from announcement.models import Announcement from announcement.models import Announcement
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from decorators import check_user_contest_permission
class ContestAdminAPITest(APITestCase): class ContestAdminAPITest(APITestCase):
@ -398,3 +401,181 @@ class ContestProblemAdminAPItEST(APITestCase):
response = self.client.put(self.url, data=data) response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 1) 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) contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist: except Contest.DoesNotExist:
return error_page(request, u"比赛不存在") return error_page(request, u"比赛不存在")
contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index") contest_problems = ContestProblem.objects.filter(contest=contest).order_by("sort_index")
submissions = ContestSubmission.objects.filter(user=request.user, contest=contest) submissions = ContestSubmission.objects.filter(user=request.user, contest=contest)
state = {} state = {}
@ -334,10 +333,8 @@ def contest_problems_list_page(request, contest_id):
item.state = 2 item.state = 2
else: else:
item.state = 0 item.state = 0
# 右侧的公告列表 # 右侧的公告列表
announcements = Announcement.objects.filter(is_global=True, visible=True).order_by("-create_time") 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, return render(request, "oj/contest/contest_problems_list.html", {"contest_problems": contest_problems,
"announcements": announcements, "announcements": announcements,
"contest": {"id": contest_id}}) "contest": {"id": contest_id}})

View File

@ -1,14 +1,97 @@
# coding=utf-8
import json import json
from django.test import TestCase, Client
from django.core.urlresolvers import reverse 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 contest.models import Contest, ContestProblem
from submission.models import Submission from submission.models import Submission
from rest_framework.test import APITestCase, APIClient 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): class SubmissionAPITest(APITestCase):
def setUp(self): def setUp(self):

View File

@ -1,6 +1,5 @@
# coding=utf-8 # coding=utf-8
import json import json
import redis import redis
from django.shortcuts import render from django.shortcuts import render
from django.core.paginator import Paginator 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.tasks import judge
from judge.judger_controller.settings import redis_config from judge.judger_controller.settings import redis_config
from account.decorators import login_required from account.decorators import login_required
from account.models import SUPER_ADMIN from account.models import SUPER_ADMIN
from contest.decorators import check_user_contest_permission from contest.decorators import check_user_contest_permission
from problem.models import Problem from problem.models import Problem
from contest.models import Contest, ContestProblem from contest.models import Contest, ContestProblem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
from submission.models import Submission from submission.models import Submission
from .serializers import CreateContestSubmissionSerializer from .serializers import CreateContestSubmissionSerializer
from submission.serializers import SubmissionSerializer from submission.serializers import SubmissionSerializer
@ -35,31 +33,24 @@ class ContestSubmissionAPIView(APIView):
serializer = CreateContestSubmissionSerializer(data=request.data) serializer = CreateContestSubmissionSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
try: contest = Contest.objects.get(id=data["contest_id"])
contest = Contest.objects.get(id=data["contest_id"])
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
try: try:
problem = ContestProblem.objects.get(contest=contest, id=data["problem_id"]) problem = ContestProblem.objects.get(contest=contest, id=data["problem_id"])
# 更新题目提交计数器 # 更新题目提交计数器
problem.total_submit_number += 1 problem.total_submit_number += 1
problem.save() problem.save()
except Problem.DoesNotExist: except ContestProblem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]), submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
contest_id=contest.id, code=data["code"], problem_id=problem.id) contest_id=contest.id, code=data["code"], problem_id=problem.id)
try: try:
judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception: except Exception:
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
# 增加redis 中判题队列长度的计数器 # 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length") r.incr("judge_queue_length")
return success_response({"submission_id": submission.id}) return success_response({"submission_id": submission.id})
else: else:
return serializer_invalid_response(serializer) 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"比赛不存在") return error_page(request, u"比赛不存在")
try: try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True) contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except Problem.DoesNotExist: except ContestProblem.DoesNotExist:
return error_page(request, u"比赛问题不存在") return error_page(request, u"比赛问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by( submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by(
"-create_time"). \ "-create_time"). \
@ -95,8 +86,26 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
return error_page(request, u"比赛不存在") return error_page(request, u"比赛不存在")
# 以下是本场比赛中所有的提交 # 以下是本场比赛中所有的提交
submissions = Submission.objects.filter(contest_id=contest_id). \ 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) 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: try:
current_page = paginator.page(int(page)) current_page = paginator.page(int(page))
except Exception: except Exception:
@ -111,10 +120,16 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
except Exception: except Exception:
pass pass
# 如果该用户是超级管理员那么他可以查看所有的提交记录详情
if request.user.admin_type > 1:
return render(request, "oj/contest/submissions_list_admin.html",
{"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest})
return render(request, "oj/contest/submissions_list.html", return render(request, "oj/contest/submissions_list.html",
{"submissions": current_page, "page": int(page), {"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20, "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20,
"contest": contest}) "contest": contest, "filter":filter})
class ContestSubmissionAdminAPIView(APIView): class ContestSubmissionAdminAPIView(APIView):
@ -147,5 +162,4 @@ class ContestSubmissionAdminAPIView(APIView):
return error_response(u"参数错误!") return error_response(u"参数错误!")
if problem_id: if problem_id:
submissions = submissions.filter(problem_id=problem_id) submissions = submissions.filter(problem_id=problem_id)
return paginate(request, submissions, SubmissionSerializer) return paginate(request, submissions, SubmissionSerializer)

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 # coding=utf-8
# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息
redis_config = { redis_config = {
"host": "121.42.32.129", "host": "121.42.32.129",
"port": 6379, "port": 6379,
@ -6,17 +7,21 @@ redis_config = {
} }
# 判题的 docker 容器的配置参数
docker_config = { docker_config = {
"image_name": " a7673b55d263", "image_name": "3da0e526934e",
"docker_path": "docker", "docker_path": "docker",
"shell": True "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 = { submission_db = {
"host": "127.0.0.1", "host": "127.0.0.1",
"port": 3306, "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': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 0.3,
}, },
# submission 的 name 和 engine 请勿修改,其他代码会用到
'submission': { 'submission': {
'NAME': 'oj_submission', 'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql', 'ENGINE': 'django.db.backends.mysql',
'HOST': "121.42.32.129", 'HOST': "121.42.32.129",
'PORT': 3306, 'PORT': 3306,
'USER': 'root', '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/') TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []

View File

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

View File

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

View File

@ -26,8 +26,8 @@ class CreateProblemSerializer(serializers.Serializer):
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30, required=False, default=None) source = serializers.CharField(max_length=30, required=False, default=None)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField(min_value=1)
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)
@ -61,8 +61,8 @@ class EditProblemSerializer(serializers.Serializer):
output_description = serializers.CharField(max_length=10000) output_description = serializers.CharField(max_length=10000)
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30) source = serializers.CharField(max_length=30)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField(min_value=1)
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=20)) tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()

View File

@ -187,5 +187,19 @@ class ProblemListPageTest(TestCase):
hint="hint1", hint="hint1",
created_by=User.objects.get(username="test")) 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

@ -7,4 +7,5 @@ django-rest-swagger
celery celery
gunicorn gunicorn
coverage coverage
django-extensions django-extensions
supervisor

View File

@ -1,3 +1,13 @@
/** /**
* Created by virusdefender on 8/25/15. * Created by virusdefender on 8/25/15.
*/ */
fis.match('*.{js,css,png,gif}', {
useHash: true // 开启 md5 戳
});
fis.config.set(
'roadmap.path',
[{reg:'*.html',isHtmlLike : true}
])
;

View File

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

View File

@ -48,7 +48,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
if (!data.result) { if (!data.result) {
html += "CPU time: " + data.accepted_answer_time + "ms &nbsp;&nbsp;"; 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; return html;
} }

View File

@ -1,8 +1,9 @@
({ ({
// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。 // RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
baseUrl: "js/", baseUrl: "/static/js/",
// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了 // 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了
paths: { paths: {
jquery: "lib/jquery/jquery", jquery: "lib/jquery/jquery",
avalon: "lib/avalon/avalon", avalon: "lib/avalon/avalon",
editor: "utils/editor", editor: "utils/editor",
@ -37,12 +38,12 @@
webUploader: "lib/webuploader/webuploader", webUploader: "lib/webuploader/webuploader",
"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker" "_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker"
}, },
shim: { shim: {
"bootstrap": {"deps": ['jquery']}, bootstrap: {deps: ["jquery"]},
"_datetimepicker": {"deps": ["jquery"]}, _datetimePicker: {dep: ["jquery"]},
"datetimepicker": {"deps": ["_datetimepicker"]} datetimePicker: {deps: ["_datetimePicker"]},
validator: ["jquery"]
}, },
findNestedDependencies: true, findNestedDependencies: true,
appDir: "../", appDir: "../",

View File

@ -1,6 +1,6 @@
# coding=utf-8 # coding=utf-8
import json import json
from django.test import TestCase from django.test import TestCase, Client
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from problem.models import Problem from problem.models import Problem
@ -11,7 +11,7 @@ from rest_framework.test import APITestCase, APIClient
class SubmissionsListPageTest(TestCase): class SubmissionsListPageTest(TestCase):
def setUp(self): def setUp(self):
self.client = APIClient() self.client = Client()
self.user = User.objects.create(username="gogoing", admin_type=REGULAR_USER) self.user = User.objects.create(username="gogoing", admin_type=REGULAR_USER)
self.user2 = User.objects.create(username="cool", admin_type=REGULAR_USER) self.user2 = User.objects.create(username="cool", admin_type=REGULAR_USER)
self.user2.set_password("666666") self.user2.set_password("666666")
@ -124,25 +124,78 @@ class SubmissionAPITest(APITestCase):
response = self.client.get(self.url, data=data) response = self.client.get(self.url, data=data)
self.assertEqual(response.data["code"], 0) 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): def setUp(self):
self.client = APIClient() self.client = APIClient()
self.url = reverse('contest_submission_api') self.url = reverse('submission_admin_api_view')
self.user1 = User.objects.create(username="test1", admin_type=REGULAR_USER) self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user1.set_password("testaa") self.user.set_password("testaa")
self.user1.save() self.user.save()
self.user2 = User.objects.create(username="test2", admin_type=SUPER_ADMIN) self.client.login(username="test1", password="testaa")
self.user2.set_password("testbb") self.problem = Problem.objects.create(title="title1",
self.user2.save() 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, self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1,
contest_type=2, show_rank=True, show_user_submission=True, contest_type=2, show_rank=True, show_user_submission=True,
start_time="2015-08-15T10:00:00.000Z", start_time="2015-08-15T10:00:00.000Z",
end_time="2015-08-15T12: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): 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") self.client.login(username="test1", password="testaa")
data = {"language": 1} self.problem = Problem.objects.create(title="title1",
response = self.client.post(self.url, data=data) description="description1",
pass 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). \ 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) language = request.GET.get("language", None)
filter = None filter = None
if language: if language:

View File

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

View File

@ -21,33 +21,67 @@
</li> </li>
</ul> </ul>
</div> </div>
{% if submissions %}
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr class="" success> <tr class="" success>
<th>#</th> <th>#</th>
<td>用户</td> <th>题目名称</th>
<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>语言</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> </tr>
</thead> </thead>
{% if submissions %}
<tbody> <tbody>
{% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}">
{% for item in submissions %}
<tr>
{% ifequal item.user_id request.user.id %} {% 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> {{ forloop.counter |add:start_id }}</a></th>
{% else %} {% else %}
<th scope="row">{{ forloop.counter |add:start_id }}</th> <th scope="row">{{ forloop.counter |add:start_id }}</th>
{% endifequal %} {% 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.user_id|get_username }}</td>
<td>{{ item.create_time }}</td> <td>{{ item.create_time }}</td>
<td>{{ item.result|translate_result }}</td> <td>
{{ item.language|translate_language }}
</td>
<td> <td>
{% if item.accepted_answer_time %} {% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms {{ item.accepted_answer_time }}ms
@ -55,28 +89,28 @@
-- --
{% endif %} {% endif %}
</td> </td>
<td> <td class="alert-{{ item.result|translate_result_class }}">
{{ item.language|translate_language }} <strong>{{ item.result|translate_result }}</strong>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
{% else %}
<p>本场比赛还没有提交记录</p>
{% endif %}
</table> </table>
{% else %}
<p>你还没有提交记录!</p>
{% endif %}
<nav> <nav>
<ul class="pager"> <ul class="pager">
{% if previous_page %} {% if previous_page %}
<li class="previous"><a <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> <span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %} {% endif %}
{% if next_page %} {% if next_page %}
<li class="next"> <li class="next">
<a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/">下一页 <span <a href="/contest/{{ contest.id }}/submissions/{{ next_page }}/{% if filter %}?{{ filter.name }}={{ filter.content }}{% endif %}">
aria-hidden="true">&rarr;</span></a></li> 下一页 <span aria-hidden="true">&rarr;</span></a></li>
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>

View File

@ -0,0 +1,78 @@
{% extends 'oj_base.html' %}
{% block body %}
{% load submission %}
{% load user %}
<div class="container main">
<div class="contest-tab">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/problems/">题目</a>
</li>
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
</li>
</ul>
</div>
<table class="table table-bordered">
<thead>
<tr class="" success>
<th>#</th>
<td>用户</td>
<th>提交时间</th>
<th>结果</th>
<th>运行时间</th>
<th>语言</th>
</tr>
</thead>
{% if submissions %}
<tbody>
{% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}">
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
{{ forloop.counter |add:start_id }}</a></th>
<td>{{ item.user_id|get_username }}</td>
<td>{{ item.create_time }}</td>
<td>{{ item.result|translate_result }}</td>
<td>
{% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms
{% else %}
--
{% endif %}
</td>
<td>
{{ item.language|translate_language }}
</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<p>本场比赛还没有提交记录!</p>
{% endif %}
</table>
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/contest/{{ contest.id }}/submissions/{{ previous_page }}/">
<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>
{% endif %}
</ul>
</nav>
</div>
{% endblock %}

View File

@ -4,8 +4,14 @@
<div class="container main"> <div class="container main">
<ul class="nav nav-tabs nav-tabs-google"> <ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active"> <li role="presentation" class="active">
<a href="/problem/{{ problem.id }}/">题目</a></li> <a href="/problem/{{ problem.id }}/">题目</a>
<li role="presentation"><a href="/problem/{{ problem.id }}/submissions/">我的提交</a></li> </li>
<li role="presentation">
<a href="/problem/{{ problem.id }}/submissions/">我的提交</a>
</li>
<li role="presentation">
<a href="/problems/">返回</a>
</li>
</ul> </ul>
{% include "oj/problem/_problem_header.html" %} {% include "oj/problem/_problem_header.html" %}
@ -23,7 +29,7 @@
<div class="problem-section"> <div class="problem-section">
<label class="problem-label">输出</label> <label class="problem-label">输出</label>
<p class="problem-detail">{{ problem.output_description }}k</p> <p class="problem-detail">{{ problem.output_description }}</p>
</div> </div>
{% for item in samples %} {% for item in samples %}
<div class="problem-section"> <div class="problem-section">
@ -33,7 +39,6 @@
</div> </div>
<div class="problem-section"> <div class="problem-section">
<label class="problem-label">样例输出{{ forloop.counter }}</label> <label class="problem-label">样例输出{{ forloop.counter }}</label>
<pre> <pre>
{{ item.output }}</pre> {{ item.output }}</pre>
@ -45,23 +50,19 @@
{% if problem.hint %} {% if problem.hint %}
<div class="problem-section hide"> <div class="problem-section hide">
<label class="problem-label">提示</label> <label class="problem-label">提示</label>
<div class="problem-detail">{{ problem.hint|safe }}</div> <div class="problem-detail">{{ problem.hint|safe }}</div>
</div> </div>
{% endif %} {% endif %}
<div class="problem-section hide"> <div class="problem-section hide">
<label class="problem-label">标签</label> <label class="problem-label">标签</label>
<p class="problem-detail"> <p class="problem-detail">
{% for tag in problem.tags.all %} {% for tag in problem.tags.all %}
<span class="label label-success">{{ tag.name }}</span> <span class="label label-success">{{ tag.name }}</span>
{% endfor %} {% endfor %}
</p> </p>
</div> </div>
<div> <div>
<label>选择语言</label> <label>选择语言</label>
<div> <div>
<label class="radio-inline"> <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)
@ -74,7 +75,6 @@
</label> </label>
</div> </div>
</div> </div>
<div id="code-field"> <div id="code-field">
<label class="problem-label">提交代码</label> <label class="problem-label">提交代码</label>
<textarea id="code-editor"></textarea> <textarea id="code-editor"></textarea>
@ -85,9 +85,7 @@
提交代码 提交代码
</button> </button>
<img src="/static/img/loading.gif" id="loading-gif"> <img src="/static/img/loading.gif" id="loading-gif">
</div> </div>
<div id="result"> <div id="result">
</div> </div>
<hr> <hr>

View File

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

View File

@ -56,7 +56,7 @@
{{ request.user.username }} {{ request.user.username }}
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/submission/">我的提交</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>
<li><a href="/logout/">退出</a></li> <li><a href="/logout/">退出</a></li>
@ -97,4 +97,4 @@
</div> </div>
<!-- footer end --> <!-- footer end -->
</body> </body>
</html> </html>

View File

@ -4,7 +4,7 @@
def get_problem_accepted_radio(problem): def get_problem_accepted_radio(problem):
if problem.total_submit_number: if problem.total_submit_number:
return str(int((problem.total_accepted_number * 100) / problem.total_submit_number)) \ return str(int((problem.total_accepted_number * 100) / problem.total_submit_number)) \
+ "% (" + str(problem.total_accepted_number) + "/" + str(problem.total_submit_number) + ")" + "% (" + str(problem.total_accepted_number) + " / " + str(problem.total_submit_number) + ")"
return "0%" return "0%"