Add common app

common app used as write public api or templatetags

modify user list view and user edit view
pull/530/head
ibuler 2016-08-16 00:09:48 +08:00
parent edd60cad11
commit 3bf0d4aabb
19 changed files with 242 additions and 122 deletions

0
apps/common/__init__.py Normal file
View File

7
apps/common/apps.py Normal file
View File

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class CommonConfig(AppConfig):
name = 'common'

View File

5
apps/common/models.py Normal file
View File

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

View File

View File

@ -0,0 +1,20 @@
# ~*~ coding: utf-8 ~*~
from django import template
from django.utils import timezone
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def is_expired(datetime):
if datetime > timezone.now():
return False
else:
return True

3
apps/common/tests.py Normal file
View File

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

3
apps/common/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -36,6 +36,7 @@ INSTALLED_APPS = [
'perms.apps.PermsConfig', 'perms.apps.PermsConfig',
'ops.apps.OpsConfig', 'ops.apps.OpsConfig',
'audits.apps.AuditsConfig', 'audits.apps.AuditsConfig',
'common.apps.CommonConfig',
'bootstrapform', 'bootstrapform',
# 'django.contrib.admin', # 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',

View File

@ -8,7 +8,7 @@
<i class="fa fa-group"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span> <i class="fa fa-group"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span>
</a> </a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li class="group"><a href="#">用户列表</a></li> <li class="group"><a href="{% url 'users:user-list' %}">用户列表</a></li>
<li class="user"><a href="#">用户组列表</a></li> <li class="user"><a href="#">用户组列表</a></li>
</ul> </ul>
</li> </li>

View File

@ -9,7 +9,6 @@ class UserForm(ModelForm):
class Meta: class Meta:
model = User model = User
fields = [ fields = [
'username', 'name', 'email', 'groups', 'wechat', 'username', 'password', 'name', 'email', 'groups', 'wechat',
'phone', 'enable_2FA', 'role', 'date_expired', 'comment', 'phone', 'enable_2FA', 'role', 'date_expired', 'comment',
] ]

View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-15 14:57
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0003_auto_20160814_1758'),
]
operations = [
migrations.AlterField(
model_name='user',
name='date_expired',
field=models.DateTimeField(default=datetime.datetime(9999, 12, 31, 23, 59, 59, 999999), verbose_name='\u6709\u6548\u671f'),
),
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(help_text='* required', max_length=30, unique=True, verbose_name='\u90ae\u4ef6'),
),
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(to='users.UserGroup', verbose_name='\u7528\u6237\u7ec4'),
),
migrations.AlterField(
model_name='user',
name='name',
field=models.CharField(help_text='* required', max_length=20, verbose_name='\u59d3\u540d'),
),
migrations.AlterField(
model_name='user',
name='username',
field=models.CharField(help_text='* required', max_length=20, unique=True, verbose_name='\u7528\u6237\u540d'),
),
]

View File

@ -49,6 +49,12 @@ class UserGroup(models.Model):
class Meta: class Meta:
db_table = 'usergroup' db_table = 'usergroup'
@classmethod
def init(cls):
if not cls.objects.all():
group = cls(name='所有人', comment='所有人默认都在用户组', created_by='System')
group.save()
class User(AbstractUser): class User(AbstractUser):
username = models.CharField(max_length=20, unique=True, verbose_name='用户名', help_text='* required') username = models.CharField(max_length=20, unique=True, verbose_name='用户名', help_text='* required')
@ -63,7 +69,7 @@ class User(AbstractUser):
role = models.ForeignKey(Role, on_delete=models.PROTECT, verbose_name='角色') role = models.ForeignKey(Role, on_delete=models.PROTECT, verbose_name='角色')
private_key = models.CharField(max_length=5000, blank=True, verbose_name='ssh私钥') # ssh key max length 4096 bit private_key = models.CharField(max_length=5000, blank=True, verbose_name='ssh私钥') # ssh key max length 4096 bit
public_key = models.CharField(max_length=1000, blank=True, verbose_name='公钥') public_key = models.CharField(max_length=1000, blank=True, verbose_name='公钥')
comment = models.CharField(max_length=200, blank=True, verbose_name='描述') comment = models.TextField(max_length=200, blank=True, verbose_name='描述')
created_by = models.CharField(max_length=30, default='') created_by = models.CharField(max_length=30, default='')
date_expired = models.DateTimeField(default=datetime.datetime.max, verbose_name='有效期') date_expired = models.DateTimeField(default=datetime.datetime.max, verbose_name='有效期')

