diff --git a/apps/assets/api.py b/apps/assets/api.py index e3570e0f1..896aadc88 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -6,17 +6,18 @@ from rest_framework.views import APIView from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin, ListBulkCreateUpdateDestroyAPIView from django.shortcuts import get_object_or_404 -from common.mixins import BulkDeleteApiMixin +from common.mixins import IDInFilterMixin from common.utils import get_object_or_none, signer from .hands import IsSuperUserOrTerminalUser, IsSuperUser from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser from . import serializers -class AssetViewSet(viewsets.ModelViewSet): +class AssetViewSet(IDInFilterMixin, viewsets.ModelViewSet): """API endpoint that allows Asset to be viewed or edited.""" queryset = Asset.objects.all() serializer_class = serializers.AssetSerializer + filter_fields = ('id', 'ip', 'hostname') def get_queryset(self): queryset = super(AssetViewSet, self).get_queryset() @@ -27,7 +28,6 @@ class AssetViewSet(viewsets.ModelViewSet): if asset_group_id: queryset = queryset.filter(groups__id=asset_group_id) - return queryset @@ -71,7 +71,7 @@ class SystemUserViewSet(viewsets.ModelViewSet): # return self.object.assets.all() -class AssetListUpdateApi(BulkDeleteApiMixin, ListBulkCreateUpdateDestroyAPIView): +class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): queryset = Asset.objects.all() serializer_class = serializers.AssetSerializer permission_classes = (IsSuperUser,) diff --git a/apps/assets/forms.py b/apps/assets/forms.py index 09fcc9a24..aeb7062cb 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -309,4 +309,8 @@ class AssetTagForm(forms.ModelForm): } help_texts = { 'name': '* required', - } \ No newline at end of file + } + + +class FileForm(forms.Form): + file = forms.FileField() \ No newline at end of file diff --git a/apps/assets/models.py b/apps/assets/models.py index 1b13b8621..aa22a2f02 100644 --- a/apps/assets/models.py +++ b/apps/assets/models.py @@ -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( @@ -233,6 +201,10 @@ class SystemUser(models.Model): def assets_amount(self): return self.assets.count() + @property + def asset_group_amount(self): + return self.asset_groups.count() + class Meta: db_table = 'system_user' @@ -294,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')) @@ -326,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=8, null=True, blank=True, + default='In use', 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='Prod', 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')) @@ -400,7 +380,7 @@ class Tag(models.Model): def init_all_models(): - for cls in (AssetExtend, AssetGroup): + for cls in (AssetGroup,): cls.initial() @@ -410,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() diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py index 9613da621..7b13606e5 100644 --- a/apps/assets/serializers.py +++ b/apps/assets/serializers.py @@ -1,8 +1,8 @@ # -*- 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 common.mixins import BulkDeleteApiMixin +from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser +from common.mixins import IDInFilterMixin from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin @@ -35,7 +35,7 @@ class SystemUserSerializer(serializers.ModelSerializer): def get_field_names(self, declared_fields, info): fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) - fields.append('assets_amount') + fields.extend(['assets_amount']) return fields @@ -43,7 +43,6 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): # system_users = SystemUserSerializer(many=True, read_only=True) # admin_user = AdminUserSerializer(many=False, read_only=True) hardware = serializers.SerializerMethodField() - type_display = serializers.SerializerMethodField() class Meta(object): model = Asset @@ -51,15 +50,16 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): @staticmethod def get_hardware(obj): - return '%s %s %s' % (obj.cpu, obj.memory, obj.disk) - - @staticmethod - def get_type_display(obj): - if obj.type: - return obj.type.value + if obj.cpu: + return '%s %s %s' % (obj.cpu, obj.memory, obj.disk) else: return '' + def get_field_names(self, declared_fields, info): + fields = super(AssetSerializer, self).get_field_names(declared_fields, info) + fields.extend(['get_type_display', 'get_env_display']) + return fields + class AssetGrantedSerializer(serializers.ModelSerializer): system_users = SystemUserSerializer(many=True, read_only=True) diff --git a/apps/assets/templates/assets/_asset_import_modal.html b/apps/assets/templates/assets/_asset_import_modal.html new file mode 100644 index 000000000..72d13f7a8 --- /dev/null +++ b/apps/assets/templates/assets/_asset_import_modal.html @@ -0,0 +1,27 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}asset_import_modal{% endblock %} +{% block modal_title%}{% trans "Import asset" %}{% endblock %} +{% block modal_body %} +

{% trans "Download template or use export excel format" %}

+
+ {% csrf_token %} +
+ + {% trans 'Download' %} +
+
+ + +
+
+

+

+

+

+

+

+

+

