Merge branch 'dev' into sxw-dev

This commit is contained in:
sxw 2015-08-05 19:51:02 +08:00
commit b91ff0688a
13 changed files with 326 additions and 14 deletions

View File

@ -1,3 +1,14 @@
from django.shortcuts import render
# coding=utf-8
from django.conf import settings
from django.http import HttpResponse, Http404
# Create your views here.
from rest_framework.views import APIView
class AdminTemplateView(APIView):
def get(self, request, template_dir, template_name):
path = settings.TEMPLATE_DIRS[0] + "/admin/" + template_dir + "/" + template_name + ".html"
try:
return HttpResponse(open(path).read(), content_type="text/html")
except IOError:
raise Http404

View File

@ -47,6 +47,7 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'account',
'utils',
'rest_framework',
'rest_framework_swagger',

View File

@ -5,11 +5,12 @@ from django.views.generic import TemplateView
from account.views import UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView, UserChangePasswordAPIView
from announcement.views import AnnouncementAPIView
from admin.views import AdminTemplateView
urlpatterns = [
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/index.html"), name="admin_index_page"),
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"),
url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"),
url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), name="user_change_password_page"),
@ -22,4 +23,5 @@ urlpatterns = [
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'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html', AdminTemplateView.as_view(), name="admin_template")
]

View File

@ -0,0 +1,31 @@
define("admin", ["jquery", "avalon"], function($, avalon){
function li_active(selector){
$(selector).attr("class", "list-group-item active");
}
function li_inactive(selector){
$(".list-group-item").attr("class", "list-group-item");
}
var hash = window.location.hash.substring(1);
if(hash){
li_active("#li-" + hash);
}else {
li_active("#li-index");
}
window.onhashchange = function() {
var hash = window.location.hash.substring(1);
if(hash){
li_inactive(".list-group-item");
li_active("#li-" + hash);
vm.template_url = "template/index/" + hash + ".html";
}
};
var vm = avalon.define({
$id: "admin",
template_url: "template/index/index.html"
});
});

View File

