diff --git a/apps/__init__.py b/apps/__init__.py index 597573362..f93d0bec7 100644 --- a/apps/__init__.py +++ b/apps/__init__.py @@ -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 diff --git a/apps/assets/api.py b/apps/assets/api.py index e1e1900e8..27539eb09 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -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. diff --git a/apps/assets/forms.py b/apps/assets/forms.py index 0c6ac66e4..90283c37a 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -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: diff --git a/apps/assets/migrations/0001_initial.py b/apps/assets/migrations/0001_initial.py new file mode 100644 index 000000000..dc20ec9f1 --- /dev/null +++ b/apps/assets/migrations/0001_initial.py @@ -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'), + ), + ] diff --git a/apps/assets/migrations/0002_auto_20160821_1757.py b/apps/assets/migrations/0002_auto_20160821_1757.py new file mode 100644 index 000000000..e22966fd8 --- /dev/null +++ b/apps/assets/migrations/0002_auto_20160821_1757.py @@ -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'), + ), + ] diff --git a/apps/assets/migrations/0003_auto_20160821_1759.py b/apps/assets/migrations/0003_auto_20160821_1759.py new file mode 100644 index 000000000..e5c49bcd5 --- /dev/null +++ b/apps/assets/migrations/0003_auto_20160821_1759.py @@ -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'), + ), + ] diff --git a/apps/assets/models.py b/apps/assets/models.py index 66612e7b4..5098e052c 100644 --- a/apps/assets/models.py +++ b/apps/assets/models.py @@ -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' diff --git a/apps/assets/templates/assets/asset_add.html b/apps/assets/templates/assets/asset_add.html index f42a06c9f..5a265253d 100644 --- a/apps/assets/templates/assets/asset_add.html +++ b/apps/assets/templates/assets/asset_add.html @@ -1,12 +1,17 @@ {% extends 'base.html' %} +{% load static %} {% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} {% block content %}
-
填写资产基本信息
+
添加资产
@@ -22,81 +27,73 @@
-
-
- {% if error %} -
{{ error }}
- {% endif %} - {% if msg %} -
{{ msg }}
- {% endif %} - +
{% csrf_token %} +

基本信息

{{ form.hostname|bootstrap_horizontal }} -
{{ form.ip|bootstrap_horizontal }} -

Tips: 如果IP地址不填写, IP默认会设置与主机名一致

