Merge branch 'hohoTT-dev' into virusdefender-dev

* hohoTT-dev:
  前台比赛、比赛题目与普通题目的一系列界面

Conflicts:
	submission/views.py
	template/oj/contest/contest_problem.html
	template/oj/problem/my_submission.html
This commit is contained in:
virusdefender 2015-08-25 10:33:44 +08:00
commit a82f46a001
24 changed files with 573 additions and 206 deletions

View File

@ -255,6 +255,9 @@ class ContestPasswordVerifyAPIView(APIView):
@check_user_contest_permission @check_user_contest_permission
def contest_page(request, contest_id): def contest_page(request, contest_id):
"""
单个比赛的详情页
"""
try: try:
contest = Contest.objects.get(id=contest_id) contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist: except Contest.DoesNotExist:
@ -265,6 +268,9 @@ def contest_page(request, contest_id):
@check_user_contest_permission @check_user_contest_permission
def contest_problem_page(request, contest_id, contest_problem_id): def contest_problem_page(request, contest_id, contest_problem_id):
"""
单个比赛题目的详情页
"""
try: try:
contest = Contest.objects.get(id=contest_id) contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist: except Contest.DoesNotExist:
@ -286,6 +292,9 @@ def contest_problem_page(request, contest_id, contest_problem_id):
@check_user_contest_permission @check_user_contest_permission
def contest_problems_list_page(request, contest_id): def contest_problems_list_page(request, contest_id):
"""
比赛所有题目的列表页
"""
try: try:
contest_problems = ContestProblem.objects.filter(contest=Contest.objects.get(id=contest_id)).order_by("sort_index") contest_problems = ContestProblem.objects.filter(contest=Contest.objects.get(id=contest_id)).order_by("sort_index")
except Contest.DoesNotExist: except Contest.DoesNotExist:
@ -298,6 +307,9 @@ def contest_problems_list_page(request, contest_id):
def contest_list_page(request, page=1): def contest_list_page(request, page=1):
"""
所有比赛的列表页
"""
# 正常情况 # 正常情况
contests = Contest.objects.filter(visible=True) contests = Contest.objects.filter(visible=True)

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,11 @@
# coding=utf-8
from rest_framework import serializers
from account.models import User
class CreateContestSubmissionSerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
problem_id = serializers.IntegerField()
language = serializers.IntegerField()
code = serializers.CharField(max_length=3000)

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

117
contest_submission/views.py Normal file
View File

@ -0,0 +1,117 @@
# coding=utf-8
import json
import redis
from django.shortcuts import render
from django.core.paginator import Paginator
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
class ContestSubmissionAPIView(APIView):
@check_user_contest_permission
def post(self, request):
"""
创建比赛的提交
---
request_serializer: CreateContestSubmissionSerializer
"""
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:
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)
@login_required
def contest_problem_my_submissions_list_page(request, contest_id, contest_problem_id):
"""
我比赛单个题目的所有提交列表
"""
try:
Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except Problem.DoesNotExist:
return error_page(request, u"比赛问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by("-create_time"). \
values("id", "result", "create_time", "accepted_answer_time", "language")
return render(request, "oj/contest/my_submissions_list.html",
{"submissions": submissions, "problem": contest_problem})
@login_required
def contest_problem_submissions_list_page(request, contest_id, page=1):
"""
单个比赛中的所有提交包含自己和别人自己可查提交结果其他人不可查
"""
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
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")
paginator = Paginator(submissions, 20)
try:
current_page = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = current_page.previous_page_number()
except Exception:
pass
try:
next_page = current_page.next_page_number()
except Exception:
pass
print current_page
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})

View File

