From a5211f50da1ad536786062ce8ea87efc9aa731c6 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Mon, 17 Aug 2015 20:54:10 +0800
Subject: [PATCH 1/8] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AA?=
=?UTF-8?q?=E7=82=B9=E5=87=BB=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
template/oj/problem/problem.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/template/oj/problem/problem.html b/template/oj/problem/problem.html
index 2b8dfa32..5a7d8474 100644
--- a/template/oj/problem/problem.html
+++ b/template/oj/problem/problem.html
@@ -4,7 +4,7 @@
{% include "oj/problem/_problem_header.html" %}
From 937c382b2590c4177caaedf09164a49932cdf162 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Tue, 18 Aug 2015 14:59:00 +0800
Subject: [PATCH 2/8] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E6=AF=94=E8=B5=9B?=
=?UTF-8?q?=E5=92=8C=E6=AF=94=E8=B5=9B=E9=A2=98=E7=9B=AE=E7=9A=84=E9=83=A8?=
=?UTF-8?q?=E5=88=86=EF=BC=8C=E8=BF=98=E6=9C=89=E8=A6=81=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E5=92=8C=E4=BF=AE=E6=94=B9=E7=9A=84=E5=9C=B0=E6=96=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
contest/serializers.py | 95 +++++++++++++++++++++++
contest/views.py | 169 ++++++++++++++++++++++++++++++++++++++++-
problem/models.py | 4 +-
problem/tests.py | 5 ++
4 files changed, 270 insertions(+), 3 deletions(-)
create mode 100644 contest/serializers.py
diff --git a/contest/serializers.py b/contest/serializers.py
new file mode 100644
index 00000000..424ba0ef
--- /dev/null
+++ b/contest/serializers.py
@@ -0,0 +1,95 @@
+# coding=utf-8
+import json
+from rest_framework import serializers
+
+from account.models import User
+from .models import Contest, ContestProblem
+
+
+class CreateContestSerializer(serializers.Serializer):
+ title = serializers.CharField(max_length=40)
+ description = serializers.CharField(max_length=5000)
+ mode = serializers.IntegerField()
+ show_rank = serializers.BooleanField()
+ password = serializers.CharField(max_length=30, required=False)
+ start_time = serializers.DateTimeField()
+ end_time = serializers.DateTimeField()
+
+
+class ContestSerializer(serializers.ModelSerializer):
+ class UserSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = User
+ fields = ["username"]
+
+ created_by = UserSerializer()
+
+ class Meta:
+ model = Contest
+
+
+class EditContestSerializer(serializers.Serializer):
+ title = serializers.CharField(max_length=40)
+ description = serializers.CharField(max_length=10000)
+ mode = serializers.IntegerField()
+ show_rank = serializers.BooleanField()
+ password = serializers.CharField(max_length=30, required=False)
+ start_time = serializers.DateTimeField()
+ end_time = serializers.DateTimeField()
+
+
+class ContestProblemSampleSerializer(serializers.ListField):
+ input = serializers.CharField(max_length=3000)
+ output = serializers.CharField(max_length=3000)
+
+
+class JSONField(serializers.Field):
+ def to_representation(self, value):
+ return json.loads(value)
+
+
+class CreateContestProblemSerializer(serializers.Serializer):
+ title = serializers.CharField(max_length=50)
+ description = serializers.CharField(max_length=10000)
+ input_description = serializers.CharField(max_length=10000)
+ output_description = serializers.CharField(max_length=10000)
+ # [{"input": "1 1", "output": "2"}]
+ samples = ContestProblemSampleSerializer()
+ test_case_id = serializers.CharField(max_length=40)
+ time_limit = serializers.IntegerField()
+ memory_limit = serializers.IntegerField()
+ difficulty = serializers.IntegerField()
+ hint = serializers.CharField(max_length=3000, allow_blank=True)
+ sort_index = serializers.CharField(max_length=30)
+
+
+class ContestProblemSerializer(serializers.ModelSerializer):
+ samples = JSONField()
+
+ class ContestSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Contest
+ fields = ["title"]
+
+ created_by = ContestSerializer()
+
+ class Meta:
+ model = ContestProblem
+
+
+class EditContestProblemSerializer(serializers.Serializer):
+ id = serializers.IntegerField()
+ title = serializers.CharField(max_length=50)
+ description = serializers.CharField(max_length=10000)
+ input_description = serializers.CharField(max_length=10000)
+ output_description = serializers.CharField(max_length=10000)
+ test_case_id = serializers.CharField(max_length=40)
+ time_limit = serializers.IntegerField()
+ memory_limit = serializers.IntegerField()
+ difficulty = serializers.IntegerField()
+ samples = ContestProblemSampleSerializer()
+ hint = serializers.CharField(max_length=3000, allow_blank=True)
+ visible = serializers.BooleanField()
+ sort_index = serializers.CharField(max_length=30)
+
+
diff --git a/contest/views.py b/contest/views.py
index 91ea44a2..3746b2bf 100644
--- a/contest/views.py
+++ b/contest/views.py
@@ -1,3 +1,170 @@
+# coding=utf-8
+import json
from django.shortcuts import render
+from django.db import IntegrityError
+from django.db.models import Q
+from rest_framework.views import APIView
-# Create your views here.
+from .models import Contest, ContestProblem
+from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
+ CreateContestProblemSerializer, ContestProblemSerializer, EditContestProblemSerializer)
+from utils.shortcuts import (serializer_invalid_response, error_response,
+ success_response, paginate, rand_str, error_page)
+
+
+def contest_page(request, contest_id):
+ pass
+
+
+class ContestAdminAPIView(APIView):
+ def post(self, request):
+ """
+ 比赛发布json api接口
+ ---
+ request_serializer: CreateContestSerializer
+ response_serializer: ContestSerializer
+ """
+ serializer = CreateContestSerializer(data=request.data)
+ if serializer.is_valid():
+ data = serializer.data
+ try:
+ contest = Contest.objects.create(title=data["title"], description=data["description"],
+ mode=data["mode"], show_rank=data["show_rank"],
+ start_time=["start_time"], end_time=data["end_time"])
+ if data["password"]:
+ contest.setpassword(data["password"])
+ contest.save()
+ except IntegrityError:
+ return error_response(u"比赛名已经存在")
+ return success_response(ContestSerializer(contest).data)
+ else:
+ serializer_invalid_response(serializer)
+
+ def put(self, request):
+ """
+ 比赛编辑json api接口
+ ---
+ request_serializer: EditContestSerializer
+ response_serializer: ContestSerializer
+ """
+ serializer = EditContestSerializer(data=request.data)
+ if serializer.is_valid():
+ data = serializer.data
+ try:
+ contest = Contest.objects.get(id=data["id"])
+ except Contest.DoesNotExist:
+ error_response(u"该比赛不存在!")
+ try:
+ contest.title = data["contest"]
+ contest.description = data["description"]
+ contest.mode = data["mode"]
+ contest.show_rank = data["show_"]
+ if data["password"]:
+ contest.set_password(data["password"])
+ contest.save()
+ except IntegrityError:
+ return error_response(u"比赛名已经存在")
+
+ return success_response(ContestSerializer(contest).data)
+ else:
+ serializer_invalid_response(serializer)
+
+ def get(self, request):
+ """
+ 比赛分页json api接口
+ ---
+ response_serializer: ContestSerializer
+ """
+ contest = Contest.objects.all().order_by("-last_updated_time")
+ visible = request.GET.get("visible", None)
+ if visible:
+ contest = contest.filter(visible=(visible == "true"))
+ keyword = request.GET.get("keyword", None)
+ if keyword:
+ contest = contest.filter(Q(title__contains=keyword) |
+ Q(description__contains=keyword))
+ return paginate(request, contest, ContestSerializer)
+
+
+class ContestProblemAdminAPIView(APIView):
+ def post(self, request):
+ """
+ 比赛题目发布json api接口
+ ---
+ request_serializer: CreateContestProblemSerializer
+ response_serializer: ContestProblemSerializer
+ """
+ serializer = CreateContestProblemSerializer(data=request.data)
+ if serializer.is_valid():
+ data = serializer.data
+ contest_problem = ContestProblem.objects.create(title=data["title"],
+ description=data["description"],
+ input_description=data["input_description"],
+ output_description=data["output_description"],
+ test_case_id=data["test_case_id"],
+ samples=json.dumps(data["samples"]),
+ time_limit=data["time_limit"],
+ memory_limit=data["memory_limit"],
+ difficulty=data["difficulty"],
+ created_by=request.user,
+ hint=data["hint"],
+ contest=request.contest,
+ sort_index=data["sort_index"])
+ return success_response(ContestProblemSerializer(contest_problem).data)
+ else:
+ serializer_invalid_response(serializer)
+
+ def put(self, request):
+ """
+ 比赛题目编辑json api接口
+ ---
+ request_serializer: EditContestSerializer
+ response_serializer: ContestProblemSerializer
+ """
+ serializer = EditContestSerializer(data=request.data)
+ if serializer.is_valid():
+ data = serializer.data
+ try:
+ contest_problem = ContestProblem.objects.get(id=data["id"])
+ except ContestProblem.DoesNotExist:
+ return error_response(u"该比赛题目不存在!")
+ contest_problem.title = data["title"]
+ contest_problem.description = data["description"]
+ contest_problem.input_description = data["input_description"]
+ contest_problem.output_description = data["output_description"]
+ contest_problem.test_case_id = data["test_case_id"]
+ contest_problem.time_limit = data["time_limit"]
+ contest_problem.memory_limit = data["memory_limit"]
+ contest_problem.difficulty = data["difficulty"]
+ contest_problem.samples = json.dumps(data["samples"])
+ contest_problem.hint = data["hint"]
+ contest_problem.visible = data["visible"]
+ contest_problem.sort_index = data["sort_index"]
+ contest_problem.save()
+ return success_response(ContestProblem(contest_problem).data)
+ else:
+ return serializer_invalid_response(serializer)
+
+ def get(self, request):
+ """
+ 比赛题目分页json api接口
+ ---
+ response_serializer: ProblemSerializer
+ """
+ contest_problem_id = request.GET.get("contest_problem_id", None)
+ if contest_problem_id:
+ try:
+ contest_problem = ContestProblemSerializer.objects.get(id=contest_problem_id)
+ return success_response(ContestProblemSerializer(contest_problem).data)
+ except contest_problem.DoesNotExist:
+ return error_response(u"比赛题目不存在")
+ contest_problem = ContestProblem.objects.all().order_by("sort_index")
+ visible = request.GET.get("visible", None)
+ if visible:
+ contest_problem = contest_problem.filter(visible=(visible == "true"))
+ keyword = request.GET.get("keyword", None)
+ if keyword:
+ contest_problem = contest_problem.filter(Q(title__contains=keyword) |
+ Q(description__contains=keyword))
+
+ return paginate(request, contest_problem, ContestProblemSerializer)
\ No newline at end of file
diff --git a/problem/models.py b/problem/models.py
index d6ac77bb..dbc886b6 100644
--- a/problem/models.py
+++ b/problem/models.py
@@ -32,8 +32,6 @@ class AbstractProblem(models.Model):
# last_update_time = models.DateTimeField(auto_now=True)
# 这个题是谁创建的
created_by = models.ForeignKey(User)
- # 来源
- source = models.CharField(max_length=30, blank=True, null=True)
# 时间限制 单位是毫秒
time_limit = models.IntegerField()
# 内存限制 单位是MB
@@ -54,3 +52,5 @@ class Problem(AbstractProblem):
difficulty = models.IntegerField()
# 标签
tags = models.ManyToManyField(ProblemTag)
+ # 来源
+ source = models.CharField(max_length=30, blank=True, null=True)
diff --git a/problem/tests.py b/problem/tests.py
index 91affaea..925ffe08 100644
--- a/problem/tests.py
+++ b/problem/tests.py
@@ -164,3 +164,8 @@ class ProblemTagAdminAPITest(APITestCase):
def test_get_all_problem_tag_successfully(self):
self.assertEqual(self.client.get(self.url).data["code"], 0)
+
+class ProblemListPageTest(TestCase):
+ def setUp(self):
+ pass
+
From bdf3fa9ed997967a2da7a967cb6333e765aea900 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Tue, 18 Aug 2015 20:12:27 +0800
Subject: [PATCH 3/8] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=BF=AE=E6=94=B9?=
=?UTF-8?q?=E6=AF=94=E8=B5=9B=E5=88=9B=E5=BB=BA=E9=83=A8=E5=88=86=EF=BC=8C?=
=?UTF-8?q?=E5=90=8C=E6=97=B6=E5=9C=A8models=E4=B8=AD=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E4=BA=86=E5=87=A0=E4=B8=AA=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
contest/models.py | 16 +++++++++++++---
contest/serializers.py | 6 ++++++
contest/views.py | 40 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/contest/models.py b/contest/models.py
index 56762ecb..eb0f5e68 100644
--- a/contest/models.py
+++ b/contest/models.py
@@ -3,18 +3,25 @@ from django.db import models
from account.models import User
from problem.models import AbstractProblem
+from group.models import Group
class Contest(models.Model):
title = models.CharField(max_length=40)
description = models.TextField()
- # 比赛模式 现在有 acm 模式,按照 ac 题目数量得分模式,
- # 按照 ac 的题目的总分得分模式和按照通过的测试用例总分得分模式等
+ # 比赛模式:0 即为是acm模式,1 即为是按照总的 ac 题目数量排名模式,2 即为按照 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()
# 结束时间
@@ -23,7 +30,10 @@ class Contest(models.Model):
create_time = models.DateTimeField(auto_now_add=True)
# 最后修改时间
last_updated_time = models.DateTimeField(auto_now=True)
+ # 这个比赛是谁创建的
created_by = models.ForeignKey(User)
+ groups = models.ManyToManyField(Group)
+
class Meta:
db_table = "contest"
diff --git a/contest/serializers.py b/contest/serializers.py
index 424ba0ef..51a4066a 100644
--- a/contest/serializers.py
+++ b/contest/serializers.py
@@ -10,10 +10,13 @@ class CreateContestSerializer(serializers.Serializer):
title = serializers.CharField(max_length=40)
description = serializers.CharField(max_length=5000)
mode = serializers.IntegerField()
+ contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
+ show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
+ groups = serializers.ListField(child=serializers.IntegerField())
class ContestSerializer(serializers.ModelSerializer):
@@ -32,10 +35,13 @@ class EditContestSerializer(serializers.Serializer):
title = serializers.CharField(max_length=40)
description = serializers.CharField(max_length=10000)
mode = serializers.IntegerField()
+ contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
+ show_user_submission = serializers.BooleanField()
password = serializers.CharField(max_length=30, required=False)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
+ groups = serializers.ListField(child=serializers.IntegerField())
class ContestProblemSampleSerializer(serializers.ListField):
diff --git a/contest/views.py b/contest/views.py
index 3746b2bf..243d4799 100644
--- a/contest/views.py
+++ b/contest/views.py
@@ -4,12 +4,16 @@ from django.shortcuts import render
from django.db import IntegrityError
from django.db.models import Q
from rest_framework.views import APIView
+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 group.models import Group
from .models import Contest, ContestProblem
from .serializers import (CreateContestSerializer, ContestSerializer, EditContestSerializer,
CreateContestProblemSerializer, ContestProblemSerializer, EditContestProblemSerializer)
-from utils.shortcuts import (serializer_invalid_response, error_response,
- success_response, paginate, rand_str, error_page)
+
def contest_page(request, contest_id):
@@ -27,15 +31,47 @@ class ContestAdminAPIView(APIView):
serializer = CreateContestSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
+ groups = []
+ # 首先判断比赛的类型: 0 即为是小组赛,1 即为是无密码的公开赛,2 即为是有密码的公开赛
+ # 密码字段不为空的情况,此时为有密码的公开赛,
+ # 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
+ if data["contest_type"] == 2:
+ if data["password"]:
+ if request.user.admin_type == SUPER_ADMIN:
+ pass
+ else:
+ return error_response(u"只有超级管理员才可创建公开赛(有密码)")
+ else:
+ return error_response(u"此比赛为有密码的公开赛,密码不可为空")
+ # 此时为没有密码的公开赛,并且此时只能是超级管理员才有权限创建此比赛
+ elif data["contest_type"]:
+ if not data["password"]:
+ if request.user.admin_type == SUPER_ADMIN:
+ pass
+ else:
+ return error_response(u"只有超级管理员才可创建公开赛(没有密码)")
+ else:
+ return error_response(u"此比赛为没有密码的公开赛,密码无需填写")
+ # 此时为没有密码的小组赛,并且此时只能是超级管理员和管理员才有权限创建此比赛
+ else:
+ if request.user.admin_type == REGULAR_USER:
+ return error_response(u"只有超级管理员和管理员才有权限创建比赛")
+ else:
+ if not data["password"]:
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
+ else:
+ return error_response(u"此比赛为没有密码的小组赛,密码无需填写")
try:
contest = Contest.objects.create(title=data["title"], description=data["description"],
mode=data["mode"], show_rank=data["show_rank"],
+ show_user_submission=data["show_user_submission"],
start_time=["start_time"], end_time=data["end_time"])
if data["password"]:
contest.setpassword(data["password"])
contest.save()
except IntegrityError:
return error_response(u"比赛名已经存在")
+ contest.groups.add(*groups)
return success_response(ContestSerializer(contest).data)
else:
serializer_invalid_response(serializer)
From 10e4d534b292030ba1d4d2439dc7f45ef438a11a Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Wed, 19 Aug 2015 17:53:43 +0800
Subject: [PATCH 4/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=AF=94=E8=B5=9B?=
=?UTF-8?q?=E7=9A=84views=E5=8F=8A=E9=83=A8=E5=88=86=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
announcement/serializers.py | 2 +-
announcement/views.py | 4 +-
contest/models.py | 3 +-
contest/views.py | 93 ++++++++++++++++++++-----------------
4 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/announcement/serializers.py b/announcement/serializers.py
index d896564a..7fffe045 100644
--- a/announcement/serializers.py
+++ b/announcement/serializers.py
@@ -9,7 +9,7 @@ class CreateAnnouncementSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50)
content = serializers.CharField(max_length=10000)
is_global = serializers.BooleanField()
- groups = serializers.ListField(child=serializers.IntegerField(), allow_empty=True)
+ groups = serializers.ListField(child=serializers.IntegerField())
class AnnouncementSerializer(serializers.ModelSerializer):
diff --git a/announcement/views.py b/announcement/views.py
index 8059b908..73f49c8e 100644
--- a/announcement/views.py
+++ b/announcement/views.py
@@ -68,7 +68,7 @@ class AnnouncementAdminAPIView(APIView):
if request.user.admin_type == SUPER_ADMIN:
announcement = Announcement.objects.get(id=data["id"])
else:
- announcement = Announcement.objects.get(id=data["id"], admin=request.user)
+ announcement = Announcement.objects.get(id=data["id"], created_by=request.user)
except Announcement.DoesNotExist:
return error_response(u"公告不存在")
groups = []
@@ -101,7 +101,7 @@ class AnnouncementAdminAPIView(APIView):
if request.user.admin_type == SUPER_ADMIN:
announcement = Announcement.objects.all().order_by("-last_update_time")
else:
- announcement = Announcement.objects.filter(admin=request.user)
+ announcement = Announcement.objects.filter(created_by=request.user)
visible = request.GET.get("visible", None)
if visible:
announcement = announcement.filter(visible=(visible == "true"))
diff --git a/contest/models.py b/contest/models.py
index eb0f5e68..838d6d90 100644
--- a/contest/models.py
+++ b/contest/models.py
@@ -7,7 +7,7 @@ from group.models import Group
class Contest(models.Model):
- title = models.CharField(max_length=40)
+ title = models.CharField(max_length=40, unique=True)
description = models.TextField()
# 比赛模式:0 即为是acm模式,1 即为是按照总的 ac 题目数量排名模式,2 即为按照 ac 的题目的总分排名模式
mode = models.IntegerField()
@@ -34,7 +34,6 @@ class Contest(models.Model):
created_by = models.ForeignKey(User)
groups = models.ManyToManyField(Group)
-
class Meta:
db_table = "contest"
diff --git a/contest/views.py b/contest/views.py
index 243d4799..31ed0f44 100644
--- a/contest/views.py
+++ b/contest/views.py
@@ -33,48 +33,34 @@ class ContestAdminAPIView(APIView):
data = serializer.data
groups = []
# 首先判断比赛的类型: 0 即为是小组赛,1 即为是无密码的公开赛,2 即为是有密码的公开赛
- # 密码字段不为空的情况,此时为有密码的公开赛,
# 此时为有密码的公开赛,并且此时只能超级管理员才有权限此创建比赛
+ if data["contest_type"] in [1, 2]:
+ if request.user.admin_type != SUPER_ADMIN:
+ return error_response(u"只有超级管理员才可创建公开赛")
if data["contest_type"] == 2:
- if data["password"]:
- if request.user.admin_type == SUPER_ADMIN:
- pass
- else:
- return error_response(u"只有超级管理员才可创建公开赛(有密码)")
- else:
- return error_response(u"此比赛为有密码的公开赛,密码不可为空")
- # 此时为没有密码的公开赛,并且此时只能是超级管理员才有权限创建此比赛
- elif data["contest_type"]:
if not data["password"]:
- if request.user.admin_type == SUPER_ADMIN:
- pass
- else:
- return error_response(u"只有超级管理员才可创建公开赛(没有密码)")
+ return error_response(u"此比赛为有密码的公开赛,密码不可为空")
+
+ # 没有密码的公开赛 没有密码的小组赛
+ elif data["contest_type"] == 0:
+ if request.user.admin_type == SUPER_ADMIN:
+ groups = Group.objects.filter(id__in=data["groups"])
else:
- return error_response(u"此比赛为没有密码的公开赛,密码无需填写")
- # 此时为没有密码的小组赛,并且此时只能是超级管理员和管理员才有权限创建此比赛
- else:
- if request.user.admin_type == REGULAR_USER:
- return error_response(u"只有超级管理员和管理员才有权限创建比赛")
- else:
- if not data["password"]:
- groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
- else:
- return error_response(u"此比赛为没有密码的小组赛,密码无需填写")
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
+ if not groups.count():
+ return error_response(u"请至少选择一个小组")
try:
contest = Contest.objects.create(title=data["title"], description=data["description"],
mode=data["mode"], show_rank=data["show_rank"],
show_user_submission=data["show_user_submission"],
- start_time=["start_time"], end_time=data["end_time"])
- if data["password"]:
- contest.setpassword(data["password"])
- contest.save()
+ start_time=["start_time"], end_time=data["end_time"],
+ password=data["password"])
except IntegrityError:
return error_response(u"比赛名已经存在")
contest.groups.add(*groups)
return success_response(ContestSerializer(contest).data)
else:
- serializer_invalid_response(serializer)
+ return serializer_invalid_response(serializer)
def put(self, request):
"""
@@ -86,24 +72,45 @@ class ContestAdminAPIView(APIView):
serializer = EditContestSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
+ groups = []
try:
contest = Contest.objects.get(id=data["id"])
except Contest.DoesNotExist:
- error_response(u"该比赛不存在!")
+ return error_response(u"该比赛不存在!")
try:
- contest.title = data["contest"]
- contest.description = data["description"]
- contest.mode = data["mode"]
- contest.show_rank = data["show_"]
- if data["password"]:
- contest.set_password(data["password"])
- contest.save()
- except IntegrityError:
- return error_response(u"比赛名已经存在")
+ contest = Contest.objects.get(title=data["title"])
+ if contest.id != data["id"]:
+ return error_response(u"该比赛名称已经存在")
+ except Contest.DoesNotExist:
+ pass
+ if data["contest_type"] in [1, 2]:
+ if request.user.admin_type != SUPER_ADMIN:
+ return error_response(u"只有超级管理员才可创建公开赛")
+ if data["contest_type"] == 2:
+ if not data["password"]:
+ return error_response(u"此比赛为有密码的公开赛,密码不可为空")
+ elif data["contest_type"] == 0:
+ if request.user.admin_type == SUPER_ADMIN:
+ groups = Group.objects.filter(id__in=data["groups"])
+ else:
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
+ if not groups.count():
+ return error_response(u"请至少选择一个小组")
+ contest.title = data["title"]
+ contest.description = data["description"]
+ contest.mode = data["mode"]
+ contest.show_rank = data["show_rank"]
+ contest.show_user_submission = data["show_user_submission"]
+ contest.start_time = ["start_time"]
+ contest.end_time = data["end_time"]
+ contest.password = data["password"]
+ contest.save()
+ contest.groups.clear()
+ contest.groups.add(*groups)
return success_response(ContestSerializer(contest).data)
else:
- serializer_invalid_response(serializer)
+ return serializer_invalid_response(serializer)
def get(self, request):
"""
@@ -148,7 +155,7 @@ class ContestProblemAdminAPIView(APIView):
sort_index=data["sort_index"])
return success_response(ContestProblemSerializer(contest_problem).data)
else:
- serializer_invalid_response(serializer)
+ return serializer_invalid_response(serializer)
def put(self, request):
"""
@@ -190,9 +197,9 @@ class ContestProblemAdminAPIView(APIView):
contest_problem_id = request.GET.get("contest_problem_id", None)
if contest_problem_id:
try:
- contest_problem = ContestProblemSerializer.objects.get(id=contest_problem_id)
+ contest_problem = ContestProblem.objects.get(id=contest_problem_id)
return success_response(ContestProblemSerializer(contest_problem).data)
- except contest_problem.DoesNotExist:
+ except ContestProblem.DoesNotExist:
return error_response(u"比赛题目不存在")
contest_problem = ContestProblem.objects.all().order_by("sort_index")
visible = request.GET.get("visible", None)
From 0fcbbc962e6c697388b246e81fb82029a9b85e14 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Thu, 20 Aug 2015 20:24:51 +0800
Subject: [PATCH 5/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=8A=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9account=E4=B8=8Eannouncement=E7=9A=84=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
account/tests.py | 68 +++++++++++++------
announcement/serializers.py | 4 +-
announcement/tests.py | 129 +++++++++++++++++++++++++-----------
announcement/views.py | 1 -
oj/settings.py | 5 ++
5 files changed, 145 insertions(+), 62 deletions(-)
diff --git a/account/tests.py b/account/tests.py
index 10070fa6..a84911c0 100644
--- a/account/tests.py
+++ b/account/tests.py
@@ -130,7 +130,7 @@ class UserChangePasswordAPITest(APITestCase):
self.assertEqual(response.data, {"code": 1, "data": u"密码不正确,请重新修改!"})
def test_invalid_data_format(self):
- data = {"username": "test", "old_password": "aaa", "new_password": "aaaddd"}
+ data = {"old_password": "aaa", "new_password": "aaaddd"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
@@ -152,15 +152,50 @@ class UserAdminAPITest(APITestCase):
user = User.objects.create(username="testx", real_name="xx", admin_type=SUPER_ADMIN)
user.set_password("testxx")
user.save()
+ user = User.objects.create(username="testy", real_name="yy", admin_type=SUPER_ADMIN)
+ user.set_password("testyy")
+ user.save()
self.client.login(username="testx", password="testxx")
+ # 以下是编辑用户的测试
def test_success_get_data(self):
self.assertEqual(self.client.get(self.url).data["code"], 0)
+ def test_put_invalid_data(self):
+ data = {"username": "test", "password": "testaa", "email": "60@qq.com", "admin_type": "2"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 1)
+
+ def test_user_does_not_exist(self):
+ data = {"id": 3, "username": "test0", "real_name": "test00",
+ "password": "testaa", "email": "60@qq.com", "admin_type": "2"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"该用户不存在!"})
+
+ def test_username_exists(self):
+ data = {"id": 1, "username": "testy", "real_name": "test00",
+ "password": "testaa", "email": "60@qq.com", "admin_type": "2"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"昵称已经存在"})
+
+ def test_user_edit_not_password_successfully(self):
+ data = {"id": 1, "username": "test0", "real_name": "test00",
+ "email": "60@qq.com", "admin_type": "2"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+ def test_user_edit_change_password_successfully(self):
+ data = {"id": 1, "username": "test0", "real_name": "test00", "password": "111111",
+ "email": "60@qq.com", "admin_type": "2"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+ self.assertIsNotNone(auth.authenticate(username="test0", password="111111"))
+
def test_error_admin_type(self):
response = self.client.get(self.url + "?admin_type=error")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
+ # 以下是用户分页的测试
def test_query_by_keyword(self):
user1 = User.objects.create(username="test1", real_name="aa")
user1.set_password("testaa")
@@ -177,29 +212,18 @@ class UserAdminAPITest(APITestCase):
response = self.client.get(self.url + "?keyword=test1")
self.assertEqual(response.data["code"], 0)
- def test_put_invalid_data(self):
- data = {"username": "test", "password": "testaa", "email": "60@qq.com", "admin_type": "2"}
- response = self.client.put(self.url, data=data)
- self.assertEqual(response.data["code"], 1)
- def test_user_does_not_exist(self):
- data = {"id": 2, "username": "test0", "real_name": "test00",
- "password": "testaa","email": "60@qq.com", "admin_type": "2"}
- response = self.client.put(self.url, data=data)
- self.assertEqual(response.data, {"code": 1, "data": u"该用户不存在!"})
+class UserInfoAPITest(APITestCase):
+ def setUp(self):
+ self.client = APIClient()
+ self.url = reverse('user_info_api')
+ user = User.objects.create(username="test1", real_name="aa")
+ user.set_password("testaa")
+ user.save()
- def test_success_user_edit_not_password(self):
- data = {"id": 1, "username": "test0", "real_name": "test00",
- "email": "60@qq.com", "admin_type": "2"}
- response = self.client.put(self.url, data=data)
- self.assertEqual(response.data["code"], 0)
-
- def test_success_user_edit_change_password(self):
- data = {"id": 1, "username": "test0", "real_name": "test00", "password": "111111",
- "email": "60@qq.com", "admin_type": "2"}
- response = self.client.put(self.url, data=data)
- self.assertEqual(response.data["code"], 0)
- self.assertIsNotNone(auth.authenticate(username="test0", password="111111"))
+ def test_get_data_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ self.assertEqual(self.client.get(self.url).data["code"], 0)
@login_required
diff --git a/announcement/serializers.py b/announcement/serializers.py
index 7fffe045..ec24116f 100644
--- a/announcement/serializers.py
+++ b/announcement/serializers.py
@@ -9,7 +9,7 @@ class CreateAnnouncementSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50)
content = serializers.CharField(max_length=10000)
is_global = serializers.BooleanField()
- groups = serializers.ListField(child=serializers.IntegerField())
+ groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
class AnnouncementSerializer(serializers.ModelSerializer):
@@ -31,4 +31,4 @@ class EditAnnouncementSerializer(serializers.Serializer):
content = serializers.CharField(max_length=10000)
visible = serializers.BooleanField()
is_global = serializers.BooleanField()
- groups = serializers.ListField(child=serializers.IntegerField())
+ groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
diff --git a/announcement/tests.py b/announcement/tests.py
index 7ce24673..6ac3fb2a 100644
--- a/announcement/tests.py
+++ b/announcement/tests.py
@@ -5,6 +5,7 @@ from django.test import TestCase
from rest_framework.test import APITestCase, APIClient
from account.models import User
+from group.models import Group
from announcement.models import Announcement
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
@@ -13,76 +14,127 @@ class AnnouncementAdminAPITest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse("announcement_admin_api")
- user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
- user.set_password("testaa")
- user.save()
+ user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
+ user1.set_password("testaa")
+ user1.save()
+ user2 = User.objects.create(username="test2", admin_type=ADMIN)
+ user2.set_password("testbb")
+ user2.save()
+ self.group = Group.objects.create(name="group1", description="des0",
+ join_group_setting=0, visible=True,
+ admin=user2)
+ self.announcement = Announcement.objects.create(title="bb",
+ content="BB",
+ created_by=User.objects.get(username="test2"),
+ is_global=False)
# 以下是发布公告的测试
def test_invalid_format(self):
- self.client.login(username="test", password="testaa")
+ self.client.login(username="test1", password="testaa")
data = {"title": "test1"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
- def test_success_announcement(self):
- self.client.login(username="test", password="testaa")
- data = {"title": "title0", "content": "content0"}
+ def test_group_at_least_one(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title0", "content": "content0", "is_global": False}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"至少选择一个小组"})
+
+ def test_global_announcement_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title0", "content": "content0", "is_global": True}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data, {"code": 0, "data": u"公告发布成功!"})
- def test_post_invalid_data(self):
- self.client.login(username="test", password="testaa")
- data = {"title": "test"}
+ def test_group_announcement_successfully(self):
+ self.client.login(username="test2", password="testbb")
+ data = {"title": "title0", "content": "content0", "is_global": False, "groups": [self.group.id]}
response = self.client.post(self.url, data=data)
- self.assertEqual(response.data["code"], 1)
+ self.assertEqual(response.data, {"code": 0, "data": u"公告发布成功!"})
+
+ def test_global_announcement_does_not_has_privileges(self):
+ self.client.login(username="test2", password="testbb")
+ data = {"title": "title0", "content": "content0", "is_global": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"只有超级管理员可以创建全局公告"})
# 以下是编辑公告的测试
def test_put_invalid_data(self):
- self.client.login(username="test", password="testaa")
+ self.client.login(username="test1", password="testaa")
data = {"title": "test0", "content": "test0", "visible": "True"}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_announcement_does_not_exist(self):
- self.client.login(username="test", password="testaa")
+ self.client.login(username="test1", password="testaa")
announcement = Announcement.objects.create(title="aa",
content="AA",
- created_by=User.objects.get(username="test"))
- data = {"id": announcement.id + 1, "title": "11", "content": "22", "visible": True}
+ created_by=User.objects.get(username="test1"),
+ is_global=True)
+ data = {"id": announcement.id + 1, "title": "11", "content": "22",
+ "visible": True, "is_global": True}
response = self.client.put(self.url, data=data)
- self.assertEqual(response.data, {"code": 1, "data": u"该公告不存在!"})
+ self.assertEqual(response.data, {"code": 1, "data": u"公告不存在"})
- def test_success_edit_announcement(self):
- self.client.login(username="test", password="testaa")
- announcement = Announcement.objects.create(title="bb",
- content="BB",
- created_by=User.objects.get(username="test"))
- data = {"id": announcement.id, "title": "11", "content": "22", "visible": True}
+ def test_edit_global_announcement_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.announcement.id, "title": "11", "content": "22",
+ "visible": True, "is_global": True}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 0)
+ def test_edit_group_announcement_successfully(self):
+ self.client.login(username="test2", password="testbb")
+ data = {"id": self.announcement.id, "title": "11", "content": "22",
+ "visible": True, "is_global": False, "groups": [self.group.id]}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
-class AnnouncementAPITest(APITestCase):
- def setUp(self):
- self.client = APIClient()
- self.url = reverse("announcement_list_api")
- user = User.objects.create(username="test")
- user.set_password("testaa")
- user.save()
+ def test_edit_group_at_least_one(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.announcement.id, "title": "title0", "content": "content0",
+ "visible": True, "is_global": False}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"至少选择一个小组"})
- def test_success_get_data(self):
+ # 以下是公告分页的测试
+ def test_get_data_successfully(self):
+ self.client.login(username="test1", password="testaa")
self.assertEqual(self.client.get(self.url).data["code"], 0)
- def test_keyword_announcement(self):
+ def test_keyword_global_announcement(self):
+ self.client.login(username="test1", password="testaa")
Announcement.objects.create(title="aa",
content="AA",
- created_by=User.objects.get(username="test"),
- visible=True)
+ created_by=User.objects.get(username="test1"),
+ visible=True,
+ is_global=True)
Announcement.objects.create(title="bb",
content="BB",
- created_by=User.objects.get(username="test"),
- visible=False)
+ created_by=User.objects.get(username="test1"),
+ visible=False,
+ is_global=True)
+
+ response = self.client.get(self.url + "?visible=true")
+ self.assertEqual(response.data["code"], 0)
+ for item in response.data["data"]:
+ self.assertEqual(item["visible"], True)
+
+ def test_keyword_group_announcement(self):
+ self.client.login(username="test2", password="testbb")
+ Announcement.objects.create(title="aa",
+ content="AA",
+ created_by=User.objects.get(username="test2"),
+ visible=True,
+ is_global=False)
+
+ Announcement.objects.create(title="cc",
+ content="CC",
+ created_by=User.objects.get(username="test2"),
+ visible=False,
+ is_global=False)
response = self.client.get(self.url + "?visible=true")
self.assertEqual(response.data["code"], 0)
@@ -98,12 +150,14 @@ class AnnouncementPageTest(TestCase):
Announcement.objects.create(title="aa",
content="AA",
created_by=User.objects.get(username="test"),
- visible=True)
+ visible=True,
+ is_global=True)
Announcement.objects.create(title="bb",
content="BB",
created_by=User.objects.get(username="test"),
- visible=False)
+ visible=False,
+ is_global=True)
def test_visit_announcement_successfully(self):
response = self.client.get('/announcement/1/')
@@ -112,3 +166,4 @@ class AnnouncementPageTest(TestCase):
def test_announcement_does_not_exist(self):
response = self.client.get('/announcement/3/')
self.assertTemplateUsed(response, "utils/error.html")
+
diff --git a/announcement/views.py b/announcement/views.py
index 73f49c8e..818aa0a9 100644
--- a/announcement/views.py
+++ b/announcement/views.py
@@ -49,7 +49,6 @@ class AnnouncementAdminAPIView(APIView):
is_global=data["is_global"])
announcement.groups.add(*groups)
-
return success_response(u"公告发布成功!")
else:
return serializer_invalid_response(serializer)
diff --git a/oj/settings.py b/oj/settings.py
index 8d012d03..f956f5bc 100644
--- a/oj/settings.py
+++ b/oj/settings.py
@@ -156,3 +156,8 @@ LOGGING = {
}
},
}
+
+
+REST_FRAMEWORK = {
+ 'TEST_REQUEST_DEFAULT_FORMAT': 'json'
+}
\ No newline at end of file
From 33fec6531acc4a6fe59e9145a6dc30074d630db3 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Fri, 21 Aug 2015 15:52:18 +0800
Subject: [PATCH 6/8] =?UTF-8?q?CodeMirror=E8=87=AA=E5=8A=A8=E6=9B=B4?=
=?UTF-8?q?=E6=94=B9=E9=AB=98=E5=BA=A6=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
static/src/css/oj.css | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/static/src/css/oj.css b/static/src/css/oj.css
index cc6ac62d..b0985580 100644
--- a/static/src/css/oj.css
+++ b/static/src/css/oj.css
@@ -67,4 +67,19 @@ li.list-group-item {
.panel>.list-group{
padding: 0 0;
+}
+
+.CodeMirror{
+ min-height: 250px;
+ _height:250px;
+ height: auto;
+}
+
+.CodeMirror-scroll {
+ overflow: auto;
+ min-height: 250px;
+ _height:250px;
+ height: auto;
+ position: relative;
+ outline: none;
}
\ No newline at end of file
From 53d2b674c93b0a074747dd48721ac707b495b4b6 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Fri, 21 Aug 2015 18:16:34 +0800
Subject: [PATCH 7/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B9=B6=E5=AE=8C?=
=?UTF-8?q?=E5=96=84=E6=AF=94=E8=B5=9B=E5=8F=8A=E5=85=B6=E4=BB=96=E9=83=A8?=
=?UTF-8?q?=E5=88=86=E7=9A=84=E5=86=85=E5=AE=B9=E5=8F=8A=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
announcement/tests.py | 2 +
contest/migrations/0001_initial.py | 74 +++++++
contest/migrations/0002_contest_visible.py | 19 ++
contest/models.py | 2 +
contest/serializers.py | 11 +-
contest/tests.py | 218 ++++++++++++++++++++-
contest/views.py | 20 +-
group/views.py | 3 +-
oj/settings.py | 1 +
oj/urls.py | 4 +
problem/tests.py | 26 ++-
problem/views.py | 1 -
12 files changed, 365 insertions(+), 16 deletions(-)
create mode 100644 contest/migrations/0001_initial.py
create mode 100644 contest/migrations/0002_contest_visible.py
diff --git a/announcement/tests.py b/announcement/tests.py
index 6ac3fb2a..e37c1834 100644
--- a/announcement/tests.py
+++ b/announcement/tests.py
@@ -90,6 +90,8 @@ class AnnouncementAdminAPITest(APITestCase):
"visible": True, "is_global": False, "groups": [self.group.id]}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 0)
+ self.assertEqual(response.data["data"]["title"], "11")
+ self.assertEqual(response.data["data"]["content"], "22")
def test_edit_group_at_least_one(self):
self.client.login(username="test1", password="testaa")
diff --git a/contest/migrations/0001_initial.py b/contest/migrations/0001_initial.py
new file mode 100644
index 00000000..01df2877
--- /dev/null
+++ b/contest/migrations/0001_initial.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('group', '0004_merge'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Contest',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('title', models.CharField(unique=True, max_length=40)),
+ ('description', models.TextField()),
+ ('mode', models.IntegerField()),
+ ('show_rank', models.BooleanField()),
+ ('show_user_submission', models.BooleanField()),
+ ('password', models.CharField(max_length=30, null=True, blank=True)),
+ ('contest_type', models.IntegerField()),
+ ('start_time', models.DateTimeField()),
+ ('end_time', models.DateTimeField()),
+ ('create_time', models.DateTimeField(auto_now_add=True)),
+ ('last_updated_time', models.DateTimeField(auto_now=True)),
+ ('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+ ('groups', models.ManyToManyField(to='group.Group')),
+ ],
+ options={
+ 'db_table': 'contest',
+ },
+ ),
+ migrations.CreateModel(
+ name='ContestProblem',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('title', models.CharField(max_length=50)),
+ ('description', models.TextField()),
+ ('input_description', models.CharField(max_length=10000)),
+ ('output_description', models.CharField(max_length=10000)),
+ ('samples', models.TextField(blank=True)),
+ ('test_case_id', models.CharField(max_length=40)),
+ ('hint', models.TextField(null=True, blank=True)),
+ ('create_time', models.DateTimeField(auto_now_add=True)),
+ ('time_limit', models.IntegerField()),
+ ('memory_limit', models.IntegerField()),
+ ('visible', models.BooleanField(default=True)),
+ ('total_submit_number', models.IntegerField(default=0)),
+ ('total_accepted_number', models.IntegerField(default=0)),
+ ('sort_index', models.CharField(max_length=30)),
+ ('contest', models.ForeignKey(to='contest.Contest')),
+ ('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'db_table': 'contest_problem',
+ },
+ ),
+ migrations.CreateModel(
+ name='ContestProblemTestCase',
+ fields=[
+ ('id', models.CharField(max_length=40, serialize=False, primary_key=True, db_index=True)),
+ ('score', models.IntegerField()),
+ ('problem', models.ForeignKey(to='contest.ContestProblem')),
+ ],
+ options={
+ 'db_table': 'contest_problem_test_case',
+ },
+ ),
+ ]
diff --git a/contest/migrations/0002_contest_visible.py b/contest/migrations/0002_contest_visible.py
new file mode 100644
index 00000000..7ee207d7
--- /dev/null
+++ b/contest/migrations/0002_contest_visible.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contest', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='contest',
+ name='visible',
+ field=models.BooleanField(default=True),
+ ),
+ ]
diff --git a/contest/models.py b/contest/models.py
index 838d6d90..0ece5fff 100644
--- a/contest/models.py
+++ b/contest/models.py
@@ -33,6 +33,8 @@ class Contest(models.Model):
# 这个比赛是谁创建的
created_by = models.ForeignKey(User)
groups = models.ManyToManyField(Group)
+ # 是否可见 false的话相当于删除
+ visible = models.BooleanField(default=True)
class Meta:
db_table = "contest"
diff --git a/contest/serializers.py b/contest/serializers.py
index 51a4066a..3f791912 100644
--- a/contest/serializers.py
+++ b/contest/serializers.py
@@ -13,10 +13,11 @@ class CreateContestSerializer(serializers.Serializer):
contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField()
- password = serializers.CharField(max_length=30, required=False)
+ password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
- groups = serializers.ListField(child=serializers.IntegerField())
+ groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
+ visible = serializers.BooleanField()
class ContestSerializer(serializers.ModelSerializer):
@@ -32,16 +33,18 @@ class ContestSerializer(serializers.ModelSerializer):
class EditContestSerializer(serializers.Serializer):
+ id = serializers.IntegerField()
title = serializers.CharField(max_length=40)
description = serializers.CharField(max_length=10000)
mode = serializers.IntegerField()
contest_type = serializers.IntegerField()
show_rank = serializers.BooleanField()
show_user_submission = serializers.BooleanField()
- password = serializers.CharField(max_length=30, required=False)
+ password = serializers.CharField(max_length=30, required=False, default=None)
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
- groups = serializers.ListField(child=serializers.IntegerField())
+ groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[])
+ visible = serializers.BooleanField()
class ContestProblemSampleSerializer(serializers.ListField):
diff --git a/contest/tests.py b/contest/tests.py
index 7ce503c2..01be7f84 100644
--- a/contest/tests.py
+++ b/contest/tests.py
@@ -1,3 +1,219 @@
+# coding=utf-8
+import json
+from django.core.urlresolvers import reverse
from django.test import TestCase
-# Create your tests here.
+from rest_framework.test import APITestCase, APIClient
+
+from account.models import User
+from group.models import Group
+from contest.models import Contest, ContestProblem
+from announcement.models import Announcement
+from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
+
+
+class ContestAdminAPITest(APITestCase):
+ def setUp(self):
+ self.client = APIClient()
+ self.url = reverse('contest_admin_api')
+ user1 = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
+ user1.set_password("testaa")
+ user1.save()
+ user2 = User.objects.create(username="test2", admin_type=ADMIN)
+ user2.set_password("testbb")
+ user2.save()
+ user3 = User.objects.create(username="test3", admin_type=REGULAR_USER)
+ user3.set_password("testcc")
+ user3.save()
+ self.group = Group.objects.create(name="group1", description="des0",
+ join_group_setting=0, visible=True,
+ admin=user2)
+ 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.group_contest = Contest.objects.create(title="titley", description="descriptiony", 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="test1", password="testaa")
+ data = {"title": "test1"}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data["code"], 1)
+
+ def test_global_contest_does_not_has_privileges(self):
+ self.client.login(username="test2", password="testbb")
+ data = {"title": "title0", "description": "description0", "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": "aabb", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"只有超级管理员才可创建公开赛"})
+
+ def test_global_contest_password_exists(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title0", "description": "description0", "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", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"此比赛为有密码的公开赛,密码不可为空"})
+
+ def test_group_contest_group_at_least_one(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title0", "description": "description0", "mode": 1, "contest_type": 0,
+ "show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
+ "end_time": "2015-08-15T12:00:00.000Z", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"请至少选择一个小组"})
+
+ def test_global_contest_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title1", "description": "description1", "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": "aabb", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+ def test_group_contest_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title3", "description": "description3", "mode": 1, "contest_type": 0,
+ "show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T10:00:00.000Z",
+ "end_time": "2015-08-15T12:00:00.000Z", "groups": [self.group.id], "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+ def test_time_error(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "title2", "description": "description2", "mode": 1, "contest_type": 2,
+ "show_rank": True, "show_user_submission": True, "start_time": "2015-08-15T12:00:00.000Z",
+ "end_time": "2015-08-15T10:00:00.000Z", "password": "aabb", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"比赛的开始时间不能晚于或等于比赛结束的时间"})
+
+ def test_contest_has_exists(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"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": "aabb", "visible": True}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"比赛名已经存在"})
+
+ # 以下是编辑比赛的测试
+ def test_put_invalid_data(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"title": "test0", "description": "description0"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 1)
+
+ def test_contest_does_not_exist(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.global_contest.id + 10, "title": "title2", "description": "description2", "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": "aabb",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"该比赛不存在!"})
+
+ def test_edit_global_contest_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.global_contest.id, "title": "titlez", "description": "descriptionz", "mode": 1,
+ "contest_type": 2, "show_rank": True, "show_user_submission": True,
+ "start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T13:00:00.000Z", "password": "aabb",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+ self.assertEqual(response.data["data"]["title"], "titlez")
+ self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
+
+ def test_edit_group_contest_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.group_contest.id, "title": "titleyyy", "description": "descriptionyyyy", "mode": 1,
+ "contest_type": 0, "show_rank": True, "show_user_submission": True,
+ "start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T13:00:00.000Z",
+ "groups": [self.group.id], "visible": False}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+ self.assertEqual(response.data["data"]["title"], "titleyyy")
+ self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
+ self.assertEqual(response.data["data"]["visible"], False)
+
+ def test_edit_group_at_least_one(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.group_contest.id, "title": "titleyyy", "description": "descriptionyyyy", "mode": 1,
+ "contest_type": 0, "show_rank": True, "show_user_submission": True,
+ "start_time": "2015-08-15T10:00:00.000Z", "end_time": "2015-08-15T13:00:00.000Z", "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"请至少选择一个小组"})
+
+ def test_edit_contest_has_exists(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.global_contest.id, "title": "titley", "description": "descriptiony", "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": "aabb",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"该比赛名称已经存在"})
+
+ def test_edit_global_contest_does_not_has_privileges(self):
+ self.client.login(username="test2", password="testbb")
+ data = {"id": self.global_contest.id, "title": "titlexxxxxxxxx", "description": "descriptionxxxxxx", "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": "aabb",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"只有超级管理员才可创建公开赛"})
+
+ def test_edit_global_contest_password_exists(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.global_contest.id, "title": "title0", "description": "description0", "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", "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"此比赛为有密码的公开赛,密码不可为空"})
+
+ def test_edit_time_error(self):
+ self.client.login(username="test1", password="testaa")
+ data = {"id": self.global_contest.id, "title": "titleaaaa", "description": "descriptionaaaaa", "mode": 1,
+ "contest_type": 2, "show_rank": True, "show_user_submission": True,
+ "start_time": "2015-08-15T12:00:00.000Z", "end_time": "2015-08-15T10:00:00.000Z", "password": "aabb",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"比赛的开始时间不能晚于或等于比赛结束的时间"})
+
+ # 以下是比赛分页的测试
+ def test_get_data_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ self.assertEqual(self.client.get(self.url).data["code"], 0)
+
+ def test_keyword_contest(self):
+ self.client.login(username="test1", password="testaa")
+ response = self.client.get(self.url + "?visible=true")
+ self.assertEqual(response.data["code"], 0)
+ for item in response.data["data"]:
+ self.assertEqual(item["visible"], True)
+
+
+class ContestProblemAdminAPItEST(APITestCase):
+ def setUp(self):
+ self.client = APIClient()
+ self.url = reverse('contest_problem_admin_api')
+ self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
+ self.user.set_password("testaa")
+ self.user.save()
+ self.client.login(username="test", password="testaa")
+ self. contest_problem = ContestProblem.objects.create(title="title1",
+ description="description1",
+ 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,
+ difficulty=1,
+ hint="hint1",
+ created_by=User.objects.get(username="test"),
+ sort_index="a")
diff --git a/contest/views.py b/contest/views.py
index 31ed0f44..338a4893 100644
--- a/contest/views.py
+++ b/contest/views.py
@@ -2,6 +2,7 @@
import json
from django.shortcuts import render
from django.db import IntegrityError
+from django.utils import dateparse
from django.db.models import Q
from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response,
@@ -15,7 +16,6 @@ from .serializers import (CreateContestSerializer, ContestSerializer, EditContes
CreateContestProblemSerializer, ContestProblemSerializer, EditContestProblemSerializer)
-
def contest_page(request, contest_id):
pass
@@ -49,12 +49,16 @@ class ContestAdminAPIView(APIView):
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"请至少选择一个小组")
+ if data["start_time"] >= data["end_time"]:
+ return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
try:
contest = Contest.objects.create(title=data["title"], description=data["description"],
- mode=data["mode"], show_rank=data["show_rank"],
+ mode=data["mode"], contest_type=data["contest_type"],
+ show_rank=data["show_rank"], password=data["password"],
show_user_submission=data["show_user_submission"],
- start_time=["start_time"], end_time=data["end_time"],
- password=data["password"])
+ start_time=dateparse.parse_datetime(data["start_time"]),
+ end_time=dateparse.parse_datetime(data["end_time"]),
+ created_by=request.user, visible=data["visible"])
except IntegrityError:
return error_response(u"比赛名已经存在")
contest.groups.add(*groups)
@@ -96,13 +100,17 @@ class ContestAdminAPIView(APIView):
groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"请至少选择一个小组")
+ if data["start_time"] >= data["end_time"]:
+ return error_response(u"比赛的开始时间不能晚于或等于比赛结束的时间")
contest.title = data["title"]
contest.description = data["description"]
contest.mode = data["mode"]
+ contest.contest_type = data["contest_type"]
contest.show_rank = data["show_rank"]
contest.show_user_submission = data["show_user_submission"]
- contest.start_time = ["start_time"]
- contest.end_time = data["end_time"]
+ contest.start_time = dateparse.parse_datetime(data["start_time"])
+ contest.end_time = dateparse.parse_datetime(data["end_time"])
+ contest.visible = data["visible"]
contest.password = data["password"]
contest.save()
diff --git a/group/views.py b/group/views.py
index a9ec8d24..ff1cbde4 100644
--- a/group/views.py
+++ b/group/views.py
@@ -226,7 +226,8 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
if serializer.is_valid():
data = serializer.data
try:
- join_request = JoinGroupRequest.objects.get(id=data["request_id"], group__admin=request.user, status=False)
+ join_request = JoinGroupRequest.objects.get(id=data["request_id"], group__admin=request.user,
+ status=False)
except JoinGroupRequest.DoesNotExist:
return error_response(u"请求不存在")
diff --git a/oj/settings.py b/oj/settings.py
index f956f5bc..472d77ea 100644
--- a/oj/settings.py
+++ b/oj/settings.py
@@ -52,6 +52,7 @@ INSTALLED_APPS = (
'problem',
'admin',
'submission',
+ 'contest',
'rest_framework',
'rest_framework_swagger',
diff --git a/oj/urls.py b/oj/urls.py
index ef9e5032..0d3afa55 100644
--- a/oj/urls.py
+++ b/oj/urls.py
@@ -8,6 +8,8 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
UserAdminAPIView, UserInfoAPIView)
from announcement.views import AnnouncementAdminAPIView
+from contest.views import ContestAdminAPIView, ContestAdminAPIView
+
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@@ -34,6 +36,7 @@ urlpatterns = [
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/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/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
url(r'^problem/(?P
\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^announcement/(?P\d+)/$', "announcement.views.announcement_page",
@@ -48,6 +51,7 @@ urlpatterns = [
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/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
+ url(r'^api/admin/contest_problem/$', ContestAdminAPIView.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/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
url(r'^problem/(?P\d+)/my_submissions/$', "submission.views.problem_my_submissions_list_page",
diff --git a/problem/tests.py b/problem/tests.py
index 925ffe08..ab6d8985 100644
--- a/problem/tests.py
+++ b/problem/tests.py
@@ -1,7 +1,7 @@
# coding=utf-8
import json
-from django.test import TestCase
+from django.test import TestCase, Client
from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase, APIClient
@@ -39,7 +39,6 @@ class ProblemPageTest(TestCase):
self.assertTemplateUsed(response, "utils/error.html")
-
class ProblemAdminTest(APITestCase):
def _create_data(self, problem_id, visible, tags):
data = {"id": problem_id,
@@ -167,5 +166,26 @@ class ProblemTagAdminAPITest(APITestCase):
class ProblemListPageTest(TestCase):
def setUp(self):
- pass
+ self.client = Client()
+ self.url = reverse('problem_list_page', kwargs={"page": 1})
+ self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
+ self.user.set_password("testaa")
+ self.user.save()
+ self.client.login(username="test", password="testaa")
+ ProblemTag.objects.create(name="tag1")
+ ProblemTag.objects.create(name="tag2")
+ 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="test"))
+
+
diff --git a/problem/views.py b/problem/views.py
index 4a6e2c62..6ae22800 100644
--- a/problem/views.py
+++ b/problem/views.py
@@ -56,7 +56,6 @@ class ProblemAdminAPIView(APIView):
difficulty=data["difficulty"],
created_by=request.user,
hint=data["hint"])
-
for tag in data["tags"]:
try:
tag = ProblemTag.objects.get(name=tag)
From 8b4580d8f608542b475bccb3cc025c15be6203b4 Mon Sep 17 00:00:00 2001
From: hohoTT <609029365@qq.com>
Date: Sat, 22 Aug 2015 14:00:09 +0800
Subject: [PATCH 8/8] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E6=AF=94=E8=B5=9B?=
=?UTF-8?q?=E4=B8=8E=E6=AF=94=E8=B5=9B=E9=A2=98=E7=9B=AE=E9=83=A8=E5=88=86?=
=?UTF-8?q?=E5=B7=B2=E4=BF=AE=E6=94=B9=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
announcement/views.py | 4 +-
.../0003_contestproblem_difficulty.py | 20 +++
.../0004_remove_contestproblem_difficulty.py | 18 +++
contest/serializers.py | 11 +-
contest/tests.py | 129 +++++++++++++++++-
contest/views.py | 14 +-
oj/urls.py | 4 +-
7 files changed, 179 insertions(+), 21 deletions(-)
create mode 100644 contest/migrations/0003_contestproblem_difficulty.py
create mode 100644 contest/migrations/0004_remove_contestproblem_difficulty.py
diff --git a/announcement/views.py b/announcement/views.py
index e49b1b4a..818aa0a9 100644
--- a/announcement/views.py
+++ b/announcement/views.py
@@ -36,7 +36,7 @@ class AnnouncementAdminAPIView(APIView):
if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter(id__in=data["groups"])
else:
- groups = Group.objects.filter(id__in=data["groups"], created_by=request.user)
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"至少选择一个小组")
else:
@@ -75,7 +75,7 @@ class AnnouncementAdminAPIView(APIView):
if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter(id__in=data["groups"])
else:
- groups = Group.objects.filter(id__in=data["groups"], created_by=request.user)
+ groups = Group.objects.filter(id__in=data["groups"], admin=request.user)
if not groups.count():
return error_response(u"至少选择一个小组")
announcement.title = data["title"]
diff --git a/contest/migrations/0003_contestproblem_difficulty.py b/contest/migrations/0003_contestproblem_difficulty.py
new file mode 100644
index 00000000..9d33b591
--- /dev/null
+++ b/contest/migrations/0003_contestproblem_difficulty.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contest', '0002_contest_visible'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='contestproblem',
+ name='difficulty',
+ field=models.IntegerField(default=1),
+ preserve_default=False,
+ ),
+ ]
diff --git a/contest/migrations/0004_remove_contestproblem_difficulty.py b/contest/migrations/0004_remove_contestproblem_difficulty.py
new file mode 100644
index 00000000..41ee147b
--- /dev/null
+++ b/contest/migrations/0004_remove_contestproblem_difficulty.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contest', '0003_contestproblem_difficulty'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='contestproblem',
+ name='difficulty',
+ ),
+ ]
diff --git a/contest/serializers.py b/contest/serializers.py
index 3f791912..dd9f3709 100644
--- a/contest/serializers.py
+++ b/contest/serializers.py
@@ -3,6 +3,7 @@ import json
from rest_framework import serializers
from account.models import User
+from account.serializers import UserSerializer
from .models import Contest, ContestProblem
@@ -58,6 +59,7 @@ class JSONField(serializers.Field):
class CreateContestProblemSerializer(serializers.Serializer):
+ contest_id = serializers.IntegerField()
title = serializers.CharField(max_length=50)
description = serializers.CharField(max_length=10000)
input_description = serializers.CharField(max_length=10000)
@@ -67,20 +69,20 @@ class CreateContestProblemSerializer(serializers.Serializer):
test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
- difficulty = serializers.IntegerField()
hint = serializers.CharField(max_length=3000, allow_blank=True)
sort_index = serializers.CharField(max_length=30)
class ContestProblemSerializer(serializers.ModelSerializer):
- samples = JSONField()
class ContestSerializer(serializers.ModelSerializer):
class Meta:
model = Contest
- fields = ["title"]
+ fields = ["title", "id"]
- created_by = ContestSerializer()
+ samples = JSONField()
+ contest = ContestSerializer()
+ created_by = UserSerializer()
class Meta:
model = ContestProblem
@@ -95,7 +97,6 @@ class EditContestProblemSerializer(serializers.Serializer):
test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
- difficulty = serializers.IntegerField()
samples = ContestProblemSampleSerializer()
hint = serializers.CharField(max_length=3000, allow_blank=True)
visible = serializers.BooleanField()
diff --git a/contest/tests.py b/contest/tests.py
index 01be7f84..6cce9e85 100644
--- a/contest/tests.py
+++ b/contest/tests.py
@@ -196,24 +196,141 @@ class ContestAdminAPITest(APITestCase):
for item in response.data["data"]:
self.assertEqual(item["visible"], True)
+ def test_query_by_keyword(self):
+ self.client.login(username="test1", password="testaa")
+ response = self.client.get(self.url + "?keyword=title1")
+ self.assertEqual(response.data["code"], 0)
+
class ContestProblemAdminAPItEST(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse('contest_problem_admin_api')
- self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
+ self.user = User.objects.create(username="test1", admin_type=SUPER_ADMIN)
self.user.set_password("testaa")
self.user.save()
- self.client.login(username="test", password="testaa")
- self. contest_problem = ContestProblem.objects.create(title="title1",
- description="description1",
+ 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,
- difficulty=1,
hint="hint1",
- created_by=User.objects.get(username="test"),
+ created_by=User.objects.get(username="test1"),
+ contest=Contest.objects.get(title="titlex"),
sort_index="a")
+
+ # 以下是发布比赛题目的测试
+ def test_invalid_format(self):
+ data = {"title": "test1"}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data["code"], 1)
+
+ def test_release_contest_problem_successfully(self):
+ data = {"title": "title2",
+ "description": "description2",
+ "input_description": "input_description2",
+ "output_description": "output_description2",
+ "test_case_id": "1",
+ "source": "source1",
+ "samples": [{"input": "1 1", "output": "2"}],
+ "time_limit": "100",
+ "memory_limit": "1000",
+ "hint": "hint1",
+ "sort_index": "b",
+ "contest_id": self.global_contest.id}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+ def test_contest_does_not_exists(self):
+ data = {"title": "titlezzzzzzzz",
+ "description": "descriptionzzzzzzzzzzz",
+ "input_description": "input_description2",
+ "output_description": "output_description2",
+ "test_case_id": "1",
+ "source": "source1",
+ "samples": [{"input": "1 1", "output": "2"}],
+ "time_limit": "100",
+ "memory_limit": "1000",
+ "hint": "hint1",
+ "sort_index": "b",
+ "contest_id": self.global_contest.id + 10}
+ response = self.client.post(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"比赛不存在"})
+
+ # 以下是编辑比赛题目的测试
+ def test_invalid_data(self):
+ data = {"title": "test1"}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 1)
+
+ def test_edit_problem_does_not_exist(self):
+ data = {"id": self.contest_problem.id + 1,
+ "title": "title2",
+ "description": "description2",
+ "input_description": "input_description2",
+ "output_description": "output_description2",
+ "test_case_id": "1",
+ "source": "source1",
+ "samples": [{"input": "1 1", "output": "2"}],
+ "time_limit": "100",
+ "memory_limit": "1000",
+ "hint": "hint1",
+ "sort_index": "b",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"该比赛题目不存在!"})
+
+ def test_edit_problem_successfully(self):
+ data = {"id": self.contest_problem.id,
+ "title": "title2222222",
+ "description": "description22222222",
+ "input_description": "input_description2",
+ "output_description": "output_description2",
+ "test_case_id": "1",
+ "source": "source1",
+ "samples": [{"input": "1 1", "output": "2"}],
+ "time_limit": "100",
+ "memory_limit": "1000",
+ "hint": "hint1",
+ "sort_index": "b",
+ "visible": True}
+ response = self.client.put(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+ # 以下是比赛题目分页的测试
+ def test_get_data_successfully(self):
+ self.client.login(username="test1", password="testaa")
+ self.assertEqual(self.client.get(self.url).data["code"], 0)
+
+ def test_keyword_contest(self):
+ self.client.login(username="test1", password="testaa")
+ response = self.client.get(self.url + "?visible=true")
+ self.assertEqual(response.data["code"], 0)
+ for item in response.data["data"]:
+ self.assertEqual(item["visible"], True)
+
+ def test_query_by_keyword(self):
+ self.client.login(username="test1", password="testaa")
+ response = self.client.get(self.url + "?keyword=title1")
+ self.assertEqual(response.data["code"], 0)
+
+ def test_query_contest_problem_does_not_exist(self):
+ data = {"contest_problem_id": 1000000}
+ response = self.client.get(self.url, data=data)
+ self.assertEqual(response.data, {"code": 1, "data": u"比赛题目不存在"})
+
+ def test_query_contest_problem_exists(self):
+ data = {"contest_problem_id": self.contest_problem.id}
+ response = self.client.get(self.url, data=data)
+ self.assertEqual(response.data["code"], 0)
+
+
diff --git a/contest/views.py b/contest/views.py
index 338a4893..d00bee5a 100644
--- a/contest/views.py
+++ b/contest/views.py
@@ -148,6 +148,10 @@ class ContestProblemAdminAPIView(APIView):
serializer = CreateContestProblemSerializer(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"比赛不存在")
contest_problem = ContestProblem.objects.create(title=data["title"],
description=data["description"],
input_description=data["input_description"],
@@ -156,10 +160,9 @@ class ContestProblemAdminAPIView(APIView):
samples=json.dumps(data["samples"]),
time_limit=data["time_limit"],
memory_limit=data["memory_limit"],
- difficulty=data["difficulty"],
created_by=request.user,
hint=data["hint"],
- contest=request.contest,
+ contest=contest,
sort_index=data["sort_index"])
return success_response(ContestProblemSerializer(contest_problem).data)
else:
@@ -169,10 +172,10 @@ class ContestProblemAdminAPIView(APIView):
"""
比赛题目编辑json api接口
---
- request_serializer: EditContestSerializer
+ request_serializer: EditContestProblemSerializer
response_serializer: ContestProblemSerializer
"""
- serializer = EditContestSerializer(data=request.data)
+ serializer = EditContestProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
@@ -186,13 +189,12 @@ class ContestProblemAdminAPIView(APIView):
contest_problem.test_case_id = data["test_case_id"]
contest_problem.time_limit = data["time_limit"]
contest_problem.memory_limit = data["memory_limit"]
- contest_problem.difficulty = data["difficulty"]
contest_problem.samples = json.dumps(data["samples"])
contest_problem.hint = data["hint"]
contest_problem.visible = data["visible"]
contest_problem.sort_index = data["sort_index"]
contest_problem.save()
- return success_response(ContestProblem(contest_problem).data)
+ return success_response(ContestProblemSerializer(contest_problem).data)
else:
return serializer_invalid_response(serializer)
diff --git a/oj/urls.py b/oj/urls.py
index 3cfcd90f..6dc76064 100644
--- a/oj/urls.py
+++ b/oj/urls.py
@@ -8,7 +8,7 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
UserAdminAPIView, UserInfoAPIView)
from announcement.views import AnnouncementAdminAPIView
-from contest.views import ContestAdminAPIView, ContestAdminAPIView
+from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@@ -52,7 +52,7 @@ urlpatterns = [
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/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
- url(r'^api/admin/contest_problem/$', ContestAdminAPIView.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/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
url(r'^problem/(?P\d+)/my_submissions/$', "submission.views.problem_my_submissions_list_page",