Merge branch 'dev' into sxw-dev

This commit is contained in:
esp
2015-08-10 17:03:00 +08:00
11 changed files with 372 additions and 10 deletions

View File

@@ -149,15 +149,21 @@ class UserAPITest(APITestCase):
def setUp(self): def setUp(self):
self.client = APIClient() self.client = APIClient()
self.url = reverse("user_list_api") self.url = reverse("user_list_api")
user = User.objects.create(username="testx", real_name="xx", admin_type=SUPER_ADMIN)
user.set_password("testxx")
user.save()
def test_success_get_data(self): def test_success_get_data(self):
self.client.login(username="testx", password="testxx")
self.assertEqual(self.client.get(self.url).data["code"], 0) self.assertEqual(self.client.get(self.url).data["code"], 0)
def test_error_admin_type(self): def test_error_admin_type(self):
self.client.login(username="testx", password="testxx")
response = self.client.get(self.url + "?admin_type=error") response = self.client.get(self.url + "?admin_type=error")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
def test_query_by_keyword(self): def test_query_by_keyword(self):
self.client.login(username="testx", password="testxx")
user1 = User.objects.create(username="test1", real_name="aa") user1 = User.objects.create(username="test1", real_name="aa")
user1.set_password("testaa") user1.set_password("testaa")
user1.save() user1.save()

10
admin/test_urls.py Normal file
View File

@@ -0,0 +1,10 @@
# coding=utf-8
from django.conf.urls import include, url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
url(r'^api/admin/test/$', "admin.tests.middleware_test_func"),
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
]

View File

@@ -1,15 +1,23 @@
# coding=utf-8 # coding=utf-8
from rest_framework.views import APIView from rest_framework.views import APIView
from django.shortcuts import render
from utils.shortcuts import serializer_invalid_response, error_response, success_response from utils.shortcuts import serializer_invalid_response, error_response, success_response
from account.models import User
from utils.shortcuts import paginate from utils.shortcuts import paginate
from .models import Announcement from .models import Announcement
from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer, from .serializers import (CreateAnnouncementSerializer, AnnouncementSerializer,
EditAnnouncementSerializer) EditAnnouncementSerializer)
def announcement_page(request, announcement_id):
try:
announcement = Announcement.objects.get(id=announcement_id, visible=True)
except Announcement.DoesNotExist:
return render(request, "utils/error.html", {"error": u"模板不存在"})
return render(request, "oj/announcement/announcement.html", {"announcement": announcement})
class AnnouncementAdminAPIView(APIView): class AnnouncementAdminAPIView(APIView):
def post(self, request): def post(self, request):
""" """

View File

@@ -49,6 +49,7 @@ INSTALLED_APPS = (
'announcement', 'announcement',
'utils', 'utils',
'group', 'group',
'problem',
'admin', 'admin',
'rest_framework', 'rest_framework',

View File

@@ -9,6 +9,8 @@ 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 ProblemAdminAPIView
from problem.views import TestCaseUploadAPIView from problem.views import TestCaseUploadAPIView
@@ -28,6 +30,7 @@ urlpatterns = [
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"), url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
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'^announcement/(?P<announcement_id>\d+)/$', "announcement.views.announcement_page", name="announcement_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/admin/users/$', UserAPIView.as_view(), name="user_list_api"), url(r'^api/admin/users/$', UserAPIView.as_view(), name="user_list_api"),
@@ -36,6 +39,6 @@ urlpatterns = [
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/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"), url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
] ]

View File

@@ -0,0 +1,55 @@
# -*- 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),
]
operations = [
migrations.CreateModel(
name='Problem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=50)),
('description', models.TextField()),
('sample', 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)),
('last_update_time', models.DateTimeField(auto_now=True)),
('source', models.CharField(max_length=30, null=True, blank=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)),
('difficulty', models.IntegerField()),
('created_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='ProblemTag',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30)),
('description', models.CharField(max_length=50)),
],
options={
'db_table': 'problem_tag',
},
),
migrations.AddField(
model_name='problem',
name='tags',
field=models.ManyToManyField(to='problem.ProblemTag', null=True),
),
]

View File

