创建了单个比赛的详情页

This commit is contained in:
virusdefender
2015-08-22 20:46:52 +08:00
parent f86ebd8ba3
commit 1fe35bd6e0
8 changed files with 178 additions and 10 deletions

View File

@@ -9,19 +9,17 @@ from group.models import Group
class Contest(models.Model): class Contest(models.Model):
title = models.CharField(max_length=40, unique=True) title = models.CharField(max_length=40, unique=True)
description = models.TextField() description = models.TextField()
# 比赛模式0 即为是acm模式1 即为是按照总的 ac 题目数量排名模式2 即为按照 ac 的题目的总分排名模式 # 比赛模式0 即为是acm模式1 即为是按照总的 ac 题目数量排名模式
mode = models.IntegerField() mode = models.IntegerField()
# 是否显示排名结果 # 是否显示排名结果
show_rank = models.BooleanField() show_rank = models.BooleanField()
# 是否显示别人的提交记录 # 是否显示别人的提交记录
show_user_submission = models.BooleanField() show_user_submission = models.BooleanField()
# 只能超级管理员创建公开赛,管理员只能创建小组内部的比赛 # 只能超级管理员创建公开赛,管理员只能创建小组内部的比赛
# 如果这一项不为空,即为有密码的公开赛,没有密码的可以为小组赛或者是公开赛(此时用比赛的类型来表示) # 如果这一项不为空,即为有密码的公开赛,没有密码的可以为小组赛或者是公开赛(此时用比赛的类型来表示)
password = models.CharField(max_length=30, blank=True, null=True) password = models.CharField(max_length=30, blank=True, null=True)
# 比赛的类型: 0 即为是小组赛1 即为是无密码的公开赛2 即为是有密码的公开赛 # 比赛的类型: 0 即为是小组赛1 即为是无密码的公开赛2 即为是有密码的公开赛
contest_type = models.IntegerField() contest_type = models.IntegerField()
# 开始时间 # 开始时间
start_time = models.DateTimeField() start_time = models.DateTimeField()
# 结束时间 # 结束时间

View File

@@ -103,3 +103,8 @@ class EditContestProblemSerializer(serializers.Serializer):
sort_index = serializers.CharField(max_length=30) sort_index = serializers.CharField(max_length=30)
class ContestPasswordVerifySerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
password = serializers.CharField(max_length=30)

View File

@@ -9,15 +9,13 @@ from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str, error_page) success_response, paginate, rand_str, error_page)
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from account.decorators import login_required
from group.models import Group from group.models import Group
from .models import Contest, ContestProblem from .models import Contest, ContestProblem
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer, from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer, EditContestProblemSerializer) CreateContestProblemSerializer, ContestProblemSerializer,
EditContestProblemSerializer, ContestPasswordVerifySerializer)
def contest_page(request, contest_id):
pass
class ContestAdminAPIView(APIView): class ContestAdminAPIView(APIView):
@@ -220,4 +218,60 @@ class ContestProblemAdminAPIView(APIView):
contest_problem = contest_problem.filter(Q(title__contains=keyword) | contest_problem = contest_problem.filter(Q(title__contains=keyword) |
Q(description__contains=keyword)) Q(description__contains=keyword))
return paginate(request, contest_problem, ContestProblemSerializer) return paginate(request, contest_problem, ContestProblemSerializer)
class ContestPasswordVerifyAPIView(APIView):
@login_required
def post(self, request):
serializer = ContestPasswordVerifySerializer(data=request.data)
if serializer.is_valid():
data = request.data
try:
contest = Contest.objects.get(id=data["contest_id"], contest_type=2)
except Contest.DoesNotExist:
return error_response(u"密码错误")
if data["password"] != contest.password:
return error_response(u" 密码错误")
else:
print request.session.get("contests", None)
if "contests" not in request.session:
request.session["contests"] = []
request.session["contests"].append(int(data["contest_id"]))
print request.session["contests"]
return success_response(True)
else:
return serializer_invalid_response(serializer)
def check_user_contest_permission(request, contest):
# 有密码的公开赛
if contest.contest_type == 2:
# 没有输入过密码
if contest.id not in request.session.get("contests", []):
return {"result": False, "reason": "password_protect"}
# 指定小组参加的
if contest.contest_type == 0:
if not contest.groups.filter(id__in=request.user.group_set.all()).exists():
return {"result": False, "reason": "limited_group"}
return {"result": True}
@login_required
def contest_page(request, contest_id):
print request.session.get("contests", None)
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_page(request, u"比赛不存在")
Contest.objects.filter(Q(contest_type__in=[1, 2]) | Q(groups__in=request.user.group_set.all()))
result = check_user_contest_permission(request, contest)
if not result["result"]:
return render(request, "oj/contest/contest_no_privilege.html", {"contenst": contest, "reason": result["reason"]})
return render(request, "oj/contest/contest_index.html", {"contest": contest})

