Commit 0d4ca971 authored by ibuler's avatar ibuler

Merge branch 'master' into connect

parents ab18fe46 7ab47916
...@@ -11,9 +11,8 @@ build ...@@ -11,9 +11,8 @@ build
_mailinglist _mailinglist
.tox .tox
.cache/ .cache/
migrations/
.idea/ .idea/
db.sqlite3 db.sqlite3
config.py config.py
*/migrations/* migrations/
*.log *.log
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from rest_framework import serializers from rest_framework import serializers
from rest_framework import viewsets, serializers from rest_framework import viewsets, serializers,generics
from .models import AssetGroup, Asset, IDC, AssetExtend from .models import AssetGroup, Asset, IDC, AssetExtend
...@@ -45,9 +44,11 @@ class AssetViewSet(viewsets.ModelViewSet): ...@@ -45,9 +44,11 @@ class AssetViewSet(viewsets.ModelViewSet):
serializer_class = AssetSerializer serializer_class = AssetSerializer
class IDCViewSet(viewsets.ModelViewSet): class IDCViewSet(viewsets.ReadOnlyModelViewSet):
""" """
API endpoint that allows IDC to be viewed or edited. API endpoint that allows IDC to be viewed or edited.
""" """
queryset = IDC.objects.all() queryset = IDC.objects.all()
serializer_class = IDCSerializer serializer_class = IDCSerializer
\ No newline at end of file
...@@ -91,7 +91,7 @@ class AssetGroupForm(forms.ModelForm): ...@@ -91,7 +91,7 @@ class AssetGroupForm(forms.ModelForm):
class Meta: class Meta:
model = AssetGroup model = AssetGroup
fields = [ fields = [
"name", "comment","system_users" "name", "comment","system_users",
] ]
widgets = { widgets = {
'name' : forms.TextInput(attrs={}), 'name' : forms.TextInput(attrs={}),
......
...@@ -47,7 +47,6 @@ class IDC(models.Model): ...@@ -47,7 +47,6 @@ class IDC(models.Model):
contact=forgery_py.name.full_name(), contact=forgery_py.name.full_name(),
phone=forgery_py.address.phone(), phone=forgery_py.address.phone(),
address=forgery_py.address.city() + forgery_py.address.street_address(), address=forgery_py.address.city() + forgery_py.address.street_address(),
network="192.168.1.10/24\n192.168.1.20",
operator=choice(['北京联通', '北京电信', 'BGP全网通']), operator=choice(['北京联通', '北京电信', 'BGP全网通']),
comment=forgery_py.lorem_ipsum.sentence(), comment=forgery_py.lorem_ipsum.sentence(),
created_by='Fake') created_by='Fake')
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
{% load static %} {% load static %}
{% load bootstrap %} {% load bootstrap %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet"> <link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script> <script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
<link href="{% static 'css/plugins/dataTables/datatables.min.css' %}" rel="stylesheet">
<script src="{% static 'js/plugins/dataTables/datatables.min.js' %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
...@@ -37,18 +39,13 @@ ...@@ -37,18 +39,13 @@
{{ form.name|bootstrap_horizontal }} {{ form.name|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }} {{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3 class="widget-head-color-box">资产</h3> <h3 class="widget-head-color-box">资产数量</h3>
<div class="form-group"> <div class="form-group">
<label for="assets" class="col-sm-2 control-label">资产</label> <label class="col-sm-2 control-label">已选</label>
<div class="col-sm-9"> <div class="col-sm-9" id="asset_sed">
<select name="assets" id="assets" data-placeholder="选择资产" class="select2 form-control m-b" multiple tabindex="2"> <input type="text" class=" form-control" id="add_asset" value="{{ assets_count }}">
{% for asset in assets %} </div>
<option value="{{ asset.id }}">{{ asset.hostname }}</option> </div>
{% endfor %}
</select>
</div>
</div>
<!--{{ form.name|bootstrap_horizontal }}-->
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3 class="widget-head-color-box">资产用户</h3> <h3 class="widget-head-color-box">资产用户</h3>
{{ form.system_users|bootstrap_horizontal }} {{ form.system_users|bootstrap_horizontal }}
...@@ -56,6 +53,7 @@ ...@@ -56,6 +53,7 @@
<div class="col-sm-4 col-sm-offset-5"> <div class="col-sm-4 col-sm-offset-5">
<button class="btn btn-white" type="reset"> 重置 </button> <button class="btn btn-white" type="reset"> 重置 </button>
<button class="btn btn-primary" type="submit"> 提交 </button> <button class="btn btn-primary" type="submit"> 提交 </button>
<div id='box2'> </div>
</div> </div>
</div> </div>
</form> </form>
...@@ -68,13 +66,55 @@ ...@@ -68,13 +66,55 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 模态框(Modal) -->
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content" id="box">
<!--此部分为主体内容,将远程加载进来-->
</div>
</div>
</div>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2();
$('.select2-system-user').select2(); $('.select2-system-user').select2();
}) })
</script>
$('#add_asset').on('click',function(){
$('#modal').modal('show');
});
$('#modal').modal({
show: false,
backdrop: 'static',
keyboard: 'false',
remote:"{% url 'assets:asset-modal-list' %}?group_id={{ group_id }}",
});
$('#modal').on('show.bs.modal',function(){
//alert('当调用show方法时,立即触发;')
});
$('#modal').on('shown.bs.modal',function(){
//alert('当弹窗完全加载完后,再触发;')
});
$('#modal').on('hide.bs.modal',function(){
//alert('当关闭时,立即触发;')
});
$('#modal').on('hidden.bs.modal',function(){
//alert('当关完全关闭后,再触发;')
});
$('#modal').on('loaded.bs.modal',function(){
//alert('当远程数据加载完毕后,再触发;')
});
</script>
{% endblock %} {% endblock %}
\ No newline at end of file
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">分配/回收资产</h4>
</div>
<div class="modal-body" style="padding-bottom: 0px;">
<table aria-describedby="editable_info" role="grid" class="table table-striped table-bordered table-hover dataTable" id="editable">
<thead>
<tr>
<th class="text-center" style="background-color:white">
<input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')">
</th>
<th>资产名称</th>
<th>IP</th>
<th>硬件类型</th>
<th>资产组</th>
<th>部门</th>
</tr>
</thead>
<tbody>
{% for asset in asset_modal_list %}
<tr>
{% if asset.id in group_assets %}
<td class="text-center" ><input type="checkbox" name="checked" value="{{ asset.id }}" checked="checked"></td>
{% else %}
<td class="text-center" ><input type="checkbox" name="checked" value="{{ asset.id }}"></td>
{% endif %}
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>虚拟机</td>
<td>网络设备</td>
<td>微信事业部</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="close-btn">取消</button>
<button type="button" class="btn btn-primary" id="save-btn">保存</button>
</div>
<script type="text/javascript">
$('#close-btn').on('click',function(){
//alert('点击关闭按钮时触发;')
$('#modal').modal('hide');
});
$('#save-btn').on('click',function(){
// alert('点击保存按钮时触发2;')
var box = $("input[name='checked']:checked");
var size=box.length;
document.getElementById('add_asset').value = size;
var ids=[];
$("#asset_sed").find("input[name='assets']").remove();
for(var i=0;i<box.length;i++){
var value = $(box[i]).val();
$("#asset_sed").append("<input type='hidden' name='assets' value='"+value+"'>");
}
$('#modal').modal('hide');
});
$(document).ready(function(){
$('#editable').DataTable({
"aaSorting": [[1, "asc"]], //给列表排序 ,第一个参数表示数组 (由0开始)。第二个参数为 desc或是asc
"aoColumnDefs": [ { "bSortable": false, "aTargets": [ 0 ] }], // 0列不参加排序
"aLengthMenu": [[10, 25, 50, -1], ["10", "25", "50", "all"]], //设置每页显示记录的下拉菜单
"oLanguage": {
"sLengthMenu": "每页显示 _MENU_ 条记录",
"sZeroRecords": "对不起,查询不到任何相关数据",
"sInfo": "当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录",
"sInfoEmtpy": "找不到相关数据",
"sInfoFiltered": "数据表中共为 _MAX_ 条记录)",
"sProcessing": "正在加载中...",
"sSearch": "搜索",
"sUrl": "", //多语言配置文件,可将oLanguage的设置放在一个txt文件中,例:Javascript/datatable/dtCH.txt
"oPaginate": {
"sFirst": "第一页",
"sPrevious": " 上一页 ",
"sNext": " 下一页 ",
"sLast": " 最后一页 "
}
} //多语言配置
});
/* Init DataTables */
var oTable = $('#editable').DataTable();
/* Apply the jEditable handlers to the table */
oTable.$('td').editable( '../example_ajax.php', {
"callback": function( sValue, y ) {
var aPos = oTable.fnGetPosition( this );
oTable.fnUpdate( sValue, aPos[0], aPos[1] );
},
"submitdata": function ( value, settings ) {
return {
"row_id": this.parentNode.getAttribute('id'),
"column": oTable.fnGetPosition( this )[2]
};
},
"width": "90%",
"height": "100%",
});
});
function fnClickAddRow() {
$('#editable').dataTable().fnAddData( [
"Custom row",
"New row",
"New row",
"New row",
"New row" ] );
}
</script>
...@@ -9,13 +9,10 @@ ...@@ -9,13 +9,10 @@
<th class="text-center"> <th class="text-center">
<input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')"> <input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')">
</th> </th>
{# <th class="text-center">{% trans 'ID' %}</th>#}
<th class="text-center"><a href="{% url 'assets:idc-list' %}?sort=name">{% trans 'Name' %}</a></th> <th class="text-center"><a href="{% url 'assets:idc-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th> <th class="text-center">{% trans 'Asset num' %}</th>
{# <th class="text-center">{% trans 'Bandwidth' %}</th>#}
<th class="text-center">{% trans 'Contact' %}</th> <th class="text-center">{% trans 'Contact' %}</th>
<th class="text-center">{% trans 'Phone' %}</th> <th class="text-center">{% trans 'Phone' %}</th>
{# <th class="text-center">{% trans 'Address' %}</th>#}
<th class="text-center">{% trans 'operation' %}</th> <th class="text-center">{% trans 'operation' %}</th>
{% endblock %} {% endblock %}
......
# coding:utf-8 # coding:utf-8
from django.conf.urls import url, include from django.conf.urls import url, include
import views import views
import api
# from .api import ( # from .api import (
# AssetGroupViewSet, AssetViewSet, IDCViewSet # AssetGroupViewSet, AssetViewSet, IDCViewSet
# ) # )
...@@ -19,6 +20,7 @@ urlpatterns = [ ...@@ -19,6 +20,7 @@ urlpatterns = [
url(r'^asset/(?P<pk>[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'), url(r'^asset/(?P<pk>[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'),
url(r'^asset/(?P<pk>[0-9]+)/update', views.AssetUpdateView.as_view(), name='asset-update'), url(r'^asset/(?P<pk>[0-9]+)/update', views.AssetUpdateView.as_view(), name='asset-update'),
url(r'^asset/(?P<pk>[0-9]+)/delete$', views.AssetDeleteView.as_view(), name='asset-delete'), url(r'^asset/(?P<pk>[0-9]+)/delete$', views.AssetDeleteView.as_view(), name='asset-delete'),
url(r'^asset-modal$', views.AssetModalListView.as_view(), name='asset-modal-list'),
# Resource asset group url # Resource asset group url
url(r'^asset-group$', views.AssetGroupListView.as_view(), name='asset-group-list'), url(r'^asset-group$', views.AssetGroupListView.as_view(), name='asset-group-list'),
...@@ -50,5 +52,13 @@ urlpatterns = [ ...@@ -50,5 +52,13 @@ urlpatterns = [
url(r'^system-user/(?P<pk>[0-9]+)/asset$', views.SystemUserAssetView.as_view(), name='system-user-asset'), url(r'^system-user/(?P<pk>[0-9]+)/asset$', views.SystemUserAssetView.as_view(), name='system-user-asset'),
# url(r'^system-user/(?P<pk>[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(), # url(r'^system-user/(?P<pk>[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(),
# name='system-user-asset-group'), # name='system-user-asset-group'),
# url(r'^api/v1.0/', include(router.urls)),
]
urlpatterns += [
#json
url(r'^v1/assets/$', api.AssetViewSet.as_view({'get':'list'}), name='assets-list-api'),
url(r'^v1/idc/$', api.IDCViewSet.as_view({'get':'list'}), name='idc-list-json'),
] ]
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
from rest_framework import serializers
from models import Asset
...@@ -100,6 +100,22 @@ class AssetDetailView(DetailView): ...@@ -100,6 +100,22 @@ class AssetDetailView(DetailView):
kwargs.update(context) kwargs.update(context)
return super(AssetDetailView, self).get_context_data(**kwargs) return super(AssetDetailView, self).get_context_data(**kwargs)
class AssetModalListView(AdminUserRequiredMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
model = Asset
context_object_name = 'asset_modal_list'
template_name = 'assets/asset_modal_list.html'
def get_context_data(self, **kwargs):
group_id = self.request.GET.get('group_id')
if group_id:
group = AssetGroup.objects.get(id=group_id)
context = {
'group_assets':[x.id for x in group.assets.all()]
}
kwargs.update(context)
return super(AssetModalListView, self).get_context_data(**kwargs)
class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
model = AssetGroup model = AssetGroup
...@@ -113,8 +129,7 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): ...@@ -113,8 +129,7 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
'action': _('Create asset group'), 'action': _('Create asset group'),
'assets': Asset.objects.all(), 'assets_count': 0,
# 'systemusers':SystemUser.objects.all(),
} }
kwargs.update(context) kwargs.update(context)
return super(AssetGroupCreateView, self).get_context_data(**kwargs) return super(AssetGroupCreateView, self).get_context_data(**kwargs)
...@@ -123,7 +138,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): ...@@ -123,7 +138,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
asset_group = form.save() asset_group = form.save()
assets_id_list = self.request.POST.getlist('assets', []) assets_id_list = self.request.POST.getlist('assets', [])
assets = [get_object_or_404(Asset, id=asset_id) for asset_id in assets_id_list] assets = [get_object_or_404(Asset, id=int(asset_id)) for asset_id in assets_id_list]
print assets
asset_group.created_by = self.request.user.username or 'Admin' asset_group.created_by = self.request.user.username or 'Admin'
asset_group.assets.add(*tuple(assets)) asset_group.assets.add(*tuple(assets))
asset_group.save() asset_group.save()
...@@ -148,11 +164,9 @@ class AssetGroupListView(AdminUserRequiredMixin, ListView): ...@@ -148,11 +164,9 @@ class AssetGroupListView(AdminUserRequiredMixin, ListView):
self.queryset = super(AssetGroupListView, self).get_queryset() self.queryset = super(AssetGroupListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '') self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created') self.sort = sort = self.request.GET.get('sort', '-date_created')
if keyword: if keyword:
self.queryset = self.queryset.filter(Q(name__icontains=keyword) | self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
Q(comment__icontains=keyword)) Q(comment__icontains=keyword))
if sort: if sort:
self.queryset = self.queryset.order_by(sort) self.queryset = self.queryset.order_by(sort)
return self.queryset return self.queryset
...@@ -178,19 +192,23 @@ class AssetGroupDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView): ...@@ -178,19 +192,23 @@ class AssetGroupDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView):
kwargs.update(context) kwargs.update(context)
return super(AssetGroupDetailView, self).get_context_data(**kwargs) return super(AssetGroupDetailView, self).get_context_data(**kwargs)
class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView): class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
model = AssetGroup model = AssetGroup
form_class = AssetGroupForm form_class = AssetGroupForm
template_name = 'assets/asset_group_create.html' template_name = 'assets/asset_group_create.html'
success_url = reverse_lazy('assets:asset-group-list') success_url = reverse_lazy('assets:asset-group-list')
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetGroup.objects.all())
return super(AssetGroupUpdateView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
'action': _('Create asset group'), 'action': _('Create asset group'),
'assets': Asset.objects.all(), # 'assets': Asset.objects.all(),
'assets_count': self.object.assets.all().count(),
'group_id':self.object.id,
} }
kwargs.update(context) kwargs.update(context)
return super(AssetGroupUpdateView, self).get_context_data(**kwargs) return super(AssetGroupUpdateView, self).get_context_data(**kwargs)
...@@ -283,6 +301,7 @@ class IDCDeleteView(AdminUserRequiredMixin, DeleteView): ...@@ -283,6 +301,7 @@ class IDCDeleteView(AdminUserRequiredMixin, DeleteView):
success_url = reverse_lazy('assets:idc-list') success_url = reverse_lazy('assets:idc-list')
class AdminUserListView(AdminUserRequiredMixin, ListView): class AdminUserListView(AdminUserRequiredMixin, ListView):
model = AdminUser model = AdminUser
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
...@@ -527,3 +546,5 @@ class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView): ...@@ -527,3 +546,5 @@ class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
# kwargs.update(context) # kwargs.update(context)
# return super(SystemUserAssetGroupView, self).get_context_data(**kwargs) # return super(SystemUserAssetGroupView, self).get_context_data(**kwargs)
This diff is collapsed.
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
This source diff could not be displayed because it is too large. You can view the blob instead.
File mode changed from 100755 to 100644
This diff is collapsed.
/**
* English - this is the default DataTables ships with
* @name English
* @anchor English
* @author <a href="http://www.sprymedia.co.uk/">Allan Jardine</a>
*/
{
"sEmptyTable": "No data available in table",
"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
"sInfoEmpty": "Showing 0 to 0 of 0 entries",
"sInfoFiltered": "(filtered from _MAX_ total entries)",
"sInfoPostFix": "",
"sInfoThousands": ",",
"sLengthMenu": "Show _MENU_ entries",
"sLoadingRecords": "Loading...",
"sProcessing": "Processing...",
"sSearch": "Search:",
"sZeroRecords": "No matching records found",
"oPaginate": {
"sFirst": "First",
"sLast": "Last",
"sNext": "Next",
"sPrevious": "Previous"
},
"oAria": {
"sSortAscending": ": activate to sort column ascending",
"sSortDescending": ": activate to sort column descending"
}
}
\ No newline at end of file
{
"sProcessing": "处理中...",
"sLengthMenu": "显示 _MENU_ 项结果",
"sZeroRecords": "没有匹配结果",
"sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
"sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
"sInfoFiltered": "(由 _MAX_ 项结果过滤)",
"sInfoPostFix": "",
"sSearch": "搜索:",
"sUrl": "",
"sEmptyTable": "表中数据为空",
"sLoadingRecords": "载入中...",
"sInfoThousands": ",",
"oPaginate": {
"sFirst": "首页",
"sPrevious": "上页",
"sNext": "下页",
"sLast": "末页"
},
"oAria": {
"sSortAscending": ": 以升序排列此列",
"sSortDescending": ": 以降序排列此列"
}
}
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %}
{% load common_tags %} {% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/dataTables/dataTables.min.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/dataTables/dataTables.min.js" %}"></script>
{% endblock %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
...@@ -19,10 +24,10 @@ ...@@ -19,10 +24,10 @@
</a> </a>
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<div class=""> <div class="">
{% block content_left_head %} {% endblock %} {% block content_left_head %} {% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right mail-search"> <form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}"> <input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
...@@ -33,8 +38,9 @@ ...@@ -33,8 +38,9 @@
</div> </div>
</div> </div>
</form> </form>
{% endblock %}
</div> </div>
{% block table_container %}
<table class="table table-striped table-bordered table-hover " id="editable" > <table class="table table-striped table-bordered table-hover " id="editable" >
<thead> <thead>
<tr> <tr>
...@@ -45,17 +51,19 @@ ...@@ -45,17 +51,19 @@
{% block table_body %} {% endblock %} {% block table_body %} {% endblock %}
</tbody> </tbody>
</table> </table>
{% endblock %}
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col-sm-4">
{# Update batch #} {# Update batch #}
{% block content_bottom_left %} {% endblock %} {% block content_bottom_left %} {% endblock %}
</div> </div>
{% block table_pagination %}
{% include '_pagination.html' %} {% include '_pagination.html' %}
{% endblock %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
import logging import logging
from rest_framework import generics from rest_framework import generics
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from .serializers import UserSerializer, UserGroupSerializer, UserAttributeSerializer, UserGroupEditSerializer, \ from .serializers import UserSerializer, UserGroupSerializer, UserAttributeSerializer, UserGroupEditSerializer, \
GroupEditSerializer, UserPKUpdateSerializer GroupEditSerializer, UserPKUpdateSerializer, UserBulkUpdateSerializer
from .models import User, UserGroup from .models import User, UserGroup
...@@ -92,3 +93,21 @@ class UserUpdatePKApi(generics.UpdateAPIView): ...@@ -92,3 +93,21 @@ class UserUpdatePKApi(generics.UpdateAPIView):
class GroupDeleteApi(generics.DestroyAPIView): class GroupDeleteApi(generics.DestroyAPIView):
queryset = UserGroup.objects.all() queryset = UserGroup.objects.all()
serializer_class = GroupEditSerializer serializer_class = GroupEditSerializer
class UserBulkUpdateApi(ListBulkCreateUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserBulkUpdateSerializer
def filter_queryset(self, queryset):
id_list = self.request.query_params.get('id__in')
if id_list:
import json
try:
ids = json.loads(id_list)
except Exception as e:
logger.error(str(e))
return queryset
if isinstance(ids, list):
queryset = queryset.filter(id__in=ids)
return queryset
...@@ -215,6 +215,11 @@ class User(AbstractUser): ...@@ -215,6 +215,11 @@ class User(AbstractUser):
user.save() user.save()
user.groups.add(UserGroup.initial()) user.groups.add(UserGroup.initial())
def delete(self):
if self.is_superuser:
return
return super(User, self).delete()
@classmethod @classmethod
def generate_fake(cls, count=100): def generate_fake(cls, count=100):
from random import seed, choice from random import seed, choice
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin
from .models import User, UserGroup from .models import User, UserGroup
...@@ -67,3 +68,22 @@ class UserPKUpdateSerializer(serializers.ModelSerializer): ...@@ -67,3 +68,22 @@ class UserPKUpdateSerializer(serializers.ModelSerializer):
print e print e
raise serializers.ValidationError(_('Not a valid ssh public key')) raise serializers.ValidationError(_('Not a valid ssh public key'))
return value return value
class UserBulkUpdateSerializer(BulkSerializerMixin, serializers.ModelSerializer):
group_display = serializers.SerializerMethodField()
active_display = serializers.SerializerMethodField()
class Meta(object):
model = User
list_serializer_class = BulkListSerializer
fields = ['id', 'is_active', 'username', 'name', 'email', 'role', 'avatar',
'enable_otp', 'comment', 'groups', 'get_role_display',
'group_display', 'active_display']
def get_group_display(self, obj):
return " ".join([group.name for group in obj.groups.all()])
def get_active_display(self, obj):
# TODO: user ative state
return not (obj.is_expired and obj.is_active)
This diff is collapsed.
...@@ -36,6 +36,7 @@ urlpatterns = [ ...@@ -36,6 +36,7 @@ urlpatterns = [
urlpatterns += [ urlpatterns += [
url(r'^v1/users$', api.UserListAddApi.as_view(), name='user-list-api'), url(r'^v1/users$', api.UserListAddApi.as_view(), name='user-list-api'),
url(r'^v1/users/update/$', api.UserBulkUpdateApi.as_view(), name='user-bulk-update-api'),
url(r'^v1/users/(?P<pk>[0-9]+)$', url(r'^v1/users/(?P<pk>[0-9]+)$',
api.UserDetailDeleteUpdateApi.as_view(), name='user-detail-api'), api.UserDetailDeleteUpdateApi.as_view(), name='user-detail-api'),
url(r'^v1/users/(?P<pk>[0-9]+)/patch$', url(r'^v1/users/(?P<pk>[0-9]+)/patch$',
......
...@@ -19,3 +19,4 @@ ansible==2.1.1.0 ...@@ -19,3 +19,4 @@ ansible==2.1.1.0
django-simple-captcha==0.5.2 django-simple-captcha==0.5.2
django-formtools==1.0 django-formtools==1.0
sshpubkeys==2.2.0 sshpubkeys==2.2.0
djangorestframework-bulk==0.2.1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment