Merge branch 'cmdb'

pull/530/head
ibuler 2016-09-04 21:54:17 +08:00
commit 1b9c9c48b6
30 changed files with 1249 additions and 442 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
if __name__ == '__main__':
pass
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
if __name__ == '__main__':
pass

View File

@ -22,7 +22,8 @@ class IDCSerializer(serializers.ModelSerializer):
class Meta:
model = IDC
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
class AssetGroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows AssetGroup to be viewed or edited.
@ -30,6 +31,7 @@ class AssetGroupViewSet(viewsets.ModelViewSet):
queryset = AssetGroup.objects.all()
serializer_class = AssetGroupSerializer
class AssetViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Asset to be viewed or edited.
@ -37,6 +39,7 @@ class AssetViewSet(viewsets.ModelViewSet):
queryset = Asset.objects.all()
serializer_class = AssetSerializer
class IDCViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows IDC to be viewed or edited.

View File

@ -2,6 +2,7 @@
from django import forms
from .models import IDC, Asset, AssetGroup
from django.utils.translation import gettext_lazy as _
class AssetForm(forms.ModelForm):
@ -10,11 +11,15 @@ class AssetForm(forms.ModelForm):
model = Asset
fields = [
"ip", "other_ip", "hostname", "port", "group", "username", "password", "idc", "mac_addr",
"remote_card_ip", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos",
"ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password",
"idc", "mac_addr", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos",
"number", "status", "type", "env", "sn", "is_active", "comment"
]
widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join assetgroups')}),
}
class AssetGroupForm(forms.ModelForm):
class Meta:

View File

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-09-03 14:30
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Asset',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip', models.CharField(blank=True, max_length=32, verbose_name='\u8d44\u4ea7IP')),
('other_ip', models.CharField(blank=True, max_length=255, verbose_name='\u5176\u4ed6IP')),
('remote_card_ip', models.CharField(blank=True, max_length=16, verbose_name='\u8fdc\u63a7\u5361IP')),
('hostname', models.CharField(blank=True, max_length=128, unique=True, verbose_name='\u4e3b\u673a\u540d')),
('port', models.IntegerField(blank=True, verbose_name='\u7aef\u53e3')),
('username', models.CharField(blank=True, max_length=16, verbose_name='\u7ba1\u7406\u7528\u6237\u540d')),
('password', models.CharField(blank=True, max_length=256, verbose_name='\u5bc6\u7801')),
('mac_addr', models.CharField(blank=True, max_length=20, unique=True, verbose_name='MAC\u5730\u5740')),
('brand', models.CharField(blank=True, max_length=64, verbose_name='\u786c\u4ef6\u5382\u5546\u578b\u53f7')),
('cpu', models.CharField(blank=True, max_length=64, verbose_name='CPU')),
('memory', models.CharField(blank=True, max_length=128, verbose_name='\u5185\u5b58')),
('disk', models.CharField(blank=True, max_length=1024, verbose_name='\u786c\u76d8')),
('os', models.CharField(blank=True, max_length=128, verbose_name='\u7cfb\u7edf\u4fe1\u606f')),
('cabinet_no', models.CharField(blank=True, max_length=32, verbose_name='\u673a\u67dc\u53f7')),
('cabinet_pos', models.IntegerField(blank=True, null=True, verbose_name='\u8d44\u4ea7\u4f4d\u7f6e')),
('number', models.CharField(blank=True, max_length=32, unique=True, verbose_name='\u8d44\u4ea7\u7f16\u53f7')),
('sn', models.CharField(blank=True, max_length=128, unique=True, verbose_name='SN\u7f16\u53f7')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='\u521b\u5efa\u8005')),
('is_active', models.BooleanField(default=True, verbose_name='\u662f\u5426\u6fc0\u6d3b')),
('date_added', models.DateTimeField(auto_now=True, null=True)),
('comment', models.CharField(blank=True, max_length=128, verbose_name='\u5907\u6ce8')),
],
options={
'db_table': 'asset',
},
),
migrations.CreateModel(
name='AssetExtend',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
migrations.CreateModel(
name='AssetGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, unique=True)),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='\u521b\u5efa\u8005')),
('comment', models.CharField(blank=True, max_length=128, null=True)),
],
options={
'db_table': 'assetgroup',
},
),
migrations.CreateModel(
name='IDC',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=32, verbose_name='\u673a\u623f\u540d\u79f0')),
('bandwidth', models.CharField(blank=True, max_length=32, verbose_name='\u673a\u623f\u5e26\u5bbd')),
('contact', models.CharField(blank=True, max_length=16, verbose_name='\u8054\u7cfb\u4eba')),
('phone', models.CharField(blank=True, max_length=32, verbose_name='\u8054\u7cfb\u7535\u8bdd')),
('address', models.CharField(blank=True, max_length=128, verbose_name='\u673a\u623f\u5730\u5740')),
('network', models.TextField(blank=True, verbose_name='IP\u5730\u5740\u6bb5')),
('date_added', models.DateField(auto_now=True, null=True)),
('operator', models.CharField(blank=True, max_length=32, verbose_name='\u8fd0\u8425\u5546')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='\u521b\u5efa\u8005')),
('comment', models.CharField(blank=True, max_length=128, verbose_name='\u5907\u6ce8')),
],
options={
'db_table': 'idc',
'verbose_name': 'IDC\u673a\u623f',
'verbose_name_plural': 'IDC\u673a\u623f',
},
),
migrations.AddField(
model_name='asset',
name='env',
field=models.ManyToManyField(blank=True, related_name='asset_env_extend', to='assets.AssetExtend', verbose_name='\u6240\u5c5e\u4e3b\u673a\u7ec4\u73af\u5883'),
),
migrations.AddField(
model_name='asset',
name='group',
field=models.ManyToManyField(blank=True, to='assets.AssetGroup', verbose_name='\u6240\u5c5e\u4e3b\u673a\u7ec4'),
),
migrations.AddField(
model_name='asset',
name='idc',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.IDC', verbose_name='\u673a\u623f'),
),
migrations.AddField(
model_name='asset',
name='status',
field=models.ManyToManyField(blank=True, related_name='asset_status_extend', to='assets.AssetExtend', verbose_name='\u8d44\u4ea7\u72b6\u6001'),
),
migrations.AddField(
model_name='asset',
name='type',
field=models.ManyToManyField(blank=True, related_name='asset_type_extend', to='assets.AssetExtend', verbose_name='\u8d44\u4ea7\u7c7b\u578b'),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-21 09:57
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='asset',
name='cabinet_pos',
field=models.IntegerField(blank=True, max_length=4, verbose_name='\u673a\u5668\u4f4d\u7f6e'),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-21 09:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0002_auto_20160821_1757'),
]
operations = [
migrations.AlterField(
model_name='asset',
name='cabinet_pos',
field=models.IntegerField(blank=True, max_length=4, null=True, verbose_name='\u673a\u5668\u4f4d\u7f6e'),
),
]