View File

@ -0,0 +1,109 @@
{% extends 'base.html' %}
{% load bootstrap %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>填写用户信息</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action="">
{% csrf_token %}
<h3>账户</h3>
{{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{% block password %} {% endblock %}
<div class="hr-line-dashed"></div>
<h3>角色安全</h3>
{{ form.role|bootstrap_horizontal }}
{{ form.date_expired|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.enable_2FA.id_for_label }}" class="col-sm-2 control-label">二次验证</label>
<div class="col-sm-8">
{{ form.enable_2FA }}
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>信息</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">取消</button>
<button id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block self_footer_js %}
<script>
$('#userForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_username: [/^[\w.]{3,20}$/, '大小写字母数字和下划线小数点'],
type_m: function(element){
return $("#M").is(":checked");
}
},
fields: {
"username": {
rule: "required;check_username",
tip: "输入用户名",
ok: "",
msg: {required: "必须填写!"}
},
"password": {
rule: "required;length[6~50]",
tip: "输入密码",
ok: "",
msg: {required: "必须填写!"}
},
"name": {
rule: "required",
tip: "姓名",
ok: "",
msg: {required: "必须填写"}
},
"email": {
rule: "required",
tip: "Email",
ok: "",
msg: {required: "必须填写"}
}
},
valid: function(form) {
form.submit();
}
});
</script>
{% endblock %}

View File

@ -1,115 +1,10 @@
{% extends 'base.html' %} {% extends 'users/_user.html' %}
{% load bootstrap %} {% block password %}
<h3>密码</h3>
{% block content %} <div class="form-group">
<div class="wrapper wrapper-content animated fadeInRight"> <label class="col-sm-2 control-label">密码</label>
<div class="row"> <div class="col-sm-8 controls" >
<div class="col-sm-12"> 生成重置密码连接,通过邮件发送给用户
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>填写用户信息</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action="{% url 'users:user-add' %}">
{% csrf_token %}
<h3>账户</h3>
{{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>密码</h3>
<div class="form-group">
<label class="col-sm-2 control-label">密码</label>
<div class="col-sm-8 controls" >
生成重置密码连接,通过邮件发送给用户
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>角色安全</h3>
{{ form.role|bootstrap_horizontal }}
{{ form.date_expired|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.enable_2FA.id_for_label }}" class="col-sm-2 control-label">二次验证</label>
<div class="col-sm-8">
{{ form.enable_2FA }}
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>信息</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">取消</button>
<button id="submit_button" class="btn btn-primary" type="submit">确认保存</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div> </div>
</div> </div>
{% endblock %}
{% block self_footer_js %}
<script>
$('#userForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_username: [/^[\w.]{3,20}$/, '大小写字母数字和下划线小数点'],
type_m: function(element){
return $("#M").is(":checked");
}
},
fields: {
"username": {
rule: "required;check_username",
tip: "输入用户名",
ok: "",
msg: {required: "必须填写!"}
},
"password": {
rule: "required;length[6~50]",
tip: "输入密码",
ok: "",
msg: {required: "必须填写!"}
},
"name": {
rule: "required",
tip: "姓名",
ok: "",
msg: {required: "必须填写"}
},
"email": {
rule: "required",
tip: "Email",
ok: "",
msg: {required: "必须填写"}
}
},
valid: function(form) {
form.submit();
}
});
</script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,10 @@
{% extends 'users/_user.html' %}
{% block password %}
<h3>密码</h3>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">密码</label>
<div class="col-sm-9 controls" >
<input id="password" name="password" type="password" class="form-control">
</div>
</div>
{% endblock %}

