From a9b9ae7f767ed03f3b3a0bf27eb32f07809b59fd Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 19:06:55 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E5=B0=8F=E7=BB=84=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/migrations/0001_initial.py | 18 +++++++++++++++- group/models.py | 11 +++++++++- group/serializers.py | 2 +- group/views.py | 35 ++++++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/group/migrations/0001_initial.py b/group/migrations/0001_initial.py index f996a63..68da3ae 100644 --- a/group/migrations/0001_initial.py +++ b/group/migrations/0001_initial.py @@ -22,7 +22,6 @@ class Migration(migrations.Migration): ('join_group_setting', models.IntegerField()), ('visible', models.BooleanField(default=True)), ('admin', models.ForeignKey(related_name='my_groups', to=settings.AUTH_USER_MODEL)), - ('members', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), ], options={ 'db_table': 'group', @@ -42,4 +41,21 @@ class Migration(migrations.Migration): 'db_table': 'join_group_request', }, ), + migrations.CreateModel( + name='UserGroupRelation', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('join_time', models.DateTimeField(auto_now_add=True)), + ('group', models.ForeignKey(to='group.Group')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'user_group_relation', + }, + ), + migrations.AddField( + model_name='group', + name='members', + field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, through='group.UserGroupRelation'), + ), ] diff --git a/group/models.py b/group/models.py index aa255f4..0508dc0 100644 --- a/group/models.py +++ b/group/models.py @@ -11,7 +11,7 @@ class Group(models.Model): admin = models.ForeignKey(User, related_name="my_groups") # 0是公开 1是需要申请后加入 2是不允许任何人加入 join_group_setting = models.IntegerField() - members = models.ManyToManyField(User) + members = models.ManyToManyField(User, through="UserGroupRelation") # 解散小组后,这一项改为False visible = models.BooleanField(default=True) @@ -19,6 +19,15 @@ class Group(models.Model): db_table = "group" +class UserGroupRelation(models.Model): + group = models.ForeignKey(Group) + user = models.ForeignKey(User) + join_time = models.DateTimeField(auto_now_add=True) + + class Meta: + db_table = "user_group_relation" + + class JoinGroupRequest(models.Model): group = models.ForeignKey(User) user = models.ForeignKey(User, related_name="my_join_group_requests") diff --git a/group/serializers.py b/group/serializers.py index bd655ed..3bc88d4 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -24,4 +24,4 @@ class JoinGroupRequestSerializer(serializers.Serializer): class GroupSerializer(serializers.ModelSerializer): class Meta: model = Group - exclude = ["members"] \ No newline at end of file + exclude = ["members"] diff --git a/group/views.py b/group/views.py index 5ccdcd9..65499f1 100644 --- a/group/views.py +++ b/group/views.py @@ -5,8 +5,9 @@ from rest_framework.views import APIView from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN +from account.decorators import login_required -from .models import Group, JoinGroupRequest +from .models import Group, JoinGroupRequest, UserGroupRelation from .serializers import (CreateGroupSerializer, EditGroupSerializer, JoinGroupRequestSerializer, GroupSerializer) @@ -53,6 +54,8 @@ class GroupAdminAPIView(APIView): def get(self, request): """ 查询小组列表或者单个小组的信息 + --- + response_serializer: GroupSerializer """ group_id = request.GET.get("group_id", None) if group_id: @@ -69,4 +72,32 @@ class GroupAdminAPIView(APIView): groups = Group.objects.filter(visible=True) else: groups = Group.objects.filter(admin=request.user, visible=True) - return paginate(request, groups, GroupSerializer) \ No newline at end of file + return paginate(request, groups, GroupSerializer) + + +def join_group(user, group): + return UserGroupRelation.objects.create(user=user, group=group) + + +class JoinGroupAPIView(APIView): + @login_required + def post(self, request): + serializer = JoinGroupRequestSerializer(data=request.data) + if serializer.is_valid(): + data = serializer.data + try: + group = Grouo.objects.get(id=data["group"]) + except Group.DesoNotExist: + return error_response(u"小组不存在") + if group.join_group_setting == 0: + join_group(request.user, group) + return success_response(u"你已经成功的加入该小组") + elif group.join_group_setting == 1: + return success_response(u"申请提交成功,请等待审核") + elif group.join_group_setting == 2: + return error_response(u"该小组不允许任何人加入") + else: + return serializer_invalid_response(serializer) + + def get(self, request): + pass \ No newline at end of file From 06528d379ac970affe930d9e5102669306db059e Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 19:13:48 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=B0=8F=E7=BB=84=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/serializers.py | 2 +- group/views.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/group/serializers.py b/group/serializers.py index 3bc88d4..e8f83e3 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -17,7 +17,7 @@ class EditGroupSerializer(serializers.Serializer): class JoinGroupRequestSerializer(serializers.Serializer): - group = serializers.IntegerField() + group_id = serializers.IntegerField() message = serializers.CharField(max_length=30) diff --git a/group/views.py b/group/views.py index 65499f1..461b665 100644 --- a/group/views.py +++ b/group/views.py @@ -86,7 +86,7 @@ class JoinGroupAPIView(APIView): if serializer.is_valid(): data = serializer.data try: - group = Grouo.objects.get(id=data["group"]) + group = Grouo.objects.get(id=data["group_id"]) except Group.DesoNotExist: return error_response(u"小组不存在") if group.join_group_setting == 0: @@ -100,4 +100,8 @@ class JoinGroupAPIView(APIView): return serializer_invalid_response(serializer) def get(self, request): - pass \ No newline at end of file + keyword = request.GET.get("keyword", None) + if not keyword: + return error_response(u"参数错误") + groups = Group.objects.filter(name__contains=keyword, visible=True, join_group_setting__lte=2) + return paginate(request, groups, GroupSerializer) From c772a4bcdca4a015c9b6293e75fcb97da7c8d655 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 19:59:25 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E6=88=90=E5=91=98=E7=AE=A1=E7=90=86=E7=9A=84api=EF=BC=9B?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90=E5=88=A4=E6=96=AD=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=92=8C=E7=B2=BE=E7=AE=80=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/serializers.py | 16 ++++++++++- group/views.py | 67 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/group/serializers.py b/group/serializers.py index e8f83e3..9718fed 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -1,7 +1,8 @@ # coding=utf-8 from rest_framework import serializers -from .models import Group +from account.serializers import UserSerializer +from .models import Group, UserGroupRelation class CreateGroupSerializer(serializers.Serializer): @@ -25,3 +26,16 @@ class GroupSerializer(serializers.ModelSerializer): class Meta: model = Group exclude = ["members"] + + +class GroupMemberSerializer(serializers.ModelSerializer): + user = UserSerializer() + + class Meta: + model = UserGroupRelation + exclude = ["id", "group"] + + +class EditGroupMemberSerializer(serializers.Serializer): + group_id = serializers.IntegerField() + members = serializers.ListField(child=serializers.IntegerField()) \ No newline at end of file diff --git a/group/views.py b/group/views.py index 461b665..7b9677b 100644 --- a/group/views.py +++ b/group/views.py @@ -9,10 +9,34 @@ from account.decorators import login_required from .models import Group, JoinGroupRequest, UserGroupRelation from .serializers import (CreateGroupSerializer, EditGroupSerializer, - JoinGroupRequestSerializer, GroupSerializer) + JoinGroupRequestSerializer, GroupSerializer, + GroupMemberSerializer, EditGroupMemberSerializer) -class GroupAdminAPIView(APIView): +class GroupAPIViewBase(object): + def get_group(request, group_id): + """ + 根据group_id查询指定的小组的信息,结合判断用户权限 + 管理员可以查询所有的小组,其他用户查询自己创建的自傲组 + """ + if request.user.admin_type == SUPER_ADMIN: + group = Group.object.get(id=group_id, visible=True) + else: + group = Group.object.get(id=group_id, visible=True, admin=request.user) + return group + + def get_groups(request): + """ + 如果是超级管理员,就返回全部的小组 + 如果是管理员,就返回他创建的全部小组 + """ + if request.user.admin_type == SUPER_ADMIN: + groups = Group.objects.filter(visible=True) + else: + groups = Group.objects.filter(admin=request.user, visible=True) + + +class GroupAdminAPIView(APIView, GroupAPIViewBase): def post(self, request): """ 创建小组的api @@ -40,7 +64,7 @@ class GroupAdminAPIView(APIView): if serializer.is_valid(): data = serializer.data try: - group = Group.objects.get(id=data["id"], admin=request.user) + group = self.get_group(request, data["group_id"]) except Group.DoesNotExist: return error_response(u"小组不存在") group.name = data["name"] @@ -60,21 +84,41 @@ class GroupAdminAPIView(APIView): group_id = request.GET.get("group_id", None) if group_id: try: - if request.user.admin_type == SUPER_ADMIN: - group = Group.object.get(id=group_id) - else: - group = Group.object.get(id=group_id, admin=request.user) + group = self.get_group(request, group_id) return success_response(GroupSerializer(group).data) except Group.DoesNotExist: return error_response(u"小组不存在") else: - if request.user.admin_type == SUPER_ADMIN: - groups = Group.objects.filter(visible=True) - else: - groups = Group.objects.filter(admin=request.user, visible=True) + groups = self.get_groups(request) return paginate(request, groups, GroupSerializer) +class GroupMemberAdminAPIView(APIView, GroupAPIViewBase): + def get(self, request): + group_id = request.GET.get("group_id", None) + if not group_id: + return error_response(u"参数错误") + try: + group = self.get_group(request, group_id) + except Group.DoesNotExist: + return error_response(u"小组不存在") + + return paginate(request, UserGroupRelation.objects.filter(group=group), GroupMemberSerializer) + + def put(self, request): + serializer = EditGroupMemberSerializer(data=request.data) + if serializer.is_valid(): + try: + group = self.get_group(request, group_id) + except Group.DoesNotExist: + return error_response(u"小组不存在") + user_id_list = serializer.data["members"] + UserGroupRelation.objects.delete(group=group, user__id__in=user_id_list) + return success_response(u"删除成功") + else: + return serializer_invalid_response(serializer) + + def join_group(user, group): return UserGroupRelation.objects.create(user=user, group=group) @@ -103,5 +147,6 @@ class JoinGroupAPIView(APIView): keyword = request.GET.get("keyword", None) if not keyword: return error_response(u"参数错误") + # 搜索包含这个关键词的 没有解散的 而且允许加入的小组 groups = Group.objects.filter(name__contains=keyword, visible=True, join_group_setting__lte=2) return paginate(request, groups, GroupSerializer) From a11e935119a5a40622efb2861b19c7d68a667d03 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 20:05:10 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B0=8F=E7=BB=84?= =?UTF-8?q?=E6=9C=89=E5=85=B3api=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/group/views.py b/group/views.py index 7b9677b..fb19086 100644 --- a/group/views.py +++ b/group/views.py @@ -42,6 +42,7 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase): 创建小组的api --- request_serializer: CreateGroupSerializer + response_serializer: GroupSerializer """ serializer = CreateGroupSerializer(data=request.data) if serializer.is_valid(): @@ -59,6 +60,7 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase): 修改小组信息的api --- request_serializer: EditGroupSerializer + response_serializer: GroupSerializer """ serializer = EditGroupSerializer(data=request.data) if serializer.is_valid(): @@ -77,7 +79,7 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase): def get(self, request): """ - 查询小组列表或者单个小组的信息 + 查询小组列表或者单个小组的信息,查询单个小组需要传递group_id参数,否则返回全部 --- response_serializer: GroupSerializer """ @@ -95,6 +97,11 @@ class GroupAdminAPIView(APIView, GroupAPIViewBase): class GroupMemberAdminAPIView(APIView, GroupAPIViewBase): def get(self, request): + """ + 查询小组成员的api,需要传递group_id参数 + --- + response_serializer: GroupMemberSerializer + """ group_id = request.GET.get("group_id", None) if not group_id: return error_response(u"参数错误") @@ -106,6 +113,11 @@ class GroupMemberAdminAPIView(APIView, GroupAPIViewBase): return paginate(request, UserGroupRelation.objects.filter(group=group), GroupMemberSerializer) def put(self, request): + """ + 删除小组成员的api接口 + --- + request_serializer: EditGroupMemberSerializer + """ serializer = EditGroupMemberSerializer(data=request.data) if serializer.is_valid(): try: @@ -126,6 +138,11 @@ def join_group(user, group): class JoinGroupAPIView(APIView): @login_required def post(self, request): + """ + 加入某个小组的api + --- + request_serializer: JoinGroupRequestSerializer + """ serializer = JoinGroupRequestSerializer(data=request.data) if serializer.is_valid(): data = serializer.data @@ -144,6 +161,11 @@ class JoinGroupAPIView(APIView): return serializer_invalid_response(serializer) def get(self, request): + """ + 搜素小组的api,需要传递keyword参数 + --- + response_serializer: GroupSerializer + """ keyword = request.GET.get("keyword", None) if not keyword: return error_response(u"参数错误") From f938950de2050776e23ab5bb92de875a7a52d62f Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 21:00:16 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=88=97=E8=A1=A8url=E7=BC=BA=E5=B0=91admin=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oj/urls.py b/oj/urls.py index b2eecb9..ef840e0 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -27,7 +27,7 @@ urlpatterns = [ url(r'^problem/(?P\d+)/$', "problem.views.problem_page", name="problem_page"), url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"), - url(r'^api/users/$', UserAPIView.as_view(), name="user_list_api"), + url(r'^api/admin/users/$', UserAPIView.as_view(), name="user_list_api"), url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"), name="add_contest_page"), url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), name="problem_list_page"), From a90fdd3f1d34ddbd33242bc5784fbe3311fa5376 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 22:05:22 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- group/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group/views.py b/group/views.py index fb19086..6119cc4 100644 --- a/group/views.py +++ b/group/views.py @@ -14,7 +14,7 @@ from .serializers import (CreateGroupSerializer, EditGroupSerializer, class GroupAPIViewBase(object): - def get_group(request, group_id): + def get_group(self, request, group_id): """ 根据group_id查询指定的小组的信息,结合判断用户权限 管理员可以查询所有的小组,其他用户查询自己创建的自傲组 @@ -25,7 +25,7 @@ class GroupAPIViewBase(object): group = Group.object.get(id=group_id, visible=True, admin=request.user) return group - def get_groups(request): + def get_groups(self, request): """ 如果是超级管理员,就返回全部的小组 如果是管理员,就返回他创建的全部小组 From b6c31ba7a63a7a35e7ad6ce5fd41d482d0494586 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Sun, 9 Aug 2015 22:06:23 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install/__init__.py | 0 install/admin.py | 3 +++ install/migrations/__init__.py | 0 install/models.py | 3 +++ install/tests.py | 3 +++ install/views.py | 12 ++++++++++++ oj/urls.py | 1 + 7 files changed, 22 insertions(+) create mode 100644 install/__init__.py create mode 100644 install/admin.py create mode 100644 install/migrations/__init__.py create mode 100644 install/models.py create mode 100644 install/tests.py create mode 100644 install/views.py diff --git a/install/__init__.py b/install/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/install/admin.py b/install/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/install/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/install/migrations/__init__.py b/install/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/install/models.py b/install/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/install/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/install/tests.py b/install/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/install/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/install/views.py b/install/views.py new file mode 100644 index 0000000..521d8a6 --- /dev/null +++ b/install/views.py @@ -0,0 +1,12 @@ +# coding=utf-8 +from django.shortcuts import render +from django.http import HttpResponse + +from account.models import User + + +def install(request): + user = User.objects.create(username="root", admin_type=2) + user.set_password("root") + user.save() + return HttpResponse("success") \ No newline at end of file diff --git a/oj/urls.py b/oj/urls.py index ef840e0..45d4b80 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -11,6 +11,7 @@ from group.views import GroupAdminAPIView from admin.views import AdminTemplateView urlpatterns = [ + url(r'^install/$', "install.views.install"), url("^$", TemplateView.as_view(template_name="oj/index.html"), name="index_page"), url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"), From 09b59d6e43cf00dde6077459e7014d096b3f8e15 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 12:24:36 +0800 Subject: [PATCH 08/13] fix typo --- group/serializers.py | 1 + group/views.py | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/group/serializers.py b/group/serializers.py index 9718fed..6c40eae 100644 --- a/group/serializers.py +++ b/group/serializers.py @@ -12,6 +12,7 @@ class CreateGroupSerializer(serializers.Serializer): class EditGroupSerializer(serializers.Serializer): + group_id = serializers.IntegerField() name = serializers.CharField(max_length=20) description = serializers.CharField(max_length=300) join_group_setting = serializers.IntegerField() diff --git a/group/views.py b/group/views.py index 6119cc4..cd8ac54 100644 --- a/group/views.py +++ b/group/views.py @@ -20,9 +20,9 @@ class GroupAPIViewBase(object): 管理员可以查询所有的小组,其他用户查询自己创建的自傲组 """ if request.user.admin_type == SUPER_ADMIN: - group = Group.object.get(id=group_id, visible=True) + group = Group.objects.get(id=group_id, visible=True) else: - group = Group.object.get(id=group_id, visible=True, admin=request.user) + group = Group.objects.get(id=group_id, visible=True, admin=request.user) return group def get_groups(self, request): @@ -34,6 +34,7 @@ class GroupAPIViewBase(object): groups = Group.objects.filter(visible=True) else: groups = Group.objects.filter(admin=request.user, visible=True) + return groups class GroupAdminAPIView(APIView, GroupAPIViewBase): @@ -121,11 +122,11 @@ class GroupMemberAdminAPIView(APIView, GroupAPIViewBase): serializer = EditGroupMemberSerializer(data=request.data) if serializer.is_valid(): try: - group = self.get_group(request, group_id) + group = self.get_group(request, serializer.data["group_id"]) except Group.DoesNotExist: return error_response(u"小组不存在") user_id_list = serializer.data["members"] - UserGroupRelation.objects.delete(group=group, user__id__in=user_id_list) + UserGroupRelation.objects.filter(group=group, user__id__in=user_id_list).delete() return success_response(u"删除成功") else: return serializer_invalid_response(serializer) @@ -147,7 +148,7 @@ class JoinGroupAPIView(APIView): if serializer.is_valid(): data = serializer.data try: - group = Grouo.objects.get(id=data["group_id"]) + group = Group.objects.get(id=data["group_id"]) except Group.DesoNotExist: return error_response(u"小组不存在") if group.join_group_setting == 0: From c809d0de479e5c3f556fd650c727644104113b63 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 12:25:35 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=92=8C=E8=A7=A3=E6=9E=90=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9=E5=8C=85=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 4 +++ problem/views.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ utils/shortcuts.py | 9 +++++++ 3 files changed, 79 insertions(+) diff --git a/oj/urls.py b/oj/urls.py index 45d4b80..bcfb211 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -9,6 +9,8 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView from group.views import GroupAdminAPIView from admin.views import AdminTemplateView +from problem.views import TestCaseUploadAPIView + urlpatterns = [ url(r'^install/$', "install.views.install"), @@ -34,4 +36,6 @@ urlpatterns = [ url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), name="problem_list_page"), url(r'^admin/template/(?P\w+)/(?P\w+).html', AdminTemplateView.as_view(), name="admin_template"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), + + url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"), ] diff --git a/problem/views.py b/problem/views.py index 58fb9e6..bf5927e 100644 --- a/problem/views.py +++ b/problem/views.py @@ -1,7 +1,73 @@ # coding=utf-8 +import zipfile +import re from django.shortcuts import render +from django.views.decorators.csrf import csrf_exempt + +from rest_framework.views import APIView + +from utils.shortcuts import rand_str, error_response, success_response def problem_page(request, problem_id): # todo return render(request, "oj/problem/problem.html") + + +class TestCaseUploadAPIView(APIView): + + def _is_legal_test_case_file_name(self, file_name): + # 正整数开头的 .in 或者.out 结尾的 + regex = r"^[1-9]\d*\.(in|out)$" + return re.compile(regex).match(file_name) is not None + + @csrf_exempt + def post(self, request): + f = request.FILES["file"] + + tmp_zip = "tmp/" + rand_str() + ".zip" + with open(tmp_zip) as test_case_zip: + for chunk in f: + test_case_zip.write(chunk) + + test_case_file = zipfile.ZipFile(tmp_zip, 'r') + name_list = test_case_file.namelist() + + l = [] + + # 如果文件是直接打包的,那么name_list 就是["1.in", "1.out"]这样的 + # 如果文件还有一层文件夹test_case,那么name_list就是["test_case/", "test_case/1.in", "test_case/1.out"] + # 现在暂时只支持第一种,先判断一下是什么格式的 + + # 第一种格式的 + if "1.in" in name_list and "1.out" in name_list: + for file_name in name_list: + if self._is_legal_test_case_file_name(file_name): + name = file_name.spit(".") + # 有了.in 判断对应的.out 在不在 + if name[1] == "in": + if (name[0] + ".out") in name_list: + l.append(file_name) + else: + return error_response(u"测试用例文件不完整,缺少" + name[0] + ".out") + else: + # 有了.out 判断对应的 .in 在不在 + if (name[0] + ".in") in name_list: + l.append(file_name) + else: + return error_response(u"测试用例文件不完整,缺少" + name[0] + ".in") + + problem_test_dir = rand_str() + test_case_dir = "test_case/" + problem_test_dir + "/" + + # 得到了合法的测试用例文件列表 然后去解压缩 + for name in l: + f = open(test_case_dir + name, "w+b") + f.write(test_case_file.read(name)) + f.close() + + return success_response(problem_test_dir) + + else: + return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩") + diff --git a/utils/shortcuts.py b/utils/shortcuts.py index 44610a9..a254346 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -1,4 +1,8 @@ # coding=utf-8 +import hashlib +import time +import random + from django.core.paginator import Paginator from rest_framework.response import Response @@ -87,3 +91,8 @@ def paginate(request, query_set, object_serializer): pass return success_response(data) + + +def rand_str(length=32): + string = hashlib.md5(str(time.time()) + str(random.randrange(1, 9999999900))).hexdigest() + return string[0:length] \ No newline at end of file From d58dd821aa57094ae79ed1f0ac804eb6dfba819d Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 13:45:56 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=98=AF=20jQuery=20=E7=9A=84=20Ajax=20=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E8=BF=98=E6=98=AF=20webuploader=20=E7=9A=84=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E8=AF=B7=E6=B1=82=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=9A=84=20csrf=20token.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/utils/csrf.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/static/src/js/utils/csrf.js b/static/src/js/utils/csrf.js index 767542b..6a004b4 100644 --- a/static/src/js/utils/csrf.js +++ b/static/src/js/utils/csrf.js @@ -9,8 +9,15 @@ define("csrf",function(){ } return ""; } - function csrfHeader(xhr){ - xhr.setRequestHeader("X-CSRFToken", get_cookie("csrftoken")); + function csrfHeader(){ + // jquery的请求 + if(arguments.length == 1) { + arguments[0].setRequestHeader("X-CSRFToken", get_cookie("csrftoken")); + } + // 百度webuploader 的请求 + else if(arguments.length == 3){ + arguments[2]["X-CSRFToken"] = get_cookie("csrftoken"); + } } return csrfHeader; }); From 17de985404b6c3450bff193f511e116edba4c244 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 13:53:03 +0800 Subject: [PATCH 11/13] =?UTF-8?q?fix=20typo=20=EF=BC=9B=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E6=96=87=E4=BB=B6=E5=A4=B9?= =?UTF-8?q?=20=EF=BC=9B=E5=8A=A0=E5=BC=BA=E6=9C=89=E6=95=88=E6=80=A7?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problem/views.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/problem/views.py b/problem/views.py index bf5927e..08d096d 100644 --- a/problem/views.py +++ b/problem/views.py @@ -1,8 +1,9 @@ # coding=utf-8 import zipfile import re +import os + from django.shortcuts import render -from django.views.decorators.csrf import csrf_exempt from rest_framework.views import APIView @@ -15,18 +16,19 @@ def problem_page(request, problem_id): class TestCaseUploadAPIView(APIView): - def _is_legal_test_case_file_name(self, file_name): # 正整数开头的 .in 或者.out 结尾的 regex = r"^[1-9]\d*\.(in|out)$" return re.compile(regex).match(file_name) is not None - @csrf_exempt def post(self, request): + if "file" not in request.FILES: + return error_response(u"文件上传失败") + f = request.FILES["file"] tmp_zip = "tmp/" + rand_str() + ".zip" - with open(tmp_zip) as test_case_zip: + with open(tmp_zip, "wb") as test_case_zip: for chunk in f: test_case_zip.write(chunk) @@ -43,7 +45,7 @@ class TestCaseUploadAPIView(APIView): if "1.in" in name_list and "1.out" in name_list: for file_name in name_list: if self._is_legal_test_case_file_name(file_name): - name = file_name.spit(".") + name = file_name.split(".") # 有了.in 判断对应的.out 在不在 if name[1] == "in": if (name[0] + ".out") in name_list: @@ -61,13 +63,14 @@ class TestCaseUploadAPIView(APIView): test_case_dir = "test_case/" + problem_test_dir + "/" # 得到了合法的测试用例文件列表 然后去解压缩 + os.mkdir(test_case_dir) for name in l: - f = open(test_case_dir + name, "w+b") + f = open(test_case_dir + name, "wb") f.write(test_case_file.read(name)) f.close() - - return success_response(problem_test_dir) - + l.sort() + return success_response({"test_case_id": problem_test_dir, + "file_list": {"input": l[0::2], + "output": l[1::2]}}) else: return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩") - From 63bcb09c0f2f284dc216a3d5454d3d145ae5af4b Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 13:54:19 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E6=8E=92=E9=99=A4=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E4=B8=8A=E4=BC=A0=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 12a8c85..73adda5 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,6 @@ db.db db.sqlite3 .DS_Store log/ -release/ \ No newline at end of file +release/ +tmp/ +test_case/ \ No newline at end of file From 526b2d0f6e1c1f96326d80b25cf667549e6dc0b9 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Mon, 10 Aug 2015 14:30:06 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8E=E5=86=99=E5=85=A5=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problem/views.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/problem/views.py b/problem/views.py index 08d096d..0d9d2b1 100644 --- a/problem/views.py +++ b/problem/views.py @@ -2,6 +2,8 @@ import zipfile import re import os +import hashlib +import json from django.shortcuts import render @@ -69,6 +71,26 @@ class TestCaseUploadAPIView(APIView): f.write(test_case_file.read(name)) f.close() l.sort() + + file_info = {"test_case_number": len(l) / 2, "test_cases": {}} + + # 计算输出文件的md5 + for i in range(len(l) / 2): + md5 = hashlib.md5() + f = open(test_case_dir + str(i + 1) + ".out", "r") + while True: + data = f.read(2 ** 8) + if not data: + break + md5.update(data) + + file_info["test_cases"][str(i + 1)] = {"input_name": str(i + 1) + ".in", + "output_name": str(i + 1) + ".out", + "output_md5": md5.hexdigest(), + "output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")} + # 写入配置文件 + open(test_case_dir + "info", "w").write(json.dumps(file_info)) + return success_response({"test_case_id": problem_test_dir, "file_list": {"input": l[0::2], "output": l[1::2]}})