View File

@ -1,13 +1,14 @@
# coding:utf-8
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
from django.db import models
from django.utils.translation import ugettext_lazy as _
class AssetGroup(models.Model):
name = models.CharField(max_length=64, unique=True)
created_by = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"创建者")
comment = models.CharField(max_length=128, blank=True, null=True)
name = models.CharField(max_length=64, unique=True, null=True, blank=True, verbose_name=_('Name'))
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
@ -17,71 +18,137 @@ class AssetGroup(models.Model):
class IDC(models.Model):
name = models.CharField(max_length=32, verbose_name=u'机房名称')
bandwidth = models.CharField(max_length=32, blank=True, null=True, default='', verbose_name=u'机房带宽')
contact = models.CharField(max_length=16, blank=True, null=True, default='', verbose_name=u'联系人')
phone = models.CharField(max_length=32, blank=True, null=True, default='', verbose_name=u'联系电话')
address = models.CharField(max_length=128, blank=True, null=True, default='', verbose_name=u"机房地址")
network = models.TextField(blank=True, null=True, default='', verbose_name=u"IP地址段")
date_added = models.DateField(auto_now=True, null=True)
operator = models.CharField(max_length=32, blank=True, default='', null=True, verbose_name=u"运营商")
created_by = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"创建者")
comment = models.CharField(max_length=128, blank=True, default='', null=True, verbose_name=u"备注")
name = models.CharField(max_length=32, verbose_name=_('Name'))
bandwidth = models.CharField(max_length=32, blank=True, verbose_name=_('Bandwidth'))
contact = models.CharField(max_length=16, blank=True, verbose_name=_('Contact'))
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
address = models.CharField(max_length=128, blank=True, verbose_name=_("Address"))
network = models.TextField(blank=True, verbose_name=_('Network'))
date_added = models.DateField(auto_now=True, null=True, verbose_name=_('Date added'))
operator = models.CharField(max_length=32, blank=True, verbose_name=_('Operator'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
class Meta:
db_table = 'idc'
verbose_name = u"IDC机房"
verbose_name_plural = verbose_name
class AssetExtend(models.Model):
pass
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'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
date_added = models.DateTimeField(auto_now=True, null=True, blank=True)
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
class Meta:
db_table = 'assetextend'
class AdminUser(models.Model):
name = models.CharField(max_length=128, unique=True, null=True, blank=True, verbose_name=_('Name'))
username = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Username'))
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_('Password'))
private_key = models.CharField(max_length=4096, null=True, blank=True, verbose_name=_('SSH private key'))
is_default = models.BooleanField(default=True, verbose_name=_('As default'))
auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key'))
date_added = models.DateTimeField(auto_now=True, null=True, blank=True)
create_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
class Meta:
db_table = 'adminuser'
class SysUser(models.Model):
PROTOCOL_CHOICES = (
('ssh', 'ssh'),
('telnet', 'telnet'),
)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=16, blank=True, verbose_name=_('Username'))
password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
protocol = models.CharField(max_length=16, default='ssh', verbose_name=_('Protocol'))
private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key'))
public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
is_default = models.BooleanField(default=True, verbose_name=_('As default'))
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key'))
sudo = models.TextField(max_length=4096, blank=True, verbose_name=_('Sudo'))
shell = models.CharField(max_length=64, blank=True, verbose_name=_('Shell'))
home = models.CharField(max_length=64, blank=True, verbose_name=_('Home'))
uid = models.IntegerField(blank=True, verbose_name=_('Uid'))
date_added = models.DateTimeField(auto_now=True, null=True)
create_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
class Meta:
db_table = 'sysuser'
class Asset(models.Model):
ip = models.CharField(max_length=32, blank=True, verbose_name="主机IP")
other_ip = models.CharField(max_length=255, blank=True, null=True, verbose_name="其他IP")
remote_card_ip = models.CharField(max_length=16, blank=True, null=True, verbose_name=u'远控卡IP')
hostname = models.CharField(unique=True, max_length=128, verbose_name=u"主机名")
port = models.IntegerField(blank=True, null=True, verbose_name=u"端口号")
group = models.ManyToManyField(AssetGroup, blank=True, verbose_name=u"所属主机组")
username = models.CharField(max_length=16, blank=True, null=True, verbose_name=u"管理用户名")
password = models.CharField(max_length=256, blank=True, null=True, verbose_name=u"密码")
idc = models.ForeignKey(IDC, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=u'机房')
mac_addr = models.CharField(max_length=20, blank=True, null=True, verbose_name=u"MAC地址")
brand = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'硬件厂商型号')
cpu = models.CharField(max_length=64, blank=True, null=True, verbose_name=u'CPU')
memory = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'内存')
disk = models.CharField(max_length=1024, blank=True, null=True, verbose_name=u'硬盘')
os = models.CharField(max_length=128, blank=True, null=True, verbose_name=u'系统信息')
cabinet_no = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'机柜号')
cabinet_pos = models.IntegerField(blank=True, null=True, verbose_name=u'机器位置')
number = models.CharField(max_length=32, blank=True, null=True, verbose_name=u'资产编号')
status = models.ManyToManyField(AssetExtend, blank=True, related_name="asset_status_extend", verbose_name="机器状态")
type = models.ManyToManyField(AssetExtend, blank=True, related_name="asset_type_extend", verbose_name="机器类型")
env = models.ManyToManyField(AssetExtend, blank=True, related_name="asset_env_extend", verbose_name="所属主机组环境")
sn = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"SN编号")
created_by = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"创建者")
is_active = models.BooleanField(default=True, verbose_name=u"是否激活")
date_added = models.DateTimeField(auto_now=True, null=True)
comment = models.CharField(max_length=128, blank=True, null=True, verbose_name=u"备注")
ip = models.CharField(max_length=32, null=True, blank=True, 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(null=True, blank=True, verbose_name=_('Port'))
groups = models.ManyToManyField(AssetGroup, null=True, blank=True, 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, on_delete=models.SET_NULL, verbose_name=_("Admin User"))
sys_user = models.ManyToManyField(SysUser, null=True, blank=True, verbose_name=_("Sys User"))
idc = models.ForeignKey(IDC, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('IDC'))
mac_addr = 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'))
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, unique=True, verbose_name=_('Asset number'))
status = models.ManyToManyField(AssetExtend, related_name="asset_status_extend", verbose_name=_('Asset status'))
type = models.ManyToManyField(AssetExtend, related_name="asset_type_extend", verbose_name=_('Asset type'))
env = models.ManyToManyField(AssetExtend, related_name="asset_env_extend", verbose_name=_('Asset environment'))
sn = models.CharField(max_length=128, null=True, blank=True, unique=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_added = 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'))
def __unicode__(self):
return self.ip
def initial(self):
pass
class Meta:
db_table = 'asset'
index_together = ('ip', 'port')
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_added = models.DateTimeField(auto_now=True, null=True)
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
class Meta:
db_table = 'label'

View File

@ -1,12 +1,17 @@
{% extends 'base.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>
<h5> 添加资产 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
@ -22,81 +27,73 @@
<div class="ibox-content">
<div class="panel blank-panel">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="{% url 'assets:asset-add' %}" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
{# <li><a href="{% url 'asset_add_batch' %}" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>#}
</ul>
</div>
<div class="panel-body">
<div class="tab-content">
<div id="tab-1" class="ibox float-e-margins tab-pane active">
{% if error %}
<div class="alert alert-warning text-center">{{ error }}</div>
{% endif %}
{% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div>
{% endif %}
<div id="tab-1" class="ibox float-e-margins tab-pane active"></div>
<form id="assetForm" method="post" class="form-horizontal">
{% csrf_token %}
<h3 class="widget-head-color-box">基本信息</h3>
{{ form.hostname|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
{{ form.ip|bootstrap_horizontal }}
<p class="col-sm-offset-2">Tips: 如果IP地址不填写, IP默认会设置与主机名一致</p>
{# <div class="hr-line-dashed"></div>#}
{# <div class="form-group">#}
{# <label for="j_group" class="col-sm-2 control-label">管理用户<span class="red-fonts"> *</span></label>#}
{# <div class="col-sm-2">#}
{# <div class="radio i-checks">#}
{# <label style="padding-left: 0">#}
{# <input type="checkbox" checked="checked" id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>#}
{# </label>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <p class="col-sm-offset-2">Tips: 管理用户是服务器存在的root或拥有sudo的用户用来推送系统用户</p>#}
{# <div class="form-group" id="admin_account" style="display: none">#}
{# <label class="col-sm-2 control-label"> <span class="red-fonts"></span> </label>#}
{# <div class="col-sm-3">#}
{# <input type="text" placeholder="Username" name="username" class="form-control">#}
{# </div>#}
{##}
{# <label class="col-sm-1 control-label"> <span class="red-fonts"></span> </label>#}
{# <div class="col-sm-4">#}
{# <input type="password" placeholder="Password" name="password" class="form-control">#}
{# </div>#}
{# </div>#}
<div class="form-group" id="id_port">
<div class="hr-line-dashed"></div>
<label class="col-sm-2 control-label"> 端口<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
<input type="text" placeholder="Port" name="port" class="form-control" value="{{ default_port }}">
<label class="col-sm-2 control-label">端口</label>
<div class="col-sm-9">
<input type="text" placeholder="" name="port" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
{{ form.group|bootstrap_horizontal }}
{# <div class="form-group" id="id_type">#}
{# <label class="col-sm-2 control-label">资产类型</label>#}
{# <div class="col-sm-9">#}
{# <input type="text" placeholder="" name="type" class="form-control">#}
{# </div>#}
{# </div>#}
{# {{ af.is_active|bootstrap_horizontal }}#}
{{ form.type|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts"> *</span> </label>
<div class="col-sm-8">
<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="" value="1" name="is_active">激活 </label>
<label> <input type="radio" value="0" name="is_active"> 禁用</label>
<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>
<div class="form-group" id="id_manager_user">
<div class="col-sm-offset-2 col-sm-9">
<input type="text" placeholder="请选择管理用户" name="manager_user" class="form-control">
</div>
</div>
<p class="col-sm-offset-2">Tips: 管理用户是服务器存在的root或拥有sudo的用户用来推送系统用户</p>
<div class="form-group">
<label for="system_user" class="col-sm-2 control-label">系统用户</label>
<div class="col-sm-9">
<input type="text" placeholder="" name="system_user" class="form-control">
</div>
</div>
<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="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<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>
@ -113,85 +110,10 @@
</div>
{% endblock %}
{% block self_footer_js %}
<script>
$('document').ready(function(){
var check_default = "{{ default_setting.name }}";
console.log(check_default);
if (check_default != 'default'){
$('#id_use_default_auth').attr('disabled', true);
$('#id_use_default_auth').attr('checked', false);
$('#admin_account').css('display', 'block');
} else {
$('#id_use_default_auth').click(function(){
if ($(this).is(':checked')){
$('#admin_account').css('display', 'none');
}
else {
$('#admin_account').css('display', 'block');
}
})
}
});
var required_fields = ["id_hostname", "id_port"];
required_fields.forEach(function(field) {
$('label[for="' + field + '"]').parent().addClass("required");
});
$('#assetForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_ip: [/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/, 'ip地址不正确'],
check_port: [/^\d{1,5}$/, '端口号不正确'],
use_default_auth: function() {
var str1 = $("#id_use_default_auth").is(":checked");
if (str1 == true){
var decide = false;
} else {
var decide = true;
}
return decide}
},
fields: {
"ip": {
rule: "check_ip;",
tip: "输入IP",
ok: "",
msg: {required: "必须填写!"}
},
"hostname": {
rule: "required;length[0~53]",
tip: "填写主机名",
ok: "",
msg: {required: "必须填写!"}
},
"port": {
rule: "required",
tip: "输入端口号",
ok: "",
msg: {required: "必须填写!"}
},
"username": {
rule: "required(use_default_auth)",
tip: "输入用户名",
ok: "",
msg: {required: "必须填写!"}
},
"password": {
rule: "required(use_default_auth);length[0~64]",
tip: "输入密码",
ok: "",
msg: {required: "必须填写!"}
}
},
valid: function(form) {
form.submit();
}
});
</script>
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2();
})
</script>
{% endblock %}

View File

@ -0,0 +1,374 @@
{% extends 'base.html' %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-4">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="text text-primary"><b>{{ asset.ip }}</b></span>
<div class="ibox-tools">
{# <a class="" href="{% url 'assets:asset-update' %}">#}
<i class="fa fa-refresh"></i>
</a>
<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>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content ibox-heading">
<h3>主机详细信息</h3>
<small><i class="fa fa-map-marker"></i> 此主机详细信息.</small>
</div>
<div class="ibox-content">
<div>
<div class="text-left">
<table class="table">
<tr>
<td class="text-navy">主机名</td>
<td>{{ asset.hostname|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">IP</td>
<td>{{ asset.ip|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">其他IP</td>
<td>
<table class="table">
{% if asset.other_ip %}
{% for ip in asset.other_ip %}
<tr>
<td>{{ ip }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
</td>
</tr>
<tr>
<td class="text-navy">远控IP</td>
<td>{{ asset.remote_ip|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">端口</td>
<td>{{ asset.port|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">主机组</td>
<td>
<table class="table">
{% for asset_group in asset.group.all %}
<tr>
<td>{{ asset_group.name|default_if_none:"" }}</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
<tr>
<td class="text-navy">使用默认管理账号</td>
{# <td>{{ asset.use_default_auth|bool2str }}</td>#}
{# <td>{{ asset.use_default_auth|bool2str }} {% if not asset.use_default_auth %} <span class="text-info">{{ asset.username }}</span> {% endif %}</td>#}
</tr>
<tr>
<td class="text-navy">机房</td>
<td>{{ asset.idc.name|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">硬件厂商型号</td>
<td>{{ asset.brand|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">CPU</td>
<td>{{ asset.cpu|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">内存</td>
<td>{{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %}</td>
</tr>
<tr>
<td class="text-navy">硬盘</td>
<td>
<table class="table">
{% if asset.disk %}
{% for disk, value in asset.disk %}
<tr>
<td><span class="text-navy">{{ disk|default_if_none:"" }}</span> &nbsp&nbsp&nbsp {{ value|default_if_none:"" }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
</td>
</tr>
<tr>
<td class="text-navy">资产编号</td>
<td>{{ asset.number|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">SN</td>
<td>{{ asset.sn|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">主机类型</td>
<td>{{ asset.get_asset_type_display|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">系统版本</td>
<td>{{ asset.system_type|default_if_none:"" }} {{ asset.system_version|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">系统平台</td>
<td>{{ asset.system_arch|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">运行环境</td>
<td>{{ asset.get_env_display|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">机器状态</td>
<td>{{ asset.get_status_display|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">机柜号</td>
<td>{{ asset.cabinet|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">机柜位置</td>
<td>{{ asset.position|default_if_none:"" }}</td>
</tr>
<tr>
<td class="text-navy">激活</td>
<td>{{ asset.is_active }}</td>
</tr>
<tr>
<td class="text-navy">添加日期</td>
<td>{{ asset.date_added|date:"Y-m-d H:i:s" }}</td>
</tr>
<tr>
<td class="text-navy">备注</td>
<td>{{ asset.comment|default_if_none:"" }}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="ibox float-e-margins">
<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>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content ibox-heading">
<h3>主机所有授权的信息</h3>
<small><i class="fa fa-map-marker"></i> 包含了此主机所有授权的信息.</small>
</div>
<div class="ibox-content">
<div>
<div class="text-left">
{% if perm_info %}
{% if user_perm %}
<table class="table">
<p>授权用户信息</p>
<td class="text-navy">授权用户</td>
<td class="text-navy">关联用户</td>
{% for perm in user_perm %}
<tr>
<td class="text-navy"><a href="{% url 'user_detail' %}?id={{ perm.0.id }}">{{ perm.0 }}</a></td>
<td>
<table class="table">
{% if perm.1 %}
{% for role in perm.1 %}
<tr>
<td class="text-navy"><a href="{% url 'role_detail' %}?id={{ role.id }}">{{ role }}</a></td>
</tr>
{% endfor %}
{% endif %}
</table>
</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if user_group_perm %}
<table class="table">
<p>授权用户组信息</p>
<td class="text-navy">授权用户组</td>
<td class="text-navy">组详情</td>
{% for user_group in user_group_perm %}
<tr>
<td class="text-navy">{{ user_group }}</td>
<td class="text-navy"><a href="{% url 'user_group_list' %}?gid={{ user_group.id }}">详情</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if user_rule_perm %}
<table class="table">
<p>授权规则信息</p>
<td class="text-navy">授权规则</td>
<td class="text-navy">详情</td>
{% for rule in user_rule_perm %}
<tr>
<td class="text-navy">{{ rule }}</td>
<td class="text-navy"><a href="{% url 'rule_detail' %}?id={{ rule.id }}">详情</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
{% else %}
<p class="text-center">(暂无)</p>
{% endif %}
</div>
</div>
</div>
<div class="ibox-title">
<h5>主机修改记录</h5>
{# <a href="{% url 'asset_edit' %}?id={{ asset.id }}" data-toggle="tooltip" class="text-success pull-center" data-placement="bottom" title="修改">&nbsp&nbsp&nbsp&nbsp点击修改</a>#}
<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>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content ibox-heading">
<h3>主机修改记录</h3>
<small><i class="fa fa-map-marker"></i> 包含了此主机所有历史修改记录.</small>
</div>
<div class="ibox-content">
<div class="feed-activity-list">
{% if asset_record %}
{# {% for r in asset_record %}#}
{# <div class="feed-element">#}
{# <div>#}
{# <small class="pull-right">{{ r.alert_time|naturaltime }}</small>#}
{# <strong class="text-navy">{{ r.username }}</strong>#}
{# {% for i in r.content|str_to_list %}#}
{# <div>{{ i.0 }} 由 <span class="text-success">{{ i.1|str_to_code }}</span> 改为 <span class="text-warning">{{ i.2|str_to_code }}</span></div>#}
{# {% endfor %}#}
{# <small class="text-success">{{ r.alert_time }}</small>#}
{# </div>#}
{# </div>#}
{# {% endfor %}#}
{% else %}
<p class="text-center">(暂无)</p>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="ibox float-e-margins">
<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>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content ibox-heading">
<h3>最近一周登录记录</h3>
<small><i class="fa fa-map-marker"></i> 此主机最近一周用户登录信息.</small>
</div>
<div class="ibox-content inspinia-timeline">
{% if log %}
{% for l in log %}
<div class="timeline-item">
<div class="row">
<div class="col-xs-5 date">
<i class="fa fa-info-circle"></i>
<small class="text-navy">{{ l.user }}</small>
<br/>
</div>
<div class="col-xs-7 content no-top-border">
<p class="m-b-xs"><strong>详细信息</strong></p>
<p>来源IP: {{ l.remote_ip }}</p>
<p>开始: {{ l.start_time |date:"Y-m-d H:i:s" }}</p>
<p>结束: {{ l.end_time |date:"Y-m-d H:i:s" }}</p>
</div>
</div>
</div>
{% endfor %}
<button id="show" class="btn btn-primary btn-block m-t"><i class="fa fa-arrow-down"></i> 所有 </button>
<div id='more' style="display: none">
<br/>
{% for l in log_more %}
<div class="timeline-item">
<div class="row">
<div class="col-xs-5 date">
<i class="fa fa-info-circle"></i>
<small class="text-navy">{{ l.user }}</small>
<br/>
</div>
<div class="col-xs-7 content no-top-border">
<p class="m-b-xs"><strong>详细信息</strong></p>
<p>来源IP: {{ l.remote_ip }}</p>
<p>开始: {{ l.start_time |date:"Y-m-d H:i:s" }}</p>
<p>结束: {{ l.end_time |date:"Y-m-d H:i:s" }}</p>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class="text-center">(暂无)</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#show').click(function(){
$('#show').css('display', 'none');
$('#more').css('display', 'block');
})
})
</script>
{% endblock %}

View File

@ -6,7 +6,7 @@
<div class="col-sm-12">
<div class="ibox float-e-margins" id="all">
<div class="ibox-title">
<h5> 主机详细信息列表</h5>
<h5> 资产列表</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
@ -102,14 +102,11 @@
<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"> IDC </th>
<th class="text-center"> 所属主机组 </th>
{# <th class="text-center"> 配置信息 </th>#}
<th class="text-center"> 操作系统 </th>
<th class="text-center"> cpu核数 </th>
<th class="text-center"> 内存 </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>
@ -119,15 +116,18 @@
<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 hostname"> <a href="{% url 'assets:asset-detail' %}?id={{ asset.id }}">{{ asset.hostname|default_if_none:"" }}</a></td>
<td class="text-center"> {{ asset.ip|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.idc.name|default_if_none:"" }} </td>
{# <td class="text-center">{{ asset.group.all|group_str2 }}</td>#}
{# <td class="text-center">{{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}</td>#}
<td class="text-center">{{ asset.system_type|default_if_none:"" }}{{ asset.system_version|default_if_none:"" }}</td>
<td class="text-center"> {{ asset.cpu|default_if_none:"" }} </td>
<td class="text-center"> {{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %}</td>
<td class="text-center"> {{ asset.disk }}{% if asset.disk %}G{% endif %}</td>
<td class="text-center"> {{ asset.hostname }} </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>
@ -145,7 +145,7 @@
{# <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 'paginator.html' %}#}
{% include '_pagination.html' %}
</div>
</form>
</div>

View File

@ -0,0 +1,66 @@
{% 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>
{% 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>{% trans 'Create asset group' %}</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">
<form method="post" id="userForm" class="form-horizontal" action="" >
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
<div class="form-group">
<label for="users" class="col-sm-2 control-label">{% trans 'Asset' %}</label>
<div class="col-sm-9">
<select name="assets" id="assets" data-placeholder="{% trans 'Select asset' %}" class="select2 form-control m-b" multiple tabindex="2">
{% for asset in assets %}
<option value="{{ asset.id }}">{{ asset.ip }}:{{ asset.port }}</option>
{% endfor %}
</select>
</div>
</div>
{{ form.comment|bootstrap_horizontal }}
<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>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2();
})
</script>
{% endblock %}

View File

@ -0,0 +1,59 @@
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'assets:assetgroup-add' %}" class="btn btn-sm btn-primary "> {% trans "Create asset group" %} </a>
{% endblock %}
{% 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:assetgroup-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center"><a href="{% url 'assets:assetgroup-list' %}?sort=date_expired">{% trans 'Comment' %}</a></th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for assetgroup in assetgroups %}
<tr class="gradeX">
<td class="text-center">
<input type="checkbox" name="checked" value="{{ assetgroup.id }}">
</td>
<td class="text-center">
<a href="{% url 'assets:assetgroup-detail' pk=assetgroup.id %}">
{{ assetgroup.name }}
</a>
</td>
<td class="text-center">{{ assetgroup.asset_set.count }}</td>
<td class="text-center">{{ assetgroup.comment }}</td>
<td class="text-center">
<a href="{% url 'assets:assetgroup-edit' pk=assetgroup.id %}" class="btn btn-xs btn-info">{% trans 'Edit' %}</a>
<a href="{% url 'assets:assetgroup-delete' pk=assetgroup.id %}" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
{% endblock %}
{% 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>
<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>
</form>
{% endblock %}

View File

@ -1,20 +1,27 @@
# coding:utf-8
from django.conf.urls import url,include
from .views import *
from .api import (
AssetGroupViewSet,AssetViewSet,IDCViewSet
)
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'assetgroup', AssetGroupViewSet)
router.register(r'asset', AssetViewSet)
router.register(r'idc', IDCViewSet)
from django.conf.urls import url, include
import views
# from .api import (
# AssetGroupViewSet, AssetViewSet, IDCViewSet
# )
# from rest_framework import routers
# router = routers.DefaultRouter()
# router.register(r'assetgroup', AssetGroupViewSet)
# router.register(r'asset', AssetViewSet)
# router.register(r'idc', IDCViewSet)
app_name = 'assets'
urlpatterns = [
url(r'^add/$', AssetAddView.as_view(), name='asset-add'),
url(r'^list/$', AssetListView.as_view(), name='asset-list'),
url(r'^(?P<pk>[0-9]+)/delete/$', AssetDeleteView.as_view(), name='asset-list'),
url(r'^(?P<pk>[0-9]+)/detail/$', AssetDetailView.as_view(), name='asset-detail'),
url(r'^api/v1.0/', include(router.urls)),
url(r'^$', views.AssetListView.as_view(), name='asset-index'),
url(r'^asset$', views.AssetListView.as_view(), name='asset-list'),
url(r'^asset/add$', views.AssetAddView.as_view(), name='asset-add'),
url(r'^asset/(?P<pk>[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'),
url(r'^asset/(?P<pk>[0-9]+)$/edit', views.AssetEditView.as_view(), name='asset-edit'),
url(r'^asset/(?P<pk>[0-9]+)/delete$', views.AssetDeleteView.as_view(), name='asset-delete'),
url(r'^assetgroup$', views.AssetGroupListView.as_view(), name='assetgroup-list'),
url(r'^assetgroup/add$', views.AssetGroupAddView.as_view(), name='assetgroup-add'),
url(r'^assetgroup/(?P<pk>[0-9]+)$', views.AssetGroupDetailView.as_view(), name='assetgroup-detail'),
url(r'^assetgroup/(?P<pk>[0-9]+)/edit$', views.AssetGroupEditView.as_view(), name='assetgroup-edit'),
url(r'^assetgroup/(?P<pk>[0-9]+)/delete$', views.AssetGroupDeleteView.as_view(), name='assetgroup-delete'),
# url(r'^api/v1.0/', include(router.urls)),
]

View File

@ -1,2 +1,23 @@
# ~*~ coding: utf-8 ~*~
#
from django.contrib.auth.mixins import UserPassesTestMixin
from django.urls import reverse_lazy
from common.tasks import send_mail_async
from common.utils import reverse
from users.models import User
try:
import cStringIO as StringIO
except ImportError:
import StringIO
class AdminUserRequiredMixin(UserPassesTestMixin):
login_url = reverse_lazy('users:login')
def test_func(self):
return self.request.user.is_staff

View File

@ -1,28 +1,19 @@
from django.views.generic import (
TemplateView, ListView
)
# coding:utf-8
from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext as _
from django.views.generic import TemplateView, ListView
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.views.generic import TemplateView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy
from django.views.generic.detail import DetailView
from .models import Asset, AssetGroup, IDC, AssetExtend
from .forms import AssetForm, AssetGroupForm
from django.views.generic.edit import (
CreateView, DeleteView, FormView, UpdateView
)
from django.views.generic.detail import (
DetailView
)
from .models import (
Asset, AssetGroup, IDC, AssetExtend
)
from .forms import (
AssetForm,
)
from .utils import AdminUserRequiredMixin
class AssetAddView(CreateView):
@ -31,8 +22,12 @@ class AssetAddView(CreateView):
template_name = 'assets/asset_add.html'
success_url = reverse_lazy('assets:asset-list')
def form_invalid(self, form):
print(form.errors)
return super(AssetAddView, self).form_invalid(form)
class AssetEdit():
class AssetEditView(UpdateView):
pass
@ -52,3 +47,44 @@ class AssetDetailView(DetailView):
context_object_name = 'asset'
template_name = 'assets/asset_detail.html'
class AssetGroupAddView(CreateView):
model = AssetGroup
form_class = AssetGroupForm
template_name = 'assets/assetgroup_add.html'
success_url = reverse_lazy('assets:assetgroup-list')
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Create asset group'),
'assets': Asset.objects.all(),
}
kwargs.update(context)
return super(AssetGroupAddView, self).get_context_data(**kwargs)
class AssetGroupListView(ListView):
model = AssetGroup
context_object_name = 'assetgroups'
template_name = 'assets/assetgroup_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Asset group list')
}
kwargs.update(context)
return super(AssetGroupListView, self).get_context_data(**kwargs)
class AssetGroupDetailView(DetailView):
pass
class AssetGroupEditView(UpdateView):
pass
class AssetGroupDeleteView(DeleteView):
pass

View File

@ -1,39 +1,35 @@
# ~*~ coding: utf-8 ~*~
from django import template
from django.utils import timezone
from django.conf import settings
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def pagination_range(total_page, current_num=1, display=5):
"""Return Page range
:param total_page: Total numbers of paginator
:param current_num: current display page num
:param display: Display as many as [:display:] page
In order to display many page num on web like:
< 1 2 3 4 5 >
"""
try:
current_num = int(current_num)
except ValueError:
current_num = 1
start = current_num - display/2 if current_num > display/2 else 1
end = start + display if start + display <= total_page else total_page + 1
return range(start, end)
# ~*~ coding: utf-8 ~*~
from django import template
from django.utils import timezone
from django.conf import settings
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def pagination_range(total_page, current_num=1, display=5):
"""Return Page range
:param total_page: Total numbers of paginator
:param current_num: current display page num
:param display: Display as many as [:display:] page
In order to display many page num on web like:
< 1 2 3 4 5 >
"""
try:
current_num = int(current_num)
except ValueError:
current_num = 1
start = current_num - display/2 if current_num > display/2 else 1
end = start + display if start + display <= total_page else total_page + 1
return range(start, end)

View File

@ -1,24 +1,23 @@
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
from django.shortcuts import reverse as dj_reverse
from django.conf import settings
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, external=False):
url = dj_reverse(viewname, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app)
if external:
url = settings.SITE_URL.strip('/') + url
return url
def get_object_or_none(model, **kwargs):
try:
obj = model.objects.get(**kwargs)
except model.DoesNotExist:
obj = None
return obj
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
from django.shortcuts import reverse as dj_reverse
from django.conf import settings
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, external=False):
url = dj_reverse(viewname, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app)
if external:
url = settings.SITE_URL.strip('/') + url
return url
def get_object_or_none(model, **kwargs):
try:
obj = model.objects.get(**kwargs)
except model.DoesNotExist:
obj = None
return obj

View File

@ -132,7 +132,7 @@ else:
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
#
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@ -215,7 +215,7 @@ LOGGING = {
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'zh_CN'
LANGUAGE_CODE = 'en_US'
TIME_ZONE = 'Asia/Shanghai'

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-04 12:20+0800\n"
"POT-Creation-Date: 2016-09-04 17:31+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,6 +17,140 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: assets/models.py:9 assets/models.py:21
msgid "Name"
msgstr "名称"
#: assets/models.py:10 assets/models.py:29 assets/models.py:71
msgid "Created by"
msgstr "创建者"
#: assets/models.py:11 assets/models.py:30 assets/models.py:74
msgid "Comment"
msgstr "备注"
#: assets/models.py:22
msgid "Bandwidth"
msgstr "带宽"
#: assets/models.py:23
msgid "Contact"
msgstr "联系人"
#: assets/models.py:24
msgid "Phone"
msgstr "手机"
#: assets/models.py:25
msgid "Address"
msgstr "地址"
#: assets/models.py:26
msgid "Network"
msgstr "网络"
#: assets/models.py:27 assets/models.py:73
msgid "Date added"
msgstr "加入日期"
#: assets/models.py:28
msgid "Operator"
msgstr "运营商"
#: assets/models.py:37 assets/models.py:54 templates/_nav.html:23
msgid "IDC"
msgstr "机房"
#: assets/models.py:46
msgid "IP"
msgstr ""
#: assets/models.py:47
msgid "Other IP"
msgstr ""
#: assets/models.py:48
msgid "Remote card IP"
msgstr ""
#: assets/models.py:49
msgid "Hostname"
msgstr "用户名"
#: assets/models.py:50
msgid "Port"
msgstr "端口"
#: assets/models.py:51
msgid "Asset groups"
msgstr "用户组"
#: assets/models.py:52
#, fuzzy
#| msgid "Edit user"
msgid "Admin user"
msgstr "编辑用户"
#: assets/models.py:53
msgid "Admin password"
msgstr "管理员密码"
#: assets/models.py:55
msgid "Mac address"
msgstr "Mac地址"
#: assets/models.py:56
msgid "Brand"
msgstr "品牌"
#: assets/models.py:57
msgid "CPU"
msgstr "CPU"
#: assets/models.py:58
msgid "Memory"
msgstr "内存"
#: assets/models.py:59
msgid "Disk"
msgstr "硬盘"
#: assets/models.py:60
msgid "OS"
msgstr "操作系统"
#: assets/models.py:61
msgid "Cabinet number"
msgstr "机柜编号"
#: assets/models.py:62
msgid "Cabinet position"
msgstr "机柜层号"
#: assets/models.py:63
msgid "Asset number"
msgstr "资产编号"
#: assets/models.py:65
msgid "Asset status"
msgstr "资产状态"
#: assets/models.py:67
msgid "Asset type"
msgstr "系统类型"
#: assets/models.py:69
msgid "Asset environment"
msgstr "资产环境"
#: assets/models.py:70
msgid "Serial number"
msgstr "序列号"
#: assets/models.py:72
msgid "Is active"
msgstr "是否激活"
#: templates/_header_bar.html:8
msgid "Search"
msgstr "搜索"
@ -57,16 +191,16 @@ msgstr "资产"
msgid "Assetgroup"
msgstr "用户组"
#: templates/_nav.html:23
msgid "IDC"
msgstr "机房"
#: templates/_nav.html:24
msgid "Asset admin"
#, fuzzy
#| msgid "Asset admin"
msgid "Assetadmin"
msgstr "管理用户"
#: templates/_nav.html:25
msgid "Asset user"
#, fuzzy
#| msgid "Asset user"
msgid "Assetuser"
msgstr "系统用户"
#: templates/_nav.html:26
@ -121,22 +255,15 @@ msgstr "注销登录"
msgid "Play CAPTCHA as audio file"
msgstr ""
#~ msgid "Username"
#~ msgstr "用户"
#~ msgid "Asset user"
#~ msgstr "系统用户"
#~ msgid "Password"
#~ msgstr "密码"
#, fuzzy
#~ msgid "Join usergroups"
#~ msgstr "添加到用户组"
#~ msgid "Name"
#~ msgstr "名称"
#~ msgid "Comment"
#~ msgstr "备注"
#~ msgid "Administrator"
#~ msgstr "管理员"
@ -152,9 +279,6 @@ msgstr ""
#~ msgid "Wechat"
#~ msgstr "微信"
#~ msgid "Phone"
#~ msgstr "手机"
#~ msgid "Enable OTP"
#~ msgstr "二次验证"
@ -200,9 +324,6 @@ msgstr ""
#~ msgid "Captcha invalid"
#~ msgstr "验证码错误"
#~ msgid "Reset password"
#~ msgstr "重置密码"
#~ msgid "Password again"
#~ msgstr "再次输入密码"
@ -224,12 +345,6 @@ msgstr ""
#~ msgid "User log"
#~ msgstr "登录日志"
#~ msgid "Created by"
#~ msgstr "创建者"
#~ msgid "Date joined"
#~ msgstr "加入日期"
#~ msgid "Last login"
#~ msgstr "最后登录"
@ -245,12 +360,6 @@ msgstr ""
#~ msgid "Add"
#~ msgstr "添加"
#~ msgid "Asset num"
#~ msgstr "资产数量"
#~ msgid "Active"
#~ msgstr "有效"
#~ msgid "Edit"
#~ msgstr "编辑"
@ -377,9 +486,6 @@ msgstr ""
#~ msgid "Create user<a href=\"%s\">%s</a> success."
#~ msgstr "创建用户<a href=\"%s\">%s</a> 成功"
#~ msgid "Edit user"
#~ msgstr "编辑用户"
#~ msgid "Usergroup list"
#~ msgstr "用户组列表"

View File

@ -11,7 +11,7 @@
</div>
<ul class="nav navbar-top-links navbar-right">
<li>
<span class="m-r-sm text-muted welcome-message">{% trans 'Welcome use Jumpserver system' %}</span>
<span class="m-r-sm text-muted welcome-message">{% trans 'Welcome to use Jumpserver system' %}</span>
</li>
<li class="dropdown">
<a class="dropdown-toggle count-info" data-toggle="dropdown" href="#">

View File

@ -18,8 +18,8 @@
<i class="fa fa-inbox"></i> <span class="nav-label">{% trans 'Assets' %}</span><span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li class=""><a href="">{% trans 'Asset' %}</a></li>
<li class=""><a href="">{% trans 'Assetgroup' %}</a></li>
<li class="{% url 'assets:asset-list' %}"><a href="">{% trans 'Asset' %}</a></li>
<li class=""><a href="{% url 'assets:assetgroup-list' %}">{% trans 'Assetgroup' %}</a></li>
<li class=""><a href="">{% trans 'IDC' %}</a></li>
<li class=""><a href="">{% trans 'Assetadmin' %}</a></li>
<li class=""><a href="">{% trans 'Assetuser' %}</a></li>

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-04 12:20+0800\n"
"POT-Creation-Date: 2016-09-04 17:31+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -97,6 +97,10 @@ msgstr ""
msgid "Date expired"
msgstr ""
#: users/models.py:122 users/templates/users/user_detail.html:101
msgid "Created by"
msgstr ""
#: users/models.py:228
msgid "Administrator is the super user of system"
msgstr ""
@ -131,7 +135,7 @@ msgstr ""
#: users/templates/users/_user.html:70
#: users/templates/users/forget_password.html:44
#: users/templates/users/user_list.html:63
msgid "Commit"
msgid "Submit"
msgstr ""
#: users/templates/users/forget_password.html:26
@ -187,10 +191,6 @@ msgstr ""
msgid "Search"
msgstr ""
#: users/templates/users/user_detail.html:101
msgid "Created by"
msgstr ""
#: users/templates/users/user_detail.html:105
msgid "Date joined"
msgstr ""

View File

@ -119,7 +119,7 @@ class User(AbstractUser):
is_first_login = models.BooleanField(default=False)
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True,
verbose_name=_('Date expired'))
created_by = models.CharField(max_length=30, default='')
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
@property
def password_raw(self):

View File

@ -1,33 +1,31 @@
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from .models import User, UserGroup
class UserSerializer(serializers.ModelSerializer):
groups = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:usergroup-detail-api')
class Meta:
model = User
exclude = [
'password', 'first_name', 'last_name', 'secret_key_otp',
'private_key', 'public_key', 'avatar',
]
class UserActiveSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['is_active']
class UserGroupSerializer(serializers.ModelSerializer):
users = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:user-detail-api')
class Meta:
model = UserGroup
fields = '__all__'
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from .models import User, UserGroup
class UserSerializer(serializers.ModelSerializer):
groups = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:usergroup-detail-api')
class Meta:
model = User
exclude = [
'password', 'first_name', 'last_name', 'secret_key_otp',
'private_key', 'public_key', 'avatar',
]
class UserActiveSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['is_active']
class UserGroupSerializer(serializers.ModelSerializer):
users = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:user-detail-api')
class Meta:
model = UserGroup
fields = '__all__'

View File

@ -67,7 +67,7 @@
<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 'Commit' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>

View File

@ -41,7 +41,7 @@
<input type="email" name="email" class="form-control" placeholder="Email address" required="">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Commit' %}</button>
<button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Submit' %}</button>
</form>
</div>

View File

@ -60,7 +60,7 @@
<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 'Commit' %}
{% trans 'Submit' %}
</button>
</div>

View File

@ -1,41 +1,38 @@
# ~*~ coding: utf-8 ~*~
import os
import urllib
import hashlib
from django import template
from django.utils import timezone
from django.conf import settings
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def is_expired(datetime):
if datetime > timezone.now():
return False
else:
return True
@register.filter
def user_avatar_url(user):
if user.avatar:
return user.avatar.url
else:
default_dir = os.path.join(settings.MEDIA_ROOT, 'avatar', 'default')
if os.path.isdir(default_dir):
default_avatar_list = os.listdir(default_dir)
default_avatar = default_avatar_list[len(user.username) % len(default_avatar_list)]
return os.path.join(settings.MEDIA_URL, 'avatar', 'default', default_avatar)
return 'https://www.gravatar.com/avatar/c6812ab450230979465d7bf288eadce2a?s=120&d=identicon'
# ~*~ coding: utf-8 ~*~
import os
import urllib
import hashlib
from django import template
from django.utils import timezone
from django.conf import settings
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def is_expired(datetime):
if datetime > timezone.now():
return False
else:
return True
@register.filter
def user_avatar_url(user):
if user.avatar:
return user.avatar.url
else:
default_dir = os.path.join(settings.MEDIA_ROOT, 'avatar', 'default')
if os.path.isdir(default_dir):
default_avatar_list = os.listdir(default_dir)
default_avatar = default_avatar_list[len(user.username) % len(default_avatar_list)]
return os.path.join(settings.MEDIA_URL, 'avatar', 'default', default_avatar)
return 'https://www.gravatar.com/avatar/c6812ab450230979465d7bf288eadce2a?s=120&d=identicon'

View File

@ -168,10 +168,10 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
context_object_name = "user"
def get_context_data(self, **kwargs):
context = super(UserDetailView, self).get_context_data(**kwargs)
groups = [group for group in UserGroup.objects.iterator() if group not in self.object.groups.iterator()]
context.update({'app': _('Users'), 'action': _('User detail'), 'groups': groups})
return context
context = {'app': _('Users'), 'action': _('User detail'), 'groups': groups}
kwargs.update(context)
return super(UserDetailView, self).get_context_data(**kwargs)
class UserGroupListView(AdminUserRequiredMixin, ListView):

View File

@ -19,7 +19,7 @@ apps_dir = os.path.join(BASE_DIR, 'apps')
def start_django():
http_host = CONFIG.HTTP_LISTEN_HOST or 'locahost'
http_host = CONFIG.HTTP_LISTEN_HOST or '127.0.0.1'
http_port = CONFIG.HTTP_LISTEN_PORT or '8080'
os.chdir(apps_dir)
print('start django')