@ -54,6 +54,7 @@ INSTALLED_APPS = (
'submission', 'submission',
'mq', 'mq',
'contest', 'contest',
'contest_submission',
'django_extensions', 'django_extensions',
'rest_framework', 'rest_framework',

View File

@ -16,48 +16,44 @@ from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
from admin.views import AdminTemplateView from admin.views import AdminTemplateView
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
from submission.views import SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView from submission.views import SubmissionAPIView, SubmissionAdminAPIView
from contest_submission.views import ContestSubmissionAPIView
from monitor.views import QueueLengthMonitorAPIView from monitor.views import QueueLengthMonitorAPIView
from contest_submission.views import contest_problem_my_submissions_list_page
urlpatterns = [ urlpatterns = [
url(r'^install/$', "install.views.install"), url(r'^install/$', "install.views.install"),
url("^$", TemplateView.as_view(template_name="oj/index.html"), name="index_page"), url("^$", TemplateView.as_view(template_name="oj/index.html"), name="index_page"),
url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^docs/', include('rest_framework_swagger.urls')),
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"), url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"),
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(),
name="admin_template"),
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"),
name="user_register_page"), name="user_register_page"),
url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"),
name="user_change_password_page"), name="user_change_password_page"),
url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page",
name="announcement_page"),
url(r'^api/user/$', UserInfoAPIView.as_view(), name="user_info_api"), url(r'^api/user/$', UserInfoAPIView.as_view(), name="user_info_api"),
url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"),
url(r'^api/register/$', UserRegisterAPIView.as_view(), name="user_register_api"), url(r'^api/register/$', UserRegisterAPIView.as_view(), name="user_register_api"),
url(r'^api/change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api"), url(r'^api/change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api"),
url(r'^api/username_check/$', UsernameCheckAPIView.as_view(), name="username_check_api"), url(r'^api/username_check/$', UsernameCheckAPIView.as_view(), name="username_check_api"),
url(r'^api/email_check/$', EmailCheckAPIView.as_view(), name="email_check_api"), url(r'^api/email_check/$', EmailCheckAPIView.as_view(), name="email_check_api"),
url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"),
url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"),
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"), url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"), url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/$', "contest.views.contest_problem_page",
name="contest_problem_page"),
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^contest/(?P<contest_id>\d+)/problems/$', "contest.views.contest_problems_list_page",
name="contest_problems_list_page"),
url(r'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page",
name="announcement_page"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^contests/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^contests/(?P<page>\d+)/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(),
name="admin_template"),
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"), url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"), url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"),
@ -65,24 +61,43 @@ urlpatterns = [
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"), url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"), url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"), url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
url(r'^problem/(?P<problem_id>\d+)/my_submissions/$', "submission.views.problem_my_submissions_list_page",
name="problem_my_submissions_page"),
url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/my_submissions/$',
"submission.views.contest_problem_my_submissions_list_page", name="contest_problem_my_submissions_list_page"),
url(r'^my_submission/(?P<submission_id>\w+)/$', "submission.views.my_submission", name="my_submission_page"),
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(), url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
name="join_group_request_admin_api"), name="join_group_request_admin_api"),
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
url(r'^api/admin/submission/$', SubmissionAdminAPIView.as_view(), name="submission_admin_api_view"), url(r'^api/admin/submission/$', SubmissionAdminAPIView.as_view(), name="submission_admin_api_view"),
url(r'^my_submissions/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
url(r'^my_submissions/(?P<page>\d+)/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
url(r'^api/admin/monitor/$', QueueLengthMonitorAPIView.as_view(), name="queue_length_monitor_api"), url(r'^api/admin/monitor/$', QueueLengthMonitorAPIView.as_view(), name="queue_length_monitor_api"),
url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/$', "contest.views.contest_problem_page",
name="contest_problem_page"),
url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/submissions/$',
"contest_submission.views.contest_problem_my_submissions_list_page",
name="contest_problem_my_submissions_list_page"),
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"), url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"), url(r'^contest/(?P<contest_id>\d+)/problems/$', "contest.views.contest_problems_list_page",
url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"), name="contest_problems_list_page"),
url(r'^contest/(?P<contest_id>\d+)/submissions/$', "contest_submission.views.contest_problem_submissions_list_page",
name="contest_problem_submissions_list_page"),
url(r'^contest/(?P<contest_id>\d+)/submissions/(?P<page>\d+)/$',
"contest_submission.views.contest_problem_submissions_list_page", name="contest_problem_submissions_list_page"),
url(r'^contests/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^contests/(?P<page>\d+)/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problem/(?P<problem_id>\d+)/submissions/$', "submission.views.problem_my_submissions_list_page",
name="problem_my_submissions_page"),
url(r'^submission/(?P<submission_id>\w+)/$', "submission.views.my_submission", name="my_submission_page"),
url(r'^submissions/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
url(r'^submissions/(?P<page>\d+)/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
url(r'^contest/(?P<contest_id>\d+)/rank/$', "contest.views.contest_rank_page", name="contest_rank_page") url(r'^contest/(?P<contest_id>\d+)/rank/$', "contest.views.contest_rank_page", name="contest_rank_page")

View File

@ -90,5 +90,5 @@ li.list-group-item {
} }
.contest-tab{ .contest-tab{
margin-bottom: 5px; margin-bottom: 15px;
} }

View File

@ -22,8 +22,3 @@ class SubmissionSerializer(serializers.ModelSerializer):
return User.objects.get(id=obj.user_id).username return User.objects.get(id=obj.user_id).username
class CreateContestSubmissionSerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
problem_id = serializers.IntegerField()
language = serializers.IntegerField()
code = serializers.CharField(max_length=3000)

View File

@ -1,5 +1,10 @@
# coding=utf-8
import json
from django.test import TestCase from django.test import TestCase
from account.models import User, REGULAR_USER from django.core.urlresolvers import reverse
from account.models import User, REGULAR_USER, ADMIN, SUPER_ADMIN
from problem.models import Problem
from contest.models import Contest
from submission.models import Submission from submission.models import Submission
from rest_framework.test import APITestCase, APIClient from rest_framework.test import APITestCase, APIClient
@ -12,6 +17,7 @@ class SubmissionsListPageTest(TestCase):
self.user2.set_password("666666") self.user2.set_password("666666")
self.user.set_password("666666") self.user.set_password("666666")
self.user.save() self.user.save()
self.user2.save()
# self.client.login(username="gogoing", password="666666") # self.client.login(username="gogoing", password="666666")
self.submission = Submission.objects.create(user_id=self.user.id, self.submission = Submission.objects.create(user_id=self.user.id,
language=1, language=1,
@ -42,3 +48,99 @@ class SubmissionsListPageTest(TestCase):
self.client.login(username="cool", password="666666") self.client.login(username="cool", password="666666")
response = self.client.get('/my_submissions/') response = self.client.get('/my_submissions/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
class SubmissionAPITest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse('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.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="test2"))
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"))
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)
def test_invalid_format(self):
self.client.login(username="test1", password="testaa")
data = {"language": 1}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_problem_does_not_exist(self):
self.client.login(username="test1", password="testaa")
data = {"language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}',
"problem_id": self.problem.id + 10}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"题目不存在"})
def test_submission_successfully(self):
self.client.login(username="test1", password="testaa")
data = {"language": 1, "code": '#include "stdio.h"\nint main(){\n\treturn 0;\n}',
"problem_id": self.problem.id}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 0)
def test_submission_does_not_exist(self):
self.client.login(username="test1", password="testaa")
data = {"submission_id": self.submission.id + "111"}
response = self.client.get(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"提交不存在"})
def test_get_submission_successfully(self):
self.client.login(username="test1", password="testaa")
data = {"submission_id": self.submission.id}
response = self.client.get(self.url, data=data)
self.assertEqual(response.data["code"], 0)
class ContestSubmissionAPITest(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.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"))
def test_invalid_format(self):
self.client.login(username="test1", password="testaa")
data = {"language": 1}
response = self.client.post(self.url, data=data)
pass

View File

@ -19,7 +19,7 @@ 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 .models import Submission from .models import Submission
from .serializers import CreateSubmissionSerializer, SubmissionSerializer, CreateContestSubmissionSerializer from .serializers import CreateSubmissionSerializer, SubmissionSerializer
class SubmissionAPIView(APIView): class SubmissionAPIView(APIView):
@ -73,34 +73,24 @@ class SubmissionAPIView(APIView):
@login_required @login_required
def problem_my_submissions_list_page(request, problem_id): def problem_my_submissions_list_page(request, problem_id):
"""
我单个题目所有提交的列表页
"""
try: try:
problem = Problem.objects.get(id=problem_id, visible=True) problem = Problem.objects.get(id=problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"问题不存在") return error_page(request, u"问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id).order_by("-create_time"). \ submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id, contest_id__isnull=True).order_by("-create_time"). \
values("id", "result", "create_time", "accepted_answer_time", "language") values("id", "result", "create_time", "accepted_answer_time", "language")
return render(request, "oj/problem/my_submissions_list.html", return render(request, "oj/problem/my_submissions_list.html",
{"submissions": submissions, "problem": problem}) {"submissions": submissions, "problem": problem})
@login_required
def contest_problem_my_submissions_list_page(request, contest_id, contest_problem_id):
try:
Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
try:
contest_problem = ContestProblem.objects.get(id=contest_problem_id, visible=True)
except Problem.DoesNotExist:
return error_page(request, u"比赛问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=contest_problem.id).order_by("-create_time"). \
values("id", "result", "create_time", "accepted_answer_time", "language")
return render(request, "oj/contest/my_submissions_list.html",
{"submissions": submissions, "contest_problem": contest_problem})
@login_required @login_required
def my_submission(request, submission_id): def my_submission(request, submission_id):
"""
单个题目的提交详情页
"""
try: try:
# 超级管理员可以查看所有的提交 # 超级管理员可以查看所有的提交
if request.user.admin_type != SUPER_ADMIN: if request.user.admin_type != SUPER_ADMIN:
@ -110,10 +100,18 @@ def my_submission(request, submission_id):
except Submission.DoesNotExist: except Submission.DoesNotExist:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
if submission.contest_id:
try:
problem = ContestProblem.objects.get(id=submission.problem_id,
visible=True)
except ContestProblem.DoesNotExist:
return error_page(request, u"提交不存在")
else:
try: try:
problem = Problem.objects.get(id=submission.problem_id, visible=True) problem = Problem.objects.get(id=submission.problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
if submission.info: if submission.info:
try: try:
info = json.loads(submission.info) info = json.loads(submission.info)
@ -136,6 +134,9 @@ class SubmissionAdminAPIView(APIView):
@login_required @login_required
def my_submission_list_page(request, page=1): def my_submission_list_page(request, page=1):
"""
我的所有提交的列表页
"""
submissions = Submission.objects.filter(user_id=request.user.id). \ submissions = Submission.objects.filter(user_id=request.user.id). \
values("id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time") values("id", "result", "create_time", "accepted_answer_time", "language").order_by("-create_time")
paginator = Paginator(submissions, 20) paginator = Paginator(submissions, 20)
@ -157,44 +158,3 @@ def my_submission_list_page(request, page=1):
{"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})
class ContestSubmissionAPIView(APIView):
@check_user_contest_permission
def post(self, request):
"""
创建比赛的提交
---
request_serializer: ConestSubmissionSerializer
"""
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"比赛不存在")
if contest.status != 0:
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:
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)

View File

@ -1,13 +1,11 @@
{% extends 'oj_base.html' %} {% extends 'oj_base.html' %}
{% block body %} {% block body %}
<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="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/">题目</a></li> <a href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/">题目</a></li>
<li role="presentation"><a <li role="presentation"><a href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/submissions/">我的提交</a></li>
href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/my_submissions/">我的提交</a>
</li>
</ul> </ul>
<h2 class="text-center">{{ contest_problem.title }}</h2> <h2 class="text-center">{{ contest_problem.title }}</h2>
@ -16,6 +14,15 @@
内存限制 : {{ contest_problem.memory_limit }}M 内存限制 : {{ contest_problem.memory_limit }}M
</p> </p>
<div>
<div class="problem-section">
<label class="problem-label">描述</label>
<p class="problem-detail">{{ contest_problem.description|safe }}</p>
</div>
<div class="problem-section">
<label class="problem-label">输入</label>
<div> <div>
<div class="problem-section"> <div class="problem-section">
<label class="problem-label">描述</label> <label class="problem-label">描述</label>

View File

@ -1,7 +1,7 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
{% load problem %} {% load problem %}
<div class="container main"> <div class="container main">
<div class="row"> <div class="row">
@ -21,10 +21,12 @@
<a href="/contest/{{ contest.id }}/rank/">排名</a> <a href="/contest/{{ contest.id }}/rank/">排名</a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-lg-9">
<div class="col-lg-9">
<div> <div>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
@ -38,45 +40,27 @@
<tbody> <tbody>
{% for item in contest_problems %} {% for item in contest_problems %}
<tr> <tr>
<th> <th><span class="glyphicon glyphicon-ok ac-flag"></span></th>
<span class="glyphicon glyphicon-ok ac-flag"></span> <th scope="row"><a
href="/contest/{{ item.contest.id }}/problem/{{ item.id }}/">{{ item.sort_index }}</a>
</th> </th>
<th scope="row"> <td><a href="/contest/{{ item.contest.id }}/problem/{{ item.id }}/">{{ item.title }}</a>
<a href="/contest/{{ item.contest.id }}/problem/{{ item.id }}/" target="_blank">{{ item.sort_index }}</a>
</th>
<td>
<a href="/contest/{{ item.contest.id }}/problem/{{ item.id }}/" target="_blank">{{ item.title }}</a>
</td> </td>
<td>{{ item|accepted_radio }}</td> <td>{{ item|accepted_radio }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/problems/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %}
{% if next_page %}
<li class="next"><a
href="/problems/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">下一页 <span
aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
{% include "oj/announcement/_announcement_panel.html" %} {% include "oj/announcement/_announcement_panel.html" %}
</div> </div>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script src="/static/js/app/oj/problem/problem_list.js"></script> <script src="/static/js/app/oj/problem/problem_list.js"></script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,71 @@
{% extends 'oj_base.html' %}
{% block css_block %}
<style>
.CodeMirror {
height: auto;
}
</style>
{% endblock %}
{% block body %}
{% load submission %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/contest/{{ problem.contest.id }}/problem/{{ problem.id }}/">题目</a></li>
<li role="presentation" class="active">
<a href="/contest/{{ problem.contest.id }}/problem/{{ problem.id }}/submissions/">
我的提交</a>
</li>
</ul>
{% include "oj/problem/_problem_header.html" %}
<div class="panel panel-default">
<div class="panel-body">
<h4>运行结果 : <span class="text-{{ submission.result|translate_result_class }}">
{{ submission.result|translate_result }}
</span>
</h4>
{% ifequal submission.result 0 %}
<p>时间 : {{ submission.accepted_answer_time }}ms 语言 :
{{ submission.language|translate_language }}
</p>
{% endifequal %}
{% ifequal submission.result 4 %}
<p>{{ submission.info }}</p>
{% endifequal %}
<p>提交时间 : {{ submission.create_time }}</p>
</div>
</div>
{% ifequal request.user.admin_type 2 %}
<p>本调试信息仅超级管理员可见</p>
{% ifequal submission.result 7 %}
<pre>System Error: {{ submission.info }}</pre>
{% else %}
<pre>{{ info }}</pre>
{% endifequal %}
{% endifequal %}
<div id="code-field">
<textarea id="code-editor">{{ submission.code }}</textarea>
</div>
</div>
{% endblock %}
{% block js_block %}
<script>
require(["jquery", "codeMirror"], function ($, codeMirror) {
{% ifequal submission.language 1 %}
var language = "text/x-csrc";
{% else %}
{% ifequal submission.language 2 %}
var language = "text/x-c++src";
{% else %}
var language = "text/x-java";
{% endifequal %}
{% endifequal %}
var codeEditor = codeMirror($("#code-editor")[0], language);
codeEditor.setOption("readOnly", true);
});
</script>
{% endblock %}

View File

@ -6,17 +6,13 @@
<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"> <li role="presentation">
<a href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/">题目</a></li> <a href="/contest/{{ problem.contest.id }}/problem/{{ problem.id }}/">题目</a></li>
<li role="presentation" class="active"> <li role="presentation" class="active">
<a href="/contest/{{ contest_problem.contest.id }}/problem/{{ contest_problem.id }}/my_submissions/"> <a href="/contest/{{ problem.contest.id }}/problem/{{ problem.id }}/submissions/">
我的提交</a> 我的提交</a>
</li> </li>
</ul> </ul>
<h2 class="text-center">{{ contest_problem.title }}</h2> {% include "oj/problem/_problem_header.html" %}
<p class="text-muted text-center">发布时间: {{ contest_problem.create_time }}&nbsp;&nbsp;
时间限制: {{ contest_problem.time_limit }}ms&nbsp;&nbsp;
内存限制: {{ contest_problem.memory_limit }}M</p>
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr class="" success> <tr class="" success>
@ -30,7 +26,7 @@
<tbody> <tbody>
{% for item in submissions %} {% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}"> <tr class="{{ item.result|translate_result_class }}">
<th scope="row"><a href="/my_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.result|translate_result }}</td>
<td> <td>

View File

@ -0,0 +1,80 @@
{% extends 'oj_base.html' %}
{% block body %}
{% load submission %}
<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>
{% if submissions %}
<table class="table table-bordered">
<thead>
<tr class="" success>
<th>#</th>
<th>提交时间</th>
<th>结果</th>
<th>运行时间</th>
<th>语言</th>
</tr>
</thead>
<tbody>
{% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}">
{% ifequal item.user_id request.user.id %}
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
{{ forloop.counter |add:start_id }}</a></th>
{% else %}
<th scope="row">{{ forloop.counter |add:start_id }}</th>
{% endifequal %}
<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>
</table>
{% else %}
<p>你还没有提交记录!</p>
{% endif %}
<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

@ -12,12 +12,23 @@
<ul class="nav nav-tabs nav-tabs-google"> <ul class="nav nav-tabs nav-tabs-google">
<li role="presentation"> <li role="presentation">
{% if submission.contest_id %} {% if submission.contest_id %}
<a href="/contest/{{ submission.contest_id }}/problem/{{ problem.id }}/">题目</a> <a href="/contest/{{ submission.contest_id }}/problem/{{ problem.id }}/">题目</a>
{% else %} {% else %}
<a href="/problem/{{ problem.id }}/">题目</a> <a href="/problem/{{ problem.id }}/">题目</a>
{% endif %} {% endif %}
</li> </li>
<li role="presentation" class="active"><a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li>
<li role="presentation" class="active">
{% if submission.contest_id %}
<a href="/contest/{{ submission.contest_id }}/problem/{{ problem.id }}/submissions/">我的提交</a>
{% else %}
<a href="/problem/{{ problem.id }}/submissions/">我的提交</a>
{% endif %}
</li>
</ul> </ul>
{% include "oj/problem/_problem_header.html" %} {% include "oj/problem/_problem_header.html" %}
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -8,13 +8,9 @@
<li role="presentation"> <li role="presentation">
<a href="/problem/{{ problem.id }}/">题目</a></li> <a href="/problem/{{ problem.id }}/">题目</a></li>
<li role="presentation" class="active"> <li role="presentation" class="active">
<a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li> <a href="/problem/{{ problem.id }}/submissions/">我的提交</a></li>
</ul> </ul>
<h2 class="text-center">{{ problem.title }}</h2> {% include "oj/problem/_problem_header.html" %}
<p class="text-muted text-center">发布时间: {{ problem.create_time }}&nbsp;&nbsp;
时间限制: {{ problem.time_limit }}ms&nbsp;&nbsp;
内存限制: {{ problem.memory_limit }}M</p>
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr class="" success> <tr class="" success>
@ -28,7 +24,7 @@
<tbody> <tbody>
{% for item in submissions %} {% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}"> <tr class="{{ item.result|translate_result_class }}">
<th scope="row"><a href="/my_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.result|translate_result }}</td>
<td> <td>

View File

@ -5,7 +5,7 @@
<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>
<li role="presentation"><a href="/problem/{{ problem.id }}/my_submissions/">我的提交</a></li> <li role="presentation"><a href="/problem/{{ problem.id }}/submissions/">我的提交</a></li>
</ul> </ul>
{% include "oj/problem/_problem_header.html" %} {% include "oj/problem/_problem_header.html" %}

View File

@ -44,12 +44,12 @@
<ul class="pager"> <ul class="pager">
{% if previous_page %} {% if previous_page %}
<li class="previous"><a <li class="previous"><a
href="/my_submissions/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}"> href="/submissions/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% 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"><a <li class="next"><a
href="/my_submissions/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">下一页 <span href="/submissions/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">下一页 <span
aria-hidden="true">&rarr;</span></a></li> aria-hidden="true">&rarr;</span></a></li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -43,7 +43,7 @@
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="/problems/">题目</a></li> <li><a href="/problems/">题目</a></li>
<li><a href="/my_submissions/">提交</a></li> <li><a href="/submissions/">提交</a></li>
<li><a href="/contests/">比赛</a></li> <li><a href="/contests/">比赛</a></li>
<li><a href="/about/">关于</a></li> <li><a href="/about/">关于</a></li>
</ul> </ul>