@ -15,6 +15,7 @@ var require = {
submit_code: "app/oj/problem/submit_code",
contest: "app/admin/contest/contest",
csrf: "utils/csrf",
admin: "app/admin/admin",
//formValidation 不要在代码中单独使用而是使用和修改utils/validation
base: "lib/formValidation/base",

122
template/admin/admin.html Normal file
View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="renderer" content="webkit">
<title>在线评测系统 - 后台管理</title>
<!-- custom css begin -->
{% block css_block %}{% endblock %}
<!-- custom css end -->
<!-- global css begin -->
<link href="/static/css/admin.css" rel="stylesheet">
<!-- global css end -->
</head>
<body>
<!-- nav begin -->
<nav class="navbar navbar-masthead navbar-default navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">qduoj admin</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">主页</a></li>
<li><a href="#about">题目</a></li>
<li><a href="#contact">提交</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
李扬
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">我的提交</a></li>
<li><a href="#">我的资料</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">退出</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- nav end -->
<!--browser happy begin -->
<!--[if lt IE 9]>
<div class="alert alert-danger text-center" role="alert">
当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>.
</div>
<![endif]-->
<!-- browser happy end -->
<div class="container" ms-controller="admin">
<div class="row">
<!-- admin left begin-->
<div class="col-md-2">
<ul class="list-group">
<li class="list-group-header">List header</li>
<li class="list-group-item" id="li-index"><a href="#index">主页</a></li>
<li class="list-group-item" id="li-announcement"><a href="#announcement">公告</a></li>
<li class="list-group-item"><a href="#">Applications</a></li>
<li class="list-group-header">Another list header</li>
<li class="list-group-item"><a href="#">Help</a></li>
</ul>
</div>
<!-- admin left end -->
<!-- custom body begin -->
<div ms-include-src="template_url"></div>
<!-- custom body end -->
</div>
</div>
<div class="modal fade" id="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">提示</h4>
</div>
<div class="modal-body">
<p id="modal-text"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<script src="/static/js/config.js"></script>
<script src="/static/js/require.js"></script>
<script>
require(["bootstrap", "admin"]);
</script>
<!-- footer begin -->
<div class="footer">
<p class="text-muted text-center">Copyright © 2015 青岛大学信息工程学院 创新实验室</p>
</div>
<!-- footer end -->
</body>
</html>

View File

@ -1,4 +0,0 @@
{% extends "admin_base.html" %}
{% block body %}
Hello world
{% endblock %}

View File

@ -0,0 +1 @@
<h1>Hello world</h1>

View File

@ -65,14 +65,14 @@
<![endif]-->
<!-- browser happy end -->
<div class="container">
<div class="container" ms-controller="admin">
<div class="row">
<!-- admin left begin-->
<div class="col-md-2">
<ul class="list-group">
<li class="list-group-header">List header</li>
<li class="list-group-item active"><a href="#">Home</a></li>
<li class="list-group-item"><a href="#">Library</a></li>
<li class="list-group-item" id="li-index"><a href="#index">主页</a></li>
<li class="list-group-item" id="li-announcement"><a href="#announcement">公告</a></li>
<li class="list-group-item"><a href="#">Applications</a></li>
<li class="list-group-header">Another list header</li>
<li class="list-group-item"><a href="#">Help</a></li>
@ -108,7 +108,7 @@
<script src="/static/js/config.js"></script>
<script src="/static/js/require.js"></script>
<script>
require(["bootstrap"]);
require(["bootstrap", "admin"]);
</script>
{% block js_block %}{% endblock %}
<!-- footer begin -->

View File

@ -1,4 +1,7 @@
#!/usr/bin/env bash
coverage run --source='.' manage.py test
coverage html
open htmlcov/index.html
test_result=$?
if [ "$test_result" -eq 0 ];then
coverage html
open htmlcov/index.html
fi

View File

@ -1,4 +1,6 @@
# coding=utf-8
from django.core.paginator import Paginator
from rest_framework.response import Response
@ -12,3 +14,72 @@ def serializer_invalid_response(serializer):
def success_response(data):
return Response(data={"code": 0, "data": data})
def paginate(request, query_set, object_serializer):
"""
用于分页的函数
如果 url 里面不含有paging=true那么将返回全部数据类似
[
{
"username": "1111111",
"password": "123456"
}
]
如果 url 中有 paging=true 的参数
然后还需要读取其余的两个参数page=[int]需要的页码p
age_size=[int]一页的数据条数
参数错误的时候返回{"code": 1, "data": u"参数错误"}
返回的数据格式
{
"code": 0,
"data": {
"previous_page": null,
"results": [
{
"username": "1111111",
"password": "123456"
}
],
"next_page": 2
}
}
:param query_set 数据库查询结果
:param object_serializer: 序列化单个object的serializer
:return response
"""
need_paginate = request.GET.get("paging", None)
# 如果请求的参数里面没有paging=true的话 就返回全部数据
if need_paginate != "true":
return success_response(data=object_serializer(query_set, many=True).data)
page_size = request.GET.get("page_size", None)
if not page_size:
return error_response(u"参数错误")
try:
page_size = int(page_size)
except Exception:
return error_response(u"参数错误")
paginator = Paginator(query_set, page_size)
page = request.GET.get("page", None)
try:
current_page = paginator.page(page)
except Exception:
return error_response(u"参数错误")
data = {"results": object_serializer(current_page, many=True).data, "previous_page": None, "next_page": None}
try:
data["previous_page"] = current_page.previous_page_number()
except Exception:
pass
try:
data["next_page"] = current_page.next_page_number()
except Exception:
pass
return success_response(data)

9
utils/test_urls.py Normal file
View File

@ -0,0 +1,9 @@
# coding=utf-8
from django.conf.urls import include, url
urlpatterns = [
url(r'^paginate_test/$', "utils.tests.pagination_test_func"),
]

64
utils/tests.py Normal file
View File

@ -0,0 +1,64 @@
# coding=utf-8
from rest_framework.test import APIClient, APITestCase
from rest_framework import serializers
from rest_framework.decorators import api_view
from account.models import User
from .shortcuts import paginate
class PaginationTestSerialiser(serializers.Serializer):
username = serializers.CharField(max_length=100)
@api_view(["GET"])
def pagination_test_func(request):
return paginate(request, User.objects.all(), PaginationTestSerialiser)
class PaginatorTest(APITestCase):
urls = "utils.test_urls"
def setUp(self):
self.client = APIClient()
self.url = "/paginate_test/"
User.objects.create(username="test1")
User.objects.create(username="test2")
def test_no_paginate(self):
response = self.client.get(self.url)
self.assertEqual(response.data["code"], 0)
self.assertNotIn("next_page", response.data["data"])
self.assertNotIn("previous_page", response.data["data"])
def test_error_parameter(self):
response = self.client.get(self.url + "?paging=true")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
response = self.client.get(self.url + "?paging=true&page_size=-1")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
response = self.client.get(self.url + "?paging=true&page_size=aa")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
response = self.client.get(self.url + "?paging=true&page_size=1&page=-1")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
response = self.client.get(self.url + "?paging=true&page_size=aaa&page=1")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
response = self.client.get(self.url + "?paging=true&page_size=1&page=aaa")
self.assertEqual(response.data, {"code": 1, "data": u"参数错误"})
def test_correct_paginate(self):
response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=1")
self.assertEqual(response.data["code"], 0)
self.assertEqual(response.data["data"]["previous_page"], None)
self.assertEqual(response.data["data"]["next_page"], 2)
self.assertEqual(len(response.data["data"]["results"]), 1)
response = self.client.get(self.url + "?paging=true&limit=1&page_size=2&page=1")
self.assertEqual(response.data["code"], 0)
self.assertEqual(response.data["data"]["previous_page"], None)
self.assertEqual(response.data["data"]["next_page"], None)
self.assertEqual(len(response.data["data"]["results"]), 2)