创建了单个比赛的详情页

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

View File

@ -103,3 +103,8 @@ class EditContestProblemSerializer(serializers.Serializer):
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)
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from account.decorators import login_required
from group.models import Group
from .models import Contest, ContestProblem
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer, EditContestProblemSerializer)
def contest_page(request, contest_id):
pass
CreateContestProblemSerializer, ContestProblemSerializer,
EditContestProblemSerializer, ContestPasswordVerifySerializer)
class ContestAdminAPIView(APIView):
@ -221,3 +219,59 @@ class ContestProblemAdminAPIView(APIView):
Q(description__contains=keyword))
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)
from announcement.views import AnnouncementAdminAPIView
from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView
from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView, ContestPasswordVerifyAPIView
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@ -64,5 +64,7 @@ urlpatterns = [
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/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 %}