@@ -18,21 +18,19 @@ class AbstractProblem(models.Model):
# 问题描述 HTML 格式 # 问题描述 HTML 格式
description = models.TextField() description = models.TextField()
# 样例输入 可能会存储 json 格式的数据 # 样例输入 可能会存储 json 格式的数据
sample_input = models.TextField(blank=True) sample = models.TextField(blank=True)
# 样例输出 同上
sample_output = models.TextField(blank=True)
# 测试用例id 这个id 可以用来拼接得到测试用例的文件存储位置 # 测试用例id 这个id 可以用来拼接得到测试用例的文件存储位置
test_case_id = models.CharField(max_length=40) test_case_id = models.CharField(max_length=40)
# 提示 # 提示
hint = models.TextField(blank=True) hint = models.TextField(blank=True, null=True)
# 创建时间 # 创建时间
create_time = models.DateTimeField(auth_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
# 最后更新时间 # 最后更新时间
last_update_time = models.DateTimeField(auto_now=True) last_update_time = models.DateTimeField(auto_now=True)
# 这个题是谁创建的 # 这个题是谁创建的
created_by = models.ForeignKey(User) created_by = models.ForeignKey(User)
# 来源 # 来源
source = models.CharField(max_length=30, blank=True) source = models.CharField(max_length=30, blank=True, null=True)
# 时间限制 单位是毫秒 # 时间限制 单位是毫秒
time_limit = models.IntegerField() time_limit = models.IntegerField()
# 内存限制 单位是MB # 内存限制 单位是MB

62
problem/serizalizers.py Normal file
View File

@@ -0,0 +1,62 @@
# coding=utf-8
import json
from rest_framework import serializers
from account.models import User
from .models import Problem
class ProblemSampleSerializer(serializers.ListField):
input = serializers.CharField(max_length=3000)
output = serializers.CharField(max_length=3000)
class JSONField(serializers.Field):
def to_representation(self, value):
print value, type(value)
return json.loads(value)
class CreateProblemSerializer(serializers.Serializer):
title = serializers.CharField(max_length=50)
description = serializers.CharField(max_length=10000)
# [{"input": "1 1", "output": "2"}]
sample = ProblemSampleSerializer()
test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30, required=False, default=None)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.IntegerField())
hint = serializers.CharField(max_length=3000, required=False, default=None)
class ProblemSerializer(serializers.ModelSerializer):
sample = JSONField()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username"]
created_by = UserSerializer()
class Meta:
model = Problem
class EditProblemSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=50)
description = serializers.CharField(max_length=10000)
test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30)
time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField()
difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.IntegerField())
sample = ProblemSampleSerializer()
hint = serializers.CharField(max_length=10000)
visible = serializers.BooleanField()

View File

@@ -1,6 +1,115 @@
# coding=utf-8 # coding=utf-8
from django.test import TestCase from django.test import TestCase
from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase, APIClient
from account.models import User, SUPER_ADMIN
from problem.models import Problem, ProblemTag
class ProblemPageTest(TestCase): class ProblemPageTest(TestCase):
pass pass
class ProblemAdminTest(APITestCase):
def setUp(self):
self.client = APIClient()
self.url = reverse("problem_admin_api")
user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
user.set_password("testaa")
user.save()
# 以下是发布题目的测试
def test_invalid_format(self):
self.client.login(username="test", password="testaa")
data = {"title": "test1"}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_success_problem(self):
self.client.login(username="test", password="testaa")
ProblemTag.objects.create(name="tag1", description="destag1")
data = {"title": "title1",
"description": "des1",
"test_case_id": "1",
"source": "source1",
"sample": [{"input": "1 1", "output": "2"}],
"time_limit": "100",
"memory_limit": "1000",
"difficulty": "1",
"hint": "hint1",
"tags": [1]}
response = self.client.post(self.url, data=data)
self.assertEqual(response.data["code"], 0)
# 以下是编辑题目的测试
def test_put_invalid_data(self):
self.client.login(username="test", password="testaa")
data = {"title": "test0"}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 1)
def test_problem_does_not_exist(self):
self.client.login(username="test", password="testaa")
ProblemTag.objects.create(name="tag1", description="destag1")
tags = ProblemTag.objects.filter(id__in=[1])
problem = Problem.objects.create(title="title1",
description="des1",
test_case_id="1",
source="source1",
sample=[{"input": "1 1", "output": "2"}],
time_limit=100,
memory_limit=1000,
difficulty=1,
hint="hint1",
created_by=User.objects.get(username="test"))
problem.tags.add(*tags)
data = {"id": 2,
"title": "title1",
"description": "des1",
"test_case_id": "1",
"source": "source1",
"sample": [{"input": "1 1", "output": "2"}],
"time_limit": "100",
"memory_limit": "1000",
"difficulty": "1",
"hint": "hint1",
"tags": [1]}
response = self.client.put(self.url, data=data)
self.assertEqual(response.data, {"code": 1, "data": u"该题目不存在!"})
def test_success_edit_problem(self):
self.client.login(username="test", password="testaa")
self.client.login(username="test", password="testaa")
ProblemTag.objects.create(name="tag1", description="destag1")
ProblemTag.objects.create(name="tag2", description="destag2")
tags = ProblemTag.objects.filter(id__in=[1])
problem0 = Problem.objects.create(title="title1",
description="des1",
test_case_id="1",
source="source1",
sample=[{"input": "1 1", "output": "2"}],
time_limit=100,
memory_limit=1000,
difficulty=1,
hint="hint1",
created_by=User.objects.get(username="test"))
problem0.tags.add(*tags)
data = {"id": 1,
"title": "title1",
"description": "des1",
"test_case_id": "1",
"source": "source1",
"sample": [{"input": "1 1", "output": "2"}],
"time_limit": "100",
"memory_limit": "1000",
"difficulty": "1",
"hint": "hint1",
"visible": True,
"tags": [1, 2]}
problem = Problem.objects.get(id=data["id"])
problem.tags.remove(*problem.tags.all())
problem.tags.add(*ProblemTag.objects.filter(id__in=data["tags"]))
response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 0)

