mirror of https://github.com/jumpserver/jumpserver
Merge with asset
commit
ce5950ca73
|
@ -1,24 +1,69 @@
|
|||
# coding:utf-8
|
||||
from django import forms
|
||||
|
||||
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser
|
||||
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class AssetForm(forms.ModelForm):
|
||||
# class AssetForm(forms.ModelForm):
|
||||
# class Meta:
|
||||
# model = Asset
|
||||
#
|
||||
# fields = [
|
||||
# 'ip', 'other_ip', 'remote_card_ip', 'hostname', 'port', 'groups', 'username', 'password',
|
||||
# 'idc', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', 'cabinet_pos',
|
||||
# 'number', 'status', 'type', 'env', 'sn', 'is_active', 'comment', 'admin_user', 'system_users'
|
||||
# ]
|
||||
#
|
||||
# widgets = {
|
||||
# 'groups': forms.SelectMultiple(attrs={'class': 'select2-groups', 'data-placeholder': _('Select asset groups')}),
|
||||
# 'system_user': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}),
|
||||
# 'admin_user': forms.SelectMultiple(attrs={'class': 'select2-admin-user', 'data-placeholder': _('Select asset admin user')}),
|
||||
# }
|
||||
#
|
||||
|
||||
class AssetCreateForm(forms.ModelForm):
|
||||
tags = forms.CharField(label=_('Tags'), widget=forms.TextInput(attrs={'id': 'tags'}),
|
||||
required=False, help_text='Use `,` split')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get('instance', None)
|
||||
|
||||
if instance:
|
||||
initial = kwargs.get('initial', {})
|
||||
tags = instance.tags.all()
|
||||
initial['tags'] = ",".join([tag.value for tag in tags])
|
||||
print(kwargs.get('initial'))
|
||||
super(AssetCreateForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def _save_m2m(self):
|
||||
tags = self.cleaned_data['tags']
|
||||
|
||||
if tags:
|
||||
value_list = tags.split(',')
|
||||
self.instance.tags.all().delete()
|
||||
Tag.objects.bulk_create(
|
||||
[Tag(value=value, asset=self.instance) for value in value_list]
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
|
||||
fields = [
|
||||
"ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password",
|
||||
"idc", "mac_address", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos",
|
||||
"number", "status", "type", "env", "sn", "is_active", "comment", "admin_user", "system_users"
|
||||
'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups',
|
||||
'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no',
|
||||
'cabinet_pos', 'number', 'status', 'env', 'sn',
|
||||
]
|
||||
|
||||
widgets = {
|
||||
'groups': forms.SelectMultiple(attrs={'class': 'select2-groups', 'data-placeholder': _('Select asset groups')}),
|
||||
'system_users': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}),
|
||||
# 'admin_user': forms.SelectMultiple(attrs={'class': 'select2-admin-user', 'data-placeholder': _('Select asset admin user')}),
|
||||
'groups': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset system users')}),
|
||||
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
'ip': '* required',
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,7 +77,7 @@ class AssetGroupForm(forms.ModelForm):
|
|||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get('instance'):
|
||||
if kwargs.get('instance', None):
|
||||
initial = kwargs.get('initial', {})
|
||||
initial['assets'] = kwargs['instance'].assets.all()
|
||||
super(AssetGroupForm, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# coding:utf-8
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import functools
|
||||
from django.db import models
|
||||
import logging
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -26,6 +27,10 @@ class IDC(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def initial(cls):
|
||||
return cls.objects.get_or_create(name=_('Default'), created_by=_('System'), comment=_('Default IDC'))[0]
|
||||
|
||||
class Meta:
|
||||
db_table = 'idc'
|
||||
|
||||
|
@ -55,10 +60,10 @@ class IDC(models.Model):
|
|||
|
||||
|
||||
class AssetExtend(models.Model):
|
||||
key = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('KEY'))
|
||||
value = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('VALUE'))
|
||||
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=True, null=True, blank=True)
|
||||
date_created = models.DateTimeField(auto_now=True, null=True)
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -83,6 +88,7 @@ class AssetExtend(models.Model):
|
|||
|
||||
class Meta:
|
||||
db_table = 'asset_extend'
|
||||
unique_together = ('key', 'value')
|
||||
|
||||
|
||||
class AdminUser(models.Model):
|
||||
|
@ -249,7 +255,7 @@ class AssetGroup(models.Model):
|
|||
|
||||
@classmethod
|
||||
def initial(cls):
|
||||
asset_group = cls(name=_('Default'), commont=_('Default asset group'))
|
||||
asset_group = cls(name=_('Default'), comment=_('Default asset group'))
|
||||
asset_group.save()
|
||||
|
||||
@classmethod
|
||||
|
@ -271,49 +277,68 @@ 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):
|
||||
ip = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('IP'))
|
||||
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'))
|
||||
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'))
|
||||
hostname = models.CharField(max_length=128, unique=True, null=True, blank=True, verbose_name=_('Hostname'))
|
||||
port = models.IntegerField(default=22, null=True, blank=True, verbose_name=_('Port'))
|
||||
hostname = models.CharField(max_length=128, blank=True, verbose_name=_('Hostname'))
|
||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||
groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets', verbose_name=_('Asset groups'))
|
||||
username = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Admin user'))
|
||||
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_("Admin password"))
|
||||
admin_user = models.ForeignKey(AdminUser, null=True, blank=True, related_name='assets',
|
||||
on_delete=models.SET_NULL, verbose_name=_("Admin user"))
|
||||
system_users = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User"))
|
||||
idc = models.ForeignKey(IDC, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('IDC'))
|
||||
idc = models.ForeignKey(IDC, null=True, related_name='assets',
|
||||
on_delete=models.SET_NULL, verbose_name=_('IDC'),)
|
||||
# default=get_default_idc)
|
||||
mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address"))
|
||||
brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand'))
|
||||
cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU'))
|
||||
cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU'))
|
||||
memory = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Memory'))
|
||||
disk = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk'))
|
||||
os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS'))
|
||||
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="asset_status_extend",
|
||||
verbose_name=_('Asset status'))
|
||||
type = models.ForeignKey(AssetExtend, null=True, blank=True, related_name="asset_type_extend",
|
||||
verbose_name=_('Asset type'))
|
||||
env = models.ForeignKey(AssetExtend, null=True, blank=True, related_name="asset_env_extend",
|
||||
verbose_name=_('Asset environment'))
|
||||
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, 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'))
|
||||
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'))
|
||||
date_created = models.DateTimeField(auto_now=True, null=True, blank=True, verbose_name=_('Date added'))
|
||||
comment = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
|
||||
comment = models.TextField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __unicode__(self):
|
||||
return '%(ip)s:%(port)s' % {'ip': self.ip, 'port': self.port}
|
||||
|
||||
def initial(self):
|
||||
pass
|
||||
def is_valid(self):
|
||||
warning = ''
|
||||
if not self.is_active:
|
||||
warning += ' inactive'
|
||||
else:
|
||||
return True, ''
|
||||
return False, warning
|
||||
|
||||
class Meta:
|
||||
db_table = 'asset'
|
||||
index_together = ('ip', 'port')
|
||||
unique_together = ('ip', 'port')
|
||||
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100):
|
||||
|
@ -323,8 +348,8 @@ class Asset(models.Model):
|
|||
|
||||
seed()
|
||||
for i in range(count):
|
||||
asset = cls(ip='%s.%s.%s.%s' % tuple([forgery_py.forgery.basic.text(length=3, digits=True)
|
||||
for i in range(0, 4)]),
|
||||
asset = cls(ip='%s.%s.%s.%s' % (i, i, i, i),
|
||||
hostname=forgery_py.internet.user_name(True),
|
||||
admin_user=choice(AdminUser.objects.all()),
|
||||
idc=choice(IDC.objects.all()),
|
||||
port=22,
|
||||
|
@ -339,21 +364,28 @@ class Asset(models.Model):
|
|||
continue
|
||||
|
||||
|
||||
class Label(models.Model):
|
||||
key = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('KEY'))
|
||||
value = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('VALUE'))
|
||||
asset = models.ForeignKey(Asset, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('Asset'))
|
||||
created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
|
||||
date_created = models.DateTimeField(auto_now=True, null=True)
|
||||
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment'))
|
||||
class Tag(models.Model):
|
||||
value = models.CharField(max_length=64, verbose_name=_('VALUE'))
|
||||
asset = models.ForeignKey(Asset, related_name='tags', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.key
|
||||
return self.value
|
||||
|
||||
class Meta:
|
||||
db_table = 'label'
|
||||
db_table = 'tag'
|
||||
unique_together = ('value', 'asset')
|
||||
|
||||
|
||||
def init_all_models():
|
||||
for cls in (AssetExtend, AssetGroup):
|
||||
cls.initial()
|
||||
|
||||
|
||||
def generate_fake():
|
||||
for cls in (AssetGroup, IDC, AdminUser, SystemUser, Asset):
|
||||
cls.generate_fake()
|
||||
|
||||
|
||||
def flush_all():
|
||||
for cls in (AssetGroup, AssetExtend, IDC, AdminUser, SystemUser, Asset):
|
||||
cls.objects.all().delete()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
|
@ -1,109 +1,48 @@
|
|||
{% extends 'base.html' %}
|
||||
{% extends '_base_create_update.html' %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div id="ibox-content" 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>
|
||||
{% load i18n %}
|
||||
|
||||
<div class="ibox-content">
|
||||
<div class="panel blank-panel">
|
||||
<div class="tab-content">
|
||||
<form id="assetForm" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<h3 class="widget-head-color-box">基本信息</h3>
|
||||
{% block form %}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Basic' %}</h3>
|
||||
{{ form.hostname|bootstrap_horizontal }}
|
||||
{{ form.ip|bootstrap_horizontal }}
|
||||
{{ form.port|bootstrap_horizontal }}
|
||||
{{ form.type|bootstrap_horizontal }}
|
||||
|
||||
{{ form.hostname|bootstrap_horizontal }}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Group' %}</h3>
|
||||
{{ form.idc|bootstrap_horizontal }}
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
{{ form.ip|bootstrap_horizontal }}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{{ form.admin_user|bootstrap_horizontal }}
|
||||
{{ form.system_users|bootstrap_horizontal }}
|
||||
|
||||
{{ form.port|bootstrap_horizontal }}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
{{ form.tags|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
|
||||
{{ form.type|bootstrap_horizontal }}
|
||||
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>关联资产用户</h3>
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">管理用户</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="radio i-checks">
|
||||
<label><input type="radio" checked="checked" id="id_use_default_auth" name="use_default_auth"><span>使用预定义管理用户</span></label>
|
||||
<label><input type="radio" id="id_use_default_auth" name="use_default_auth"><span>自定义</span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ form.admin_user|bootstrap_horizontal }}
|
||||
<p class="col-sm-offset-2">Tips: 管理用户是服务器存在的root或拥有sudo的用户,用来推送系统用户</p>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{{ form.system_users|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>所属</h3>
|
||||
{{ form.idc|bootstrap_horizontal }}
|
||||
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>标签</h3>
|
||||
<div class="form-group" id="id_label">
|
||||
<label class="col-sm-2 control-label">Label</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" placeholder="Key" name="key" class="form-control">
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
<input type="text" placeholder="Value" name="value" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-offset-2">
|
||||
<i class="fa fa-plus-circle"></i> <span class="nav-label">添加</span><span class="fa arrow"></span>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="reset"> 重置 </button>
|
||||
<button class="btn btn-primary" type="submit"> 提交 </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2">
|
||||
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2-groups').select2();
|
||||
$('.select2-admin-user').select2();
|
||||
$('.select2-system-user').select2();
|
||||
$('.select2').select2();
|
||||
$('#tags').inputTags();
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -16,10 +16,12 @@
|
|||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
|
||||
<li class="active">
|
||||
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset login log' %}</a>
|
||||
</li>
|
||||
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset users' %}</a></li>
|
||||
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset login log' %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
|
@ -45,11 +47,6 @@
|
|||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
{# <td colspan="2">#}
|
||||
{# <img src="{{ asset | user_avatar_url }}" class="img-circle" width="64" height="64">#}
|
||||
{# </td>#}
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Hostname' %}:</td>
|
||||
<td><b>{{ asset.hostname }}</b></td>
|
||||
</tr>
|
||||
|
@ -85,20 +82,10 @@
|
|||
<td>{% trans 'Disk' %}:</td>
|
||||
<td><b>{{ asset.disk }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Label' %}:</td>
|
||||
{% for label in asset.label_set.all %}
|
||||
<td><b>{{ label.key }} - {{ label.value }}</b></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'OS' %}:</td>
|
||||
<td><b>{{ asset.os }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Mac address' %}:</td>
|
||||
<td><b>{{ asset.mac_addr }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset status' %}:</td>
|
||||
<td><b>{{ asset.status }}</b></td>
|
||||
|
@ -163,36 +150,30 @@
|
|||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Enable OTP' %}:</td>
|
||||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if asset.enable_otp %} checked {% endif %}
|
||||
id="enable_otp">
|
||||
<label class="onoffswitch-label" for="enable_otp">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset password' %}:</td>
|
||||
<td>{% trans 'Rrefresh hardware' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Refresh' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset ssh key' %}:</td>
|
||||
<td>{% trans 'Test admin user' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Reset' %}</button>
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Test' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Test system users' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Test' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -200,7 +181,7 @@
|
|||
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Asset group' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Asset groups' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit">
|
||||
|
@ -208,25 +189,25 @@
|
|||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Join user groups' %}" id="slct_groups" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for group in groups %}
|
||||
<option value="{{ group.id }}" id="opt_{{ group.id }}">{{ group.name }}</option>
|
||||
<select data-placeholder="{% trans 'Join asset groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset_group in asset_groups_remain %}
|
||||
<option value="{{ asset_group.id }}" >{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button>
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn_add_user_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in asset.groups.all %}
|
||||
{% for asset_group in asset_groups %}
|
||||
<tr>
|
||||
<td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
|
||||
<td ><b data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-sm btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
<button class="btn btn-danger pull-right btn-xs " type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -243,5 +224,8 @@
|
|||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
|
@ -1,431 +1,71 @@
|
|||
{% extends 'base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
<a href="{% url 'assets:asset-create' %}" class="btn btn-sm btn-primary "> {% trans "Create asset" %} </a>
|
||||
{% endblock %}
|
||||
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins" id="all">
|
||||
<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>
|
||||
{% block table_head %}
|
||||
<th class="text-center">
|
||||
<input type="checkbox" id="check_all" onclick="checkAll('check_all', 'checked')">
|
||||
</th>
|
||||
<th class="text-center"><a href="{% url 'assets:asset-list' %}?sort=hostname">{% trans 'Hostname' %}</a></th>
|
||||
<th class="text-center"><a href="{% url 'assets:asset-list' %}?sort=username">{% trans 'IP' %}</a></th>
|
||||
<th class="text-center">{% trans 'Port' %}</th>
|
||||
<th class="text-center">{% trans 'Type' %}</th>
|
||||
<th class="text-center">{% trans 'Hardware' %}</th>
|
||||
<th class="text-center">{% trans 'Valid' %}</th>
|
||||
<th class="text-center"></th>
|
||||
{% endblock %}
|
||||
|
||||
<div class="ibox-content">
|
||||
<form id="asset_form">
|
||||
<div class="col-sm-1" style="padding-left: 0">
|
||||
<a href="{% url 'assets:asset-create' %}" class="btn btn-sm btn-primary "> {% trans 'Create asset' %}</a>
|
||||
</div>
|
||||
{% block table_body %}
|
||||
{% for asset in asset_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center">
|
||||
<input type="checkbox" name="checked" value="{{ asset.id }}">
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'assets:asset-detail' pk=user.id %}">
|
||||
{{ asset.hostname }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-center">{{ asset.ip }}</td>
|
||||
<td class="text-center">{{ asset.port }}</td>
|
||||
<td class="text-center">{{ asset.type }}</td>
|
||||
<td class="text-center">{{ asset.cpu }} {{ asset.memory }} {{ asset.disk }} </td>
|
||||
<td class="text-center">
|
||||
{% if asset.is_valid.0 %}
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'assets:asset-update' pk=asset.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
|
||||
<a href="{% url 'assets:asset-delete' pk=asset.id %}" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>-
|
||||
{# <a href="{% url '' %}">{% trans 'Delete' %}</a>#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="col-sm-7" style="padding-left: 0px">
|
||||
<label>
|
||||
<select name="idc" class="form-control m-b input-sm" onchange="change_info()">
|
||||
<option value="">机房</option>
|
||||
{% for idc in idc_all %}
|
||||
{% ifequal idc.name idc_name %}
|
||||
<option value="{{idc.name}}" selected> {{ idc.name|slice:":20" }}</option>
|
||||
{% else %}
|
||||
<option value="{{idc.name}}"> {{ idc.name|slice:":20" }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
{% block content_bottom_left %}
|
||||
<form id="" method="get" action="" class=" mail-search">
|
||||
<div class="input-group">
|
||||
<select class="form-control m-b" style="width: auto">
|
||||
<option>{% trans 'Delete selected' %}</option>
|
||||
<option>{% trans 'Update selected' %}</option>
|
||||
<option>{% trans 'Deactive selected' %}</option>
|
||||
<option>{% trans 'Export selected' %}</option>
|
||||
</select>
|
||||
|
||||
<label>
|
||||
<select name="group" class="form-control m-b input-sm" onchange="change_info()">
|
||||
<option value="">主机组</option>
|
||||
{% for asset_group in asset_group_all %}
|
||||
{% ifequal asset_group.name group_name %}
|
||||
<option value="{{ asset_group.name }}" selected> {{ asset_group.name|slice:":20" }} </option>
|
||||
{% else %}
|
||||
<option value="{{ asset_group.name }}"> {{ asset_group.name|slice:":20" }} </option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<select name="asset_type" class="form-control m-b input-sm" onchange="change_info()">
|
||||
<option value="">资产类型</option>
|
||||
{# {% for type in asset_types %}#}
|
||||
{# {% ifequal type.0|int2str asset_type %}#}
|
||||
{# <option value="{{ type.0 }}" selected> {{ type.1 }}</option>#}
|
||||
{# {% else %}#}
|
||||
{# <option value="{{ type.0 }}"> {{ type.1 }}</option>#}
|
||||
{# {% endifequal %}#}
|
||||
{# {% endfor %}#}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<select name="status" class="form-control m-b input-sm" onchange="change_info()">
|
||||
<option value="">资产状态</option>
|
||||
{# {% for s in asset_status %}#}
|
||||
{# {% ifequal s.0|int2str status %}#}
|
||||
{# <option value="{{ s.0 }}" selected> {{ s.1 }}</option>#}
|
||||
{# {% else %}#}
|
||||
{# <option value="{{ s.0 }}"> {{ s.1 }}</option>#}
|
||||
{# {% endifequal %}#}
|
||||
{# {% endfor %}#}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4" style="padding-right: 0">
|
||||
<div class="input-group inline-group">
|
||||
<input type="text" class="form-control m-b input-sm" id="search_input" name="keyword" value="{{ keyword }}" placeholder="Search">
|
||||
<input type="text" style="display: none">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' href="{% url 'assets:asset-list' %}?search=true" type="button" class="btn btn-sm btn-primary search-btn" onclick="change_info()">
|
||||
- 搜索 -
|
||||
</button>
|
||||
<button type="button" href="{% url 'assets:asset-list' %}?export=true" name="export" class="btn btn-sm btn-success search-btn-excel" onclick="return false">
|
||||
- 导出 -
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="export"></div>
|
||||
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('asset_form')">
|
||||
</th>
|
||||
<th class="text-center"> 主机名 </th>
|
||||
<th class="text-center" name="ip"> IP </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 asset in assets %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center" name="id" value="{{ asset.id }}" data-editable='false'>
|
||||
<input name="id" value="{{ asset.id }}" type="checkbox" class="i-checks">
|
||||
</td>
|
||||
<td class="text-center"> <a href="{% url 'assets:asset-detail' pk=asset.id %}">{{ asset.hostname }}</a></td>
|
||||
<td class="text-center"> {{ asset.ip }} </td>
|
||||
<td class="text-center">{{ asset.system_type }}</td>
|
||||
<td class="text-center"> {{ asset.cpu }} | {{ asset.memory }} | {{ asset.disk }}</td>
|
||||
<td class="text-center"> {% for group in asset.group.all %} {{ group.name }} {% endfor %}</td>
|
||||
<td class="text-center">
|
||||
{% if asset.is_active %}
|
||||
<i class="fa fa-circle text-navy"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-circle text-danger"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center" data-editable='false'>
|
||||
{# <a href="{% url 'asset_edit' %}?id={{ asset.id }}" class="btn btn-xs btn-info">编辑</a>#}
|
||||
<a value="{{ asset.id }}" class="conn btn btn-xs btn-warning">连接</a>
|
||||
{# <a value="{% url 'asset_del' %}?id={{ asset.id }}" class="btn btn-xs btn-danger asset_del">删除</a>#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<input type="button" id="asset_del" class="btn btn-danger btn-sm" name="del_button" value="删除"/>
|
||||
{# <a value="{% url 'asset_edit_batch' %}" type="button" class="btn btn-sm btn-warning iframe">修改</a>#}
|
||||
<input type="button" id="asset_update" class="btn btn-info btn-sm" name="update_button" value="更新"/>
|
||||
{# <input type="button" id="asset_update_all" class="btn btn-primary btn-sm" name="update_button" value="更新全部"/>#}
|
||||
<input type="button" id="exec_cmd" class="btn btn-sm btn-primary" name="exec_cmd" value="执行命令"/>
|
||||
</div>
|
||||
{% include '_pagination.html' %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="input-group-btn pull-left" style="padding-left: 5px;">
|
||||
<button id='search_btn' type="submit" style="height: 32px;" class="btn btn-sm btn-primary">
|
||||
{% trans 'Submit' %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('.asset_del').click(function(){
|
||||
var row = $(this).closest('tr');
|
||||
if (confirm("确定删除?")) {
|
||||
$.get(
|
||||
$(this).attr('value'),
|
||||
{},
|
||||
function (data) {
|
||||
row.remove()
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
$('#exec_cmd').click(function(){
|
||||
var url = '{% url "role_get" %}';
|
||||
var new_url = '{% url "exec_cmd" %}?role=';
|
||||
var check_array = [];
|
||||
$(".gradeX input:checked").closest('tr').find('.hostname a').each(function() {
|
||||
check_array.push($(this).text())
|
||||
});
|
||||
check_assets = check_array.join(':');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: url,
|
||||
data: {},
|
||||
success: function(data){
|
||||
var dataArray = data.split(',');
|
||||
if (dataArray.length == 1 && data != 'error'){
|
||||
var title = 'Jumpserver Exec Terminal';
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
shade: false,
|
||||
area: ['725px', '600px'],
|
||||
content: new_url+data+'&check_assets='+check_assets
|
||||
});
|
||||
//window.open(new_url + data, '', 'location=no, resizeable=no, height=410, width=625, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,status=no');
|
||||
} else if (dataArray.length == '1' && data == 'error'){
|
||||
layer.alert('没有授权系统用户')
|
||||
} else {
|
||||
aUrl = '';
|
||||
$.each(dataArray, function(index, value){
|
||||
aUrl += '<a onclick="windowOpenExec(this); return false" class="btn btn-xs btn-primary newa" href=' + new_url + value + '&check_assets=' + check_assets + '>' + value + '</a> '
|
||||
});
|
||||
layer.alert(aUrl, {
|
||||
skin: 'layui-layer-molv',
|
||||
title: '授权多个系统用户,请选择一个连接',
|
||||
shade: false,
|
||||
closeBtn: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
return false
|
||||
|
||||
});
|
||||
|
||||
$('.conn').click(function(){
|
||||
var url='{% url "role_get" %}?id=' + $(this).attr('value'); // 获取用户有权限的角色
|
||||
var href = $(this).attr('href');
|
||||
var new_url = '{% url "terminal" %}?id=' + $(this).attr('value') + '&role='; // webterminal socket url
|
||||
var hostname = $(this).closest('tr').find('.hostname a')[0].innerHTML;
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: url,
|
||||
data: {},
|
||||
success: function(data){
|
||||
var dataArray = data.split(',');
|
||||
if (data == 'error' || data == '' || data == null || data == undefined){
|
||||
layer.alert('没有授权系统用户')
|
||||
}
|
||||
else if (dataArray.length == 1 && data != 'error' && navigator.platform == 'Win32'){
|
||||
/*
|
||||
var title = 'Jumpserver Web Terminal' + '<span class="text-info"> '+ hostname +'</span>';
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
shade: false,
|
||||
area: ['628px', '420px'],
|
||||
content: new_url+data
|
||||
});
|
||||
window.open(new_url+data, '_blank', 'toolbar=yes, location=yes, scrollbars=yes, resizable=yes, copyhistory=yes, width=628, height=400')
|
||||
*/
|
||||
window.open(new_url+data, "_blank");
|
||||
} else if (dataArray.length == 1 && data != 'error'){
|
||||
/*layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
shade: false,
|
||||
area: ['628px', '452px'],
|
||||
content: new_url+data
|
||||
});
|
||||
*/
|
||||
window.open(new_url+data, '_blank');
|
||||
}
|
||||
else {
|
||||
aUrl = '';
|
||||
$.each(dataArray, function(index, value){
|
||||
aUrl += '<a onclick="windowOpen(this); return false" class="btn btn-xs btn-primary newa" href=' + new_url + value + ' value=' + hostname + '>' + value + '</a> '
|
||||
});
|
||||
console.log(aUrl);
|
||||
layer.alert(aUrl, {
|
||||
skin: 'layui-layer-molv',
|
||||
title: '授权多个系统用户,请选择一个连接',
|
||||
shade: false,
|
||||
closeBtn: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
return false
|
||||
});
|
||||
});
|
||||
|
||||
function windowOpen(a){
|
||||
var new_url = $(a).attr('href');
|
||||
var hostname = $(a).attr('value');
|
||||
var title = 'Jumpserver Web Terminal - ' + '<span class="text-info"> '+ hostname +'</span>';
|
||||
if (navigator.platform == 'Win32'){
|
||||
/*
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
area: ['628px', '420px'],
|
||||
shade: false,
|
||||
content: new_url
|
||||
});
|
||||
*/
|
||||
window.open(new_url, '_blank')
|
||||
|
||||
} else {
|
||||
/*
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
area: ['628px', '452px'],
|
||||
shade: false,
|
||||
content: new_url
|
||||
});
|
||||
*/
|
||||
window.open(new_url, '_blank');
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function windowOpenExec(a){
|
||||
var new_url = $(a).attr('href');
|
||||
var title = 'Jumpserver Exec Terminal';
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
area: ['725px', '600px'],
|
||||
shade: false,
|
||||
content: new_url
|
||||
});
|
||||
return false
|
||||
}
|
||||
|
||||
$(".iframe").on('click', function(){
|
||||
var asset_id_all = getIDall();
|
||||
if (asset_id_all == ''){
|
||||
alert("请至少选择一行!");
|
||||
return false;
|
||||
}
|
||||
var url= $(this).attr("value") + '?asset_id_all=' + asset_id_all;
|
||||
parent.layer.open({
|
||||
type: 2,
|
||||
title: 'JumpServer - 批量修改主机',
|
||||
maxmin: true,
|
||||
shift: 'top',
|
||||
border: [2, 0.3, '#1AB394'],
|
||||
shade: [0.5, '#000000'],
|
||||
area: ['800px', '600px'],
|
||||
shadeClose: true,
|
||||
content: url,
|
||||
cancel: function(){
|
||||
location.replace(location.href);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.search-btn-excel').unbind('click').bind('click',function(){
|
||||
var url= $(this).attr("href");
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
data: $("#asset_form").serialize(),
|
||||
success: function (data) {
|
||||
$("#export").html(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#asset_del').click(function () {
|
||||
var asset_id_all = getIDall();
|
||||
if (asset_id_all == ''){
|
||||
alert("请至少选择一行!");
|
||||
return false;
|
||||
}
|
||||
if (confirm("确定删除?")) {
|
||||
$.ajax({
|
||||
type: "post",
|
||||
data: {asset_id_all: asset_id_all},
|
||||
url: "{% url 'asset_del' %}?arg=batch",
|
||||
success: function () {
|
||||
parent.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#asset_update').click(function () {
|
||||
var asset_id_all = getIDall();
|
||||
if (asset_id_all == ''){
|
||||
if (confirm("更新全部资产信息?")) {
|
||||
layer.msg('玩命更新中...', {time: 200000});
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: "{% url 'asset_update_batch' %}?arg=all",
|
||||
success: function () {
|
||||
parent.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
layer.msg('玩命更新中...', {time: 200000});
|
||||
$.ajax({
|
||||
type: "post",
|
||||
data: {asset_id_all: asset_id_all},
|
||||
url: "{% url 'asset_update_batch' %}",
|
||||
success: function () {
|
||||
parent.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
{# $('#asset_update_all').click(function () {#}
|
||||
{# layer.msg('玩命更新中...', {time: 200000});#}
|
||||
{# $.ajax({#}
|
||||
{# type: "post",#}
|
||||
{# url: "/jasset/asset_update_batch/?arg=all",#}
|
||||
{# success: function () {#}
|
||||
{# parent.location.reload();#}
|
||||
{# }#}
|
||||
{# });#}
|
||||
{# });#}
|
||||
|
||||
function change_info(){
|
||||
var args = $("#asset_form").serialize();
|
||||
window.location = "{% url 'asset_list' %}?" + args
|
||||
}
|
||||
|
||||
$("#search_input").keydown(function(e){
|
||||
if(e.keyCode==13){
|
||||
change_info()
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
{% extends '_base_create_update.html' %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js_create %}
|
||||
<link href="{% static "css/plugins/inputTags.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/inputTags.jquery.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block form %}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Basic' %}</h3>
|
||||
{{ form.hostname|bootstrap_horizontal }}
|
||||
{{ form.ip|bootstrap_horizontal }}
|
||||
{{ form.port|bootstrap_horizontal }}
|
||||
{{ form.type|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Group' %}</h3>
|
||||
{{ form.idc|bootstrap_horizontal }}
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{{ form.admin_user|bootstrap_horizontal }}
|
||||
{{ form.system_users|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Hardware' %}</h3>
|
||||
{{ form.sn|bootstrap_horizontal }}
|
||||
{{ form.brand|bootstrap_horizontal }}
|
||||
{{ form.cpu|bootstrap_horizontal }}
|
||||
{{ form.memory|bootstrap_horizontal }}
|
||||
{{ form.disk|bootstrap_horizontal }}
|
||||
{{ form.mac_address|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Configuration' %}</h3>
|
||||
{{ form.number|bootstrap_horizontal }}
|
||||
{{ form.other_ip|bootstrap_horizontal }}
|
||||
{{ form.remote_card_ip|bootstrap_horizontal }}
|
||||
{{ form.os|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Location' %}</h3>
|
||||
{{ form.cabinet_no|bootstrap_horizontal }}
|
||||
{{ form.cabinet_pos|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
{{ form.status|bootstrap_horizontal }}
|
||||
{{ form.env|bootstrap_horizontal }}
|
||||
{{ form.tags|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2">
|
||||
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
{# $('#tags').inputTags({#}
|
||||
{# tags: [{% for tag in form.tags.value %} {{ tag|safe }}, {% endfor %}]#}
|
||||
{# });#}
|
||||
$('#tags').inputTags(
|
||||
|
||||
);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
|
@ -10,52 +10,96 @@ 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 .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser, Label
|
||||
from .forms import AssetForm, AssetGroupForm, IDCForm, AdminUserForm, SystemUserForm
|
||||
|
||||
from common.utils import int_seq
|
||||
from .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser, Tag
|
||||
from .forms import AssetCreateForm, AssetGroupForm, IDCForm, AdminUserForm, SystemUserForm
|
||||
from .hands import AdminUserRequiredMixin
|
||||
|
||||
|
||||
class AssetListView(AdminUserRequiredMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
model = Asset
|
||||
context_object_name = 'asset_list'
|
||||
template_name = 'assets/asset_list.html'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(AssetListView, self).get_queryset()
|
||||
queryset = sorted(queryset, key=self.sorted_by_valid_and_ip)
|
||||
return queryset
|
||||
|
||||
@staticmethod
|
||||
def sorted_by_valid_and_ip(asset):
|
||||
ip_list = int_seq(asset.ip.split('.'))
|
||||
ip_list.insert(0, asset.is_valid()[0])
|
||||
return ip_list
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
'action': 'Asset list',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = Asset
|
||||
form_class = AssetForm
|
||||
form_class = AssetCreateForm
|
||||
template_name = 'assets/asset_create.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
|
||||
def form_valid(self, form):
|
||||
asset = form.save(commit=False)
|
||||
key = self.request.POST.get('key', '')
|
||||
value = self.request.POST.get('value', '')
|
||||
asset.save()
|
||||
Label.objects.create(key=key, value=value, asset=asset)
|
||||
return super(AssetCreateView, self).form_valid(form)
|
||||
def form_invalid(self, form):
|
||||
print(form.errors)
|
||||
return super(AssetCreateView, self).form_invalid(form)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(AssetCreateView, self).get_context_data(**kwargs)
|
||||
context.update({'admin_users': AdminUser.objects.all()})
|
||||
assert isinstance(context, object)
|
||||
return context
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
'action': 'Create asset',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetUpdateView(UpdateView):
|
||||
pass
|
||||
class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = Asset
|
||||
form_class = AssetCreateForm
|
||||
template_name = 'assets/asset_update.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
'action': 'Update asset',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetDeleteView(DeleteView):
|
||||
model = Asset
|
||||
template_name = 'assets/delete_confirm.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
|
||||
|
||||
class AssetListView(ListView):
|
||||
model = Asset
|
||||
context_object_name = 'assets'
|
||||
template_name = 'assets/asset_list.html'
|
||||
|
||||
|
||||
class AssetDetailView(DetailView):
|
||||
model = Asset
|
||||
context_object_name = 'asset'
|
||||
template_name = 'assets/asset_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
asset_groups = self.object.groups.all()
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
'action': 'Asset detail',
|
||||
'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all()
|
||||
if asset_group not in asset_groups],
|
||||
'asset_groups': asset_groups,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = AssetGroup
|
||||
|
|
|
@ -100,3 +100,10 @@ def search_object_attr(obj, value='', attr_list=None, ignore_case=False):
|
|||
|
||||
def get_logger(name=None):
|
||||
return logging.getLogger('jumpserver.%s' % name)
|
||||
|
||||
|
||||
def int_seq(seq):
|
||||
try:
|
||||
return map(int, seq)
|
||||
except ValueError:
|
||||
return seq
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
@import url("https://fonts.useso.com/css?family=Open+Sans:300,400,600,700");
|
||||
@import url("https://fonts.useso.com/css?family=Roboto:400,300,500,700");
|
||||
/** {*/
|
||||
/*box-sizing: border-box;*/
|
||||
/*}*/
|
||||
/*.color {*/
|
||||
/*color: #19BC9C !important;*/
|
||||
/*}*/
|
||||
/*html,*/
|
||||
/*body {*/
|
||||
/*width: 100%;*/
|
||||
/*height: 100%;*/
|
||||
/*margin: 0;*/
|
||||
/*font-family: 'Ubuntu Condensed', sans-serif;*/
|
||||
/*background-color: #fff;*/
|
||||
/*}*/
|
||||
/*h1 {*/
|
||||
/*text-align: center;*/
|
||||
/*margin-bottom: 32px;*/
|
||||
/*}*/
|
||||
div.container {
|
||||
display: block;
|
||||
width: 50%;
|
||||
margin: 32px auto;
|
||||
padding: 16px 32px;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
div.inputTags-list {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 6px;
|
||||
border: 1px solid rgba(25, 188, 156, 0.35);
|
||||
/*background-color: #f9f9f9;*/
|
||||
box-shadow: 1px 2px 2px rgba(221, 221, 221, 0.2);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
div.inputTags-list span.inputTags-item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
padding: 3px 22px 4px 8px;
|
||||
background-color: #19BC9C;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
opacity: 1;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
div.inputTags-list span.inputTags-item.is-edit {
|
||||
display: none;
|
||||
}
|
||||
div.inputTags-list span.inputTags-item.is-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
div.inputTags-list span.inputTags-item.is-exists {
|
||||
background-color: rgba(231, 76, 60, 0.7);
|
||||
}
|
||||
div.inputTags-list span.inputTags-item span.value {
|
||||
cursor: pointer;
|
||||
}
|
||||
div.inputTags-list span.inputTags-item i {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 6px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
font-weight: 400;
|
||||
font-family: sans-serif;
|
||||
line-height: 1;
|
||||
font-style: normal;
|
||||
-webkit-transition: color 0.2s;
|
||||
-khtml-transition: color 0.2s;
|
||||
-moz-transition: color 0.2s;
|
||||
-ms-transition: color 0.2s;
|
||||
-o-transition: color 0.2s;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-khtml-transform: translateY(-50%);
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
}
|
||||
div.inputTags-list span.inputTags-item i:hover {
|
||||
color: #e74c3c;
|
||||
}
|
||||
div.inputTags-list input.inputTags-field {
|
||||
border: none;
|
||||
margin-left: 4px;
|
||||
background-color: transparent;
|
||||
}
|
||||
div.inputTags-list input.inputTags-field:focus,
|
||||
div.inputTags-list input.inputTags-field:active {
|
||||
outline: none;
|
||||
}
|
||||
div.inputTags-list input.inputTags-field.is-edit {
|
||||
margin: 0 2px;
|
||||
padding: 4px 8px 3px 8px;
|
||||
border: 1px dashed #c4c4c4;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list {
|
||||
position: absolute;
|
||||
max-height: 192px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
overflow-y: auto;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
-webkit-transform: scaleY(0);
|
||||
-khtml-transform: scaleY(0);
|
||||
-moz-transform: scaleY(0);
|
||||
-ms-transform: scaleY(0);
|
||||
-o-transform: scaleY(0);
|
||||
-webkit-transform-origin: 50% 0;
|
||||
-khtml-transform-origin: 50% 0;
|
||||
-moz-transform-origin: 50% 0;
|
||||
-ms-transform-origin: 50% 0;
|
||||
-o-transform-origin: 50% 0;
|
||||
-webkit-transition-duration: 0.2s;
|
||||
-khtml-transition-duration: 0.2s;
|
||||
-moz-transition-duration: 0.2s;
|
||||
-ms-transition-duration: 0.2s;
|
||||
-o-transition-duration: 0.2s;
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list.is-active {
|
||||
opacity: 1;
|
||||
-webkit-transform: scaleY(1);
|
||||
-khtml-transform: scaleY(1);
|
||||
-moz-transform: scaleY(1);
|
||||
-ms-transform: scaleY(1);
|
||||
-o-transform: scaleY(1);
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list li {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #ddd;
|
||||
-webkit-transition-duration: 0.3s;
|
||||
-khtml-transition-duration: 0.3s;
|
||||
-moz-transition-duration: 0.3s;
|
||||
-ms-transition-duration: 0.3s;
|
||||
-o-transition-duration: 0.3s;
|
||||
-webkit-transition-duration: 0.2s;
|
||||
-khtml-transition-duration: 0.2s;
|
||||
-moz-transition-duration: 0.2s;
|
||||
-ms-transition-duration: 0.2s;
|
||||
-o-transition-duration: 0.2s;
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list li:last-child {
|
||||
border: none;
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list li:hover {
|
||||
background-color: #19BC9C;
|
||||
color: #fff;
|
||||
}
|
||||
div.inputTags-list ul.inputTags-autocomplete-list li.is-disabled {
|
||||
cursor: default;
|
||||
background-color: #f7f7f7;
|
||||
color: initial;
|
||||
}
|
||||
p.inputTags-error {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0.5em 1em;
|
||||
color: #fff;
|
||||
background-color: rgba(231, 76, 60, 0.7);
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
p.inputTags-error:first-of-type {
|
||||
margin-top: 8px;
|
||||
}
|
||||
p.inputTags-error:after {
|
||||
position: absolute;
|
||||
content: "\000D7";
|
||||
top: 50%;
|
||||
right: 0.5em;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-khtml-transform: translateY(-50%);
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
font-size: 28px;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,37 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
{% block custom_head_css_js_create %} {% endblock %}
|
||||
{% 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>{{ action }}</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">
|
||||
{% block form %} {% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,6 +1,7 @@
|
|||
{% extends 'users/_user.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
|
||||
{% block username %}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
{% extends '_list_base.html' %}
|
||||
{% load i18n static %}
|
||||
{% block custom_head_css_js %}
|
||||
|
@ -5,6 +6,11 @@
|
|||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
=======
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
>>>>>>> asset
|
||||
{% block content_left_head %}
|
||||
<a href="{% url 'users:user-group-create' %}" class="btn btn-sm btn-primary ">{% trans "Add User Group" %}</a>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends '_list_base.html' %}
|
||||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
|
|
Loading…
Reference in New Issue