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 d896564a..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(), allow_empty=True) + 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..e37c1834 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,129 @@ 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) + self.assertEqual(response.data["data"]["title"], "11") + self.assertEqual(response.data["data"]["content"], "22") -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 +152,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 +168,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 767b2065..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: @@ -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) @@ -76,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/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/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/models.py b/contest/models.py index 56762ecb..0ece5fff 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) + title = models.CharField(max_length=40, unique=True) 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,11 @@ 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) + # 是否可见 false的话相当于删除 + visible = models.BooleanField(default=True) class Meta: db_table = "contest" diff --git a/contest/serializers.py b/contest/serializers.py new file mode 100644 index 00000000..dd9f3709 --- /dev/null +++ b/contest/serializers.py @@ -0,0 +1,105 @@ +# coding=utf-8 +import json +from rest_framework import serializers + +from account.models import User +from account.serializers import UserSerializer +from .models import Contest, ContestProblem + + +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, default=None) + start_time = serializers.DateTimeField() + end_time = serializers.DateTimeField() + groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[]) + visible = serializers.BooleanField() + + +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): + 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, default=None) + start_time = serializers.DateTimeField() + end_time = serializers.DateTimeField() + groups = serializers.ListField(child=serializers.IntegerField(), required=False, default=[]) + visible = serializers.BooleanField() + + +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): + contest_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) + # [{"input": "1 1", "output": "2"}] + samples = ContestProblemSampleSerializer() + test_case_id = serializers.CharField(max_length=40) + time_limit = serializers.IntegerField() + memory_limit = serializers.IntegerField() + hint = serializers.CharField(max_length=3000, allow_blank=True) + sort_index = serializers.CharField(max_length=30) + + +class ContestProblemSerializer(serializers.ModelSerializer): + + class ContestSerializer(serializers.ModelSerializer): + class Meta: + model = Contest + fields = ["title", "id"] + + samples = JSONField() + contest = ContestSerializer() + created_by = UserSerializer() + + 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() + 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/tests.py b/contest/tests.py index 7ce503c2..6cce9e85 100644 --- a/contest/tests.py +++ b/contest/tests.py @@ -1,3 +1,336 @@ +# 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) + + 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="test1", admin_type=SUPER_ADMIN) + self.user.set_password("testaa") + self.user.save() + self.client.login(username="test1", password="testaa") + self.global_contest = Contest.objects.create(title="titlex", description="descriptionx", mode=1, + contest_type=2, show_rank=True, show_user_submission=True, + start_time="2015-08-15T10:00:00.000Z", + end_time="2015-08-15T12:00:00.000Z", + password="aacc", created_by=User.objects.get(username="test1")) + self. contest_problem = ContestProblem.objects.create(title="titlex", + description="descriptionx", + input_description="input1_description", + output_description="output1_description", + test_case_id="1", + samples=json.dumps([{"input": "1 1", "output": "2"}]), + time_limit=100, + memory_limit=1000, + hint="hint1", + created_by=User.objects.get(username="test1"), + contest=Contest.objects.get(title="titlex"), + sort_index="a") + + # 以下是发布比赛题目的测试 + def test_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 91ea44a2..d00bee5a 100644 --- a/contest/views.py +++ b/contest/views.py @@ -1,3 +1,223 @@ +# coding=utf-8 +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, + success_response, paginate, rand_str, error_page) -# Create your views here. +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) + + +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 + 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 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"请至少选择一个小组") + 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"], contest_type=data["contest_type"], + show_rank=data["show_rank"], password=data["password"], + show_user_submission=data["show_user_submission"], + 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) + return success_response(ContestSerializer(contest).data) + else: + return 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 + groups = [] + try: + contest = Contest.objects.get(id=data["id"]) + except Contest.DoesNotExist: + return error_response(u"该比赛不存在!") + try: + 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"请至少选择一个小组") + 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 = 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() + + contest.groups.clear() + contest.groups.add(*groups) + return success_response(ContestSerializer(contest).data) + else: + return 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 + 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"], + 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"], + created_by=request.user, + hint=data["hint"], + contest=contest, + sort_index=data["sort_index"]) + return success_response(ContestProblemSerializer(contest_problem).data) + else: + return serializer_invalid_response(serializer) + + def put(self, request): + """ + 比赛题目编辑json api接口 + --- + request_serializer: EditContestProblemSerializer + response_serializer: ContestProblemSerializer + """ + serializer = EditContestProblemSerializer(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.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(ContestProblemSerializer(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 = ContestProblem.objects.get(id=contest_problem_id) + return success_response(ContestProblemSerializer(contest_problem).data) + except ContestProblem.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/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 d1c10fd0..ce699b48 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -53,7 +53,7 @@ INSTALLED_APPS = ( 'admin', 'submission', 'mq', - + 'contest', 'django_extensions', 'rest_framework', @@ -165,3 +165,8 @@ LOGGING = { } }, } + + +REST_FRAMEWORK = { + 'TEST_REQUEST_DEFAULT_FORMAT': 'json' +} \ No newline at end of file diff --git a/oj/urls.py b/oj/urls.py index 60186149..6dc76064 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, ContestProblemAdminAPIView + from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, JoinGroupAPIView, JoinGroupRequestAdminAPIView) @@ -35,6 +37,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", @@ -49,6 +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/$', 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", 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..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, @@ -164,3 +163,29 @@ 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): + 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 26a3a5b7..2e9d172b 100644 --- a/problem/views.py +++ b/problem/views.py @@ -57,7 +57,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) diff --git a/static/src/css/oj.css b/static/src/css/oj.css index e6bd8355..95a16f89 100644 --- a/static/src/css/oj.css +++ b/static/src/css/oj.css @@ -69,6 +69,22 @@ li.list-group-item { padding: 0 0; } -.ac-flag{ +.ac-flag { color: green; +} + +.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 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" %}