View File

@@ -6,10 +6,15 @@ import hashlib
import json import json
from django.shortcuts import render from django.shortcuts import render
from django.db.models import Q
from rest_framework.views import APIView from rest_framework.views import APIView
from utils.shortcuts import rand_str, error_response, success_response from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate, rand_str
from .serizalizers import CreateProblemSerializer, EditProblemSerializer, ProblemSerializer
from .models import Problem, ProblemTag
def problem_page(request, problem_id): def problem_page(request, problem_id):
@@ -17,6 +22,88 @@ def problem_page(request, problem_id):
return render(request, "oj/problem/problem.html") return render(request, "oj/problem/problem.html")
class ProblemAdminAPIView(APIView):
def post(self, request):
"""
题目发布json api接口
---
request_serializer: CreateProblemSerializer
response_serializer: ProblemSerializer
"""
serializer = CreateProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
problem = Problem.objects.create(title=data["title"],
description=data["description"],
test_case_id=data["test_case_id"],
source=data["source"],
sample=json.dumps(data["sample"]),
time_limit=data["time_limit"],
memory_limit=data["memory_limit"],
difficulty=data["difficulty"],
created_by=request.user,
hint=data["hint"])
tags = ProblemTag.objects.filter(id__in=data["tags"])
problem.tags.add(*tags)
return success_response(ProblemSerializer(problem).data)
else:
return serializer_invalid_response(serializer)
def put(self, request):
"""
题目编辑json api接口
---
request_serializer: EditProblemSerializer
response_serializer: ProblemSerializer
"""
serializer = EditProblemSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
problem = Problem.objects.get(id=data["id"])
except Problem.DoesNotExist:
return error_response(u"该题目不存在!")
problem.title = data["title"]
problem.description = data["description"]
problem.test_case_id = data["test_case_id"]
problem.source = data["source"]
problem.time_limit = data["time_limit"]
problem.memory_limit = data["memory_limit"]
problem.difficulty = data["difficulty"]
problem.sample = json.dumps(data["sample"])
problem.hint = data["hint"]
problem.visible = data["visible"]
# 删除原有的标签的对应关系
problem.tags.remove(*problem.tags.all())
# 重新添加所有的标签
problem.tags.add(*ProblemTag.objects.filter(id__in=data["tags"]))
problem.save()
return success_response(ProblemSerializer(problem).data)
else:
return serializer_invalid_response(serializer)
class ProblemAPIView(APIView):
def get(self, request):
"""
题目分页json api接口
---
response_serializer: ProblemSerializer
"""
problem = Problem.objects.all().order_by("-last_update_time")
visible = request.GET.get("visible", None)
if visible:
problem = problem.filter(visible=(visible == "true"))
keyword = request.GET.get("keyword", None)
if keyword:
problem = problem.filter(Q(difficulty__contains=keyword))
return paginate(request, problem, ProblemSerializer)
class TestCaseUploadAPIView(APIView): class TestCaseUploadAPIView(APIView):
def _is_legal_test_case_file_name(self, file_name): def _is_legal_test_case_file_name(self, file_name):
# 正整数开头的 .in 或者.out 结尾的 # 正整数开头的 .in 或者.out 结尾的

View File

@@ -0,0 +1,23 @@
{% extends "oj_base.html" %}
{% block body %}
<div class="container main">
<h1 class="text-center">{{ announcement.title }}</h1>
<p class="text-muted text-center">
作者:{{ announcement.created_by }}
&nbsp;&nbsp;&nbsp;
创建时间:{{ announcement.create_time }}
{% ifequal announcement.create_time announcement.last_update_time %}
{% else %}
&nbsp;&nbsp;&nbsp;
最后更新:{{ announcement.last_update_time }}
{% endifequal %}
</p>
<div>
<p>{{ announcement.content|safe }}</p>
</div>
</div>
{% endblock %}