增加部分基础组件

This commit is contained in:
LiYang 2016-07-31 20:26:11 +08:00
parent 0fc35d4d02
commit bcee7bca67
18 changed files with 999 additions and 95 deletions

View File

@ -6,7 +6,7 @@ import functools
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext as _
from utils.shortcuts import error_response, error_page
from utils.shortcuts import error_response, error_page, redirect_to_login
from .models import AdminType
@ -34,7 +34,7 @@ class BasePermissionDecorator(object):
if self.request.is_ajax():
return error_response(_("Please login in first"))
else:
return HttpResponseRedirect("/login/?__from=" + urllib.quote(self.request.path))
return redirect_to_login(self.request)
def check_permission(self):
raise NotImplementedError()
@ -47,9 +47,11 @@ class login_required(BasePermissionDecorator):
class super_admin_required(BasePermissionDecorator):
def check_permission(self):
return self.request.user.is_authenticated() and self.request.user.admin_type == AdminType.SUPER_ADMIN
return self.request.user.is_authenticated() and \
self.request.user.admin_type == AdminType.SUPER_ADMIN
class admin_required(BasePermissionDecorator):
def check_permission(self):
return self.request.user.is_authenticated() and self.request.user.admin_type in [AdminType.SUPER_ADMIN, AdminType.ADMIN]
return self.request.user.is_authenticated() and \
self.request.user.admin_type in [AdminType.SUPER_ADMIN, AdminType.ADMIN]

View File

@ -3,27 +3,24 @@ import time
import json
import urllib
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.contrib import auth
from .models import AdminType, User
from utils.shortcuts import redirect_to_login
from .models import AdminType
# todo remove this
from django.contrib import auth
class SessionSecurityMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and request.user.admin_type in [AdminType.ADMIN, AdminType.SUPER_ADMIN]:
if "last_activity" in request.session:
# 24 hours passwd since last visit
# 24 hours passed since last visit
if time.time() - request.session["last_activity"] >= 24 * 60 * 60:
auth.logout(request)
if request.is_ajax():
return HttpResponse(json.dumps({"code": 1, "data": _("Please login in first")}),
content_type="application/json")
else:
return HttpResponseRedirect("/login/?__from=" + urllib.quote(request.path))
return redirect_to_login(request)
# 更新最后活动日期
request.session["last_activity"] = time.time()

View File

@ -1,38 +1,35 @@
# coding=utf-8
import os
import codecs
import qrcode
import StringIO
import codecs
import os
from django import http
import qrcode
from django.conf import settings
from django.contrib import auth
from django.shortcuts import render
from django.core.exceptions import MultipleObjectsReturned
from django.core.paginator import Paginator
from django.db.models import Q
from django.conf import settings
from django.http import HttpResponse
from django.core.exceptions import MultipleObjectsReturned
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, error_page, paginate, rand_str)
from utils.captcha import Captcha
from utils.otp_auth import OtpAuth
from .tasks import _send_email
from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, error_page, paginate, rand_str)
from .decorators import login_required
from .models import User, UserProfile, AdminExtraPermission, AdminType
from .decorators import super_admin_required
from .models import User, UserProfile, AdminType
from .serializers import (UserLoginSerializer, UserRegisterSerializer,
UserChangePasswordSerializer,
UserSerializer, EditUserSerializer,
ApplyResetPasswordSerializer, ResetPasswordSerializer,
SSOSerializer, EditUserProfileSerializer,
TwoFactorAuthCodeSerializer)
from .decorators import super_admin_required
from .tasks import _send_email
class UserLoginAPIView(APIView):
@ -223,7 +220,7 @@ class UserAdminAPIView(APIView):
def logout(request):
auth.logout(request)
return http.HttpResponseRedirect("/")
return HttpResponseRedirect("/")
def index_page(request):
@ -233,7 +230,7 @@ def index_page(request):
if request.META.get('HTTP_REFERER') or request.GET.get("index"):
return render(request, "oj/index.html")
else:
return http.HttpResponseRedirect('/problems/')
return HttpResponseRedirect('/problems/')
class UsernameCheckAPIView(APIView):

View File

@ -6,7 +6,6 @@
</head>
<body>
<div id="app">
<app></app>
</div>
</body>
</html>

View File