+{% endblock %} +{% block modal_confirm_id %}btn_asset_import{% endblock %} diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html index ea35972a0..35d6b6789 100644 --- a/apps/assets/templates/assets/admin_user_list.html +++ b/apps/assets/templates/assets/admin_user_list.html @@ -39,13 +39,6 @@ $(document).ready(function(){ var innerHtml = cellData.length > 8 ? cellData.substring(0, 24) + '...': cellData; $(td).html('' + innerHtml + ''); }}, -{# {targets: 6, createdCell: function (td, cellData) {#} -{# if (!cellData) {#} -{# $(td).html('')#} -{# } else {#} -{# $(td).html('')#} -{# }#} -{# }},#} {targets: 6, createdCell: function (td, cellData, rowData) { var script_btn = '{% trans "Script" %}'.replace('99991937', cellData); var update_btn = '{% trans "Update" %}'.replace('99991937', cellData); @@ -55,7 +48,6 @@ $(document).ready(function(){ ajax_url: '{% url "api-assets:admin-user-list" %}', columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: function () {return 'lost'} }, {data: "comment" }, {data: "id" }], - op_html: $('#actions').html() }; jumpserver.initDataTable(options); }); diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html index 22af9acaa..bc3a7b147 100644 --- a/apps/assets/templates/assets/asset_detail.html +++ b/apps/assets/templates/assets/asset_detail.html @@ -96,7 +96,7 @@ {% trans 'Asset status' %}: - {{ asset.status }} + {{ asset.get_status_display() }} {% trans 'Is active' %}: diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index c50361782..a2b1c306c 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -18,10 +18,11 @@ {% block table_search %}
- - PDF - - Excel + + {% trans "Import" %} + + + {% trans "Export" %}
@@ -32,7 +33,7 @@
{% for tag in tag_list %} {% else %} class="tagBtn2 label label-default"> @@ -47,7 +48,6 @@ {% block table_container %}
{% trans "Create asset" %}
-
{% trans "Import asset" %}
@@ -80,11 +80,13 @@ +{% include 'assets/_asset_import_modal.html' %} {% endblock %} {% block custom_foot_js %} + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html index fb1e41323..77526ff37 100644 --- a/apps/assets/templates/assets/system_user_list.html +++ b/apps/assets/templates/assets/system_user_list.html @@ -1,43 +1,60 @@ {% extends '_base_list.html' %} {% load i18n %} {% load common_tags %} -{% block content_left_head %} + +{% block table_search %} +{% endblock %} + +{% block table_container %} +
{% trans "Create system user" %} +
+
+ + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Username' %}{% trans 'Asset' %}{% trans 'Unreachable' %}{% trans 'Comment' %}{% trans 'Action' %}
+{% endblock %} +{% block custom_foot_js %} + {% endblock %} -{% block table_head %} - {% trans 'ID' %} - {% trans 'Name' %} - {% trans 'Username' %} - {% trans 'Asset num' %} - {% trans 'Asset group num' %} - {% trans 'Unreachable' %} - {% trans 'Comment' %} - -{% endblock %} -{% block table_body %} - {% for system_user in system_user_list %} - - {{ system_user.id }} - - - {{ system_user.name }} - - - {{ system_user.username }} - {{ system_user.get_assets|length }} - {{ system_user.asset_groups.count }} - {{ system_user.assets.count }} - {{ system_user.comment|truncatewords:4 }} - - - {% trans 'Script' %} - - {% trans 'Refresh' %} - {% trans 'Update' %} - {% trans 'Delete' %} - - - {% endfor %} -{% endblock %} + diff --git a/apps/assets/urls/views_urls.py b/apps/assets/urls/views_urls.py index 7b1f4e1bc..a2b4537a3 100644 --- a/apps/assets/urls/views_urls.py +++ b/apps/assets/urls/views_urls.py @@ -9,6 +9,8 @@ urlpatterns = [ url(r'^$', views.AssetListView.as_view(), name='asset-index'), url(r'^asset/$', views.AssetListView.as_view(), name='asset-list'), url(r'^asset/create/$', views.AssetCreateView.as_view(), name='asset-create'), + url(r'^asset/export/$', views.AssetExportView.as_view(), name='asset-export'), + url(r'^asset/import/$', views.BulkImportAssetView.as_view(), name='asset-import'), url(r'^asset/(?P[0-9]+)/$', views.AssetDetailView.as_view(), name='asset-detail'), url(r'^asset/(?P[0-9]+)/update/$', views.AssetUpdateView.as_view(), name='asset-update'), url(r'^asset/(?P[0-9]+)/delete/$', views.AssetDeleteView.as_view(), name='asset-delete'), diff --git a/apps/assets/views.py b/apps/assets/views.py index 31619621d..7070d78bf 100644 --- a/apps/assets/views.py +++ b/apps/assets/views.py @@ -1,18 +1,32 @@ # 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.db import IntegrityError +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 common.utils import int_seq -from .utils import CreateAssetTagsMiXin,UpdateAssetTagsMiXin -from .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser, Tag -from .forms import * +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.mixins import JSONResponseMixin +from common.utils import get_object_or_none +from .utils import CreateAssetTagsMiXin, UpdateAssetTagsMiXin +from . import forms +from .models import Asset, AssetGroup, AdminUser, IDC, SystemUser, Tag from .hands import AdminUserRequiredMixin @@ -33,7 +47,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView): model = Asset tag_type = 'asset' - form_class = AssetCreateForm + form_class = forms.AssetCreateForm template_name = 'assets/asset_create.html' success_url = reverse_lazy('assets:asset-list') @@ -59,7 +73,7 @@ class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView): class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListView): model = Asset - form_class = AssetCreateForm + form_class = forms.AssetCreateForm template_name = 'assets/asset_modal_update.html' success_url = reverse_lazy('assets:asset-list') @@ -87,7 +101,7 @@ class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListVie class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView): model = Asset - form_class = AssetCreateForm + form_class = forms.AssetCreateForm template_name = 'assets/asset_update.html' success_url = reverse_lazy('assets:asset-list') new_form = '' @@ -214,7 +228,7 @@ class AssetModalListView(AdminUserRequiredMixin, ListView): class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): model = AssetGroup - form_class = AssetGroupForm + form_class = forms.AssetGroupForm template_name = 'assets/asset_group_create.html' success_url = reverse_lazy('assets:asset-group-list') #ordering = '-id' @@ -275,7 +289,7 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView): class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView): model = AssetGroup - form_class = AssetGroupForm + form_class = forms.AssetGroupForm template_name = 'assets/asset_group_create.html' success_url = reverse_lazy('assets:asset-group-list') @@ -317,7 +331,7 @@ class IDCListView(AdminUserRequiredMixin, TemplateView): class IDCCreateView(AdminUserRequiredMixin, CreateView): model = IDC - form_class = IDCForm + form_class = forms.IDCForm template_name = 'assets/idc_create_update.html' success_url = reverse_lazy('assets:idc-list') @@ -339,7 +353,7 @@ class IDCCreateView(AdminUserRequiredMixin, CreateView): class IDCUpdateView(AdminUserRequiredMixin, UpdateView): model = IDC - form_class = IDCForm + form_class = forms.IDCForm template_name = 'assets/idc_create_update.html' context_object_name = 'idc' success_url = reverse_lazy('assets:idc-list') @@ -408,7 +422,7 @@ class AdminUserListView(AdminUserRequiredMixin, TemplateView): class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = AdminUser - form_class = AdminUserForm + form_class = forms.AdminUserForm template_name = 'assets/admin_user_create_update.html' success_url = reverse_lazy('assets:admin-user-list') @@ -434,7 +448,7 @@ class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView): model = AdminUser - form_class = AdminUserForm + form_class = forms.AdminUserForm template_name = 'assets/admin_user_create_update.html' def get_context_data(self, **kwargs): @@ -478,39 +492,21 @@ class AdminUserDeleteView(AdminUserRequiredMixin, DeleteView): success_url = reverse_lazy('assets:admin-user-list') -class SystemUserListView(AdminUserRequiredMixin, ListView): - model = SystemUser - paginate_by = settings.CONFIG.DISPLAY_PER_PAGE - context_object_name = 'system_user_list' +class SystemUserListView(AdminUserRequiredMixin, TemplateView): template_name = 'assets/system_user_list.html' def get_context_data(self, **kwargs): context = { 'app': _('Assets'), 'action': _('System user list'), - 'keyword': self.request.GET.get('keyword', '') } kwargs.update(context) return super(SystemUserListView, self).get_context_data(**kwargs) - def get_queryset(self): - # Todo: Default order by lose asset connection num - self.queryset = super(SystemUserListView, self).get_queryset() - self.keyword = keyword = self.request.GET.get('keyword', '') - self.sort = sort = self.request.GET.get('sort', '-date_created') - - if keyword: - self.queryset = self.queryset.filter(Q(name__icontains=keyword) | - Q(comment__icontains=keyword)) - - if sort: - self.queryset = self.queryset.order_by(sort) - return self.queryset - class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = SystemUser - form_class = SystemUserForm + form_class = forms.SystemUserForm template_name = 'assets/system_user_create_update.html' success_url = reverse_lazy('assets:system-user-list') @@ -534,7 +530,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): model = SystemUser - form_class = SystemUserForm + form_class = forms.SystemUserForm template_name = 'assets/system_user_create_update.html' def get_context_data(self, **kwargs): @@ -636,7 +632,7 @@ class TagsListView(AdminUserRequiredMixin, ListView): class AssetTagCreateView(AdminUserRequiredMixin, CreateView): model = Tag - form_class = AssetTagForm + form_class = forms.AssetTagForm template_name = 'assets/asset_tag_create.html' success_url = reverse_lazy('assets:asset-tag-list') #ordering = '-id' @@ -685,7 +681,7 @@ class AssetTagDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView): class AssetTagUpdateView(AdminUserRequiredMixin, UpdateView): model = Tag - form_class = AssetTagForm + form_class = forms.AssetTagForm template_name = 'assets/asset_tag_create.html' success_url = reverse_lazy('assets:asset-tag-list') @@ -711,3 +707,127 @@ class AssetTagDeleteView(AdminUserRequiredMixin, DeleteView): model = Tag success_url = reverse_lazy('assets:asset-tag-list') + +@method_decorator(csrf_exempt, name='dispatch') +class AssetExportView(View): + @staticmethod + def get_asset_attr(asset, attr): + if attr in ['admin_user', 'idc']: + return getattr(asset, attr).name + elif attr in ['status', 'type', 'env']: + return getattr(asset, 'get_{}_display'.format(attr))() + else: + return getattr(asset, attr) + + 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', '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([self.get_asset_attr(asset, attr) for attr in header]) + + filename = 'assets-{}.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', []) + print(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('assets:asset-export') + '?spm=%s' % spm + return JsonResponse({'redirect': url}) + + +class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): + form_class = forms.FileForm + + def form_valid(self, form): + try: + wb = load_workbook(form.cleaned_data['file']) + ws = wb.get_active_sheet() + except Exception as e: + print(e) + data = {'valid': False, 'msg': 'Not a valid Excel file'} + return self.render_json_response(data) + + rows = ws.rows + header_all = ['hostname', 'ip', 'port', 'admin_user', 'idc', 'cpu', 'memory', 'disk', + 'mac_address', 'other_ip', 'remote_card_ip', 'os', 'cabinet_no', + 'cabinet_pos', 'number', 'status', 'type', 'env', 'sn', 'comment'] + header_min = ['hostname', 'ip', 'port', 'admin_user', 'comment'] + header = [col.value for col in next(rows)] + if not set(header).issubset(set(header_all)) and not set(header).issuperset(set(header_min)): + data = {'valid': False, 'msg': 'Must be same format as template or export file'} + return self.render_json_response(data) + + created = [] + updated = [] + failed = [] + for row in rows: + asset_dict = dict(zip(header, [col.value for col in row])) + if asset_dict.get('admin_user', None): + admin_user = get_object_or_none(AdminUser, name=asset_dict['admin_user']) + asset_dict['admin_user'] = admin_user + + if asset_dict.get('idc'): + idc = get_object_or_none(IDC, name=asset_dict['idc']) + asset_dict['idc'] = idc + + if asset_dict.get('type'): + asset_display_type_map = dict(zip(dict(Asset.TYPE_CHOICES).values(), dict(Asset.TYPE_CHOICES).keys())) + asset_type = asset_display_type_map.get(asset_dict['type'], 'Server') + asset_dict['type'] = asset_type + + if asset_dict.get('status'): + asset_display_status_map = dict(zip(dict(Asset.STATUS_CHOICES).values(), + dict(Asset.STATUS_CHOICES).keys())) + asset_status = asset_display_status_map.get(asset_dict['status'], 'In use') + asset_dict['status'] = asset_status + + if asset_dict.get('env'): + asset_display_env_map = dict(zip(dict(Asset.ENV_CHOICES).values(), + dict(Asset.ENV_CHOICES).keys())) + asset_env = asset_display_env_map.get(asset_dict['env'], 'Prod') + asset_dict['env'] = asset_env + + try: + Asset.objects.create(**asset_dict) + created.append(asset_dict['ip']) + except IntegrityError as e: + asset = Asset.objects.filter(ip=asset_dict['ip'], port=asset_dict['port']) + if not asset: + failed.append(asset_dict['ip']) + continue + asset.update(**asset_dict) + updated.append(asset_dict['ip']) + except TypeError as e: + print(e) + failed.append(asset_dict['ip']) + + data = { + 'created': created, + 'created_info': 'Created {}'.format(len(created)), + 'updated': updated, + 'updated_info': 'Updated {}'.format(len(updated)), + 'failed': failed, + 'failed_info': 'Failed {}'.format(len(failed)), + 'valid': True, + 'msg': 'Created: {}. Updated: {}, Error: {}'.format(len(created), len(updated), len(failed)) + } + return self.render_json_response(data) diff --git a/apps/audits/templates/audits/command_log_list.html b/apps/audits/templates/audits/command_log_list.html index 19a9a63e6..03b786f3f 100644 --- a/apps/audits/templates/audits/command_log_list.html +++ b/apps/audits/templates/audits/command_log_list.html @@ -4,6 +4,7 @@ {% load common_tags %} {% block content_left_head %} +