View File

@ -1,4 +1,5 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
@ -63,9 +64,9 @@
</td> </td>
<td class="text-center">{{ user.username }}</td> <td class="text-center">{{ user.username }}</td>
<td class="text-center">{{ user.role.name }}</td> <td class="text-center">{{ user.role.name }}</td>
<td class="text-center" title="{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"> {{ user.group.all }} </td> <td class="text-center" title="{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"> {{ user.groups.all|join_queryset_attr:"name" }} </td>
<th class="text-center">{{ user.name }}</th> <th class="text-center">{{ user.name }}</th>
<td class="text-center">{{ user.name }}</td> <td class="text-center">{{ user.date_expired|is_expired|yesno:"过期, 有效, 分不清楚" }}</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'users:user-edit' pk=user.id %}?id={{ user.id }}" class="btn btn-xs btn-info">编辑</a> <a href="{% url 'users:user-edit' pk=user.id %}?id={{ user.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="{% url 'users:user-delete' pk=user.id %}?id={{ user.id }}" class="btn btn-xs btn-danger del {% if user.username == 'admin' %} disabled {% endif %}">删除</a> <a href="{% url 'users:user-delete' pk=user.id %}?id={{ user.id }}" class="btn btn-xs btn-danger del {% if user.username == 'admin' %} disabled {% endif %}">删除</a>

View File

@ -1,6 +1,6 @@
from django.conf.urls import url from django.conf.urls import url
from .views import UserListView, UserAddView from .views import UserListView, UserAddView, UserUpdateView
app_name = 'users' app_name = 'users'
@ -8,6 +8,6 @@ urlpatterns = [
url(r'^$', UserListView.as_view(), name='user-list'), url(r'^$', UserListView.as_view(), name='user-list'),
url(r'^(?P<pk>[0-9]+)/$', UserListView.as_view(), name='user-detail'), url(r'^(?P<pk>[0-9]+)/$', UserListView.as_view(), name='user-detail'),
url(r'^add/$', UserAddView.as_view(), name='user-add'), url(r'^add/$', UserAddView.as_view(), name='user-add'),
url(r'^(?P<pk>[0-9]+)/edit/$', UserListView.as_view(), name='user-edit'), url(r'^(?P<pk>[0-9]+)/edit/$', UserUpdateView.as_view(), name='user-edit'),
url(r'^(?P<pk>[0-9]+)/delete/$', UserListView.as_view(), name='user-delete'), url(r'^(?P<pk>[0-9]+)/delete/$', UserListView.as_view(), name='user-delete'),
] ]

View File

@ -3,9 +3,9 @@
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.db.models import Q from django.db.models import Q
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.views.generic.edit import CreateView from django.views.generic.edit import CreateView, DeleteView, UpdateView
from .models import User, UserGroup from .models import User, UserGroup, Role
from .forms import UserForm from .forms import UserForm
@ -33,6 +33,7 @@ class UserListView(ListView):
class UserAddView(CreateView): class UserAddView(CreateView):
model = User model = User
form_class = UserForm form_class = UserForm
initial = {'role': Role.objects.get(name='User')}
template_name = 'users/user_add.html' template_name = 'users/user_add.html'
success_url = reverse_lazy('users:user-list') success_url = reverse_lazy('users:user-list')
@ -41,3 +42,22 @@ class UserAddView(CreateView):
context.update({'path1': '用户管理', 'path2': '用户添加', 'title': '用户添加'}) context.update({'path1': '用户管理', 'path2': '用户添加', 'title': '用户添加'})
return context return context
def form_valid(self, form):
user = form.save()
password = form['password'].value()
user.set_password(password)
return super(UserAddView, self).form_valid(form)
class UserUpdateView(UpdateView):
model = User
form_class = UserForm
template_name = 'users/user_edit.html'
success_url = reverse_lazy('users:user-list')
def form_valid(self, form):
user = form.save()
password = form['password'].value()
if password:
user.set_password(password)
return super(UserUpdateView, self).form_valid(form)