- -{#
#} -{#
#} -{# #} -{#
#} -{#
#} -{# #} -{#
#} -{#
#} -{#
#} -{#

Tips: 管理用户是服务器存在的root或拥有sudo的用户,用来推送系统用户

#} -{# #}
-
- -
- + +
+
-
- {{ form.group|bootstrap_horizontal }} +{#
#} +{# #} +{#
#} +{# #} +{#
#} +{#
#} -{# {{ af.is_active|bootstrap_horizontal }}#} + {{ form.type|bootstrap_horizontal }} + + {{ form.comment|bootstrap_horizontal }}
-
-
+

关联资产用户

+
+ +
- - + +
+
+
+ +
+
+

Tips: 管理用户是服务器存在的root或拥有sudo的用户,用来推送系统用户

+ +
+ +
+ +
+
+ +
+

所属

+ {{ form.idc|bootstrap_horizontal }} + + {{ form.groups|bootstrap_horizontal }} + +
+

标签

+
-
+
@@ -113,85 +110,10 @@
{% endblock %} -{% block self_footer_js %} - - +{% block custom_foot_js %} + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html new file mode 100644 index 000000000..5d8a48db9 --- /dev/null +++ b/apps/assets/templates/assets/asset_detail.html @@ -0,0 +1,374 @@ +{% extends 'base.html' %} +{% block content %} +
+
+
+
+
+ {{ asset.ip }} + +
+
+

主机详细信息

+ 此主机详细信息. +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +{# #} +{# #} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
主机名{{ asset.hostname|default_if_none:"" }}
IP{{ asset.ip|default_if_none:"" }}
其他IP + + {% if asset.other_ip %} + {% for ip in asset.other_ip %} + + + + {% endfor %} + {% endif %} +
{{ ip }}
+
远控IP{{ asset.remote_ip|default_if_none:"" }}
端口{{ asset.port|default_if_none:"" }}
主机组 + + {% for asset_group in asset.group.all %} + + + + {% endfor %} +
{{ asset_group.name|default_if_none:"" }}
+
使用默认管理账号{{ asset.use_default_auth|bool2str }}{{ asset.use_default_auth|bool2str }} {% if not asset.use_default_auth %} {{ asset.username }} {% endif %}
机房{{ asset.idc.name|default_if_none:"" }}
硬件厂商型号{{ asset.brand|default_if_none:"" }}
CPU{{ asset.cpu|default_if_none:"" }}
内存{{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %}
硬盘 + + {% if asset.disk %} + {% for disk, value in asset.disk %} + + + + {% endfor %} + {% endif %} +
{{ disk|default_if_none:"" }}     {{ value|default_if_none:"" }}
+
资产编号{{ asset.number|default_if_none:"" }}
SN{{ asset.sn|default_if_none:"" }}
主机类型{{ asset.get_asset_type_display|default_if_none:"" }}
系统版本{{ asset.system_type|default_if_none:"" }} {{ asset.system_version|default_if_none:"" }}
系统平台{{ asset.system_arch|default_if_none:"" }}
运行环境{{ asset.get_env_display|default_if_none:"" }}
机器状态{{ asset.get_status_display|default_if_none:"" }}
机柜号{{ asset.cabinet|default_if_none:"" }}
机柜位置{{ asset.position|default_if_none:"" }}
激活{{ asset.is_active }}
添加日期{{ asset.date_added|date:"Y-m-d H:i:s" }}
备注{{ asset.comment|default_if_none:"" }}
+
+
+
+
+
+
+
+
+
拥有权限的用户
+
+ + + + + + + + + + +
+
+
+

主机所有授权的信息

+ 包含了此主机所有授权的信息. +
+
+
+
+ {% if perm_info %} + {% if user_perm %} + +

授权用户信息

+ + + {% for perm in user_perm %} + + + + + {% endfor %} +
授权用户关联用户
{{ perm.0 }} + + {% if perm.1 %} + {% for role in perm.1 %} + + + + {% endfor %} + {% endif %} +
{{ role }}
+
+ {% endif %} + {% if user_group_perm %} + +

授权用户组信息

+ + + {% for user_group in user_group_perm %} + + + + + {% endfor %} +
授权用户组组详情
{{ user_group }}详情
+ {% endif %} + + {% if user_rule_perm %} + +

授权规则信息

+ + + {% for rule in user_rule_perm %} + + + + + {% endfor %} +
授权规则详情
{{ rule }}详情
+ {% endif %} + {% else %} +

(暂无)

+ {% endif %} +
+
+
+
+
主机修改记录
+{#     点击修改#} +
+ + + + + + + + + + +
+
+
+

主机修改记录

+ 包含了此主机所有历史修改记录. +
+
+
+ {% if asset_record %} +{# {% for r in asset_record %}#} +{#
#} +{#
#} +{# {{ r.alert_time|naturaltime }}#} +{# {{ r.username }}#} +{# {% for i in r.content|str_to_list %}#} +{#
{{ i.0 }} 由 {{ i.1|str_to_code }} 改为 {{ i.2|str_to_code }}
#} +{# {% endfor %}#} +{# {{ r.alert_time }}#} +{#
#} +{#
#} +{# {% endfor %}#} + {% else %} +

(暂无)

+ {% endif %} +
+
+
+
+ +
+
+
+
最近一周登录记录
+
+ + + + + + + + + + +
+
+
+

最近一周登录记录

+ 此主机最近一周用户登录信息. +
+
+ {% if log %} + {% for l in log %} +
+
+
+ + {{ l.user }} +
+
+
+

详细信息

+

来源IP: {{ l.remote_ip }}

+

开始: {{ l.start_time |date:"Y-m-d H:i:s" }}

+

结束: {{ l.end_time |date:"Y-m-d H:i:s" }}

+
+
+
+ {% endfor %} + + +
+
+
+
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 53288cb83..61a56a406 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -6,7 +6,7 @@
-
主机详细信息列表
+
资产列表
@@ -102,14 +102,11 @@ 主机名 - IP地址 - IDC - 所属主机组 -{# 配置信息 #} - 操作系统 - cpu核数 - 内存 - 硬盘 + IP + 类型 + 配置 + 资产组 + 状态 操作 @@ -119,15 +116,18 @@ - {{ asset.hostname|default_if_none:"" }} - {{ asset.ip|default_if_none:"" }} - {{ asset.idc.name|default_if_none:"" }} -{# {{ asset.group.all|group_str2 }}#} -{# {{ asset.cpu }}|{{ asset.memory }}|{{ asset.disk }}#} - {{ asset.system_type|default_if_none:"" }}{{ asset.system_version|default_if_none:"" }} - {{ asset.cpu|default_if_none:"" }} - {{ asset.memory|default_if_none:"" }}{% if asset.memory %}G{% endif %} - {{ asset.disk }}{% if asset.disk %}G{% endif %} + {{ asset.hostname }} + {{ asset.ip }} + {{ asset.system_type }} + {{ asset.cpu }} | {{ asset.memory }} | {{ asset.disk }} + {% for group in asset.group.all %} {{ group.name }} {% endfor %} + + {% if asset.is_active %} + + {% else %} + + {% endif %} + {# 编辑#} 连接 @@ -145,7 +145,7 @@ {# #}
-{# {% include 'paginator.html' %}#} + {% include '_pagination.html' %}
diff --git a/apps/assets/templates/assets/assetgroup_add.html b/apps/assets/templates/assets/assetgroup_add.html new file mode 100644 index 000000000..4c032c0a8 --- /dev/null +++ b/apps/assets/templates/assets/assetgroup_add.html @@ -0,0 +1,66 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{% trans 'Create asset group' %}
+ +
+
+
+ {% csrf_token %} + {{ form.name|bootstrap_horizontal }} + +
+ +
+ +
+
+ + {{ form.comment|bootstrap_horizontal }} + +
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/assetgroup_list.html b/apps/assets/templates/assets/assetgroup_list.html new file mode 100644 index 000000000..8fb196681 --- /dev/null +++ b/apps/assets/templates/assets/assetgroup_list.html @@ -0,0 +1,59 @@ +{% extends '_list_base.html' %} +{% load i18n %} +{% load common_tags %} +{% block content_left_head %} + {% trans "Create asset group" %} +{% endblock %} + +{% block table_head %} + + + + {% trans 'Name' %} + {% trans 'Asset num' %} + {% trans 'Comment' %} + +{% endblock %} + +{% block table_body %} + {% for assetgroup in assetgroups %} + + + + + + + {{ assetgroup.name }} + + + {{ assetgroup.asset_set.count }} + {{ assetgroup.comment }} + + {% trans 'Edit' %} + {% trans 'Delete' %} + + + {% endfor %} +{% endblock %} + +{% block content_bottom_left %} + +{% endblock %} + + diff --git a/apps/assets/urls.py b/apps/assets/urls.py index a49665411..800381252 100644 --- a/apps/assets/urls.py +++ b/apps/assets/urls.py @@ -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[0-9]+)/delete/$', AssetDeleteView.as_view(), name='asset-list'), - url(r'^(?P[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[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'), + url(r'^asset/(?P[0-9]+)$/edit', views.AssetEditView.as_view(), name='asset-edit'), + url(r'^asset/(?P[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[0-9]+)$', views.AssetGroupDetailView.as_view(), name='assetgroup-detail'), + url(r'^assetgroup/(?P[0-9]+)/edit$', views.AssetGroupEditView.as_view(), name='assetgroup-edit'), + url(r'^assetgroup/(?P[0-9]+)/delete$', views.AssetGroupDeleteView.as_view(), name='assetgroup-delete'), + # url(r'^api/v1.0/', include(router.urls)), ] diff --git a/apps/assets/utils.py b/apps/assets/utils.py index c84951fd7..2fb5bfe7f 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -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 + diff --git a/apps/assets/views.py b/apps/assets/views.py index af451f4b7..7eb868a72 100644 --- a/apps/assets/views.py +++ b/apps/assets/views.py @@ -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 diff --git a/apps/common/templatetags/common_tags.py b/apps/common/templatetags/common_tags.py index b9a822c8e..ca928c1c0 100644 --- a/apps/common/templatetags/common_tags.py +++ b/apps/common/templatetags/common_tags.py @@ -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) \ No newline at end of file diff --git a/apps/common/utils.py b/apps/common/utils.py index fb4613142..7c3df178a 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -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 diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 2d44a3158..69f4b6486 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -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' diff --git a/apps/locale/zh_CN/LC_MESSAGES/django.po b/apps/locale/zh_CN/LC_MESSAGES/django.po index 5efa5a358..7648b85d0 100644 --- a/apps/locale/zh_CN/LC_MESSAGES/django.po +++ b/apps/locale/zh_CN/LC_MESSAGES/django.po @@ -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 \n" "Language-Team: LANGUAGE \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%s success." #~ msgstr "创建用户%s 成功" -#~ msgid "Edit user" -#~ msgstr "编辑用户" - #~ msgid "Usergroup list" #~ msgstr "用户组列表" diff --git a/apps/templates/_header_bar.html b/apps/templates/_header_bar.html index 012b6f013..66699be53 100644 --- a/apps/templates/_header_bar.html +++ b/apps/templates/_header_bar.html @@ -11,7 +11,7 @@
- +
diff --git a/apps/users/templates/users/user_list.html b/apps/users/templates/users/user_list.html index a27267362..51fbfa57b 100644 --- a/apps/users/templates/users/user_list.html +++ b/apps/users/templates/users/user_list.html @@ -60,7 +60,7 @@
diff --git a/apps/users/templatetags/users_tags.py b/apps/users/templatetags/users_tags.py index d3efec18b..6144474f9 100644 --- a/apps/users/templatetags/users_tags.py +++ b/apps/users/templatetags/users_tags.py @@ -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' diff --git a/apps/users/views.py b/apps/users/views.py index bebeb6df7..cc8a12f3d 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -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): diff --git a/run_server.py b/run_server.py index 5ab2d8513..e1d3240c3 100644 --- a/run_server.py +++ b/run_server.py @@ -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')