Commit c1c9c7b6 authored by ibuler's avatar ibuler

update asset

parent 6e843533
......@@ -60,38 +60,6 @@ class IDC(models.Model):
continue
class AssetExtend(models.Model):
key = models.CharField(max_length=64, verbose_name=_('KEY'))
value = models.CharField(max_length=64, verbose_name=_('VALUE'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
date_created = models.DateTimeField(auto_now_add=True, null=True)
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return '%(key)s: %(value)s' % {'key': self.key, 'value': self.value}
@classmethod
def initial(cls):
for k, v in (
(_('status'), _('In use')),
(_('status'), _('Out of use')),
(_('type'), _('Server')),
(_('type'), _('VM')),
(_('type'), _('Switch')),
(_('type'), _('Router')),
(_('type'), _('Firewall')),
(_('type'), _('Storage')),
(_('env'), _('Production')),
(_('env'), _('Development')),
(_('env'), _('Testing')),
):
cls.objects.create(key=k, value=v, created_by='System')
class Meta:
db_table = 'asset_extend'
unique_together = ('key', 'value')
def private_key_validator(value):
if not validate_ssh_private_key(value):
raise ValidationError(
......@@ -298,18 +266,29 @@ class AssetGroup(models.Model):
continue
def get_default_extend(key, value):
try:
return AssetExtend.objects.get_or_create(key=key, value=value)[0]
except:
return None
def get_default_idc():
return IDC.initial()
class Asset(models.Model):
STATUS_CHOICES = (
('In use', _('In use')),
('Out of use', _('Out of use')),
)
TYPE_CHOICES = (
('Server', _('Server')),
('VM', _('VM')),
('Switch', _('Switch')),
('Router', _('Router')),
('Firewall', _('Firewall')),
('Storage', _("Storage")),
)
ENV_CHOICES = (
('Prod', 'Production'),
('Dev', 'Development'),
('Test', 'Testing'),
)
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
other_ip = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('Other IP'))
remote_card_ip = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Remote card IP'))
......@@ -330,15 +309,12 @@ class Asset(models.Model):
cabinet_no = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Cabinet number'))
cabinet_pos = models.IntegerField(null=True, blank=True, verbose_name=_('Cabinet position'))
number = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Asset number'))
status = models.ForeignKey(AssetExtend, null=True, blank=True,
related_name="status_asset", verbose_name=_('Asset status'),)
# default=functools.partial(get_default_extend, 'status', 'In use'))
type = models.ForeignKey(AssetExtend, blank=True,null=True, limit_choices_to={'key': 'type'},
related_name="type_asset", verbose_name=_('Asset type'),)
# default=functools.partial(get_default_extend, 'type','Server'))
env = models.ForeignKey(AssetExtend, blank=True, null=True, limit_choices_to={'key': 'env'},
related_name="env_asset", verbose_name=_('Asset environment'),)
# default=functools.partial(get_default_extend, 'env', 'Production'))
status = models.CharField(choices=STATUS_CHOICES, max_length=1, null=True, blank=True,
default='I', verbose_name=_('Asset status'))
type = models.CharField(choices=TYPE_CHOICES, max_length=16, blank=True, null=True,
default='Server', verbose_name=_('Asset type'),)
env = models.CharField(choices=ENV_CHOICES, max_length=8, blank=True, null=True,
default='P', verbose_name=_('Asset environment'),)
sn = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Serial number'))
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
......@@ -404,7 +380,7 @@ class Tag(models.Model):
def init_all_models():
for cls in (AssetExtend, AssetGroup):
for cls in (AssetGroup,):
cls.initial()
......@@ -414,5 +390,5 @@ def generate_fake():
def flush_all():
for cls in (AssetGroup, AssetExtend, IDC, AdminUser, SystemUser, Asset):
for cls in (AssetGroup, IDC, AdminUser, SystemUser, Asset):
cls.objects.all().delete()
# -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _
from rest_framework import viewsets, serializers,generics
from .models import AssetGroup, Asset, IDC, AssetExtend, AdminUser, SystemUser
from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser
from common.mixins import IDInFilterMixin
from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin
......
......@@ -18,10 +18,11 @@
{% block table_search %}
<div class="html5buttons">
<div class="dt-buttons btn-group">
<a class="btn btn-default buttons-pdf" tabindex="0" href="#">
<span>PDF</span></a>
<a class="btn btn-default buttons-excel" tabindex="0" href="#">
<span>Excel</span>
<a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0">
<span>{% trans "Import" %}</span>
</a>
<a class="btn btn-default btn_export" tabindex="0">
<span>{% trans "Export" %}</span>
</a>
</div>
</div>
......@@ -32,7 +33,7 @@
<div class="tagBtnList">
{% for tag in tag_list %}
<a href="{% url 'assets:asset-tags' tag_id=tag.0 %}"
{% if tag.0|IntToStr == tag_id %}
{% if tag.0|int_to_str == tag_id %}
class="tagBtn2 label label-warning" name="tag_on">
{% else %}
class="tagBtn2 label label-default">
......@@ -84,7 +85,7 @@
{% block custom_foot_js %}
<script type="text/javascript">
window.onload=function (){
window.onload = function (){
var tag_on = document.getElementsByName("tag_on");
var oDiv = document.getElementById("ydxbd");
if(tag_on.length > 0){
......@@ -136,6 +137,27 @@
op_html: $('#actions').html()
};
var table = jumpserver.initDataTable(options);
$('.btn_export').click(function () {
var assets = [];
var rows = table.rows('.selected').data();
$.each(rows, function (index, obj) {
assets.push(obj.id)
});
$.ajax({
url: "{% url "assets:export-assets-xlsx" %}",
method: 'POST',
data: JSON.stringify({users_id: users}),
dataType: "json",
success: function (data, textStatus) {
window.open(data.redirect)
},
error: function () {
toastr.error('Export failed');
}
})
});
});
</script>
{% endblock %}
\ No newline at end of file
# coding:utf-8
from __future__ import absolute_import, unicode_literals
import json
import uuid
from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_workbook
from openpyxl import load_workbook
from django.utils.translation import ugettext as _
from django.conf import settings
from django.db.models import Q
from django.views.generic import TemplateView, ListView
from django.views.generic import TemplateView, ListView, View
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from django.shortcuts import get_object_or_404, reverse, redirect
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator
from django.core.cache import cache
from django.utils import timezone
from common.utils import int_seq
from .utils import CreateAssetTagsMiXin,UpdateAssetTagsMiXin
from .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser, Tag
from .models import Asset, AssetGroup, IDC, AdminUser, SystemUser, Tag
from .forms import *
from .hands import AdminUserRequiredMixin
......@@ -693,3 +705,46 @@ class AssetTagDeleteView(AdminUserRequiredMixin, DeleteView):
model = Tag
success_url = reverse_lazy('assets:asset-tag-list')
@method_decorator(csrf_exempt, name='dispatch')
class ExportAssetView(View):
@staticmethod
def asset_get_attr(asset, attr):
if attr in ['admin_user', 'idc']:
return getattr(asset, attr).name
if attr in ['status', 'tyoe', 'env']:
return getattr(asset, 'get_{}_display')
def get(self, request, *args, **kwargs):
spm = request.GET.get('spm', '')
assets_id = cache.get(spm)
if not assets_id and not isinstance(assets_id, list):
return HttpResponse('May be expired', status=404)
assets = Asset.objects.filter(id__in=assets_id)
wb = Workbook()
ws = wb.active
ws.title = 'Asset'
header = ['hostname', 'ip', 'port', 'admin_user', 'system_users', 'idc',
'cpu', 'memory', 'disk', 'mac_address', 'other_ip', 'remote_card_ip',
'os', 'cabinet_no', 'cabinet_pos', 'number', 'status', 'type', 'env',
'sn', 'comment']
ws.append(header)
for asset in assets:
ws.append([getattr(asset, attr) for attr in header])
filename = 'users-{}.xlsx'.format(timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response
def post(self, request, *args, **kwargs):
try:
assets_id = json.loads(request.body).get('assets_id', [])
except ValueError:
return HttpResponse('Json object not valid', status=400)
spm = uuid.uuid4().get_hex()
cache.set(spm, assets_id, 300)
url = reverse('users:export-user-csv') + '?spm=%s' % spm
return JsonResponse({'redirect': url})
[{"model": "users.usergroup", "pk": 1, "fields": {"is_discard": false, "discard_time": null, "name": "Default", "comment": "Default user group for all user", "date_created": "2016-11-02T14:49:50Z", "created_by": "System"}}, {"model": "assets.assetextend", "pk": 1, "fields": {"key": "status", "value": "In use", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 2, "fields": {"key": "status", "value": "Out of use", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 3, "fields": {"key": "type", "value": "Server", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 4, "fields": {"key": "type", "value": "VM", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 5, "fields": {"key": "type", "value": "Switch", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 6, "fields": {"key": "type", "value": "Router", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 7, "fields": {"key": "type", "value": "Firewall", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 8, "fields": {"key": "type", "value": "Storage", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 9, "fields": {"key": "env", "value": "Production", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 10, "fields": {"key": "env", "value": "Development", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetextend", "pk": 11, "fields": {"key": "env", "value": "Testing", "created_by": "System", "date_created": "2016-11-02T14:51:53Z", "comment": ""}}, {"model": "assets.assetgroup", "pk": 1, "fields": {"name": "Default", "created_by": "", "date_created": "2016-11-02T14:51:53Z", "comment": "Default asset group", "system_users": []}}, {"model": "users.user", "pk": 2, "fields": {"password": "pbkdf2_sha256$30000$y45nsj5IDfVi$KUXoECb9rZJZ2ZosQSxi9anmj2oY5LAr1MdJby/xEzU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-11-02T14:51:45Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-10-16T14:51:45Z", "created_by": "System", "user_permissions": [], "groups": [1]}}]
[{"model": "users.usergroup", "pk": 1, "fields": {"is_discard": false, "discard_time": null, "name": "Default", "comment": "Default user group for all user", "date_created": "2016-11-25T06:50:28.410Z", "created_by": "System"}}, {"model": "assets.assetgroup", "pk": 1, "fields": {"name": "Default", "created_by": "", "date_created": "2016-11-25T06:50:28.627Z", "comment": "Default asset group", "system_users": []}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$RwSpXYAYQGbQ$PADpsQmM+cO5Y/R1CVSx3qNV4EbGIm2k+iMBXUtwvNc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-11-25T06:50:28.412Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-11-08T06:50:28.412Z", "created_by": "System", "user_permissions": [], "groups": [1]}}]
\ No newline at end of file
# ~*~ coding: utf-8 ~*~
#
import base64
import json
from django.shortcuts import get_object_or_404
from django.core.cache import cache
from django.conf import settings
from rest_framework import generics, status, viewsets
from rest_framework import generics, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView, BulkModelViewSet
from rest_framework import authentication
import django_filters
from rest_framework_bulk import BulkModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
from common.mixins import IDInFilterMixin
......@@ -78,7 +73,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
user.save()
class UserGroupViewSet(viewsets.ModelViewSet):
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
queryset = UserGroup.objects.all()
serializer_class = serializers.UserGroupSerializer
......@@ -88,52 +83,7 @@ class UserGroupUpdateUserApi(generics.RetrieveUpdateAPIView):
serializer_class = serializers.UserGroupUpdateMemeberSerializer
permission_classes = (IsSuperUser,)
# class GroupDetailApi(generics.RetrieveUpdateDestroyAPIView):
# queryset = UserGroup.objects.all()
# serializer_class = serializers.GroupDetailSerializer
#
# def perform_update(self, serializer):
# users = serializer.validated_data.get('users')
# if users:
# group = self.get_object()
# Note: use `list` method to force hitting the db.
# group_users = list(group.users.all())
# serializer.save()
# group.users.set(users + group_users)
# group.save()
# return
# serializer.save()
# class UserListUpdateApi(BulkDeleteApiMixin, ListBulkCreateUpdateDestroyAPIView):
# queryset = User.objects.all()
# serializer_class = serializers.UserBulkUpdateSerializer
# permission_classes = (IsSuperUserOrTerminalUser,)
#
# def get(self, request, *args, **kwargs):
# return super(UserListUpdateApi, self).get(request, *args, **kwargs)
#
# class GroupListUpdateApi(BulkDeleteApiMixin, ListBulkCreateUpdateDestroyAPIView):
# queryset = UserGroup.objects.all()
# serializer_class = serializers.GroupBulkUpdateSerializer
#
# class DeleteUserFromGroupApi(generics.DestroyAPIView):
# queryset = UserGroup.objects.all()
# serializer_class = serializers.GroupDetailSerializer
#
# def destroy(self, request, *args, **kwargs):
# group = self.get_object()
# self.perform_destroy(group, **kwargs)
# return Response(status=status.HTTP_204_NO_CONTENT)
#
# def perform_destroy(self, instance, **kwargs):
# user_id = kwargs.get('uid')
# user = get_object_or_404(User, id=user_id)
# instance.users.remove(user)
#
#
class UserAuthApi(APIView):
permission_classes = ()
expiration = settings.CONFIG.TOKEN_EXPIRATION or 3600
......
......@@ -47,8 +47,11 @@ $(document).ready(function() {
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "users:user-group-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete_user_group" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
var update_btn = '<a href="{% url "users:user-group-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete_user_group" data-gid="99991937" data-name="99991938">{% trans "Delete" %}</a>'
.replace('99991937', cellData)
.replace('99991938', rowData.name);
if (rowData.id === 1) {
$(td).html(update_btn)
} else {
......@@ -63,38 +66,10 @@ $(document).ready(function() {
jumpserver.initDataTable(options);
}).on('click', '.btn_delete_user_group', function(){
var $this = $(this);
function doDelete() {
var group_id = $this.data('gid');
var the_url = "{% url 'api-users:user-group-detail' pk=99991937 %}".replace('99991937', group_id);
var body = {};
var success = function() {
var msg = "{% trans 'Group Deleted.' %}";
swal("{% trans 'Group Delete' %}", msg, "success");
$this.closest('tr.gradeX').remove();
};
var fail = function() {
var msg = "{% trans 'Group Deleting failed.' %}";
swal("{% trans 'Group Delete' %}", msg, "error");
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
method: 'DELETE',
success: success,
error: fail
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected group, but will not remove any user in this group.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doDelete();
});
var group_id = $this.data('gid');
var name = $this.data('name');
var the_url = "{% url 'api-users:user-group-detail' pk=99991937 %}".replace('99991937', group_id);
objectDelete($this, name, the_url)
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var $data_table = $('#group_list_table').DataTable()
......
......@@ -99,7 +99,7 @@ $(document).ready(function(){
users.push(obj.id)
});
$.ajax({
url: "{% url "users:export-user-csv" %}",
url: "{% url "users:export-user" %}",
method: 'POST',
data: JSON.stringify({users_id: users}),
dataType: "json",
......
......@@ -40,5 +40,5 @@ urlpatterns = [
name='user-group-asset-permission-create'),
url(r'^user-group/(?P<pk>[0-9]+)/assets', views.UserGroupGrantedAssetView.as_view(),
name='user-group-granted-asset'),
url(r'^export/user/csv/', views.ExportUserCsvView.as_view(), name='export-user-csv'),
url(r'^export/user/', views.ExportUserView.as_view(), name='export-user'),
]
......@@ -240,10 +240,6 @@ class UserGroupDetailView(AdminUserRequiredMixin, DetailView):
return super(UserGroupDetailView, self).get_context_data(**kwargs)
class UserGroupDeleteView(DeleteView):
pass
class UserForgotPasswordView(TemplateView):
template_name = 'users/forgot_password.html'
......@@ -561,7 +557,7 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
@method_decorator(csrf_exempt, name='dispatch')
class ExportUserCsvView(View):
class ExportUserView(View):
def get(self, request, *args, **kwargs):
spm = request.GET.get('spm', '')
users_id = cache.get(spm)
......
#!/bin/bash
#
for app in users assets perms audits teminal ops;do
rm -f $app/migrations/000*
done
#!/bin/bash
#
python ../apps/manage.py loaddata init
#!/bin/bash
#
python ../apps/manage.py dbshell << EOF
delete from django_content_type;
delete from auth_permission;
EOF
python ../apps/manage.py dumpdata > ../apps/fixtures/init.json
#!/bin/bash
#
python ../apps/manage.py shell << EOF
from users.models import *
init_all_models()
from assets.models import *
init_all_models()
EOF
python ../apps/manage.py dbshell << EOF
delete from django_content_type;
delete from auth_permission;
EOF
python ../apps/manage.py dumpdata > ../apps/fixtures/init.json
#!/bin/bash
#
python ../apps/manage.py makemigrations
python ../apps/manage.py migrate
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