Merge branch 'dev' into sxw-dev

This commit is contained in:
esp
2015-08-10 14:47:56 +08:00
15 changed files with 301 additions and 23 deletions

4
.gitignore vendored
View File

@@ -55,4 +55,6 @@ db.db
db.sqlite3 db.sqlite3
.DS_Store .DS_Store
log/ log/
release/ release/
tmp/
test_case/

View File

@@ -22,7 +22,6 @@ class Migration(migrations.Migration):
('join_group_setting', models.IntegerField()), ('join_group_setting', models.IntegerField()),
('visible', models.BooleanField(default=True)), ('visible', models.BooleanField(default=True)),
('admin', models.ForeignKey(related_name='my_groups', to=settings.AUTH_USER_MODEL)), ('admin', models.ForeignKey(related_name='my_groups', to=settings.AUTH_USER_MODEL)),
('members', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'db_table': 'group', 'db_table': 'group',
@@ -42,4 +41,21 @@ class Migration(migrations.Migration):
'db_table': 'join_group_request', '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'),
),
] ]

View File

@@ -11,7 +11,7 @@ class Group(models.Model):
admin = models.ForeignKey(User, related_name="my_groups") admin = models.ForeignKey(User, related_name="my_groups")
# 0是公开 1是需要申请后加入 2是不允许任何人加入 # 0是公开 1是需要申请后加入 2是不允许任何人加入
join_group_setting = models.IntegerField() join_group_setting = models.IntegerField()
members = models.ManyToManyField(User) members = models.ManyToManyField(User, through="UserGroupRelation")
# 解散小组后这一项改为False # 解散小组后这一项改为False
visible = models.BooleanField(default=True) visible = models.BooleanField(default=True)
@@ -19,6 +19,15 @@ class Group(models.Model):
db_table = "group" 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): class JoinGroupRequest(models.Model):
group = models.ForeignKey(User) group = models.ForeignKey(User)
user = models.ForeignKey(User, related_name="my_join_group_requests") user = models.ForeignKey(User, related_name="my_join_group_requests")

View File

@@ -1,7 +1,8 @@
# coding=utf-8 # coding=utf-8
from rest_framework import serializers from rest_framework import serializers
from .models import Group from account.serializers import UserSerializer
from .models import Group, UserGroupRelation
class CreateGroupSerializer(serializers.Serializer): class CreateGroupSerializer(serializers.Serializer):
@@ -11,17 +12,31 @@ class CreateGroupSerializer(serializers.Serializer):
class EditGroupSerializer(serializers.Serializer): class EditGroupSerializer(serializers.Serializer):
group_id = serializers.IntegerField()
name = serializers.CharField(max_length=20) name = serializers.CharField(max_length=20)
description = serializers.CharField(max_length=300) description = serializers.CharField(max_length=300)
join_group_setting = serializers.IntegerField() join_group_setting = serializers.IntegerField()
class JoinGroupRequestSerializer(serializers.Serializer): class JoinGroupRequestSerializer(serializers.Serializer):
group = serializers.IntegerField() group_id = serializers.IntegerField()
message = serializers.CharField(max_length=30) message = serializers.CharField(max_length=30)
class GroupSerializer(serializers.ModelSerializer): class GroupSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Group model = Group
exclude = ["members"] 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())

View File

@@ -5,18 +5,45 @@ from rest_framework.views import APIView
from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate from utils.shortcuts import error_response, serializer_invalid_response, success_response, paginate
from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN from account.models import REGULAR_USER, ADMIN, SUPER_ADMIN
from account.decorators import login_required
from .models import Group, JoinGroupRequest from .models import Group, JoinGroupRequest, UserGroupRelation
from .serializers import (CreateGroupSerializer, EditGroupSerializer, from .serializers import (CreateGroupSerializer, EditGroupSerializer,
JoinGroupRequestSerializer, GroupSerializer) JoinGroupRequestSerializer, GroupSerializer,
GroupMemberSerializer, EditGroupMemberSerializer)
class GroupAdminAPIView(APIView): class GroupAPIViewBase(object):
def get_group(self, request, group_id):
"""
根据group_id查询指定的小组的信息结合判断用户权限
管理员可以查询所有的小组,其他用户查询自己创建的自傲组
"""
if request.user.admin_type == SUPER_ADMIN:
group = Group.objects.get(id=group_id, visible=True)
else:
group = Group.objects.get(id=group_id, visible=True, admin=request.user)
return group
def get_groups(self, request):
"""
如果是超级管理员,就返回全部的小组
如果是管理员,就返回他创建的全部小组
"""
if request.user.admin_type == SUPER_ADMIN:
groups = Group.objects.filter(visible=True)
else:
groups = Group.objects.filter(admin=request.user, visible=True)
return groups
class GroupAdminAPIView(APIView, GroupAPIViewBase):
def post(self, request): def post(self, request):
""" """
创建小组的api 创建小组的api
--- ---
request_serializer: CreateGroupSerializer request_serializer: CreateGroupSerializer
response_serializer: GroupSerializer
""" """
serializer = CreateGroupSerializer(data=request.data) serializer = CreateGroupSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
@@ -34,12 +61,13 @@ class GroupAdminAPIView(APIView):
修改小组信息的api 修改小组信息的api
--- ---
request_serializer: EditGroupSerializer request_serializer: EditGroupSerializer
response_serializer: GroupSerializer
""" """
serializer = EditGroupSerializer(data=request.data) serializer = EditGroupSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
try: try:
group = Group.objects.get(id=data["id"], admin=request.user) group = self.get_group(request, data["group_id"])
except Group.DoesNotExist: except Group.DoesNotExist:
return error_response(u"小组不存在") return error_response(u"小组不存在")
group.name = data["name"] group.name = data["name"]
@@ -52,21 +80,96 @@ class GroupAdminAPIView(APIView):
def get(self, request): def get(self, request):
""" """
查询小组列表或者单个小组的信息 查询小组列表或者单个小组的信息查询单个小组需要传递group_id参数否则返回全部
---
response_serializer: GroupSerializer
""" """
group_id = request.GET.get("group_id", None) group_id = request.GET.get("group_id", None)
if group_id: if group_id:
try: try:
if request.user.admin_type == SUPER_ADMIN: group = self.get_group(request, group_id)
group = Group.object.get(id=group_id)
else:
group = Group.object.get(id=group_id, admin=request.user)
return success_response(GroupSerializer(group).data) return success_response(GroupSerializer(group).data)
except Group.DoesNotExist: except Group.DoesNotExist:
return error_response(u"小组不存在") return error_response(u"小组不存在")
else: else:
if request.user.admin_type == SUPER_ADMIN: groups = self.get_groups(request)
groups = Group.objects.filter(visible=True) return paginate(request, groups, GroupSerializer)
else:
groups = Group.objects.filter(admin=request.user, visible=True)
return paginate(request, groups, GroupSerializer) 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"参数错误")
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):
"""
删除小组成员的api接口
---
request_serializer: EditGroupMemberSerializer
"""
serializer = EditGroupMemberSerializer(data=request.data)
if serializer.is_valid():
try:
group = self.get_group(request, serializer.data["group_id"])
except Group.DoesNotExist:
return error_response(u"小组不存在")
user_id_list = serializer.data["members"]
UserGroupRelation.objects.filter(group=group, user__id__in=user_id_list).delete()
return success_response(u"删除成功")
else:
return serializer_invalid_response(serializer)
def join_group(user, group):
return UserGroupRelation.objects.create(user=user, group=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
try:
group = Group.objects.get(id=data["group_id"])
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):
"""
搜素小组的api需要传递keyword参数
---
response_serializer: GroupSerializer
"""
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)

0
install/__init__.py Normal file
View File

3
install/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

3
install/models.py Normal file
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

3
install/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

12
install/views.py Normal file
View File

@@ -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")

View File

@@ -9,8 +9,11 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView from announcement.views import AnnouncementAPIView, AnnouncementAdminAPIView
from group.views import GroupAdminAPIView from group.views import GroupAdminAPIView
from admin.views import AdminTemplateView from admin.views import AdminTemplateView
from problem.views import TestCaseUploadAPIView
urlpatterns = [ urlpatterns = [
url(r'^install/$', "install.views.install"),
url("^$", TemplateView.as_view(template_name="oj/index.html"), name="index_page"), url("^$", TemplateView.as_view(template_name="oj/index.html"), name="index_page"),
url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^docs/', include('rest_framework_swagger.urls')),
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"), url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
@@ -27,10 +30,12 @@ urlpatterns = [
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"), url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"), 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'^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"), url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), name="problem_list_page"),
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html', AdminTemplateView.as_view(), name="admin_template"), url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html', AdminTemplateView.as_view(), name="admin_template"),
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), 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"),
] ]

View File

@@ -1,7 +1,98 @@
# coding=utf-8 # coding=utf-8
import zipfile
import re
import os
import hashlib
import json
from django.shortcuts import render from django.shortcuts import render
from rest_framework.views import APIView
from utils.shortcuts import rand_str, error_response, success_response
def problem_page(request, problem_id): def problem_page(request, problem_id):
# todo # todo
return render(request, "oj/problem/problem.html") 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
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, "wb") 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.split(".")
# 有了.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 + "/"
# 得到了合法的测试用例文件列表 然后去解压缩
os.mkdir(test_case_dir)
for name in l:
f = open(test_case_dir + name, "wb")
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]}})
else:
return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩")

View File

@@ -9,8 +9,15 @@ define("csrf",function(){
} }
return ""; return "";
} }
function csrfHeader(xhr){ function csrfHeader(){
xhr.setRequestHeader("X-CSRFToken", get_cookie("csrftoken")); // 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; return csrfHeader;
}); });

View File

@@ -1,4 +1,8 @@
# coding=utf-8 # coding=utf-8
import hashlib
import time
import random
from django.core.paginator import Paginator from django.core.paginator import Paginator
from rest_framework.response import Response from rest_framework.response import Response
@@ -87,3 +91,8 @@ def paginate(request, query_set, object_serializer):
pass pass
return success_response(data) 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]