mirror of https://github.com/jumpserver/jumpserver
Add user list view
parent
9303415b89
commit
9493fb07cb
|
@ -0,0 +1,57 @@
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="dataTables_info" id="editable_info" role="status" aria-live="polite">
|
||||||
|
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ paginator.count }} entries
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
|
||||||
|
<ul class="pagination" style="margin-top: 0; float: right">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="paginate_button previous" aria-controls="editable" tabindex="0"
|
||||||
|
id="editable_previous">
|
||||||
|
<a class="page" href="?page={{ page_obj.previous_page_number }}">Previous</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="paginate_button active" aria-controls="editable" tabindex="0">
|
||||||
|
<a class="page" href="?page={{ page_obj.number }}" title="第{{ page_obj.number }}页">{{ page_obj.number }}</a>
|
||||||
|
</li>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="editable_next">
|
||||||
|
<a class="page" href="?page={{ page_obj.next_page_number }}">Next</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<script>
|
||||||
|
function sleep(n) { //n表示的毫秒数
|
||||||
|
var start = new Date().getTime();
|
||||||
|
while (true) if (new Date().getTime() - start > n) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('.page').click(function () {
|
||||||
|
var searchStr = location.search;
|
||||||
|
var old_href = $(this).attr('href').replace('?', '');
|
||||||
|
var searchArray = searchStr.split('&');
|
||||||
|
|
||||||
|
if (searchStr == '') {
|
||||||
|
searchStr = '?page=1'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchStr.indexOf('page') >= 0) {
|
||||||
|
searchArray.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
searchArray.push(old_href);
|
||||||
|
if (searchArray.length > 1) {
|
||||||
|
$(this).attr('href', searchArray.join('&'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10 on 2016-08-14 04:37
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='comment',
|
||||||
|
field=models.CharField(blank=True, max_length=200, verbose_name='\u63cf\u8ff0'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='date_expired',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='phone',
|
||||||
|
field=models.CharField(max_length=20, verbose_name='\u624b\u673a\u53f7'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='private_key',
|
||||||
|
field=models.CharField(max_length=5000, verbose_name='ssh\u79c1\u94a5'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='public_key',
|
||||||
|
field=models.CharField(max_length=1000, verbose_name='\u516c\u94a5'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='role',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.Role', verbose_name='\u89d2\u8272'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='usergroup',
|
||||||
|
name='comment',
|
||||||
|
field=models.TextField(blank=True, verbose_name='\u63cf\u8ff0'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='usergroup',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=100, unique=True, verbose_name='\u7ec4\u540d\u79f0'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser, Permission
|
||||||
from django.contrib.auth.models import Group as AbstractGroup
|
from django.contrib.auth.models import Group as AbstractGroup
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,10 +18,28 @@ class Role(AbstractGroup):
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'role'
|
db_table = 'role'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def init(cls):
|
||||||
|
roles = {
|
||||||
|
'Administrator': {'permissions': Permission.objects.all(), 'comment': '管理员'},
|
||||||
|
'User': {'permissions': [], 'comment': '用户'},
|
||||||
|
'Auditor': {'permissions': Permission.objects.filter(content_type__app_label='audits'),
|
||||||
|
'comment': '审计员'},
|
||||||
|
}
|
||||||
|
|
||||||
|
for role in cls.objects.all():
|
||||||
|
role.permissions.clear()
|
||||||
|
|
||||||
|
cls.objects.all().delete()
|
||||||
|
|
||||||
|
for role_name, props in roles.items():
|
||||||
|
role = cls.objects.create(name=role_name, comment=props.get('comment', ''))
|
||||||
|
role.permissions = props.get('permissions', [])
|
||||||
|
|
||||||
|
|
||||||
class UserGroup(models.Model):
|
class UserGroup(models.Model):
|
||||||
name = models.CharField(max_length=100, unique=True, verbose_name='组名称', help_text='请输入组名称')
|
name = models.CharField(max_length=100, unique=True, verbose_name='组名称')
|
||||||
comment = models.TextField(blank=True, verbose_name='描述', help_text='请输入用户组描述')
|
comment = models.TextField(blank=True, verbose_name='描述')
|
||||||
date_added = models.DateTimeField(auto_now_add=True)
|
date_added = models.DateTimeField(auto_now_add=True)
|
||||||
created_by = models.CharField(max_length=100)
|
created_by = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
@ -32,16 +52,17 @@ class UserGroup(models.Model):
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
groups = models.ManyToManyField(UserGroup)
|
groups = models.ManyToManyField(UserGroup)
|
||||||
avatar = models.ImageField(verbose_name='头像', default='')
|
avatar = models.ImageField(verbose_name='头像', blank=True)
|
||||||
wechat = models.CharField(max_length=30, verbose_name='微信')
|
wechat = models.CharField(max_length=30, blank=True, verbose_name='微信')
|
||||||
phone = models.CharField(max_length=20, verbose_name='手机')
|
phone = models.CharField(max_length=20, blank=True, verbose_name='手机号')
|
||||||
enable_2FA = models.BooleanField(default=False, verbose_name='启用二次验证')
|
enable_2FA = models.BooleanField(default=False, verbose_name='启用二次验证')
|
||||||
secret_key_2FA = models.CharField(max_length=16)
|
secret_key_2FA = models.CharField(max_length=16, blank=True)
|
||||||
role = models.ForeignKey(Role, on_delete=models.PROTECT)
|
role = models.ForeignKey(Role, on_delete=models.PROTECT, verbose_name='角色')
|
||||||
private_key = models.CharField(max_length=5000) # 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)
|
public_key = models.CharField(max_length=1000, blank=True, verbose_name='公钥')
|
||||||
created_by = models.CharField(max_length=30)
|
comment = models.CharField(max_length=200, blank=True, verbose_name='描述')
|
||||||
date_expired = models.DateTimeField()
|
created_by = models.CharField(max_length=30, default='')
|
||||||
|
date_expired = models.DateTimeField(default=datetime.datetime.max)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% 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="#" 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="" class="pull-right mail-search">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
|
||||||
|
<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">姓名</th>
|
||||||
|
<th class="text-center">用户名</th>
|
||||||
|
<th class="text-center">角色</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 user in user_list %}
|
||||||
|
<tr class="gradeX">
|
||||||
|
<td class="text-center">
|
||||||
|
<input type="checkbox" name="checked" value="{{ user.id }}">
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="{% url 'users:user-detail' pk=user.id %}?id={{ user.id }}">
|
||||||
|
{{ user.name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ user.username }}</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>
|
||||||
|
<th class="text-center">{{ user.name }}</th>
|
||||||
|
<td class="text-center">{{ user.name }}</td>
|
||||||
|
<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-delete' pk=user.id %}?id={{ user.id }}" class="btn btn-xs btn-danger del {% if user.username == 'admin' %} disabled {% endif %}">删除</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% include '_pagination.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,8 +1,12 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from . import views
|
|
||||||
|
from .views import UserListView
|
||||||
|
|
||||||
app_name = 'users'
|
app_name = 'users'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'hello/$', views.hello, name='hello'),
|
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]+)/edit/$', UserListView.as_view(), name='user-edit'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/delete/$', UserListView.as_view(), name='user-delete'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
from django.shortcuts import render
|
# ~*~ coding: utf-8 ~*~
|
||||||
from django.views.generic.base import TemplateView
|
|
||||||
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
|
from .models import User, UserGroup
|
||||||
|
|
||||||
|
|
||||||
def hello(request):
|
class UserListView(ListView):
|
||||||
return render(request, 'base.html')
|
model = User
|
||||||
|
paginate_by = 10
|
||||||
|
context_object_name = 'user_list'
|
||||||
|
template_name = 'users/user_list.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UserListView, self).get_context_data(**kwargs)
|
||||||
|
context.update({'path1': '用户管理', 'path2': '用户列表', 'title': '用户列表'})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
django==1.10
|
||||||
|
pillow
|
Loading…
Reference in New Issue