mirror of https://github.com/jumpserver/jumpserver
Add UserGroup some View
parent
651e89994e
commit
cf15b7eaff
|
@ -4600,4 +4600,6 @@ body.skin-3 {
|
|||
border-width: 1px
|
||||
}
|
||||
|
||||
|
||||
th a {
|
||||
color: #676a6c;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li class="group"><a href="{% url 'users:user-list' %}">用户列表</a></li>
|
||||
<li class="user"><a href="#">用户组列表</a></li>
|
||||
<li class="user"><a href="{% url 'users:usergroup-list' %}">用户组列表</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="">
|
||||
|
|
|
@ -26,3 +26,10 @@ class UserUpdateForm(ModelForm):
|
|||
'phone', 'enable_2FA', 'role', 'date_expired', 'comment',
|
||||
]
|
||||
|
||||
|
||||
class UserGroupForm(ModelForm):
|
||||
class Meta:
|
||||
model = UserGroup
|
||||
fields = [
|
||||
'name', 'comment',
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser, Permission
|
||||
from django.contrib.auth.models import Group as AbstractGroup
|
||||
|
@ -55,6 +55,24 @@ class UserGroup(models.Model):
|
|||
group = cls(name='所有人', comment='所有人默认都在用户组', created_by='System')
|
||||
group.save()
|
||||
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100):
|
||||
from random import seed, randint, choice
|
||||
import forgery_py
|
||||
from django.db import IntegrityError
|
||||
|
||||
seed()
|
||||
for i in range(count):
|
||||
group = cls(name=forgery_py.name.full_name(),
|
||||
comment=forgery_py.lorem_ipsum.sentence(),
|
||||
created_by=choice(User.objects.all()).username
|
||||
)
|
||||
try:
|
||||
group.save()
|
||||
except IntegrityError:
|
||||
print('Error continue')
|
||||
continue
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
username = models.CharField(max_length=20, unique=True, verbose_name='用户名', help_text='* required')
|
||||
|
@ -71,7 +89,37 @@ class User(AbstractUser):
|
|||
public_key = models.CharField(max_length=1000, blank=True, verbose_name='公钥')
|
||||
comment = models.TextField(max_length=200, blank=True, verbose_name='描述')
|
||||
created_by = models.CharField(max_length=30, default='')
|
||||
date_expired = models.DateTimeField(default=datetime.datetime.max, verbose_name='有效期')
|
||||
date_expired = models.DateTimeField(default=timezone.now()+timezone.timedelta(days=365*70), verbose_name='有效期')
|
||||
|
||||
class Meta:
|
||||
db_table = 'user'
|
||||
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100):
|
||||
from random import seed, randint, choice
|
||||
import forgery_py
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.db import IntegrityError
|
||||
|
||||
seed()
|
||||
for i in range(count):
|
||||
user = cls(username=forgery_py.internet.user_name(True),
|
||||
email=forgery_py.internet.email_address(),
|
||||
name=forgery_py.name.full_name(),
|
||||
password=make_password(forgery_py.lorem_ipsum.word()),
|
||||
role=choice(Role.objects.all()),
|
||||
wechat=forgery_py.internet.user_name(True),
|
||||
comment=forgery_py.lorem_ipsum.sentence(),
|
||||
created_by=choice(cls.objects.all()).username,
|
||||
)
|
||||
try:
|
||||
user.save()
|
||||
except IntegrityError:
|
||||
print('Error continue')
|
||||
continue
|
||||
user.groups.add(choice(UserGroup.objects.all()))
|
||||
user.save()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/chosen/chosen.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/chosen/chosen.jquery.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% 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 %}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="users" class="col-sm-2 control-label">用户</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="users" id="users" data-placeholder="选择用户" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user in users %}
|
||||
<option value="{{ user.id }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="help-block m-b-none">用户和用户组必选一个</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
|
||||
<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 custom_foot_js %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var config = {
|
||||
'.chosen-select' : {},
|
||||
'.chosen-select-deselect' : {allow_single_deselect:true},
|
||||
'.chosen-select-no-single' : {disable_search_threshold:10},
|
||||
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
|
||||
'.chosen-select-width' : {width:"95%"}
|
||||
};
|
||||
for (var selector in config) {
|
||||
$(selector).chosen(config[selector]);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,81 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% 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="collapise-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">
|
||||
<div class="">
|
||||
<a href="{% url 'users:usergroup-add' %}" class="btn btn-sm btn-primary "> 添加用户组 </a>
|
||||
<a id="del_btn" class="btn btn-sm btn-danger "> 删除所选 </a>
|
||||
<form id="search_form" method="get" action="{% url 'users:user-list' %}" class="pull-right mail-search">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="名称" value="{{ keyword }}">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
搜索
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')">
|
||||
</th>
|
||||
<th class="text-center"><a href="{% url 'users:usergroup-list' %}?sort=name">名称</a></th>
|
||||
<th class="text-center">用户数量</th>
|
||||
<th class="text-center">资产数量</th>
|
||||
<th class="text-center">描述</th>
|
||||
<th class="text-center"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for usergroup in usergroup_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center">
|
||||
<input type="checkbox" name="checked" value="{{ usergroup.id }}">
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'users:usergroup-detail' pk=usergroup.id %}">
|
||||
{{ usergroup.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-center">{{ usergroup.user_set.all|length }}</td>
|
||||
<td class="text-center">数量</td>
|
||||
<th class="text-center">{{ usergroup.comment|truncatewords:8 }}</th>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'users:usergroup-edit' pk=usergroup.id %}?id={{ user.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<a href="{% url 'users:usergroup-delete' pk=usergroup.id %}?id={{ user.id }}" class="btn btn-xs btn-danger del">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% include '_pagination.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,13 +1,19 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import UserListView, UserAddView, UserUpdateView, UserDeleteView, UserDetailView
|
||||
from .views import UserGroupListView, UserGroupAddView, UserGroupUpdateView, UserGroupDeleteView, UserGroupDetailView
|
||||
|
||||
app_name = 'users'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', UserListView.as_view(), name='user-list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', UserDetailView.as_view(), name='user-detail'),
|
||||
url(r'^add/$', UserAddView.as_view(), name='user-add'),
|
||||
url(r'^(?P<pk>[0-9]+)/edit/$', UserUpdateView.as_view(), name='user-edit'),
|
||||
url(r'^(?P<pk>[0-9]+)/delete/$', UserDeleteView.as_view(), name='user-delete'),
|
||||
url(r'^user/$', UserListView.as_view(), name='user-list'),
|
||||
url(r'^user/(?P<pk>[0-9]+)/$', UserDetailView.as_view(), name='user-detail'),
|
||||
url(r'^user/add/$', UserAddView.as_view(), name='user-add'),
|
||||
url(r'^user/(?P<pk>[0-9]+)/edit/$', UserUpdateView.as_view(), name='user-edit'),
|
||||
url(r'^user/(?P<pk>[0-9]+)/delete/$', UserDeleteView.as_view(), name='user-delete'),
|
||||
url(r'^usergroup/$', UserGroupListView.as_view(), name='usergroup-list'),
|
||||
url(r'^usergroup/(?P<pk>[0-9]+)/$', UserGroupDetailView.as_view(), name='usergroup-detail'),
|
||||
url(r'^usergroup/add/$', UserGroupAddView.as_view(), name='usergroup-add'),
|
||||
url(r'^usergroup/(?P<pk>[0-9]+)/edit/$', UserGroupUpdateView.as_view(), name='usergroup-edit'),
|
||||
url(r'^usergroup/(?P<pk>[0-9]+)/delete/$', UserGroupDeleteView.as_view(), name='usergroup-delete'),
|
||||
]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from django.db.models import Q
|
||||
from django.views.generic.list import ListView
|
||||
|
@ -7,7 +8,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
|||
from django.views.generic.detail import DetailView
|
||||
|
||||
from .models import User, UserGroup, Role
|
||||
from .forms import UserAddForm, UserUpdateForm
|
||||
from .forms import UserAddForm, UserUpdateForm, UserGroupForm
|
||||
|
||||
|
||||
class UserListView(ListView):
|
||||
|
@ -71,12 +72,6 @@ class UserUpdateView(UpdateView):
|
|||
user.set_password(password)
|
||||
return super(UserUpdateView, self).form_valid(form)
|
||||
|
||||
def form_invalid(self, form):
|
||||
print(self.request.FILES)
|
||||
print(form['avatar'].value())
|
||||
print(form.errors)
|
||||
return super(UserUpdateView, self).form_invalid(form)
|
||||
|
||||
|
||||
class UserDeleteView(DeleteView):
|
||||
model = User
|
||||
|
@ -94,3 +89,61 @@ class UserDetailView(DetailView):
|
|||
groups = [group for group in UserGroup.objects.iterator() if group not in self.object.groups.iterator()]
|
||||
context.update({'path1': '用户管理', 'path2': '用户详情', 'title': '用户详情', 'groups': groups})
|
||||
return context
|
||||
|
||||
|
||||
class UserGroupListView(ListView):
|
||||
model = UserGroup
|
||||
paginate_by = 20
|
||||
context_object_name = 'usergroup_list'
|
||||
template_name = 'users/usergroup_list.html'
|
||||
ordering = '-date_added'
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = super(UserGroupListView, self).get_queryset()
|
||||
self.keyword = keyword = self.request.GET.get('keyword', '')
|
||||
self.sort = sort = self.request.GET.get('sort')
|
||||
if keyword:
|
||||
self.queryset = self.queryset.filter(name__icontains=keyword)
|
||||
|
||||
if sort:
|
||||
self.queryset = self.queryset.order_by(sort)
|
||||
return self.queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UserGroupListView, self).get_context_data(**kwargs)
|
||||
context.update({'path1': '用户管理', 'path2': '用户组列表', 'title': '用户组列表', 'keyword': self.keyword})
|
||||
return context
|
||||
|
||||
|
||||
class UserGroupAddView(CreateView):
|
||||
model = UserGroup
|
||||
form_class = UserGroupForm
|
||||
template_name = 'users/usergroup_add.html'
|
||||
success_url = reverse_lazy('users:usergroup-list')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UserGroupAddView, self).get_context_data(**kwargs)
|
||||
users = User.objects.all()
|
||||
context.update({'path1': '用户管理', 'path2': '用户组添加', 'title': '用户组添加', 'users': users})
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
usergroup = form.save()
|
||||
users_id_list = self.request.POST.getlist('users', [])
|
||||
users = [get_object_or_404(User, id=user_id) for user_id in users_id_list]
|
||||
usergroup.created_by = self.request.user.username or 'Admin'
|
||||
usergroup.user_set.add(*tuple(users))
|
||||
usergroup.save()
|
||||
return super(UserGroupAddView, self).form_valid(form)
|
||||
|
||||
|
||||
class UserGroupUpdateView(UpdateView):
|
||||
pass
|
||||
|
||||
|
||||
class UserGroupDetailView(DetailView):
|
||||
pass
|
||||
|
||||
|
||||
class UserGroupDeleteView(DeleteView):
|
||||
pass
|
||||
|
|
Loading…
Reference in New Issue