@ -33,6 +33,7 @@
"json-loader": "^0.5.4",
"ora": "^0.2.0",
"shelljs": "^0.6.0",
"simditor-markdown": "^1.1.2",
"url-loader": "^0.5.7",
"vue-hot-reload-api": "^1.2.0",
"vue-html-loader": "^1.0.0",
@ -44,6 +45,7 @@
"webpack": "^1.12.2",
"webpack-dev-middleware": "^1.4.0",
"webpack-hot-middleware": "^2.6.0",
"webpack-merge": "^0.8.3"
"webpack-merge": "^0.8.3",
"webuploader": "^0.1.8"
}
}

View File

@ -22,8 +22,8 @@
</template>
<style>
@import "../../static/css/bootstrap.css";
@import "../../static/css/todc-bootstrap.css";
@import "../../static/css/bootstrap.css";
@import "../../static/css/todc-bootstrap.css";
</style>
<script>

View File

@ -1,6 +1,6 @@
<template>
<div>
<back url="/user"></back>
<back></back>
<h3>修改用户信息</h3>
<form v-on:submit="submit">
<div class="row">
@ -127,7 +127,7 @@
url: "/api/admin/user/",
method: "PUT",
data: data,
success: (data)=> {
success: (data)=> {
alert("更新成功");
}
})
@ -138,7 +138,7 @@
this.request({
url: "/api/admin/user/?user_id=" + this.$route.params["userId"],
method: "GET",
success:(data)=> {
success: (data)=> {
this.user = data.data;
for (var p of data.data.admin_extra_permission) {
if (this.userPermissionNum2Str[p]) {

View File

@ -0,0 +1,19 @@
<template>
<div>
<simditor editorid="problem_detail"></simditor>
<uploader uploaderid="uploader"></uploader>
</div>
</template>
<script>
import simditor from "../utils/simditor.vue"
import uploader from "../utils/uploader.vue"
export default({
components: {
simditor,
uploader
}
})
</script>

View File

@ -39,10 +39,10 @@
}
},
events: {
"showModal":(content) => {
"showModal": (content) => {
this.showModal = true;
this.content = true;
setTimeout(()=>{
setTimeout(()=> {
this.showModal = false;
}, 2000);
}

View File

@ -9,11 +9,11 @@
</div>
</template>
<script>
export default {
data() {
return {
adminNav: [{}, {}]
export default {
data() {
return {
adminNav: [{}, {}]
}
}
}
}
</script>

View File

@ -0,0 +1,25 @@
<template>
<textarea id="{{ editorid }}"></textarea>
</template>
<script>
import Simditor from 'simditor'
import SimditorMakrdown from "simditor-markdown"
export default{
props: ["editorid"],
attached() {
var self = this;
var editor = new Simditor({
textarea: document.getElementById(self.editorid),
upload: {url: "/", fileKey: "file"},
toolbar: ['bold', 'italic', 'underline', 'color', 'image', 'ol', 'ul', 'markdown']
});
}
}
</script>
<style scoped>
@import "../../../../static/css/simditor.css";
@import "../../../../static/css/simditor-markdown.css";
@import "../../../../static/css/webuploader.css";
</style>

View File

@ -0,0 +1,52 @@
<template>
<div id="{{ uploaderid }}">
<div class="btns">
<div id="picker"> picker</div>
</div>
</div>
</template>
<script>
import WebUploader from "webuploader"
export default ({
props: {
uploaderid: {
required: true
},
uploadpath: {
required: false,
default: "/server"
},
accept: {
required: false,
default(){
return {
title: 'Images',
extensions: 'gif,jpg,jpeg,bmp,png',
mimeTypes: 'image/*'
}
}
}
},
attached() {
var self = this;
var uploader = WebUploader.create({
dnd: '#' + self.uploaderid,
runtimeOrder: "html5",
server: self.uploadpath,
pick: '#' + self.uploaderid,
resize: false,
auto: true,
accept: self.accept
});
}
})
</script>
<style>
</style>

View File

@ -1,51 +1,51 @@
export default {
"zh-cn": {
nav: {
UserManagement: "用户管理"
},
pagination: {
first: "首页",
last: "末页"
},
modalAlert: {
alert: "提示",
close: "关闭"
},
request: {
error: "请求失败",
succeeded: "操作成功"
},
user: {
username: "用户名",
email: "邮箱",
realName: "真实姓名",
adminType: "用户类型",
createTime: "注册时间",
management: "管理",
edit: "编辑",
submission: "提交",
newPassword: "新密码",
leaveBlankIfDoNotChangePassword: "不需要修改密码请留空",
openAPIFunction: "OpenAPI 功能",
tfaAuth: "两步验证",
isDisabled: "禁用用户",
adminExtraPermission: "普通管理员额外权限",
showAdminOnly: "只显示管理员"
},
adminUtils: {
search: "搜索",
inputKeyword: "输入关键词",
regularUser: "普通用户",
admin: "普通管理员",
superAdmin: "超级管理员",
UserDoesNotExist: "用户不存在",
back: "返回",
saveChanges: "保存修改",
createPublicContest: "创建公开比赛",
manageAllContest: "管理所有比赛",
manageAllProblem: "管理所有题目",
manageOwnProblem: "管理自己创建的题目",
unsupportedBrowserWarningMsg: "当前网页 <strong>不支持</strong> 你正在使用的浏览器, 为了正常的访问,请到 <a href=\"http://browsehappy.com/\"> 升级你的浏览器</a>"
}
}
"zh-cn": {
nav: {
UserManagement: "用户管理"
},
pagination: {
first: "首页",
last: "末页"
},
modalAlert: {
alert: "提示",
close: "关闭"
},
request: {
error: "请求失败",
succeeded: "操作成功"
},
user: {
username: "用户名",
email: "邮箱",
realName: "真实姓名",
adminType: "用户类型",
createTime: "注册时间",
management: "管理",
edit: "编辑",
submission: "提交",
newPassword: "新密码",
leaveBlankIfDoNotChangePassword: "不需要修改密码请留空",
openAPIFunction: "OpenAPI 功能",
tfaAuth: "两步验证",
isDisabled: "禁用用户",
adminExtraPermission: "普通管理员额外权限",
showAdminOnly: "只显示管理员"
},
adminUtils: {
search: "搜索",
inputKeyword: "输入关键词",
regularUser: "普通用户",
admin: "普通管理员",
superAdmin: "超级管理员",
UserDoesNotExist: "用户不存在",
back: "返回",
saveChanges: "保存修改",
createPublicContest: "创建公开比赛",
manageAllContest: "管理所有比赛",
manageAllProblem: "管理所有题目",
manageOwnProblem: "管理自己创建的题目",
unsupportedBrowserWarningMsg: "当前网页 <strong>不支持</strong> 你正在使用的浏览器, 为了正常的访问,请到 <a href=\"http://browsehappy.com/\"> 升级你的浏览器</a>"
}
}
};

View File

@ -7,6 +7,8 @@ import locale from "./locales"
import userList from "./components/account/userList.vue"
import editUser from "./components/account/editUser.vue"
import problem from "./components/problem/problem.vue"
import uploader from "./components/utils/uploader.vue"
var request = {
@ -83,6 +85,10 @@ router.map({
"/user/edit/:userId": {
name: "editUser",
component: editUser
},
"/problem/create": {
name: "createProblem",
component: problem
}
});

View File

@ -0,0 +1,28 @@
.simditor .markdown-editor {
display: none;
}
.simditor .markdown-editor textarea {
display: block;
width: 100%;
min-height: 200px;
box-sizing: border-box;
padding: 22px 15px 40px;
border: none;
border-bottom: 1px solid #dfdfdf;
resize: none;
outline: none;
font-size: 16px;
}
.simditor.simditor-markdown .markdown-editor {
display: block;
}
.simditor.simditor-markdown .simditor-body {
min-height: 100px;
background: #f3f3f3;
}
.simditor.simditor-markdown .simditor-placeholder {
display: none !important;
}
.simditor .simditor-toolbar .toolbar-item.toolbar-item-markdown .simditor-icon {
font-size: 18px;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
.webuploader-container {
position: relative;
}
.webuploader-element-invisible {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px,1px,1px,1px);
}
.webuploader-pick {
position: relative;
display: inline-block;
cursor: pointer;
background: #00b7ee;
padding: 10px 15px;
color: #fff;
text-align: center;
border-radius: 3px;
overflow: hidden;
}
.webuploader-pick-hover {
background: #00a2d4;
}
.webuploader-pick-disable {
opacity: 0.6;
pointer-events:none;
}

View File

@ -1,12 +1,11 @@
# coding=utf-8
import os
import hashlib
import time
import random
import logging
from django.shortcuts import render
from django.core.paginator import Paginator
from django.http import HttpResponseRedirect
from rest_framework.response import Response
@ -125,3 +124,7 @@ def build_query_string(kv_data, ignore_none=True):
query_string = "?"
query_string += (k + "=" + str(v))
return query_string
def redirect_to_login(request):
return HttpResponseRedirect("/login/?__from=" + urllib.quote(request.path))