View File

@@ -8,7 +8,7 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
UserAdminAPIView, UserInfoAPIView) UserAdminAPIView, UserInfoAPIView)
from announcement.views import AnnouncementAdminAPIView from announcement.views import AnnouncementAdminAPIView
from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView, ContestPasswordVerifyAPIView
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView) JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@@ -64,5 +64,7 @@ urlpatterns = [
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_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'^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+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"),
] ]

View File

@@ -0,0 +1,24 @@
require(["jquery", "bsAlert", "csrfToken"], function($, bsAlert, csrfTokenHeader){
$("#contest-password-btn").click(function(){
var password = $("#contest-password").val();
if(!password){
bsAlert("密码不能为空!");
return;
}
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/contest/password/",
data: {password: password, contest_id: location.href.split("/")[4]},
method: "post",
dataType: "json",
success: function(data){
if(!data.code){
location.reload();
}
else{
bsAlert(data.data);
}
}
})
})
});

View File

@@ -0,0 +1,38 @@
{% load contest %}
<h2 class="text-center">{{ contest.title }}</h2>
<hr>
<div>
<table class="table table-bordered">
<thead>
<tr>
<th>开始时间</th>
<th>结束时间</th>
<th>状态</th>
<th>比赛类型</th>
<th>创建者</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ contest.start_time }}</td>
<td>{{ contest.end_time }}</td>
<td>{{ contest|contest_status }}</td>
{% ifequal contest.contest_type 0 %}
<td>小组赛</td>
{% endifequal %}
{% ifequal contest.contest_type 1 %}
<td>公开赛</td>
{% endifequal %}
{% ifequal contest.contest_type 2 %}
<td>公开赛(密码保护)</td>
{% endifequal %}
<td>{{ contest.created_by.username }}</td>
</tr>
</tbody>
</table>
<hr>
<div>{{ contest.description|safe }}</div>
</div>
<p class="text-center"></p>

View File

@@ -0,0 +1,21 @@
{% extends 'oj_base.html' %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/problems/">题目</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/submissions/">提交</a>
</li>
<li role="presentation">
<a href="/contest/{{ contest.id }}/rank/">排名</a>
</li>
</ul>
{% include "oj/contest/_contest_header.html" %}
</div>
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends 'oj_base.html' %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active">
<a href="/contest/{{ contest.id }}/">比赛详情</a>
</li>
</ul>
{% include "oj/contest/_contest_header.html" %}
{% ifequal reason "password_protect" %}
<div class="form-inline">
<div class="form-group">
<label>密码</label>
<input type="password" class="form-control" id="contest-password" placeholder="请输入密码">
</div>
<button type="button" id="contest-password-btn" class="btn btn-primary">提交</button>
</div>
{% else %}
<div class="alert alert-danger" role="alert">比赛仅指定小组可以参加,你不在这些小组中。</div>
{% endifequal %}
</div>
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/contest/contest_password.js"></script>
{% endblock %}