Commit 42012d7b authored by wangyong's avatar wangyong

merge master

parents 792908eb db5d04c3
.DS_Store .DS_Store
*.pyc *.pyc
*.pyo *.pyo
*.swp
env env
env* env*
dist dist
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from rest_framework import serializers from rest_framework import serializers
from .models import ( from rest_framework import viewsets, serializers
AssetGroup,Asset,IDC,AssetExtend
) from .models import AssetGroup, Asset, IDC, AssetExtend
from rest_framework import viewsets,serializers
class AssetGroupSerializer(serializers.ModelSerializer): class AssetGroupSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AssetGroup model = AssetGroup
#exclude = [ # exclude = [
#'password', 'first_name', 'last_name', 'secret_key_otp', # 'password', 'first_name', 'last_name', 'secret_key_otp',
#'private_key', 'public_key', 'avatar', # 'private_key', 'public_key', 'avatar',
#] # ]
class AssetSerializer(serializers.ModelSerializer): class AssetSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Asset model = Asset
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style') # fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
class IDCSerializer(serializers.ModelSerializer): class IDCSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = IDC model = IDC
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style') # fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
class AssetGroupViewSet(viewsets.ModelViewSet): class AssetGroupViewSet(viewsets.ModelViewSet):
""" """ API endpoint that allows AssetGroup to be viewed or edited.
API endpoint that allows AssetGroup to be viewed or edited.
some other comment
""" """
queryset = AssetGroup.objects.all() queryset = AssetGroup.objects.all()
serializer_class = AssetGroupSerializer serializer_class = AssetGroupSerializer
......
# coding:utf-8 # coding:utf-8
from django import forms from django import forms
from .models import IDC, Asset, AssetGroup from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
...@@ -11,16 +11,17 @@ class AssetForm(forms.ModelForm): ...@@ -11,16 +11,17 @@ class AssetForm(forms.ModelForm):
fields = [ fields = [
"ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password", "ip", "other_ip", "remote_card_ip", "hostname", "port", "groups", "username", "password",
"idc", "mac_addr", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos", "idc", "mac_address", "brand", "cpu", "memory", "disk", "os", "cabinet_no", "cabinet_pos",
"number", "status", "type", "env", "sn", "is_active", "comment" "number", "status", "type", "env", "sn", "is_active", "comment"
] ]
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join assetgroups')}), 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}),
} }
class AssetGroupForm(forms.ModelForm): class AssetGroupForm(forms.ModelForm):
# See AdminUserForm comment same it
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
label=_('Asset'), label=_('Asset'),
required=False, required=False,
...@@ -45,14 +46,169 @@ class AssetGroupForm(forms.ModelForm): ...@@ -45,14 +46,169 @@ class AssetGroupForm(forms.ModelForm):
fields = [ fields = [
"name", "comment" "name", "comment"
] ]
help_texts = {
'name': '* required',
}
class IDCForm(forms.ModelForm):
# See AdminUserForm comment same it
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
label=_('Asset'),
required=False,
widget=forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
)
def __init__(self, *args, **kwargs):
if kwargs.get('instance'):
initial = kwargs.get('initial', {})
initial['assets'] = kwargs['instance'].assets.all()
super(IDCForm, self).__init__(*args, **kwargs)
def _save_m2m(self):
super(IDCForm, self)._save_m2m()
assets = self.cleaned_data['assets']
self.instance.assets.clear()
self.instance.assets.add(*tuple(assets))
class IdcForm(forms.ModelForm):
class Meta: class Meta:
model = IDC model = IDC
fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'network', 'comment'] fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'network', 'comment']
widgets = { widgets = {
'name': forms.TextInput(attrs={'placeholder': 'Name'}), 'name': forms.TextInput(attrs={'placeholder': _('Name')}),
'network': forms.Textarea( 'network': forms.Textarea(
attrs={'placeholder': '192.168.1.0/24\n192.168.2.0/24'}) attrs={'placeholder': '192.168.1.0/24\n192.168.2.0/24'})
} }
class AdminUserForm(forms.ModelForm):
# Admin user assets define, let user select, save it in form not in view
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
label=_('Asset'),
required=False,
widget=forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
)
auto_generate_key = forms.BooleanField(required=True, initial=True)
# Form field name can not start with `_`, so redefine it,
password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True,
help_text=_('If also set private key, use that first'), required=False)
# Need use upload private key file except paste private key content
private_key_file = forms.FileField(required=False)
def __init__(self, *args, **kwargs):
# When update a admin user instance, initial it
if kwargs.get('instance'):
initial = kwargs.get('initial', {})
initial['assets'] = kwargs['instance'].assets.all()
super(AdminUserForm, self).__init__(*args, **kwargs)
def _save_m2m(self):
# Save assets relation with admin user
super(AdminUserForm, self)._save_m2m()
assets = self.cleaned_data['assets']
self.instance.assets.clear()
self.instance.assets.add(*tuple(assets))
def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save`
admin_user = super(AdminUserForm, self).save(commit=commit)
password = self.cleaned_data['password']
private_key_file = self.cleaned_data['private_key_file']
if password:
admin_user.password = password
print(password)
# Todo: Validate private key file, and generate public key
# Todo: Auto generate private key and public key
if private_key_file:
admin_user.private_key = private_key_file.read()
admin_user.save()
return self.instance
class Meta:
model = AdminUser
fields = ['name', 'username', 'auto_generate_key', 'password', 'private_key_file', 'as_default', 'comment']
widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
}
help_texts = {
'name': '* required',
'username': '* required',
}
class SystemUserForm(forms.ModelForm):
# Admin user assets define, let user select, save it in form not in view
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
label=_('Asset'),
required=False,
widget=forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
)
asset_groups = forms.ModelMultipleChoiceField(queryset=AssetGroup.objects.all(),
label=_('Asset group'),
required=False,
widget=forms.SelectMultiple(
attrs={'class': 'select2',
'data-placeholder': _('Select asset groups')})
)
auto_generate_key = forms.BooleanField(initial=True)
# Form field name can not start with `_`, so redefine it,
password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True,
help_text=_('If also set private key, use that first'), required=False)
# Need use upload private key file except paste private key content
private_key_file = forms.FileField(required=False)
def __init__(self, *args, **kwargs):
# When update a admin user instance, initial it
if kwargs.get('instance'):
initial = kwargs.get('initial', {})
initial['assets'] = kwargs['instance'].assets.all()
initial['asset_groups'] = kwargs['instance'].asset_groups.all()
super(SystemUserForm, self).__init__(*args, **kwargs)
def _save_m2m(self):
# Save assets relation with admin user
super(SystemUserForm, self)._save_m2m()
assets = self.cleaned_data['assets']
asset_groups = self.cleaned_data['asset_groups']
self.instance.assets.clear()
self.instance.assets.add(*tuple(assets))
self.instance.asset_groups.clear()
self.instance.asset_groups.add(*tuple(asset_groups))
def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save`
system_user = super(SystemUserForm, self).save(commit=commit)
password = self.cleaned_data['password']
private_key_file = self.cleaned_data['private_key_file']
if password:
system_user.password = password
print(password)
# Todo: Validate private key file, and generate public key
# Todo: Auto generate private key and public key
if private_key_file:
system_user.private_key = private_key_file.read()
system_user.save()
return self.instance
class Meta:
model = SystemUser
fields = [
'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'as_default',
'auto_push', 'auto_update', 'sudo', 'comment', 'shell', 'home', 'uid',
]
widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
}
help_texts = {
'name': '* required',
'username': '* required',
'auth_push': 'Auto push system user to asset',
'auth_update': 'Auto update system user ssh key',
}
\ No newline at end of file
"""
jumpserver.__app__.hands.py
~~~~~~~~~~~~~~~~~
This app depends other apps api, function .. should be import or write mack here.
Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-2016 by Jumpserver Team.
:license: GPL v2, see LICENSE for more details.
"""
from users.utils import AdminUserRequiredMixin
from users.models import User, UserGroup
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-09-04 11:52
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='AdminUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('username', models.CharField(max_length=16, verbose_name='Username')),
('password', models.CharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key', models.CharField(blank=True, max_length=4096, null=True, verbose_name='SSH private key')),
('is_default', models.BooleanField(default=False, 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, verbose_name='Date added')),
('create_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
],
options={
'db_table': 'adminuser',
},
),
migrations.CreateModel(
name='Asset',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip', models.CharField(max_length=32, verbose_name='IP')),
('other_ip', models.CharField(blank=True, max_length=255, verbose_name='Other IP')),
('remote_card_ip', models.CharField(blank=True, max_length=16, verbose_name='Remote card IP')),
('hostname', models.CharField(blank=True, max_length=128, unique=True, verbose_name='Hostname')),
('port', models.IntegerField(default=22, verbose_name='Port')),
('username', models.CharField(blank=True, max_length=16, verbose_name='Admin user')),
('password', models.CharField(blank=True, max_length=256, verbose_name='Admin password')),
('mac_addr', models.CharField(blank=True, max_length=20, verbose_name='Mac address')),
('brand', models.CharField(blank=True, max_length=64, verbose_name='Brand')),
('cpu', models.CharField(blank=True, max_length=64, verbose_name='CPU')),
('memory', models.CharField(blank=True, max_length=128, verbose_name='Memory')),
('disk', models.CharField(blank=True, max_length=1024, verbose_name='Disk')),
('os', models.CharField(blank=True, max_length=128, verbose_name='OS')),
('cabinet_no', models.CharField(blank=True, max_length=32, verbose_name='Cabinet number')),
('cabinet_pos', models.IntegerField(blank=True, verbose_name='Cabinet position')),
('number', models.CharField(blank=True, max_length=32, unique=True, verbose_name='Asset number')),
('sn', models.CharField(blank=True, max_length=128, unique=True, verbose_name='Serial number')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='Created by')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
('date_added', models.DateTimeField(auto_now=True, null=True, verbose_name='Date added')),
('comment', models.CharField(blank=True, max_length=128, verbose_name='Comment')),
('admin_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.AdminUser', verbose_name='Admin User')),
],
options={
'db_table': 'asset',
},
),
migrations.CreateModel(
name='AssetExtend',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=64, verbose_name='KEY')),
('value', models.CharField(max_length=64, verbose_name='VALUE')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='Created by')),
('date_added', models.DateTimeField(auto_now=True, null=True, verbose_name='Date added')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
],
options={
'db_table': 'assetextend',
},
),
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, verbose_name='Name')),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('comment', models.TextField(blank=True, null=True, verbose_name='Comment')),
],
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='Name')),
('bandwidth', models.CharField(blank=True, max_length=32, verbose_name='Bandwidth')),
('contact', models.CharField(blank=True, max_length=16, verbose_name='Contact')),
('phone', models.CharField(blank=True, max_length=32, verbose_name='Phone')),
('address', models.CharField(blank=True, max_length=128, 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(blank=True, max_length=32, verbose_name='Operator')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='Created by')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
],
options={
'db_table': 'idc',
},
),
migrations.CreateModel(
name='Label',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(max_length=64, verbose_name='KEY')),
('value', models.CharField(max_length=64, verbose_name='VALUE')),
('created_by', models.CharField(blank=True, max_length=32, verbose_name='Created by')),
('date_added', models.DateTimeField(auto_now=True, null=True, verbose_name='Date added')),
('comment', models.CharField(blank=True, max_length=128, verbose_name='Comment')),
('asset', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.Asset', verbose_name='Asset')),
],
options={
'db_table': 'label',
},
),
migrations.CreateModel(
name='SysUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(max_length=16, verbose_name='Username')),
('password', models.CharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('protocol', models.CharField(default='ssh', max_length=16, verbose_name='Protocol')),
('private_key', models.CharField(blank=True, max_length=4096, verbose_name='SSH private key')),
('public_key', models.CharField(blank=True, max_length=4096, verbose_name='SSH public key')),
('is_default', models.BooleanField(default=False, 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(blank=True, max_length=4096, verbose_name='Sudo')),
('shell', models.CharField(blank=True, max_length=64, verbose_name='Shell')),
('home', models.CharField(blank=True, max_length=64, verbose_name='Home')),
('uid', models.IntegerField(blank=True, verbose_name='Uid')),
('date_added', models.DateTimeField(auto_now=True, null=True, verbose_name='Date added')),
('create_by', models.CharField(blank=True, max_length=32, verbose_name='Created by')),
('comment', models.CharField(blank=True, max_length=128, verbose_name='Comment')),
],
options={
'db_table': 'sysuser',
},
),
migrations.AddField(
model_name='asset',
name='env',
field=models.ManyToManyField(related_name='asset_env_extend', to='assets.AssetExtend', verbose_name='Asset environment'),
),
migrations.AddField(
model_name='asset',
name='groups',
field=models.ManyToManyField(to='assets.AssetGroup', verbose_name='Asset groups'),
),
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='IDC'),
),
migrations.AddField(
model_name='asset',
name='status',
field=models.ManyToManyField(related_name='asset_status_extend', to='assets.AssetExtend', verbose_name='Asset status'),
),
migrations.AddField(
model_name='asset',
name='sys_user',
field=models.ManyToManyField(to='assets.SysUser', verbose_name='Sys User'),
),
migrations.AddField(
model_name='asset',
name='type',
field=models.ManyToManyField(related_name='asset_type_extend', to='assets.AssetExtend', verbose_name='Asset type'),
),
]
...@@ -2,8 +2,11 @@ ...@@ -2,8 +2,11 @@
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
from django.db import models from django.db import models
import logging
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils import encrypt, decrypt
class AssetGroup(models.Model): class AssetGroup(models.Model):
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
...@@ -16,6 +19,8 @@ class AssetGroup(models.Model): ...@@ -16,6 +19,8 @@ class AssetGroup(models.Model):
class Meta: class Meta:
db_table = 'asset_group' db_table = 'asset_group'
logger = logging.getLogger(__name__)
class IDC(models.Model): class IDC(models.Model):
name = models.CharField(max_length=32, verbose_name=_('Name')) name = models.CharField(max_length=32, verbose_name=_('Name'))
...@@ -24,7 +29,7 @@ class IDC(models.Model): ...@@ -24,7 +29,7 @@ class IDC(models.Model):
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone')) phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
address = models.CharField(max_length=128, blank=True, verbose_name=_("Address")) address = models.CharField(max_length=128, blank=True, verbose_name=_("Address"))
network = models.TextField(blank=True, verbose_name=_('Network')) network = models.TextField(blank=True, verbose_name=_('Network'))
date_added = models.DateField(auto_now=True, null=True, verbose_name=_('Date added')) date_created = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added'))
operator = models.CharField(max_length=32, blank=True, verbose_name=_('Operator')) operator = models.CharField(max_length=32, blank=True, verbose_name=_('Operator'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
...@@ -35,87 +40,253 @@ class IDC(models.Model): ...@@ -35,87 +40,253 @@ class IDC(models.Model):
class Meta: class Meta:
db_table = 'idc' db_table = 'idc'
@classmethod
def generate_fake(cls, count=100):
from random import seed, choice
import forgery_py
from django.db import IntegrityError
seed()
for i in range(count):
idc = cls(name=forgery_py.name.full_name(),
bandwidth='200M',
contact=forgery_py.name.full_name(),
phone=forgery_py.address.phone(),
address=forgery_py.address.city() + forgery_py.address.street_address(),
network="192.168.1.10/24\n192.168.1.20",
operator=choice(['北京联通', '北京电信', 'BGP全网通']),
comment=forgery_py.lorem_ipsum.sentence(),
created_by='Fake')
try:
idc.save()
logger.debug('Generate fake asset group: %s' % idc.name)
except IntegrityError:
print('Error continue')
continue
class AssetExtend(models.Model): class AssetExtend(models.Model):
key = models.CharField(max_length=64, verbose_name=_('KEY')) key = models.CharField(max_length=64, verbose_name=_('KEY'))
value = models.CharField(max_length=64, verbose_name=_('VALUE')) value = models.CharField(max_length=64, verbose_name=_('VALUE'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by")) created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added')) date_created = models.DateTimeField(auto_now=True, null=True, blank=True)
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self): def __unicode__(self):
return self.name return '%(key)s: %(value)s' % {'key': self.key, 'value': self.value}
@classmethod
def initial(cls):
for k, v in (
(_('status'), _('In use')),
(_('status'), _('Out of use')),
(_('type'), _('Server')),
(_('type'), _('VM')),
(_('type'), _('Switch')),
(_('type'), _('Router')),
(_('type'), _('Firewall')),
(_('type'), _('Storage')),
(_('env'), _('Production')),
(_('env'), _('Development')),
(_('env'), _('Testing')),
):
cls.objects.create(key=k, value=v, created_by='System')
class Meta: class Meta:
db_table = 'assetextend' db_table = 'asset_extend'
class AdminUser(models.Model): class AdminUser(models.Model):
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=16, verbose_name=_('Username')) username = models.CharField(max_length=16, verbose_name=_('Username'))
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
private_key = models.CharField(max_length=4096, null=True, blank=True, verbose_name=_('SSH private key')) _private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key'))
is_default = models.BooleanField(default=False, verbose_name=_('As default')) _public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key')) as_default = models.BooleanField(default=False, verbose_name=_('As default'))
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added'))
create_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now=True, null=True)
created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by'))
def __unicode__(self): def __unicode__(self):
return self.name return self.name
@property
def password(self):
return decrypt(self._password)
@password.setter
def password(self, password_raw):
self._password = encrypt(password_raw)
@property
def private_key(self):
return decrypt(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
self._private_key = encrypt(private_key_raw)
@property
def public_key(self):
return decrypt(self._public_key)
@public_key.setter
def public_key(self, public_key_raw):
self._public_key = encrypt(public_key_raw)
class Meta: class Meta:
db_table = 'adminuser' db_table = 'admin_user'
@classmethod
def generate_fake(cls, count=100):
from random import seed
import forgery_py
from django.db import IntegrityError
seed()
for i in range(count):
obj = cls(name=forgery_py.name.full_name(),
username=forgery_py.internet.user_name(),
password=forgery_py.lorem_ipsum.word(),
comment=forgery_py.lorem_ipsum.sentence(),
created_by='Fake')
try:
obj.save()
logger.debug('Generate fake asset group: %s' % obj.name)
except IntegrityError:
print('Error continue')
continue
class SysUser(models.Model): class SystemUser(models.Model):
PROTOCOL_CHOICES = ( PROTOCOL_CHOICES = (
('ssh', 'ssh'), ('ssh', 'ssh'),
('telnet', 'telnet'),
) )
name = models.CharField(max_length=128, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=16, verbose_name=_('Username')) username = models.CharField(max_length=16, verbose_name=_('Username'))
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
protocol = models.CharField(max_length=16, default='ssh', verbose_name=_('Protocol')) protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key')) _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')) _public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
is_default = models.BooleanField(default=False, verbose_name=_('As default')) as_default = models.BooleanField(default=False, verbose_name=_('As default'))
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push')) auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key')) auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key'))
sudo = models.TextField(max_length=4096, blank=True, verbose_name=_('Sudo')) sudo = models.TextField(max_length=4096, default='/user/bin/whoami', verbose_name=_('Sudo'))
shell = models.CharField(max_length=64, blank=True, verbose_name=_('Shell')) shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
home = models.CharField(max_length=64, blank=True, verbose_name=_('Home')) home = models.CharField(max_length=64, blank=True, verbose_name=_('Home'))
uid = models.IntegerField(blank=True, verbose_name=_('Uid')) uid = models.IntegerField(null=True, blank=True, verbose_name=_('Uid'))
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added')) date_created = models.DateTimeField(auto_now=True)
create_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment')) comment = models.TextField(max_length=128, blank=True, verbose_name=_('Comment'))
def __unicode__(self):
return self.name
@property
def password(self):
return decrypt(self._password)
@password.setter
def password(self, password_raw):
self._password = encrypt(password_raw)
@property
def private_key(self):
return decrypt(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
self._private_key = encrypt(private_key_raw)
@property
def public_key(self):
return decrypt(self._public_key)
@public_key.setter
def public_key(self, public_key_raw):
self._public_key = encrypt(public_key_raw)
class Meta:
db_table = 'system_user'
@classmethod
def generate_fake(cls, count=100):
from random import seed
import forgery_py
from django.db import IntegrityError
seed()
for i in range(count):
obj = cls(name=forgery_py.name.full_name(),
username=forgery_py.internet.user_name(),
password=forgery_py.lorem_ipsum.word(),
comment=forgery_py.lorem_ipsum.sentence(),
created_by='Fake')
try:
obj.save()
logger.debug('Generate fake asset group: %s' % obj.name)
except IntegrityError:
print('Error continue')
continue
class AssetGroup(models.Model):
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
system_users = models.ManyToManyField(SystemUser, related_name='asset_groups', blank=True)
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class Meta: class Meta:
db_table = 'sysuser' db_table = 'asset_group'
@classmethod
def initial(cls):
asset_group = cls(name=_('Default'), commont=_('Default asset group'))
asset_group.save()
@classmethod
def generate_fake(cls, count=100):
from random import seed
import forgery_py
from django.db import IntegrityError
seed()
for i in range(count):
group = cls(name=forgery_py.name.full_name(),
comment=forgery_py.lorem_ipsum.sentence(),
created_by='Fake')
try:
group.save()
logger.debug('Generate fake asset group: %s' % group.name)
except IntegrityError:
print('Error continue')
continue
class Asset(models.Model): class Asset(models.Model):
ip = models.CharField(max_length=32, verbose_name=_('IP')) ip = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('IP'))
other_ip = models.CharField(max_length=255, blank=True, verbose_name=_('Other IP')) other_ip = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('Other IP'))
remote_card_ip = models.CharField(max_length=16, blank=True, verbose_name=_('Remote card 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, blank=True, verbose_name=_('Hostname')) hostname = models.CharField(max_length=128, unique=True, null=True, blank=True, verbose_name=_('Hostname'))
port = models.IntegerField(default=22, verbose_name=_('Port')) port = models.IntegerField(null=True, blank=True, verbose_name=_('Port'))
groups = models.ManyToManyField(AssetGroup, blank=True, verbose_name=_('Asset groups')) groups = models.ManyToManyField(AssetGroup, related_name='assets', verbose_name=_('Asset groups'))
username = models.CharField(max_length=16, blank=True, verbose_name=_('Admin user')) username = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Admin user'))
password = models.CharField(max_length=256, blank=True, verbose_name=_("Admin password")) password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_("Admin password"))
admin_user = models.ForeignKey(AdminUser, null=True, on_delete=models.SET_NULL, verbose_name=_("Admin User")) admin_user = models.ForeignKey(AdminUser, null=True, related_name='assets',
sys_user = models.ManyToManyField(SysUser, verbose_name=_("Sys User")) on_delete=models.SET_NULL, verbose_name=_("Admin user"))
idc = models.ForeignKey(IDC, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('IDC')) system_user = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User"))
mac_addr = models.CharField(max_length=20, blank=True, verbose_name=_("Mac address")) idc = models.ForeignKey(IDC, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('IDC'))
brand = models.CharField(max_length=64, blank=True, verbose_name=_('Brand')) mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address"))
cpu = models.CharField(max_length=64, blank=True, verbose_name=_('CPU')) brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand'))
memory = models.CharField(max_length=128, blank=True, verbose_name=_('Memory')) cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU'))
disk = models.CharField(max_length=1024, blank=True, verbose_name=_('Disk')) memory = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Memory'))
os = models.CharField(max_length=128, blank=True, verbose_name=_('OS')) disk = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk'))
cabinet_no = models.CharField(max_length=32, blank=True, verbose_name=_('Cabinet number')) 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')) cabinet_pos = models.IntegerField(null=True, blank=True, verbose_name=_('Cabinet position'))
number = models.CharField(max_length=32, blank=True, verbose_name=_('Asset number')) number = models.CharField(max_length=32, blank=True, verbose_name=_('Asset number'))
status = models.ForeignKey(AssetExtend, null=True, blank=True, status = models.ForeignKey(AssetExtend, null=True, blank=True,
...@@ -127,11 +298,11 @@ class Asset(models.Model): ...@@ -127,11 +298,11 @@ class Asset(models.Model):
sn = models.CharField(max_length=128, blank=True, verbose_name=_('Serial number')) sn = models.CharField(max_length=128, blank=True, verbose_name=_('Serial number'))
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added')) date_created = models.DateTimeField(auto_now=True, null=True, blank=True, verbose_name=_('Date added'))
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment')) comment = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
def __unicode__(self): def __unicode__(self):
return '%(ip)s:%(port)d' % {'ip': self.ip, 'port': self.port} return '%(ip)s:%(port)s' % {'ip': self.ip, 'port': self.port}
def initial(self): def initial(self):
pass pass
...@@ -140,13 +311,32 @@ class Asset(models.Model): ...@@ -140,13 +311,32 @@ class Asset(models.Model):
db_table = 'asset' db_table = 'asset'
index_together = ('ip', 'port') index_together = ('ip', 'port')
@classmethod
def generate_fake(cls, count=100):
from random import seed
import forgery_py
from django.db import IntegrityError
seed()
for i in range(count):
asset = cls(ip='%s.%s.%s.%s' % tuple([forgery_py.forgery.basic.text(length=3, digits=True)
for i in range(0, 4)]),
port=22,
created_by='Fake')
try:
asset.save()
logger.debug('Generate fake asset : %s' % asset.ip)
except IntegrityError:
print('Error continue')
continue
class Label(models.Model): class Label(models.Model):
key = models.CharField(max_length=64, verbose_name=_('KEY')) key = models.CharField(max_length=64, verbose_name=_('KEY'))
value = models.CharField(max_length=64, verbose_name=_('VALUE')) value = models.CharField(max_length=64, verbose_name=_('VALUE'))
asset = models.ForeignKey(Asset, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('Asset')) 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")) created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added')) date_created = models.DateTimeField(auto_now=True, null=True)
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment')) comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment'))
def __unicode__(self): def __unicode__(self):
...@@ -155,3 +345,7 @@ class Label(models.Model): ...@@ -155,3 +345,7 @@ class Label(models.Model):
class Meta: class Meta:
db_table = 'label' db_table = 'label'
def generate_fake():
for cls in (Asset, AssetGroup, IDC):
cls.generate_fake()
{% 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 admin user' %}</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 enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label>
<div class="col-sm-8">
{{ form.auto_generate_key}}
</div>
</div>
{{ form.password|bootstrap_horizontal }}
{{ form.private_key_file|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.as_default.id_for_label }}" class="col-sm-2 control-label">{% trans 'As default' %}</label>
<div class="col-sm-8">
{{ form.as_default}}
</div>
</div>
{{ form.assets|bootstrap_horizontal }}
{{ 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 %}
\ No newline at end of file
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}</a></li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ admin_user.name }}</b></span>
<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">
<li><a href="#"></a>
</li>
<li><a href="#"></a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Name' %}:</td>
<td><b>{{ admin_user.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Username' %}:</td>
<td><b>{{ admin_user.username }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ admin_user.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_group.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ admin_user.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span>
<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">
<li><a href="#"></a>
</li>
<li><a href="#"></a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Alive' %}</th>
</tr>
</thead>
<tbody>
{% for asset in page_obj %}
<tr>
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>{{ asset.port }}</td>
<td>Alive</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="50%">{% trans 'Get install script' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Get' %}</button>
</span>
</td>
</tr>
<tr>
<td width="50%">{% trans 'Retest asset connectivity' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Start' %}</button>
</span>
</td>
</tr>
<tr>
<td width="50%">{% trans 'Reset private key' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Replace asset admin user with this' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-info btn-sm">{% trans 'Replace' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'assets:admin-user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create admin user" %} </a>
{% endblock %}
{% block table_head %}
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center"><a href="{% url 'assets:admin-user-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'assets:admin-user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Lost connection' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for admin_user in admin_user_list %}
<tr class="gradeX">
<td class="text-center">{{ admin_user.id }}</td>
<td>
<a href="{% url 'assets:admin-user-detail' pk=admin_user.id %}">
{{ admin_user.name }}
</a>
</td>
<td class="text-center">{{ admin_user.username }}</td>
<td class="text-center">{{ admin_user.assets.count }}</td>
<td class="text-center">{{ admin_user.assets.count }}</td>
<td class="text-center">{{ admin_user.comment|truncatewords:8 }}</td>
<td class="text-center">
<!-- Todo: Click script button will paste a url to clipboard like: curl http://url/admin_user_create.sh | bash -->
<a href="{% url 'assets:admin-user-update' pk=admin_user.id %}" class="btn btn-xs btn-primary">{% trans 'Script' %}</a>
<!-- Todo: Click refresh button will run a task to test admin user could connect asset or not immediately -->
<a href="{% url 'assets:admin-user-update' pk=admin_user.id %}" class="btn btn-xs btn-warning">{% trans 'Refresh' %}</a>
<a href="{% url 'assets:admin-user-update' pk=admin_user.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a onclick="obj_del(this,'{{ admin_user.name }}','{% url 'assets:admin-user-delete' admin_user.id %}')" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
{% endblock %}
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
</tr> </tr>
<tr> <tr>
<td class="text-navy">添加日期</td> <td class="text-navy">添加日期</td>
<td>{{ asset.date_added|date:"Y-m-d H:i:s" }}</td> <td>{{ asset.date_created|date:"Y-m-d H:i:s" }}</td>
</tr> </tr>
<tr> <tr>
<td class="text-navy">备注</td> <td class="text-navy">备注</td>
......
...@@ -27,22 +27,10 @@ ...@@ -27,22 +27,10 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action="" > <form method="post" class="form-horizontal" action="" >
{% csrf_token %} {% csrf_token %}
{{ form.name|bootstrap_horizontal }} {{ form.name|bootstrap_horizontal }}
{{ form.assets|bootstrap_horizontal }} {{ form.assets|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 }} {{ form.comment|bootstrap_horizontal }}
<div class="form-group"> <div class="form-group">
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset group perm' %}</a></li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ asset_group.name }}</b></span>
<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">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Name' %}:</td>
<td><b>{{ asset_group.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ asset_group.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_group.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ asset_group.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left"></span>{% trans 'Asset list of ' %} <b>{{ asset_group.name }}</b></span>
<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">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Alive' %}</th>
</tr>
</thead>
<tbody>
{% for asset in page_obj %}
<tr>
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>{{ asset.port }}</td>
<td>Alive</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Associate system user' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="50%">{% trans 'repush system user' %}:</td>
<td>
<span style="float: right">
<button class="btn btn-danger btn-xs" type="button"><i class="fa fa-refresh"></i></button>
</span>
</td>
</tr>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select system user' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Associate' %}</button>
</td>
</tr>
</form>
{% for group in user.groups.all %}
<tr>
<td ><b>{{ group.name }}</b></td>
<td>
<button class="btn btn-danger btn-xs" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset to this group' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset user' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-info btn-sm">{% trans 'Add' %}</button>
</td>
</tr>
</form>
{% for group in user.groups.all %}
<tr>
<td ><b>{{ group.name }}</b></td>
<td>
<button class="btn btn-danger btn-xs" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
})
</script>
{% endblock %}
\ No newline at end of file
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
</a> </a>
</td> </td>
<td class="text-center">{{ asset_group.assets.count }}</td> <td class="text-center">{{ asset_group.assets.count }}</td>
<td class="text-center">{{ asset_group.comment }}</td> <td class="text-center">{{ asset_group.comment|truncatewords:8 }}</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'assets:asset-group-update' pk=asset_group.id %}" class="btn btn-xs btn-info">{% trans 'Edit' %}</a> <a href="{% url 'assets:asset-group-update' pk=asset_group.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a href="{% url 'assets:asset-group-delete' pk=asset_group.id %}" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a> <a onclick="obj_del(this,'{{ asset_group.name }}','{% url 'assets:asset-group-delete' asset_group.id %}')" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% trans 'Confirm delete' %}</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object.name }}"?</p>
<input type="submit" value="Confirm" />
</form>
</body>
</html>
\ No newline at end of file
{% 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 idc' %}</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" class="form-horizontal" action="" >
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
{{ form.assets|bootstrap_horizontal }}
{{ form.bandwidth|bootstrap_horizontal }}
{{ form.operator|bootstrap_horizontal }}
{{ form.contact|bootstrap_horizontal }}
{{ form.phone|bootstrap_horizontal }}
{{ form.address|bootstrap_horizontal }}
{{ form.network|bootstrap_horizontal }}
{{ 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 %}
\ No newline at end of file
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'assets:idc-create' %}" class="btn btn-sm btn-primary "> {% trans "Create IDC" %} </a>
{% endblock %}
{% block table_head %}
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center"><a href="{% url 'assets:idc-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Bandwidth' %}</th>
<th class="text-center">{% trans 'Contact' %}</th>
<th class="text-center">{% trans 'Phone' %}</th>
<th class="text-center">{% trans 'Address' %}</th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for idc in idc_list %}
<tr class="gradeX">
<td class="text-center">{{ idc.id }}</td>
<td class="text-center">{{ idc.name }}</td>
<td class="text-center">{{ idc.assets.count }}</td>
<td class="text-center">{{ idc.bandwidth }}</td>
<td class="text-center">{{ idc.contact }}</td>
<td class="text-center">{{ idc.phone }}</td>
<td class="text-center">{{ idc.address }}</td>
<td class="text-center">
<a href="{% url 'assets:idc-update' pk=idc.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a onclick="objectDelete(this, '{{ idc.name }}', '{% url 'assets:idc-delete' idc.id %}')" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
<script>
//删除提示样式二,可以选用。
function obj_del2(obj,name,url){
//alert(local);
top.$.jBox.confirm("您确定要删除【"+name+"】吗?", "系统提示",function (c, d, e) {
if (c == "ok") {
//loading("正在提交,请稍等...");
$.ajax({
type : "post",
url : url,
data : {
// idc_id : idc_id
},
success : function(data) {
// alert('删除成功!')
$(obj).parent().parent().remove();
},
dataType : "text"
});
}
}, {buttonsFocus: 1,
draggable: false,
showClose: false});
top.$(".jbox-body .jbox-icon").css("top", "35px");
top.$(".jbox-button-panel").css("height", "35px");
return false
}
</script>
{% endblock %}
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li class="active"><a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}</a>
</li>
<li><a href="{% url 'assets:system-user-asset-group' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate asset groups' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span>
<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">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Alive' %}</th>
</tr>
</thead>
<tbody>
{% for asset in page_obj %}
<tr>
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>{{ asset.port }}</td>
<td>Alive</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset to this system user' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset in assets %}
<option value="{{ asset.id }}">{{ asset.ip}}:{{ asset.port }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Add' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li><a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}</a>
</li>
<li class="active">
<a href="{% url 'assets:system-user-asset-group' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate asset groups' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span>
<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">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Name' %}</th>
<th>{% trans 'Asset num' %}</th>
<th>{% trans 'Unavailable num' %}</th>
<th>{% trans 'Comment' %}</th>
</tr>
</thead>
<tbody>
{% for asset_group in page_obj %}
<tr>
<td>{{ asset_group.name }}</td>
<td>{{ asset_group_group.assets.count }}</td>
<td>{{ asset_group_group.assets.count }}</td>
<td>{{ asset_group.comment|truncatewords:4 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset group to this system user' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset group' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset_group in asset_groups %}
<option value="{{ asset_group.id }}">{{ asset_group.name}}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Add' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% 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 system user' %}</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 enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
{{ form.protocol|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label>
<div class="col-sm-8">
{{ form.auto_generate_key}}
</div>
</div>
{{ form.password|bootstrap_horizontal }}
{{ form.private_key_file|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.as_default.id_for_label }}" class="col-sm-2 control-label">{% trans 'As default' %}</label>
<div class="col-sm-8">
{{ form.as_default}}
</div>
</div>
<div class="form-group">
<label for="{{ form.as_push.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto push' %}</label>
<div class="col-sm-8">
{{ form.auto_push}}
</div>
</div>
<div class="form-group">
<label for="{{ form.as_update.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto update' %}</label>
<div class="col-sm-8">
{{ form.auto_update}}
</div>
</div>
{{ form.assets|bootstrap_horizontal }}
{{ form.asset_groups|bootstrap_horizontal }}
{{ form.sudo|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
{{ form.home|bootstrap_horizontal }}
{{ form.shell|bootstrap_horizontal }}
{{ form.uid|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();
if ($('#'+'{{ form.protocol.id_for_label }}').val() == 'telnet') {
$('#'+'{{ form.auto_generate_key.id_for_label }}').closest('.form-group').remove();
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group').remove();
$('#'+'{{ form.auto_push.id_for_label }}').closest('.form-group').remove();
$('#'+'{{ form.auto_update.id_for_label }}').closest('.form-group').remove();
}
})
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li>
<a href="{% url 'assets:system-user-asset' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate assets' %}
</a>
</li>
<li>
<a href="{% url 'assets:system-user-asset-group' pk=system_user.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Associate asset groups' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ system_user.name }}</b></span>
<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">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Name' %}:</td>
<td><b>{{ system_user.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Username' %}:</td>
<td><b>{{ system_user.username }}</b></td>
</tr>
<tr>
<td>{% trans 'Protocol' %}:</td>
<td><b>{{ system_user.protocol }}</b></td>
</tr>
<tr>
<td>{% trans 'Auto push' %}:</td>
<td><b>{{ system_user.protocol }}</b></td>
</tr>
<tr>
<td>{% trans 'Auto update' %}:</td>
<td><b>{{ system_user.auto_update }}</b></td>
</tr>
<tr>
<td>{% trans 'As default' %}:</td>
<td><b>{{ system_user.protocol }}</b></td>
</tr>
<tr>
<td>{% trans 'Sudo' %}:</td>
<td><b>{{ system_user.sudo }}</b></td>
</tr>
{% if system_user.shell %}
<tr>
<td>{% trans 'Shell' %}:</td>
<td><b>{{ system_user.shell }}</b></td>
</tr>
{% endif %}
{% if system_user.home %}
<tr>
<td>{% trans 'Home' %}:</td>
<td><b>{{ system_user.home }}</b></td>
</tr>
{% endif %}
{% if system_user.uid %}
<tr>
<td>{% trans 'Uid' %}:</td>
<td><b>{{ system_user.uid }}</b></td>
</tr>
{% endif %}
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ system_user.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_group.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ system_user.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="50%">{% trans 'Get mannual install script' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Get' %}</button>
</span>
</td>
</tr>
<tr>
<td width="50%">{% trans 'Retest asset connectivity' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Start' %}</button>
</span>
</td>
</tr>
<tr>
<td width="50%">{% trans 'Reset private key' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'assets:system-user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create system user" %} </a>
{% endblock %}
{% block table_head %}
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center"><a href="{% url 'assets:system-user-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'assets:system-user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Asset group num' %}</th>
<th class="text-center">{% trans 'Unavailable' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for system_user in system_user_list %}
<tr class="gradeX">
<td class="text-center">{{ system_user.id }}</td>
<td>
<a href="{% url 'assets:system-user-detail' pk=system_user.id %}">
{{ system_user.name }}
</a>
</td>
<td class="text-center">{{ system_user.username }}</td>
<td class="text-center">{{ system_user.assets.count }}</td>
<td class="text-center">{{ system_user.asset_groups.count }}</td>
<td class="text-center">{{ system_user.assets.count }}</td>
<td class="text-center">{{ system_user.comment|truncatewords:4 }}</td>
<td class="text-center">
<!-- Todo: Click script button will paste a url to clipboard like: curl http://url/system_user_create.sh | bash -->
<a href="{% url 'assets:system-user-update' pk=system_user.id %}" class="btn btn-xs btn-primary">{% trans 'Script' %}</a>
<!-- Todo: Click refresh button will run a task to test admin user could connect asset or not immediately -->
<a href="{% url 'assets:system-user-update' pk=system_user.id %}" class="btn btn-xs btn-warning">{% trans 'Refresh' %}</a>
<a href="{% url 'assets:system-user-update' pk=system_user.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a onclick="obj_del(this,'{{ system_user.name }}','{% url 'assets:system-user-delete' system_user.id %}')" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
</td>
</tr>
{% endfor %}
{% endblock %}
...@@ -12,16 +12,43 @@ import views ...@@ -12,16 +12,43 @@ import views
app_name = 'assets' app_name = 'assets'
urlpatterns = [ urlpatterns = [
# Resource asset url
url(r'^$', views.AssetListView.as_view(), name='asset-index'), url(r'^$', views.AssetListView.as_view(), name='asset-index'),
url(r'^asset$', views.AssetListView.as_view(), name='asset-list'), url(r'^asset$', views.AssetListView.as_view(), name='asset-list'),
url(r'^asset/create$', views.AssetCreateView.as_view(), name='asset-create'), url(r'^asset/create$', views.AssetCreateView.as_view(), name='asset-create'),
url(r'^asset/(?P<pk>[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'), url(r'^asset/(?P<pk>[0-9]+)$', views.AssetDetailView.as_view(), name='asset-detail'),
url(r'^asset/(?P<pk>[0-9]+)$/update', views.AssetUpdateView.as_view(), name='asset-update'), url(r'^asset/(?P<pk>[0-9]+)/update', views.AssetUpdateView.as_view(), name='asset-update'),
url(r'^asset/(?P<pk>[0-9]+)/delete$', views.AssetDeleteView.as_view(), name='asset-delete'), url(r'^asset/(?P<pk>[0-9]+)/delete$', views.AssetDeleteView.as_view(), name='asset-delete'),
# Resource asset group url
url(r'^asset-group$', views.AssetGroupListView.as_view(), name='asset-group-list'), url(r'^asset-group$', views.AssetGroupListView.as_view(), name='asset-group-list'),
url(r'^asset-group/create$', views.AssetGroupCreateView.as_view(), name='asset-group-create'), url(r'^asset-group/create$', views.AssetGroupCreateView.as_view(), name='asset-group-create'),
url(r'^asset-group/(?P<pk>[0-9]+)$', views.AssetGroupDetailView.as_view(), name='asset-group-detail'), url(r'^asset-group/(?P<pk>[0-9]+)$', views.AssetGroupDetailView.as_view(), name='asset-group-detail'),
url(r'^asset-group/(?P<pk>[0-9]+)/update$', views.AssetGroupUpdateView.as_view(), name='asset-group-update'), url(r'^asset-group/(?P<pk>[0-9]+)/update$', views.AssetGroupUpdateView.as_view(), name='asset-group-update'),
url(r'^asset-group/(?P<pk>[0-9]+)/delete$', views.AssetGroupDeleteView.as_view(), name='asset-group-delete'), url(r'^asset-group/(?P<pk>[0-9]+)/delete$', views.AssetGroupDeleteView.as_view(), name='asset-group-delete'),
# Resource idc url
url(r'^idc$', views.IDCListView.as_view(), name='idc-list'),
url(r'^idc/create$', views.IDCCreateView.as_view(), name='idc-create'),
url(r'^idc/(?P<pk>[0-9]+)$', views.IDCDetailView.as_view(), name='idc-detail'),
url(r'^idc/(?P<pk>[0-9]+)/update', views.IDCUpdateView.as_view(), name='idc-update'),
url(r'^idc/(?P<pk>[0-9]+)/delete$', views.IDCDeleteView.as_view(), name='idc-delete'),
# Resource admin user url
url(r'^admin-user$', views.AdminUserListView.as_view(), name='admin-user-list'),
url(r'^admin-user/create$', views.AdminUserCreateView.as_view(), name='admin-user-create'),
url(r'^admin-user/(?P<pk>[0-9]+)$', views.AdminUserDetailView.as_view(), name='admin-user-detail'),
url(r'^admin-user/(?P<pk>[0-9]+)/update', views.AdminUserUpdateView.as_view(), name='admin-user-update'),
url(r'^admin-user/(?P<pk>[0-9]+)/delete$', views.AdminUserDeleteView.as_view(), name='admin-user-delete'),
# Resource system user url
url(r'^system-user$', views.SystemUserListView.as_view(), name='system-user-list'),
url(r'^system-user/create$', views.SystemUserCreateView.as_view(), name='system-user-create'),
url(r'^system-user/(?P<pk>[0-9]+)$', views.SystemUserDetailView.as_view(), name='system-user-detail'),
url(r'^system-user/(?P<pk>[0-9]+)/update', views.SystemUserUpdateView.as_view(), name='system-user-update'),
url(r'^system-user/(?P<pk>[0-9]+)/delete$', views.SystemUserDeleteView.as_view(), name='system-user-delete'),
url(r'^system-user/(?P<pk>[0-9]+)/asset$', views.SystemUserAssetView.as_view(), name='system-user-asset'),
url(r'^system-user/(?P<pk>[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(),
name='system-user-asset-group'),
# url(r'^api/v1.0/', include(router.urls)), # url(r'^api/v1.0/', include(router.urls)),
] ]
# ~*~ coding: utf-8 ~*~ # ~*~ 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
...@@ -2,18 +2,17 @@ ...@@ -2,18 +2,17 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.shortcuts import get_object_or_404 from django.conf import settings
from django.views.generic import TemplateView, ListView from django.db.models import Q
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 import TemplateView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.views.generic.detail import DetailView from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from .models import Asset, AssetGroup, IDC, AssetExtend from .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser
from .forms import AssetForm, AssetGroupForm from .forms import AssetForm, AssetGroupForm, IDCForm, AdminUserForm, SystemUserForm
from .utils import AdminUserRequiredMixin from .hands import AdminUserRequiredMixin
class AssetCreateView(CreateView): class AssetCreateView(CreateView):
...@@ -50,12 +49,14 @@ class AssetDetailView(DetailView): ...@@ -50,12 +49,14 @@ class AssetDetailView(DetailView):
template_name = 'assets/asset_detail.html' template_name = 'assets/asset_detail.html'
class AssetGroupCreateView(CreateView): class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
model = AssetGroup model = AssetGroup
form_class = AssetGroupForm form_class = AssetGroupForm
template_name = 'assets/asset_group_create.html' template_name = 'assets/asset_group_create.html'
success_url = reverse_lazy('assets:asset-group-list') success_url = reverse_lazy('assets:asset-group-list')
# Todo: Asset group create template select assets so hard, need be resolve next
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
...@@ -70,25 +71,57 @@ class AssetGroupCreateView(CreateView): ...@@ -70,25 +71,57 @@ class AssetGroupCreateView(CreateView):
return super(AssetGroupCreateView, self).form_valid(form) return super(AssetGroupCreateView, self).form_valid(form)
class AssetGroupListView(ListView): class AssetGroupListView(AdminUserRequiredMixin, ListView):
model = AssetGroup model = AssetGroup
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'asset_group_list' context_object_name = 'asset_group_list'
template_name = 'assets/asset_group_list.html' template_name = 'assets/asset_group_list.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
'action': _('Asset group list') 'action': _('Asset group list'),
'keyword': self.request.GET.get('keyword', '')
} }
kwargs.update(context) kwargs.update(context)
return super(AssetGroupListView, self).get_context_data(**kwargs) return super(AssetGroupListView, self).get_context_data(**kwargs)
def get_queryset(self):
self.queryset = super(AssetGroupListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created')
class AssetGroupDetailView(DetailView): if keyword:
pass self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
Q(comment__icontains=keyword))
if sort:
self.queryset = self.queryset.order_by(sort)
return self.queryset
class AssetGroupDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView):
template_name = 'assets/asset_group_detail.html'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetGroup.objects.all())
return super(AssetGroupDetailView, self).get(request, *args, **kwargs)
def get_queryset(self):
return self.object.assets.all()
class AssetGroupUpdateView(UpdateView): def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Asset group detail'),
'asset_group': self.object,
}
kwargs.update(context)
return super(AssetGroupDetailView, self).get_context_data(**kwargs)
class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
model = AssetGroup model = AssetGroup
form_class = AssetGroupForm form_class = AssetGroupForm
template_name = 'assets/asset_group_create.html' template_name = 'assets/asset_group_create.html'
...@@ -104,5 +137,313 @@ class AssetGroupUpdateView(UpdateView): ...@@ -104,5 +137,313 @@ class AssetGroupUpdateView(UpdateView):
return super(AssetGroupUpdateView, self).get_context_data(**kwargs) return super(AssetGroupUpdateView, self).get_context_data(**kwargs)
class AssetGroupDeleteView(DeleteView): class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
template_name = 'assets/delete_confirm.html'
model = AssetGroup
success_url = reverse_lazy('assets:asset-group-list')
class IDCListView(AdminUserRequiredMixin, ListView):
model = IDC
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'idc_list'
template_name = 'assets/idc_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('IDC list'),
'keyword': self.request.GET.get('keyword', '')
}
kwargs.update(context)
return super(IDCListView, self).get_context_data(**kwargs)
def get_queryset(self):
self.queryset = super(IDCListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created')
if keyword:
self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
Q(comment__icontains=keyword))
if sort:
self.queryset = self.queryset.order_by(sort)
return self.queryset
class IDCCreateView(AdminUserRequiredMixin, CreateView):
model = IDC
form_class = IDCForm
template_name = 'assets/idc_create_update.html'
success_url = reverse_lazy('assets:idc-list')
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'Create IDC'
}
kwargs.update(context)
return super(IDCCreateView, self).get_context_data(**kwargs)
class IDCUpdateView(AdminUserRequiredMixin, UpdateView):
model = IDC
form_class = IDCForm
template_name = 'assets/idc_create_update.html'
context_object_name = 'idc'
success_url = reverse_lazy('assets:idc-list')
def form_valid(self, form):
idc = form.save(commit=False)
idc.save()
return super(IDCUpdateView, self).form_valid(form)
class IDCDetailView(AdminUserRequiredMixin, DetailView):
pass pass
class IDCDeleteView(AdminUserRequiredMixin, DeleteView):
model = IDC
template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('assets:idc-list')
class AdminUserListView(AdminUserRequiredMixin, ListView):
model = AdminUser
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'admin_user_list'
template_name = 'assets/admin_user_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Admin user list'),
'keyword': self.request.GET.get('keyword', '')
}
kwargs.update(context)
return super(AdminUserListView, self).get_context_data(**kwargs)
def get_queryset(self):
# Todo: Default order by lose asset connection num
self.queryset = super(AdminUserListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created')
if keyword:
self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
Q(comment__icontains=keyword))
if sort:
self.queryset = self.queryset.order_by(sort)
return self.queryset
class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
model = AdminUser
form_class = AdminUserForm
template_name = 'assets/admin_user_create_update.html'
success_url = reverse_lazy('assets:admin-user-list')
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'Create admin user'
}
kwargs.update(context)
return super(AdminUserCreateView, self).get_context_data(**kwargs)
def get_success_message(self, cleaned_data):
success_message = _('Create admin user <a href="%s">%s</a> successfully.' %
(
reverse_lazy('assets:admin-user-detail', kwargs={'pk': self.object.pk}),
self.object.name,
))
return success_message
class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
model = AdminUser
form_class = AdminUserForm
template_name = 'assets/admin_user_create_update.html'
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'Update admin user'
}
kwargs.update(context)
return super(AdminUserUpdateView, self).get_context_data(**kwargs)
def get_success_url(self):
success_url = reverse_lazy('assets:admin-user-detail', pk=self.object.pk)
return success_url
class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'assets/admin_user_detail.html'
context_object_name = 'admin_user'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AdminUser.objects.all())
return super(AdminUserDetailView, self).get(request, *args, **kwargs)
# Todo: queryset default order by connectivity, need ops support
def get_queryset(self):
return self.object.assets.all()
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'Admin user detail'
}
kwargs.update(context)
return super(AdminUserDetailView, self).get_context_data(**kwargs)
class AdminUserDeleteView(AdminUserRequiredMixin, DeleteView):
model = AdminUser
template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('assets:admin-user-list')
class SystemUserListView(AdminUserRequiredMixin, ListView):
model = SystemUser
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'system_user_list'
template_name = 'assets/system_user_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('System user list'),
'keyword': self.request.GET.get('keyword', '')
}
kwargs.update(context)
return super(SystemUserListView, self).get_context_data(**kwargs)
def get_queryset(self):
# Todo: Default order by lose asset connection num
self.queryset = super(SystemUserListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created')
if keyword:
self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
Q(comment__icontains=keyword))
if sort:
self.queryset = self.queryset.order_by(sort)
return self.queryset
class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
model = SystemUser
form_class = SystemUserForm
template_name = 'assets/system_user_create_update.html'
success_url = reverse_lazy('assets:system-user-list')
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Create system user'),
}
kwargs.update(context)
return super(SystemUserCreateView, self).get_context_data(**kwargs)
def get_success_message(self, cleaned_data):
success_message = _('Create system user <a href="%s">%s</a> successfully.' %
(
reverse_lazy('assets:system-user-detail', kwargs={'pk': self.object.pk}),
self.object.name,
))
return self.success_message
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
model = SystemUser
form_class = SystemUserForm
template_name = 'assets/system_user_create_update.html'
success_message = _('Update system user <a href="%s">%s</a> successfully.')
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Update system user')
}
kwargs.update(context)
return super(SystemUserUpdateView, self).get_context_data(**kwargs)
def get_success_url(self):
success_url = reverse_lazy('assets:system-user-detail', pk=self.object.pk)
return success_url
class SystemUserDetailView(AdminUserRequiredMixin, DetailView):
template_name = 'assets/system_user_detail.html'
context_object_name = 'system_user'
model = SystemUser
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('System user detail')
}
kwargs.update(context)
return super(SystemUserDetailView, self).get_context_data(**kwargs)
class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView):
model = SystemUser
template_name = 'assets/delete_confirm.html'
success_url = reverse_lazy('assets:system-user-list')
class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'assets/system_user_asset.html'
context_object_name = 'system_user'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=SystemUser.objects.all())
return super(SystemUserAssetView, self).get(request, *args, **kwargs)
# Todo: queryset default order by connectivity, need ops support
def get_queryset(self):
return self.object.assets.all()
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'System user asset',
'assets': self.get_queryset(),
}
kwargs.update(context)
return super(SystemUserAssetView, self).get_context_data(**kwargs)
class SystemUserAssetGroupView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
template_name = 'assets/system_user_asset_group.html'
context_object_name = 'system_user'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=SystemUser.objects.all())
return super(SystemUserAssetGroupView, self).get(request, *args, **kwargs)
# Todo: queryset default order by connectivity, need ops support
def get_queryset(self):
return self.object.asset_groups.all()
def get_context_data(self, **kwargs):
context = {
'app': 'assets',
'action': 'System user asset group',
'asset_groups': self.get_queryset(),
}
kwargs.update(context)
return super(SystemUserAssetGroupView, self).get_context_data(**kwargs)
# Common app
Common app provide common view, function or others.
Common app shouldn't rely on other apps, because It may lead to cycle
import.
If your want to implement some function or class, you should think
whether other app use or not. If yes, You should make in common.
If the ability more relate to your app tightness, It's mean your app
provide this ability, not common, You should write it on your app utils.
## Celery usage ## Celery usage
......
...@@ -2,9 +2,15 @@ ...@@ -2,9 +2,15 @@
# #
from __future__ import unicode_literals from __future__ import unicode_literals
from six import string_types
from itertools import chain
import string
import logging
from django.shortcuts import reverse as dj_reverse from django.shortcuts import reverse as dj_reverse
from django.conf import settings from django.conf import settings
from django.core import signing
from django.utils import timezone
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, external=False): def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, external=False):
...@@ -21,3 +27,76 @@ def get_object_or_none(model, **kwargs): ...@@ -21,3 +27,76 @@ def get_object_or_none(model, **kwargs):
except model.DoesNotExist: except model.DoesNotExist:
obj = None obj = None
return obj return obj
def encrypt(*args, **kwargs):
return signing.dumps(*args, **kwargs)
def decrypt(*args, **kwargs):
return signing.loads(*args, **kwargs)
def date_expired_default():
try:
years = int(settings.CONFIG.DEFAULT_EXPIRED_YEARS)
except TypeError:
years = 70
return timezone.now() + timezone.timedelta(days=365 * years)
def combine_seq(s1, s2, callback=None):
for s in (s1, s2):
if not hasattr(s, '__iter__'):
return []
seq = chain(s1, s2)
if callback:
seq = map(callback, seq)
return seq
def search_object_attr(obj, value='', attr_list=None, ignore_case=False):
"""It's provide a method to search a object attribute equal some value
If object some attribute equal :param: value, return True else return False
class A():
name = 'admin'
age = 7
:param obj: A object
:param value: A string match object attribute
:param attr_list: Only match attribute in attr_list
:param ignore_case: Ignore case
:return: Boolean
"""
if value == '':
return True
try:
object_attr = obj.__dict__
except AttributeError:
return False
if attr_list is not None:
new_object_attr = {}
for attr in attr_list:
new_object_attr[attr] = object_attr.pop(attr)
object_attr = new_object_attr
if ignore_case:
if not isinstance(value, string_types):
return False
if value.lower() in map(string.lower, map(str, object_attr.values())):
return True
else:
if value in object_attr.values():
return True
return False
def get_logger(name=None):
return logging.getLogger('jumpserver.%s' % name)
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
[{"model": "users.usergroup", "pk": 1, "fields": {"name": "Default", "comment": "Default user group for all user", "date_added": "2016-09-05T11:39:25.770Z", "created_by": "System"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$5ReHkQOQA2Hk$DIW0b5U/uK+U0xqjA3QpYvBcODNhm2MPCm7YWbQys3I=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-09-05T11:39:25.771Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "private_key": "", "public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-08-19T11:39:25.771Z", "created_by": "System", "user_permissions": [], "groups": [1]}}] [{"model": "users.usergroup", "pk": 1, "fields": {"name": "Default", "comment": "Default user group for all user", "date_created": "2016-09-05T11:39:25.770Z", "created_by": "System"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$5ReHkQOQA2Hk$DIW0b5U/uK+U0xqjA3QpYvBcODNhm2MPCm7YWbQys3I=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-09-05T11:39:25.771Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-08-19T11:39:25.771Z", "created_by": "System", "user_permissions": [], "groups": [1]}}]
\ No newline at end of file \ No newline at end of file
...@@ -108,6 +108,7 @@ TEMPLATES = [ ...@@ -108,6 +108,7 @@ TEMPLATES = [
# WSGI_APPLICATION = 'jumpserver.wsgi.application' # WSGI_APPLICATION = 'jumpserver.wsgi.application'
LOGIN_REDIRECT_URL = reverse_lazy('index') LOGIN_REDIRECT_URL = reverse_lazy('index')
LOGIN_URL = reverse_lazy('users:login')
# Database # Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
...@@ -227,7 +228,7 @@ USE_L10N = True ...@@ -227,7 +228,7 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
# I18N translation # I18N translation
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'),] LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'), ]
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/ # https://docs.djangoproject.com/en/1.10/howto/static-files/
...@@ -313,3 +314,5 @@ CAPTCHA_IMAGE_SIZE = (75, 33) ...@@ -313,3 +314,5 @@ CAPTCHA_IMAGE_SIZE = (75, 33)
CAPTCHA_FOREGROUND_COLOR = '#001100' CAPTCHA_FOREGROUND_COLOR = '#001100'
# #
SESSION_COOKIE_AGE = 10800 # 3 hours
SESSION_SAVE_EVERY_REQUEST = True
...@@ -17,7 +17,6 @@ from django.conf.urls import url, include ...@@ -17,7 +17,6 @@ from django.conf.urls import url, include
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.http import HttpResponseRedirect
urlpatterns = [ urlpatterns = [
...@@ -25,6 +24,7 @@ urlpatterns = [ ...@@ -25,6 +24,7 @@ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'), url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'),
url(r'^(api/)?users/', include('users.urls')), url(r'^(api/)?users/', include('users.urls')),
url(r'^assets/', include('assets.urls')), url(r'^assets/', include('assets.urls')),
url(r'^perms/', include('perms.urls')),
url(r'^terminal/', include('webterminal.urls')), url(r'^terminal/', include('webterminal.urls')),
] ]
......
...@@ -8,301 +8,1057 @@ msgid "" ...@@ -8,301 +8,1057 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-05 20:18+0800\n" "POT-Creation-Date: 2016-09-15 12:13+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
#: assets/forms.py:20 #: assets/forms.py:19 assets/forms.py:156 perms/forms.py:27
msgid "Join assetgroups" #: perms/templates/perms/asset_permission_asset_list.html:139
msgstr "添加到用户组" msgid "Select asset groups"
msgstr "添加到资产组"
#: assets/forms.py:26 assets/forms.py:57 assets/forms.py:88
#: assets/forms.py:146 assets/models.py:322
#: perms/templates/perms/asset_permission_create_update.html:40
#: templates/_nav.html:21
msgid "Asset"
msgstr "资产"
#: assets/models.py:9 assets/models.py:21 assets/models.py:54 #: assets/forms.py:29 assets/forms.py:60 assets/forms.py:91
#: assets/models.py:76 assets/templates/assets/assetgroup_list.html:12 #: assets/forms.py:149 perms/forms.py:25
#: users/models.py:60 users/models.py:107 msgid "Select assets"
#: users/templates/users/user_detail.html:69 msgstr "选择资产"
#: assets/forms.py:79 assets/forms.py:134 assets/forms.py:206
#: assets/models.py:14 assets/models.py:88 assets/models.py:153
#: assets/models.py:222 assets/templates/assets/admin_user_detail.html:50
#: assets/templates/assets/admin_user_list.html:10
#: assets/templates/assets/asset_group_detail.html:46
#: assets/templates/assets/asset_group_list.html:12
#: assets/templates/assets/idc_list.html:10
#: assets/templates/assets/system_user_asset_group.html:53
#: assets/templates/assets/system_user_detail.html:55
#: assets/templates/assets/system_user_list.html:10 perms/models.py:19
#: perms/templates/perms/asset_permission_create_update.html:33
#: perms/templates/perms/asset_permission_detail.html:56
#: perms/templates/perms/asset_permission_list.html:12
#: perms/templates/perms/asset_permission_user_list.html:66
#: perms/templates/perms/perm_user_asset_list.html:12 users/models.py:20
#: users/models.py:67 users/templates/users/user_detail.html:54
#: users/templates/users/user_list.html:12 #: users/templates/users/user_list.html:12
msgid "Name" msgid "Name"
msgstr "名称" msgstr "名称"
#: assets/models.py:10 assets/models.py:29 assets/models.py:42 #: assets/forms.py:96 assets/forms.py:161
#: assets/models.py:61 assets/models.py:90 assets/models.py:125 msgid "If also set private key, use that first"
#: assets/models.py:145 users/models.py:122 msgstr "如果设置私钥,则优先使用私钥"
#: users/templates/users/user_detail.html:101
msgid "Created by" #: assets/forms.py:135 assets/forms.py:207 assets/models.py:89
msgstr "创建者" #: assets/models.py:154 assets/templates/assets/admin_user_detail.html:54
#: assets/templates/assets/admin_user_list.html:11
#: assets/templates/assets/system_user_detail.html:59
#: assets/templates/assets/system_user_list.html:11
#: perms/templates/perms/asset_permission_user_list.html:67
#: perms/templates/perms/perm_user_asset_list.html:13 users/forms.py:13
#: users/models.py:66 users/templates/users/login.html:53
#: users/templates/users/user_detail.html:58
#: users/templates/users/user_list.html:13
#: users/templates/users/user_update.html:6
msgid "Username"
msgstr "用户名"
#: assets/models.py:11 assets/models.py:30 assets/models.py:44 #: assets/forms.py:152 perms/templates/perms/perm_user_asset_list.html:16
#: assets/models.py:62 assets/models.py:91 assets/models.py:128 #: templates/_nav.html:22
#: assets/models.py:147 assets/templates/assets/assetgroup_list.html:14 msgid "Asset group"
#: users/models.py:61 users/models.py:118 msgstr "资产组"
#: users/templates/users/user_detail.html:113
msgid "Comment"
msgstr "备注"
#: assets/models.py:22 #: assets/models.py:15 assets/templates/assets/idc_list.html:12
msgid "Bandwidth" msgid "Bandwidth"
msgstr "带宽" msgstr "带宽"
#: assets/models.py:23 #: assets/models.py:16 assets/templates/assets/idc_list.html:13
msgid "Contact" msgid "Contact"
msgstr "联系人" msgstr "联系人"
#: assets/models.py:24 users/models.py:113 #: assets/models.py:17 assets/templates/assets/idc_list.html:14
#: users/templates/users/user_detail.html:82 #: users/models.py:73 users/templates/users/user_detail.html:67
msgid "Phone" msgid "Phone"
msgstr "手机" msgstr "手机"
#: assets/models.py:25 #: assets/models.py:18 assets/templates/assets/idc_list.html:15
msgid "Address" msgid "Address"
msgstr "地址" msgstr "地址"
#: assets/models.py:26 #: assets/models.py:19
msgid "Network" msgid "Network"
msgstr "网络" msgstr "网络"
#: assets/models.py:27 assets/models.py:127 #: assets/models.py:20 assets/models.py:225 assets/models.py:286
msgid "Date added" msgid "Date added"
msgstr "加入日期" msgstr "加入日期"
#: assets/models.py:28 #: assets/models.py:21
msgid "Operator" msgid "Operator"
msgstr "运营商" msgstr "运营商"
#: assets/models.py:40 assets/models.py:142 #: assets/models.py:22 assets/models.py:59 assets/models.py:96
#: assets/models.py:167 assets/models.py:224 assets/models.py:284
#: assets/models.py:323 assets/templates/assets/admin_user_detail.html:62
#: assets/templates/assets/asset_group_detail.html:54
#: assets/templates/assets/system_user_detail.html:105 perms/models.py:28
#: perms/templates/perms/asset_permission_detail.html:96 users/models.py:82
#: users/templates/users/user_detail.html:86
msgid "Created by"
msgstr "创建者"
#: assets/models.py:23 assets/models.py:61 assets/models.py:94
#: assets/models.py:168 assets/models.py:226 assets/models.py:287
#: assets/models.py:325 assets/templates/assets/admin_user_detail.html:66
#: assets/templates/assets/admin_user_list.html:14
#: assets/templates/assets/asset_group_detail.html:58
#: assets/templates/assets/asset_group_list.html:14
#: assets/templates/assets/system_user_asset_group.html:56
#: assets/templates/assets/system_user_detail.html:109
#: assets/templates/assets/system_user_list.html:15 perms/models.py:30
#: perms/templates/perms/asset_permission_detail.html:100 users/models.py:21
#: users/models.py:78 users/templates/users/user_detail.html:98
msgid "Comment"
msgstr "备注"
#: assets/models.py:57 assets/models.py:320
msgid "KEY" msgid "KEY"
msgstr "KEY" msgstr "KEY"
#: assets/models.py:41 assets/models.py:143 #: assets/models.py:58 assets/models.py:321
msgid "VALUE" msgid "VALUE"
msgstr "VALUE" msgstr "VALUE"
#: assets/models.py:55 assets/models.py:77 users/forms.py:12 #: assets/models.py:69 assets/models.py:70
#: users/models.py:106 users/templates/users/login.html:54 msgid "status"
#: users/templates/users/user_detail.html:73 msgstr "状态"
#: users/templates/users/user_edit.html:5
#: users/templates/users/user_list.html:13 #: assets/models.py:69
msgid "Username" #, fuzzy
msgstr "用户名" #| msgid "Admin user"
msgid "In use"
msgstr "管理用户"
#: assets/models.py:70
#, fuzzy
#| msgid "Auto push"
msgid "Out of use"
msgstr "自动推送"
#: assets/models.py:71 assets/models.py:72 assets/models.py:73
#: assets/models.py:74 assets/models.py:75 assets/models.py:76
msgid "type"
msgstr ""
#: assets/models.py:71
msgid "Server"
msgstr ""
#: assets/models.py:72
msgid "VM"
msgstr ""
#: assets/models.py:73
msgid "Switch"
msgstr ""
#: assets/models.py:74
#, fuzzy
#| msgid "Role"
msgid "Router"
msgstr "角色"
#: assets/models.py:75
msgid "Firewall"
msgstr ""
#: assets/models.py:76
msgid "Storage"
msgstr ""
#: assets/models.py:77 assets/models.py:78 assets/models.py:79
msgid "env"
msgstr ""
#: assets/models.py:77
msgid "Production"
msgstr ""
#: assets/models.py:78
msgid "Development"
msgstr ""
#: assets/models.py:79
#, fuzzy
msgid "Setting"
msgstr "设置"
#: assets/models.py:56 assets/models.py:78 users/forms.py:13 #: assets/models.py:90 assets/models.py:155 users/forms.py:15
#: users/templates/users/login.html:57 #: users/templates/users/login.html:56
#: users/templates/users/reset_password.html:52 #: users/templates/users/reset_password.html:52
#: users/templates/users/user_add.html:8 users/templates/users/user_add.html:10 #: users/templates/users/user_create.html:8
#: users/templates/users/user_edit.html:12 #: users/templates/users/user_create.html:10
#: users/templates/users/user_edit.html:14 #: users/templates/users/user_update.html:13
#: users/templates/users/user_update.html:15
msgid "Password" msgid "Password"
msgstr "密码" msgstr "密码"
#: assets/models.py:57 assets/models.py:80 #: assets/models.py:91 assets/models.py:157
msgid "SSH private key" msgid "SSH private key"
msgstr "ssh密钥" msgstr "ssh密钥"
#: assets/models.py:58 assets/models.py:82 #: assets/models.py:92 assets/models.py:158
msgid "SSH public key"
msgstr "ssh公钥"
#: assets/models.py:93 assets/models.py:159
#: assets/templates/assets/admin_user_create_update.html:43
#: assets/templates/assets/system_user_create_update.html:44
#: assets/templates/assets/system_user_detail.html:75
msgid "As default" msgid "As default"
msgstr "默认使用" msgstr "默认使用"
#: assets/models.py:59 assets/models.py:84 #: assets/models.py:156 assets/templates/assets/system_user_detail.html:63
msgid "Auto update pass/key"
msgstr "自动更新密码/密钥"
#: assets/models.py:79
msgid "Protocol" msgid "Protocol"
msgstr "协议" msgstr "协议"
#: assets/models.py:81 #: assets/models.py:160
msgid "SSH public key" #: assets/templates/assets/system_user_create_update.html:50
msgstr "ssh公钥" #: assets/templates/assets/system_user_detail.html:67
#: assets/models.py:83
msgid "Auto push" msgid "Auto push"
msgstr "自动推送" msgstr "自动推送"
#: assets/models.py:85 #: assets/models.py:161
msgid "Auto update pass/key"
msgstr "自动更新密码/密钥"
#: assets/models.py:162 assets/templates/assets/system_user_detail.html:79
msgid "Sudo" msgid "Sudo"
msgstr "Sudo" msgstr "Sudo"
#: assets/models.py:86 #: assets/models.py:163 assets/templates/assets/system_user_detail.html:84
msgid "Shell" msgid "Shell"
msgstr "Shell" msgstr "Shell"
#: assets/models.py:87 templates/_header_bar.html:35 templates/_nav.html:4 #: assets/models.py:164 assets/templates/assets/system_user_detail.html:90
#: templates/_header_bar.html:41 templates/_nav.html:4
msgid "Home" msgid "Home"
msgstr "仪表盘" msgstr "仪表盘"
#: assets/models.py:88 #: assets/models.py:165 assets/templates/assets/system_user_detail.html:96
msgid "Uid" msgid "Uid"
msgstr "Uid" msgstr "Uid"
#: assets/models.py:101 #: assets/models.py:236
#, fuzzy
#| msgid "As default"
msgid "Default"
msgstr "默认使用"
#: assets/models.py:236
#, fuzzy
#| msgid "Create asset group"
msgid "Default asset group"
msgstr "创建资产组"
#: assets/models.py:259 assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_group_detail.html:88
#: assets/templates/assets/system_user_asset.html:53
#: perms/templates/perms/asset_permission_asset_list.html:67
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models.py:102 #: assets/models.py:260
msgid "Other IP" msgid "Other IP"
msgstr "其它IP" msgstr "其它IP"
#: assets/models.py:103 #: assets/models.py:261
msgid "Remote card IP" msgid "Remote card IP"
msgstr "远控卡IP" msgstr "远控卡IP"
#: assets/models.py:104 #: assets/models.py:262 assets/templates/assets/admin_user_detail.html:99
#: assets/templates/assets/asset_group_detail.html:87
#: assets/templates/assets/system_user_asset.html:52
#: perms/templates/perms/asset_permission_asset_list.html:66
msgid "Hostname" msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models.py:105 #: assets/models.py:263 assets/templates/assets/admin_user_detail.html:101
#: assets/templates/assets/asset_group_detail.html:89
#: assets/templates/assets/system_user_asset.html:54
#: perms/templates/perms/asset_permission_asset_list.html:68
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/models.py:106 #: assets/models.py:264
msgid "Asset groups" msgid "Asset groups"
msgstr "用户组" msgstr "用户组"
#: assets/models.py:107 assets/models.py:109 templates/_nav.html:24 #: assets/models.py:265 assets/models.py:268 templates/_nav.html:24
msgid "Admin user" msgid "Admin user"
msgstr "管理用户" msgstr "管理用户"
#: assets/models.py:108 #: assets/models.py:266
msgid "Admin password" msgid "Admin password"
msgstr "管理员密码" msgstr "管理员密码"
#: assets/models.py:111 templates/_nav.html:23 #: assets/models.py:269
msgid "System User"
msgstr "系统用户"
#: assets/models.py:270 templates/_nav.html:23
msgid "IDC" msgid "IDC"
msgstr "机房" msgstr "机房"
#: assets/models.py:112 #: assets/models.py:271
msgid "Mac address" msgid "Mac address"
msgstr "Mac地址" msgstr "Mac地址"
#: assets/models.py:113 #: assets/models.py:272
msgid "Brand" msgid "Brand"
msgstr "品牌" msgstr "品牌"
#: assets/models.py:114 #: assets/models.py:273
msgid "CPU" msgid "CPU"
msgstr "CPU" msgstr "CPU"
#: assets/models.py:115 #: assets/models.py:274
msgid "Memory" msgid "Memory"
msgstr "内存" msgstr "内存"
#: assets/models.py:116 #: assets/models.py:275
msgid "Disk" msgid "Disk"
msgstr "硬盘" msgstr "硬盘"
#: assets/models.py:117 #: assets/models.py:276
msgid "OS" msgid "OS"
msgstr "操作系统" msgstr "操作系统"
#: assets/models.py:118 #: assets/models.py:277
msgid "Cabinet number" msgid "Cabinet number"
msgstr "机柜编号" msgstr "机柜编号"
#: assets/models.py:119 #: assets/models.py:278
msgid "Cabinet position" msgid "Cabinet position"
msgstr "机柜层号" msgstr "机柜层号"
#: assets/models.py:120 #: assets/models.py:279
msgid "Asset number" msgid "Asset number"
msgstr "资产编号" msgstr "资产编号"
#: assets/models.py:121 #: assets/models.py:280
msgid "Asset status" msgid "Asset status"
msgstr "资产状态" msgstr "资产状态"
#: assets/models.py:122 #: assets/models.py:281
msgid "Asset type" msgid "Asset type"
msgstr "系统类型" msgstr "系统类型"
#: assets/models.py:123 #: assets/models.py:282
msgid "Asset environment" msgid "Asset environment"
msgstr "资产环境" msgstr "资产环境"
#: assets/models.py:124 #: assets/models.py:283
msgid "Serial number" msgid "Serial number"
msgstr "序列号" msgstr "序列号"
#: assets/models.py:126 #: assets/models.py:285 perms/templates/perms/asset_permission_detail.html:84
msgid "Is active" msgid "Is active"
msgstr "是否激活" msgstr "是否激活"
#: assets/models.py:144 assets/templates/assets/assetgroup_add.html:35 #: assets/templates/assets/admin_user_create_update.html:16
#: templates/_nav.html:21 #: assets/templates/assets/admin_user_list.html:5
msgid "Asset" #, fuzzy
msgstr "资产" #| msgid "Create user"
msgid "Create admin user"
#: assets/templates/assets/assetgroup_add.html:16 msgstr "创建用户"
#: assets/templates/assets/assetgroup_list.html:5 assets/views.py:60
msgid "Create asset group"
msgstr "创建资产组"
#: assets/templates/assets/assetgroup_add.html:37 #: assets/templates/assets/admin_user_create_update.html:35
msgid "Select asset" #: assets/templates/assets/system_user_create_update.html:36
msgstr "选择资产" #, fuzzy
#| msgid "Auto update pass/key"
msgid "Auto generate key"
msgstr "自动更新密码/密钥"
#: assets/templates/assets/assetgroup_add.html:49 #: assets/templates/assets/admin_user_create_update.html:53
#: assets/templates/assets/admin_user_detail.html:152
#: assets/templates/assets/asset_group_create.html:38
#: assets/templates/assets/idc_create_update.html:44
#: assets/templates/assets/system_user_create_update.html:71
#: assets/templates/assets/system_user_detail.html:148
#: perms/templates/perms/asset_permission_create_update.html:69
#: users/templates/users/_user.html:70 #: users/templates/users/_user.html:70
#: users/templates/users/user_detail.html:162 #: users/templates/users/user_detail.html:147
#: users/templates/users/user_detail.html:170 #: users/templates/users/user_detail.html:155
msgid "Reset" msgid "Reset"
msgstr "重置" msgstr "重置"
#: assets/templates/assets/assetgroup_add.html:50 #: assets/templates/assets/admin_user_create_update.html:54
#: assets/templates/assets/assetgroup_list.html:51 #: assets/templates/assets/asset_group_create.html:39
#: assets/templates/assets/asset_group_list.html:51
#: assets/templates/assets/idc_create_update.html:45
#: assets/templates/assets/system_user_create_update.html:72
#: perms/templates/perms/asset_permission_create_update.html:70
#: perms/templates/perms/asset_permission_list.html:65
#: perms/templates/perms/perm_user_asset_list.html:58
#: users/templates/users/_user.html:71 #: users/templates/users/_user.html:71
#: users/templates/users/forget_password.html:44 #: users/templates/users/forgot_password.html:44
#: users/templates/users/user_list.html:63 #: users/templates/users/user_list.html:64
msgid "Submit" msgid "Submit"
msgstr "提交" msgstr "提交"
#: assets/templates/assets/assetgroup_list.html:13 #: assets/templates/assets/admin_user_detail.html:18
#: assets/templates/assets/asset_group_detail.html:18
#: assets/templates/assets/system_user_asset.html:19
#: assets/templates/assets/system_user_asset_group.html:19
#: assets/templates/assets/system_user_detail.html:19
#: perms/templates/perms/asset_permission_asset_list.html:20
#: perms/templates/perms/asset_permission_detail.html:20
#: perms/templates/perms/asset_permission_user_list.html:20
msgid "Detail"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:20
#: assets/templates/assets/system_user_asset.html:22
#: assets/templates/assets/system_user_asset_group.html:22
#: assets/templates/assets/system_user_detail.html:23
#, fuzzy
#| msgid "User assets"
msgid "Associate assets"
msgstr "用户资产"
#: assets/templates/assets/admin_user_detail.html:58
#: assets/templates/assets/asset_group_detail.html:50
#: assets/templates/assets/system_user_detail.html:101 perms/models.py:29
#: perms/templates/perms/asset_permission_detail.html:92
#, fuzzy
#| msgid "Date added"
msgid "Date created"
msgstr "加入日期"
#: assets/templates/assets/admin_user_detail.html:76
#: assets/templates/assets/asset_group_detail.html:68
#: assets/templates/assets/system_user_asset.html:33
#: assets/templates/assets/system_user_asset_group.html:34
#: perms/templates/perms/asset_permission_asset_list.html:47
#, fuzzy
#| msgid "Asset group list"
msgid "Asset list of "
msgstr "资产组列表"
#: assets/templates/assets/admin_user_detail.html:102
#: assets/templates/assets/asset_group_detail.html:90
#: assets/templates/assets/system_user_asset.html:55
#, fuzzy
msgid "Alive"
msgstr "激活"
#: assets/templates/assets/admin_user_detail.html:125
#: assets/templates/assets/system_user_detail.html:121
#: perms/templates/perms/asset_permission_detail.html:112
msgid "Quick update"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:131
msgid "Get install script"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:134
#: assets/templates/assets/system_user_detail.html:130
msgid "Get"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:140
#: assets/templates/assets/system_user_detail.html:136
#: perms/templates/perms/asset_permission_detail.html:132
msgid "Retest asset connectivity"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:143
#: assets/templates/assets/system_user_detail.html:139
#: perms/templates/perms/asset_permission_detail.html:135
msgid "Start"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:149
#: assets/templates/assets/system_user_detail.html:145
#, fuzzy
#| msgid "ssh private key"
msgid "Reset private key"
msgstr "ssh密钥"
#: assets/templates/assets/admin_user_detail.html:163
msgid "Replace asset admin user with this"
msgstr ""
#: assets/templates/assets/admin_user_detail.html:171
#: assets/templates/assets/system_user_asset.html:86
#, fuzzy
#| msgid "Select assets"
msgid "Select asset"
msgstr "选择资产"
#: assets/templates/assets/admin_user_detail.html:180
msgid "Replace"
msgstr ""
#: assets/templates/assets/admin_user_list.html:9
#: assets/templates/assets/idc_list.html:9
#: assets/templates/assets/system_user_list.html:9
#, fuzzy
#| msgid "IDC"
msgid "ID"
msgstr "机房"
#: assets/templates/assets/admin_user_list.html:12
#: assets/templates/assets/asset_group_list.html:13
#: assets/templates/assets/idc_list.html:11
#: assets/templates/assets/system_user_asset_group.html:54
#: assets/templates/assets/system_user_list.html:12
#: perms/templates/perms/perm_user_asset_list.html:15
#: users/templates/users/user_list.html:16 #: users/templates/users/user_list.html:16
msgid "Asset num" msgid "Asset num"
msgstr "资产数量" msgstr "资产数量"
#: assets/templates/assets/assetgroup_list.html:32 #: assets/templates/assets/admin_user_list.html:13
#: users/templates/users/user_list.html:44 msgid "Lost connection"
msgid "Edit" msgstr ""
msgstr "编辑"
#: assets/templates/assets/admin_user_list.html:33
#: assets/templates/assets/system_user_list.html:35
msgid "Script"
msgstr ""
#: assets/templates/assets/assetgroup_list.html:33 #: assets/templates/assets/admin_user_list.html:35
#: assets/templates/assets/system_user_list.html:37
msgid "Refresh"
msgstr ""
#: assets/templates/assets/admin_user_list.html:36
#: assets/templates/assets/asset_group_list.html:32
#: assets/templates/assets/idc_list.html:30
#: assets/templates/assets/system_user_list.html:38
#: perms/templates/perms/asset_permission_list.html:46
#: users/templates/users/user_list.html:44
msgid "Update"
msgstr "更新"
#: assets/templates/assets/admin_user_list.html:37
#: assets/templates/assets/asset_group_list.html:33
#: assets/templates/assets/idc_list.html:31
#: assets/templates/assets/system_user_list.html:39
#: perms/templates/perms/asset_permission_list.html:47
#: users/templates/users/user_list.html:45 #: users/templates/users/user_list.html:45
#: users/templates/users/user_list.html:46
msgid "Delete" msgid "Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/assetgroup_list.html:43 #: assets/templates/assets/asset_group_create.html:16
#: users/templates/users/user_list.html:55 #: assets/templates/assets/asset_group_list.html:5 assets/views.py:61
#: assets/views.py:131
msgid "Create asset group"
msgstr "创建资产组"
#: assets/templates/assets/asset_group_detail.html:20
#, fuzzy
#| msgid "Asset group"
msgid "Asset group perm"
msgstr "资产组"
#: assets/templates/assets/asset_group_detail.html:113
#, fuzzy
#| msgid "System user"
msgid "Associate system user"
msgstr "系统"
#: assets/templates/assets/asset_group_detail.html:119
#, fuzzy
#| msgid "System user"
msgid "repush system user"
msgstr "系统"
#: assets/templates/assets/asset_group_detail.html:129
#, fuzzy
#| msgid "System user"
msgid "Select system user"
msgstr "系统"
#: assets/templates/assets/asset_group_detail.html:138
msgid "Associate"
msgstr ""
#: assets/templates/assets/asset_group_detail.html:157
#, fuzzy
#| msgid "Asset group"
msgid "Add asset to this group"
msgstr "资产组"
#: assets/templates/assets/asset_group_detail.html:165
#, fuzzy
#| msgid "Select assets"
msgid "Select asset user"
msgstr "选择资产"
#: assets/templates/assets/asset_group_detail.html:174
#: assets/templates/assets/system_user_asset.html:95
#: assets/templates/assets/system_user_asset_group.html:96
#: perms/templates/perms/asset_permission_asset_list.html:120
#: perms/templates/perms/asset_permission_user_list.html:120
#, fuzzy
#| msgid "Address"
msgid "Add"
msgstr "地址"
#: assets/templates/assets/asset_group_list.html:43
#: perms/templates/perms/asset_permission_list.html:57
#: perms/templates/perms/perm_user_asset_list.html:50
#: users/templates/users/user_list.html:56
msgid "Delete selected" msgid "Delete selected"
msgstr "批量删除" msgstr "批量删除"
#: assets/templates/assets/assetgroup_list.html:44 #: assets/templates/assets/asset_group_list.html:44
#: users/templates/users/user_list.html:56 #: perms/templates/perms/asset_permission_list.html:58
#: perms/templates/perms/perm_user_asset_list.html:51
#: users/templates/users/user_list.html:57
msgid "Update selected" msgid "Update selected"
msgstr "批量更新" msgstr "批量更新"
#: assets/templates/assets/assetgroup_list.html:45 #: assets/templates/assets/asset_group_list.html:45
#: users/templates/users/user_list.html:57 #: perms/templates/perms/asset_permission_list.html:59
#: perms/templates/perms/perm_user_asset_list.html:52
#: users/templates/users/user_list.html:58
msgid "Deactive selected" msgid "Deactive selected"
msgstr "禁用所选" msgstr "禁用所选"
#: assets/templates/assets/assetgroup_list.html:46 #: assets/templates/assets/asset_group_list.html:46
#: users/templates/users/user_list.html:58 #: perms/templates/perms/asset_permission_list.html:60
#: perms/templates/perms/perm_user_asset_list.html:53
#: users/templates/users/user_list.html:59
msgid "Export selected" msgid "Export selected"
msgstr "批量导出" msgstr "批量导出"
#: assets/views.py:59 assets/views.py:74 templates/_nav.html:18 #: assets/templates/assets/asset_list.html:27
msgid "Create asset"
msgstr "创建资产"
#: assets/templates/assets/delete_confirm.html:6
#: perms/templates/perms/delete_confirm.html:6
#: users/templates/users/user_delete_confirm.html:6
msgid "Confirm delete"
msgstr "确认删除"
#: assets/templates/assets/idc_create_update.html:16
#, fuzzy
#| msgid "Created by"
msgid "Create idc"
msgstr "创建者"
#: assets/templates/assets/idc_list.html:5
#, fuzzy
#| msgid "Created by"
msgid "Create IDC"
msgstr "创建者"
#: assets/templates/assets/system_user_asset.html:25
#: assets/templates/assets/system_user_asset_group.html:26
#: assets/templates/assets/system_user_detail.html:28
#, fuzzy
#| msgid "Create asset group"
msgid "Associate asset groups"
msgstr "创建资产组"
#: assets/templates/assets/system_user_asset.html:78
msgid "Add asset to this system user"
msgstr ""
#: assets/templates/assets/system_user_asset_group.html:55
msgid "Unavailable num"
msgstr ""
#: assets/templates/assets/system_user_asset_group.html:79
#, fuzzy
#| msgid "Asset group list"
msgid "Add asset group to this system user"
msgstr "资产组列表"
#: assets/templates/assets/system_user_asset_group.html:87
#, fuzzy
#| msgid "Select asset groups"
msgid "Select asset group"
msgstr "添加到资产组"
#: assets/templates/assets/system_user_create_update.html:16
#: assets/templates/assets/system_user_list.html:5 assets/views.py:349
#, fuzzy
#| msgid "Create user"
msgid "Create system user"
msgstr "创建用户"
#: assets/templates/assets/system_user_create_update.html:56
#: assets/templates/assets/system_user_detail.html:71
#, fuzzy
#| msgid "Auto update pass/key"
msgid "Auto update"
msgstr "自动更新密码/密钥"
#: assets/templates/assets/system_user_detail.html:127
msgid "Get mannual install script"
msgstr ""
#: assets/templates/assets/system_user_list.html:13
#, fuzzy
#| msgid "Asset group"
msgid "Asset group num"
msgstr "资产组"
#: assets/templates/assets/system_user_list.html:14
msgid "Unavailable"
msgstr ""
#: assets/views.py:60 assets/views.py:80 assets/views.py:114
#: assets/views.py:130 assets/views.py:152 assets/views.py:219
#: assets/views.py:318 assets/views.py:348 assets/views.py:372
#: assets/views.py:390 templates/_nav.html:18
msgid "Assets" msgid "Assets"
msgstr "资产管理" msgstr "资产管理"
#: assets/views.py:75 #: assets/views.py:81
msgid "Asset group list" msgid "Asset group list"
msgstr "资产组列表" msgstr "资产组列表"
#: templates/_header_bar.html:8 users/templates/users/user_detail.html:29 #: assets/views.py:115
#, fuzzy
#| msgid "Asset group list"
msgid "Asset group detail"
msgstr "资产组列表"
#: assets/views.py:153
msgid "IDC list"
msgstr ""
#: assets/views.py:220
#, fuzzy
#| msgid "Admin user"
msgid "Admin user list"
msgstr "管理用户"
#: assets/views.py:256
#, fuzzy, python-format
#| msgid "Create user <a href=\"%s\">%s</a> success."
msgid "Create admin user <a href=\"%s\">%s</a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: assets/views.py:319
#, fuzzy
#| msgid "System user"
msgid "System user list"
msgstr "系统"
#: assets/views.py:355
#, fuzzy, python-format
#| msgid "Create user <a href=\"%s\">%s</a> success."
msgid "Create system user <a href=\"%s\">%s</a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: assets/views.py:368
#, fuzzy, python-format
#| msgid "Create user <a href=\"%s\">%s</a> success."
msgid "Update system user <a href=\"%s\">%s</a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: assets/views.py:373
#, fuzzy
#| msgid "Update user"
msgid "Update system user"
msgstr "编辑用户"
#: assets/views.py:391
#, fuzzy
#| msgid "System user"
msgid "System user detail"
msgstr "系统"
#: perms/forms.py:21
#, fuzzy
#| msgid "Select assets"
msgid "Select users"
msgstr "选择资产"
#: perms/forms.py:23 perms/templates/perms/asset_permission_user_list.html:139
#, fuzzy
#| msgid "Select asset groups"
msgid "Select user groups"
msgstr "添加到资产组"
#: perms/forms.py:29 perms/templates/perms/asset_permission_detail.html:163
#, fuzzy
#| msgid "System user"
msgid "Select system users"
msgstr "系统"
#: perms/models.py:26
#: perms/templates/perms/asset_permission_create_update.html:49
#: perms/templates/perms/perm_user_asset_list.html:18
#: users/templates/users/user_detail.html:115
#: users/templates/users/user_list.html:17
#, fuzzy
msgid "Active"
msgstr "激活"
#: perms/models.py:27 perms/templates/perms/asset_permission_detail.html:88
#: users/models.py:81 users/templates/users/user_detail.html:82
msgid "Date expired"
msgstr "失效日期"
#: perms/templates/perms/asset_permission_asset_list.html:24
#: perms/templates/perms/asset_permission_detail.html:24
#: perms/templates/perms/asset_permission_user_list.html:24
#, fuzzy
#| msgid "Join user groups"
msgid "Users and user groups"
msgstr "添加到用户组"
#: perms/templates/perms/asset_permission_asset_list.html:29
#: perms/templates/perms/asset_permission_detail.html:29
#: perms/templates/perms/asset_permission_user_list.html:29
#, fuzzy
#| msgid "Select asset groups"
msgid "Assets and asset gruops"
msgstr "添加到资产组"
#: perms/templates/perms/asset_permission_asset_list.html:69
#: perms/templates/perms/asset_permission_list.html:18
#: perms/templates/perms/asset_permission_user_list.html:69
msgid "Is valid"
msgstr ""
#: perms/templates/perms/asset_permission_asset_list.html:103
msgid "Add asset to this permission"
msgstr ""
#: perms/templates/perms/asset_permission_asset_list.html:111
#, fuzzy
#| msgid "Select assets"
msgid "Select asset "
msgstr "选择资产"
#: perms/templates/perms/asset_permission_asset_list.html:131
msgid "Add asset group to this permission"
msgstr ""
#: perms/templates/perms/asset_permission_asset_list.html:148
#: perms/templates/perms/asset_permission_detail.html:172
#: perms/templates/perms/asset_permission_user_list.html:148
#: users/templates/users/user_detail.html:183
msgid "Join"
msgstr "加入"
#: perms/templates/perms/asset_permission_create_update.html:17
#, fuzzy
#| msgid "Create asset group"
msgid "Create asset permission "
msgstr "创建资产组"
#: perms/templates/perms/asset_permission_create_update.html:36
#: templates/_nav.html:12 templates/_user_profile.html:14 users/models.py:63
msgid "User"
msgstr "用户"
#: perms/templates/perms/asset_permission_create_update.html:45
#, fuzzy
#| msgid "Other IP"
msgid "Other"
msgstr "其它IP"
#: perms/templates/perms/asset_permission_detail.html:60
#: perms/templates/perms/asset_permission_list.html:13
#, fuzzy
#| msgid "User group"
msgid "User count"
msgstr "用户组"
#: perms/templates/perms/asset_permission_detail.html:64
#: perms/templates/perms/asset_permission_list.html:14
#, fuzzy
#| msgid "User group list"
msgid "User group count"
msgstr "用户组列表"
#: perms/templates/perms/asset_permission_detail.html:68
#: perms/templates/perms/asset_permission_list.html:15
#, fuzzy
#| msgid "Asset group"
msgid "Asset count"
msgstr "资产组"
#: perms/templates/perms/asset_permission_detail.html:72
#: perms/templates/perms/asset_permission_list.html:16
#, fuzzy
#| msgid "Asset group list"
msgid "Asset group count"
msgstr "资产组列表"
#: perms/templates/perms/asset_permission_detail.html:76
#: perms/templates/perms/asset_permission_list.html:17
#, fuzzy
#| msgid "System user"
msgid "System user count"
msgstr "系统"
#: perms/templates/perms/asset_permission_detail.html:80
#, fuzzy
msgid "Action"
msgstr "激活"
#: perms/templates/perms/asset_permission_detail.html:141
#, fuzzy
#| msgid "System user"
msgid "Repush system user"
msgstr "系统"
#: perms/templates/perms/asset_permission_detail.html:144
msgid "Push"
msgstr ""
#: perms/templates/perms/asset_permission_detail.html:155
#: perms/templates/perms/perm_user_asset_list.html:17 templates/_nav.html:25
msgid "System user"
msgstr "系统"
#: perms/templates/perms/asset_permission_list.html:5
#, fuzzy
#| msgid "Create perm"
msgid "Create permission"
msgstr "创建权限"
#: perms/templates/perms/asset_permission_user_list.html:47
#, fuzzy
#| msgid "User list"
msgid "User list of "
msgstr "用户列表"
#: perms/templates/perms/asset_permission_user_list.html:68 users/models.py:68
#: users/templates/users/user_detail.html:62
msgid "Email"
msgstr "邮件"
#: perms/templates/perms/asset_permission_user_list.html:103
msgid "Add user to asset permission"
msgstr ""
#: perms/templates/perms/asset_permission_user_list.html:111
#, fuzzy
#| msgid "Select assets"
msgid "Select user"
msgstr "选择资产"
#: perms/templates/perms/asset_permission_user_list.html:131
#, fuzzy
#| msgid "Asset group list"
msgid "Add user group to asset permission"
msgstr "资产组列表"
#: perms/templates/perms/perm_user_asset_list.html:5
#, fuzzy
#| msgid "Create perm"
msgid "Create perm "
msgstr "创建权限"
#: perms/templates/perms/perm_user_asset_list.html:14 users/models.py:70
#: users/templates/users/user_detail.html:78
#: users/templates/users/user_list.html:14
msgid "Role"
msgstr "角色"
#: perms/templates/perms/perm_user_asset_list.html:39
msgid "Create perm"
msgstr "创建权限"
#: perms/templates/perms/perm_user_asset_list.html:40
msgid "Flush"
msgstr ""
#: perms/views.py:29 perms/views.py:66 perms/views.py:89 perms/views.py:107
#: perms/views.py:146 perms/views.py:181 templates/_nav.html:30
msgid "Perms"
msgstr "权限管理"
#: perms/views.py:30
#, fuzzy
#| msgid "Asset group list"
msgid "Asset permission list"
msgstr "资产组列表"
#: perms/views.py:67
#, fuzzy
#| msgid "Create asset group"
msgid "Create asset permission"
msgstr "创建资产组"
#: perms/views.py:73
#, fuzzy, python-format
#| msgid "Create user <a href=\"%s\">%s</a> success."
msgid "Create asset permission <a href=\"%s\"> %s </a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: perms/views.py:85
#, fuzzy, python-format
#| msgid "Create user <a href=\"%s\">%s</a> success."
msgid "Update asset permission <a href=\"%s\"> %s </a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: perms/views.py:90
msgid "Update asset permission"
msgstr ""
#: perms/views.py:108
#, fuzzy
#| msgid "Asset environment"
msgid "Asset permission detail"
msgstr "资产环境"
#: perms/views.py:147
#, fuzzy
#| msgid "Asset group list"
msgid "Asset permission user list"
msgstr "资产组列表"
#: perms/views.py:182
#, fuzzy
#| msgid "Asset group list"
msgid "Asset permission asset list"
msgstr "资产组列表"
#: templates/_foot_js.html:24
msgid "Are you sure delete ?"
msgstr ""
#: templates/_foot_js.html:28
msgid "Cancel"
msgstr ""
#: templates/_foot_js.html:30
msgid "Yes, delete it!"
msgstr ""
#: templates/_foot_js.html:40
# msgid "Deleted!"
# msgstr "删除"
#: templates/_foot_js.html:40
msgid "has been deleted."
msgstr "已被删除"
#: templates/_header_bar.html:8
msgid "Search" msgid "Search"
msgstr "搜索" msgstr "搜索"
...@@ -314,42 +1070,40 @@ msgstr "欢迎使用Jumpserver开源跳板机系统" ...@@ -314,42 +1070,40 @@ msgstr "欢迎使用Jumpserver开源跳板机系统"
msgid "Help" msgid "Help"
msgstr "帮助" msgstr "帮助"
#: templates/_nav.html:9 users/views.py:100 users/views.py:113 #: templates/_header_bar.html:24 templates/_user_profile.html:21
#: users/views.py:153 users/views.py:170 users/views.py:195 users/views.py:208 msgid "Logout"
msgstr "注销登录"
#: templates/_header_bar.html:28 users/templates/users/login.html:42
#: users/templates/users/login.html:61
msgid "Login"
msgstr "登录"
#: templates/_modal.html:15
msgid "Close"
msgstr ""
#: templates/_nav.html:9 users/views.py:107 users/views.py:120
#: users/views.py:160 users/views.py:191 users/views.py:216 users/views.py:229
#: users/views.py:345
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:12 users/models.py:103 #: templates/_nav.html:13 users/models.py:69
msgid "User" #: users/templates/users/user_detail.html:166
msgstr "用户" #: users/templates/users/user_list.html:15
#: templates/_nav.html:13
msgid "User group" msgid "User group"
msgstr "用户组" msgstr "用户组"
#: templates/_nav.html:22
msgid "Asset group"
msgstr "资产组"
#: templates/_nav.html:25
msgid "System user"
msgstr "系统"
#: templates/_nav.html:26 #: templates/_nav.html:26
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
#: templates/_nav.html:30
msgid "Perms"
msgstr "权限管理"
#: templates/_nav.html:33 #: templates/_nav.html:33
msgid "Perm" #, fuzzy
msgstr "权限" #| msgid "Asset type"
msgid "Asset permission"
#: templates/_nav.html:36 msgstr "系统类型"
msgid "Create perm"
msgstr "创建权限"
#: templates/_nav.html:42 #: templates/_nav.html:42
msgid "Audits" msgid "Audits"
...@@ -379,10 +1133,6 @@ msgstr "访问官网" ...@@ -379,10 +1133,6 @@ msgstr "访问官网"
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
#: templates/_user_profile.html:21
msgid "Logout"
msgstr "注销登录"
#: templates/captcha/image.html:3 #: templates/captcha/image.html:3
msgid "Play CAPTCHA as audio file" msgid "Play CAPTCHA as audio file"
msgstr "" msgstr ""
...@@ -391,62 +1141,93 @@ msgstr "" ...@@ -391,62 +1141,93 @@ msgstr ""
msgid "Captcha" msgid "Captcha"
msgstr "验证码" msgstr "验证码"
#: users/forms.py:31 users/forms.py:50 #: templates/rest_framework/base.html:128
#, fuzzy
msgid "Filters"
msgstr "过滤"
#: users/forms.py:35 users/forms.py:55
#: users/templates/users/user_detail.html:174
msgid "Join user groups" msgid "Join user groups"
msgstr "添加到用户组" msgstr "添加到用户组"
#: users/models.py:102 users/models.py:225 #: users/forms.py:74
msgid "Administrator" #, fuzzy
msgstr "管理员" #| msgid "Name"
msgid "name"
msgstr "名称"
#: users/models.py:108 users/templates/users/user_detail.html:77 #: users/forms.py:75
msgid "Email" #, fuzzy
msgstr "邮件" #| msgid "Avatar"
msgid "avatar"
msgstr "头像"
#: users/models.py:109 users/templates/users/user_detail.html:181 #: users/forms.py:76
#: users/templates/users/user_list.html:15 #, fuzzy
msgid "Usergroup" #| msgid "Wechat"
msgstr "用户组" msgid "wechat"
msgstr "微信"
#: users/models.py:110 users/templates/users/user_detail.html:93 #: users/forms.py:77
#: users/templates/users/user_list.html:14 #, fuzzy
msgid "Role" #| msgid "Phone"
msgstr "角色" msgid "phone"
msgstr "手机"
#: users/forms.py:78
#, fuzzy
#| msgid "Enable OTP"
msgid "enable otp"
msgstr "二次验证"
#: users/models.py:111 #: users/forms.py:82
#, fuzzy
#| msgid "SSH private key"
msgid "private key"
msgstr "ssh密钥"
#: users/forms.py:89 users/serializers.py:55
#, fuzzy
#| msgid "ssh private key"
msgid "Not a valid ssh private key."
msgstr "ssh密钥"
#: users/models.py:62 users/models.py:206
msgid "Administrator"
msgstr "管理员"
#: users/models.py:71
msgid "Avatar" msgid "Avatar"
msgstr "头像" msgstr "头像"
#: users/models.py:112 users/templates/users/user_detail.html:88 #: users/models.py:72 users/templates/users/user_detail.html:73
msgid "Wechat" msgid "Wechat"
msgstr "微信" msgstr "微信"
#: users/models.py:114 users/templates/users/_user.html:57 #: users/models.py:74 users/templates/users/_user.html:57
#: users/templates/users/user_detail.html:129
msgid "Enable OTP" msgid "Enable OTP"
msgstr "二次验证" msgstr "二次验证"
#: users/models.py:116 #: users/models.py:76
msgid "ssh private key" msgid "ssh private key"
msgstr "ssh密钥" msgstr "ssh密钥"
#: users/models.py:117 #: users/models.py:77
msgid "ssh public key" msgid "ssh public key"
msgstr "ssh公钥" msgstr "ssh公钥"
#: users/models.py:121 users/templates/users/user_detail.html:97 #: users/models.py:209
msgid "Date expired"
msgstr "失效日期"
#: users/models.py:228
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
#: users/models.py:229 #: users/models.py:210
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
#: users/templates/users/_user.html:17 users/templates/users/user_list.html:5 #: users/templates/users/_user.html:17 users/templates/users/user_list.html:5
#: users/views.py:113 #: users/views.py:120
msgid "Create user" msgid "Create user"
msgstr "创建用户" msgstr "创建用户"
...@@ -458,24 +1239,53 @@ msgstr "账户" ...@@ -458,24 +1239,53 @@ msgstr "账户"
msgid "Security and Role" msgid "Security and Role"
msgstr "角色安全" msgstr "角色安全"
#: users/templates/users/forget_password.html:26 #: users/templates/users/_user_reset_pk_modal.html:4
msgid "Forget password" #, fuzzy
#| msgid "SSH private key"
msgid "Reset User SSH Private Key"
msgstr "ssh密钥"
#: users/templates/users/first_login.html:16 users/views.py:345
#, fuzzy
#| msgid "Last login"
msgid "First Login"
msgstr "最后登录"
#: users/templates/users/first_login.html:33
#, fuzzy
#| msgid "System"
msgid "Step"
msgstr "系统"
#: users/templates/users/first_login.html:55
msgid "first step"
msgstr ""
#: users/templates/users/first_login.html:56
msgid "prev step"
msgstr ""
#: users/templates/users/first_login.html:58
#, fuzzy
#| msgid "Submit"
msgid "submit"
msgstr "提交"
#: users/templates/users/forgot_password.html:26
#: users/templates/users/login.html:64
msgid "Forgot password"
msgstr "忘记密码" msgstr "忘记密码"
#: users/templates/users/forget_password.html:33 #: users/templates/users/forgot_password.html:33
msgid "Input your email, that will send a mail to your" msgid "Input your email, that will send a mail to your"
msgstr "输入您的邮箱, 将会发一封重置短信邮件到您的邮箱中" msgstr "输入您的邮箱, 将会发一封重置短信邮件到您的邮箱中"
#: users/templates/users/login.html:42 users/templates/users/login.html:62
msgid "Login"
msgstr "登录"
#: users/templates/users/login.html:47 #: users/templates/users/login.html:47
msgid "Captcha invalid" msgid "Captcha invalid"
msgstr "验证码错误" msgstr "验证码错误"
#: users/templates/users/reset_password.html:45 #: users/templates/users/reset_password.html:45
#: users/templates/users/user_detail.html:159 users/utils.py:98 #: users/templates/users/user_detail.html:144 users/utils.py:99
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -483,75 +1293,107 @@ msgstr "重置密码" ...@@ -483,75 +1293,107 @@ msgstr "重置密码"
msgid "Password again" msgid "Password again"
msgstr "再次输入密码" msgstr "再次输入密码"
#: users/templates/users/reset_password.html:57 #: users/templates/users/user_create.html:12
msgid "Setting"
msgstr "设置"
#: users/templates/users/user_add.html:12
msgid "Reset link will be generated and sent to the user. " msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户" msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_delete_confirm.html:6 #: users/templates/users/user_detail.html:20 users/views.py:191
msgid "Confirm delete"
msgstr "确认删除"
#: users/templates/users/user_detail.html:18 users/views.py:170
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
#: users/templates/users/user_detail.html:20 #: users/templates/users/user_detail.html:22
msgid "User assets" msgid "User assets"
msgstr "用户资产" msgstr "用户资产"
#: users/templates/users/user_detail.html:21 #: users/templates/users/user_detail.html:23
msgid "User log" msgid "User log"
msgstr "登录日志" msgstr "登录日志"
#: users/templates/users/user_detail.html:105 #: users/templates/users/user_detail.html:90
msgid "Date joined" msgid "Date joined"
msgstr "创建日期" msgstr "创建日期"
#: users/templates/users/user_detail.html:109 #: users/templates/users/user_detail.html:94
msgid "Last login" msgid "Last login"
msgstr "最后登录" msgstr "最后登录"
#: users/templates/users/user_detail.html:124 #: users/templates/users/user_detail.html:109
msgid "Quick modify" msgid "Quick modify"
msgstr "快速修改" msgstr "快速修改"
#: users/templates/users/user_detail.html:167 #: users/templates/users/user_detail.html:152
msgid "Reset ssh key" msgid "Reset ssh key"
msgstr "重置密钥" msgstr "重置密钥"
#: users/templates/users/user_detail.html:189 #: users/templates/users/user_detail.html:233
msgid "Select usergroups" msgid "UserGroup Update Success!"
msgstr "选择用户组" msgstr ""
#: users/templates/users/user_detail.html:198 #: users/templates/users/user_detail.html:251
msgid "Add" #: users/templates/users/user_detail.html:257
msgstr "添加" #, fuzzy
#| msgid "Create account successfully"
msgid "Update Successfully!"
msgstr "创建账户成功"
#: users/templates/users/user_list.html:17 #: users/templates/users/user_detail.html:290
msgid "Active" msgid "E-mail sent successfully. An e-mail has been sent to the user\\"
msgstr "激活" msgstr ""
#: users/templates/users/user_detail.html:291
#, fuzzy
#| msgid "Password"
msgid "Password-Reset"
msgstr "密码"
#: users/templates/users/user_detail.html:296
msgid "Are you sure?"
msgstr ""
#: users/templates/users/user_detail.html:297
msgid "This will reset the user\\"
msgstr ""
#: users/templates/users/user_detail.html:315
msgid "Successfully updated the SSH private key."
msgstr ""
#: users/templates/users/user_detail.html:316
#: users/templates/users/user_detail.html:321
#, fuzzy
#| msgid "SSH private key"
msgid "User SSH Private Key Reset"
msgstr "ssh密钥"
#: users/utils.py:47 #: users/templates/users/user_detail.html:319
msgid "Failed to update the user\\"
msgstr ""
#: users/templates/users/user_group_create.html:16 users/views.py:229
msgid "Create user group"
msgstr "创建用户组"
#: users/templates/users/user_update.html:3 users/views.py:160
msgid "Update user"
msgstr "编辑用户"
#: users/utils.py:48
msgid "Begin to generate ssh private key ..." msgid "Begin to generate ssh private key ..."
msgstr "开始生成ssh密钥" msgstr "开始生成ssh密钥"
#: users/utils.py:59 #: users/utils.py:60
msgid "Finish to generate ssh private key ..." msgid "Finish to generate ssh private key ..."
msgstr "生成ssh密钥成功" msgstr "生成ssh密钥成功"
#: users/utils.py:63 #: users/utils.py:64
msgid "These is error when generate ssh key." msgid "These is error when generate ssh key."
msgstr "创建密钥失败" msgstr "创建密钥失败"
#: users/utils.py:67 #: users/utils.py:68
msgid "Create account successfully" msgid "Create account successfully"
msgstr "创建账户成功" msgstr "创建账户成功"
#: users/utils.py:69 #: users/utils.py:70
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -562,8 +1404,8 @@ msgid "" ...@@ -562,8 +1404,8 @@ msgid ""
" <a href=\"%(rest_password_url)s?token=%(rest_password_token)s\">click " " <a href=\"%(rest_password_url)s?token=%(rest_password_token)s\">click "
"here to set your password</a>\n" "here to set your password</a>\n"
" </br>\n" " </br>\n"
" This link is valid for 1 hour. After it expires, <a href=" " This link is valid for 1 hour. After it expires, <a href=\"%"
"\"%(forget_password_url)s?email=%(email)s\">request new one</a>\n" "(forget_password_url)s?email=%(email)s\">request new one</a>\n"
"\n" "\n"
" </br>\n" " </br>\n"
" ---\n" " ---\n"
...@@ -592,7 +1434,7 @@ msgstr "" ...@@ -592,7 +1434,7 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:100 #: users/utils.py:101
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -604,8 +1446,8 @@ msgid "" ...@@ -604,8 +1446,8 @@ msgid ""
" <a href=\"%(rest_password_url)s?token=%(rest_password_token)s\">Click " " <a href=\"%(rest_password_url)s?token=%(rest_password_token)s\">Click "
"here reset password</a>\n" "here reset password</a>\n"
" </br>\n" " </br>\n"
" This link is valid for 1 hour. After it expires, <a href=" " This link is valid for 1 hour. After it expires, <a href=\"%"
"\"%(forget_password_url)s?email=%(email)s\">request new one<</a>\n" "(forget_password_url)s?email=%(email)s\">request new one<</a>\n"
"\n" "\n"
" </br>\n" " </br>\n"
" ---\n" " ---\n"
...@@ -636,69 +1478,64 @@ msgstr "" ...@@ -636,69 +1478,64 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/views.py:53 #: users/views.py:78
msgid "Username or password invalid"
msgstr "用户名或密码错误"
#: users/views.py:70
msgid "Logout success" msgid "Logout success"
msgstr "退出登录成功" msgstr "退出登录成功"
#: users/views.py:71 #: users/views.py:79
msgid "Logout success, return login page" msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面" msgstr "退出登录成功,返回到登录页面"
#: users/views.py:100 #: users/views.py:107
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
#: users/views.py:109 #: users/views.py:116
#, python-format #, fuzzy, python-format
msgid "Create user<a href=\"%s\">%s</a> success." #| msgid "Create user <a href=\"%s\">%s</a> success."
msgstr "创建用户<a href=\"%s\">%s</a> 成功" msgid "Create user <a href=\"%s\">%s</a> successfully."
msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#: users/views.py:153
msgid "Edit user"
msgstr "编辑用户"
#: users/views.py:195 #: users/views.py:216
msgid "Usergroup list" msgid "User group list"
msgstr "用户组列表" msgstr "用户组列表"
#: users/views.py:208 #: users/views.py:261
msgid "Create usergroup"
msgstr "创建用户组"
#: users/views.py:240
msgid "Email address invalid, input again" msgid "Email address invalid, input again"
msgstr "邮箱地址错误,重新输入" msgstr "邮箱地址错误,重新输入"
#: users/views.py:251 #: users/views.py:272
msgid "Send reset password message" msgid "Send reset password message"
msgstr "发送重置密码邮件" msgstr "发送重置密码邮件"
#: users/views.py:252 #: users/views.py:273
msgid "Send reset password mail success, login your mail box and follow it " msgid "Send reset password mail success, login your mail box and follow it "
msgstr "" msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views.py:264 #: users/views.py:285
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/views.py:265 #: users/views.py:286
msgid "Reset password success, return to login page" msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面" msgstr "重置密码成功,返回到登录页面"
#: users/views.py:281 users/views.py:294 #: users/views.py:302 users/views.py:315
msgid "Token invalid or expired" msgid "Token invalid or expired"
msgstr "Token错误或失效" msgstr "Token错误或失效"
#: users/views.py:290 #: users/views.py:311
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#, fuzzy #, fuzzy
#~| msgid "Asset groups" #~| msgid "Create user <a href=\"%s\">%s</a> success."
#~ msgid "Assetgroup" #~ msgid "Update admin user <a href=\"%s\">%s</a> successfully."
#~ msgstr "用户组" #~ msgstr "创建用户 <a href=\"%s\">%s</a> 成功"
#~ msgid "Perm"
#~ msgstr "权限"
#~ msgid "Username or password invalid"
#~ msgstr "用户名或密码错误"
# ~*~ coding: utf-8 ~*~
from __future__ import absolute_import, unicode_literals
from django import forms
from django.utils.translation import ugettext_lazy as _
# from .hands import User, UserGroup, Asset, AssetGroup, SystemUser
from .models import AssetPermission
class AssetPermissionForm(forms.ModelForm):
class Meta:
model = AssetPermission
fields = [
'name', 'users', 'user_groups', 'assets', 'asset_groups',
'system_users', 'action', 'is_active', 'date_expired', 'comment',
]
widgets = {
'users': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select users')}),
'user_groups': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select user groups')}),
'assets': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select assets')}),
'asset_groups': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select asset groups')}),
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
'data-placeholder': _('Select system users')}),
}
help_texts = {
'name': '* required',
'user_groups': '* User or user group at least one required',
'asset_groups': '* Asset or Asset group at least one required',
'system_users': '* required',
}
# ~*~ coding: utf-8 ~*~
#
from django.db import models
from django.utils.translation import ugettext_lazy as _
from users.utils import AdminUserRequiredMixin
from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser
from __future__ import unicode_literals from __future__ import unicode_literals, absolute_import
import functools
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser
from common.utils import date_expired_default, combine_seq
class AssetPermission(models.Model):
ACTION_CHOICE = (
('1', 'Allow'),
('0', 'Deny'),
)
name = models.CharField(max_length=128, verbose_name=_('Name'))
users = models.ManyToManyField(User, related_name='asset_permissions', blank=True)
user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True)
assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True)
asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True)
system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions')
action = models.CharField(choices=ACTION_CHOICE, max_length=8, default='1')
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired'))
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now=True, verbose_name=_('Date created'))
comment = models.TextField(verbose_name=_('Comment'), blank=True)
def __unicode__(self):
return '%(name)s: %(action)s' % {'name': self.name, 'action': self.action}
@property
def is_valid(self):
if self.date_expired < timezone.now() and self.is_active:
return True
return True
@staticmethod
def set_inherit(obj):
setattr(obj, 'inherited', True)
return obj
def get_granted_users(self):
return list(set(self.users.all() or []) | set(self.get_granted_user_groups_member()))
def get_granted_user_groups_member(self):
combine_users = functools.partial(combine_seq, callback=AssetPermission.set_inherit)
try:
return functools.reduce(combine_users, [user_group.users.all()
for user_group in self.user_groups.iterator()])
except TypeError:
return []
def get_granted_assets(self):
return list(set(self.assets.all() or []) | set(self.get_granted_asset_groups_member()))
def get_granted_asset_groups_member(self):
combine_assets = functools.partial(combine_seq, callback=AssetPermission.set_inherit)
try:
return functools.reduce(combine_assets, [asset_group.users.all()
for asset_group in self.asset_groups.iterator()])
except TypeError:
return []
class Meta:
db_table = 'asset_permission'
# Create your models here.
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li>
<a href="{% url 'perms:asset-permission-user-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Users and user groups' %}
</a>
</li>
<li class="active">
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a>
</li>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
<div class="input-group-btn">
<button id="search_btn" type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ asset_permission.name }}</b></span>
<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">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Is valid' %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for asset in page_obj %}
<tr>
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>{{ user.port }}</td>
<td>
{% if asset.is_active %}
<i class="fa fa-times text-danger"></i>
{% else %}
<i class="fa fa-check text-navy"></i>
{% endif %}
</td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset to this permission' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select asset ' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset in asset_remain %}
<option value="{{ asset.id }}">{{ asset.hostname }}: {{ asset.ip }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Add' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add asset group to this permission' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select asset groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for asset_group in asset_groups_remain %}
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for asset_group in asset_groups %}
<tr>
<td ><b class="bdg_user_group" data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% 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>
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% 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 permission ' %}</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" class="form-horizontal" action="" >
{% csrf_token %}
<h3>{% trans 'Name' %}</h3>
{{ form.name|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>{% trans 'User' %}</h3>
{{ form.users|bootstrap_horizontal }}
{{ form.user_groups|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Asset' %}</h3>
{{ form.assets|bootstrap_horizontal }}
{{ form.asset_groups|bootstrap_horizontal }}
{{ form.system_users |bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3>
{{ form.action|bootstrap_horizontal }}
<div class="form-group">
<label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label>
<div class="col-sm-8">
{{ form.is_active }}
</div>
</div>
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
<div class="col-sm-9">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
</div>
<span class="help-block ">{{ form.date_expired.errors }}</span>
</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 src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
$('.input-group.date').datepicker({
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true
})
})
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li>
<a href="{% url 'perms:asset-permission-user-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Users and user groups' %}
</a>
</li>
<li>
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ asset_permission.name }}</b></span>
<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">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Name' %}:</td>
<td><b>{{ asset_permission.name }}</b></td>
</tr>
<tr>
<td>{% trans 'User count' %}:</td>
<td><b>{{ asset_permission.users.count }}</b></td>
</tr>
<tr>
<td>{% trans 'User group count' %}:</td>
<td><b>{{ asset_permission.users.count }}</b></td>
</tr>
<tr>
<td>{% trans 'Asset count' %}:</td>
<td><b>{{ asset_permission.assets.count }}</b></td>
</tr>
<tr>
<td>{% trans 'Asset group count' %}:</td>
<td><b>{{ asset_permission.asset_groups.count }}</b></td>
</tr>
<tr>
<td>{% trans 'System user count' %}:</td>
<td><b>{{ asset_permission.system_users.count }}</b></td>
</tr>
<tr>
<td>{% trans 'Action' %}:</td>
<td><b>{{ asset_permission.get_action_display }}</b></td>
</tr>
<tr>
<td>{% trans 'Is active' %}:</td>
<td><b>{{ asset_permission.is_active|yesno:'Yes, No, Unkown' }}</b></td>
</tr>
<tr>
<td>{% trans 'Date expired' %}:</td>
<td><b>{{ asset_permission.date_expired }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ asset_permission.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_permission.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ asset_permission.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="50%">Active:</td>
<td><span style="float: right">
<div class="switch">
<div class="onoffswitch">
<input type="checkbox" {% if asset_permission.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
<label class="onoffswitch-label" for="is_active">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
</div>
</span></td>
</tr>
<tr>
<td width="50%">{% trans 'Retest asset connectivity' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Start' %}</button>
</span>
</td>
</tr>
<tr>
<td width="50%">{% trans 'Repush system user' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Push' %}</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'System user' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for system_user in system_users_remain %}
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user.name }}: {{ system_user.username }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for system_user in system_users %}
<tr>
<td ><b class="bdg_user_group" data-gid={{ system_user.id }}>{{ system_user.name }}</b></td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary "> {% trans "Create permission" %} </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 'perms:asset-permission-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'User count' %}</th>
<th class="text-center">{% trans 'User group count' %}</th>
<th class="text-center">{% trans 'Asset count' %}</th>
<th class="text-center">{% trans 'Asset group count' %}</th>
<th class="text-center">{% trans 'System user count' %}</th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=date_expired">{% trans 'Is valid' %}</a></th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for asset_permission in asset_permission_list %}
<tr class="gradeX">
<td class="text-center">
<input type="checkbox" name="checked" value="{{ asset_permission.id }}">
</td>
<td class="text-center">
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}">
{{ asset_permission.name }}
</a>
</td>
<td class="text-center">{{ asset_permission.users.count}}</td>
<td class="text-center">{{ asset_permission.user_groups.count}}</td>
<td class="text-center">{{ asset_permission.assets.count }}</td>
<td class="text-center">{{ asset_permission.asset_groups.count }}</td>
<td class="text-center">{{ asset_permission.system_users.count }}</td>
<td class="text-center">
{% if asset_permission.is_valid %}
<i class="fa fa-check text-navy"></i>
{% else %}
<i class="fa fa-times text-danger"></i>
{% endif %}
</td>
<td class="text-center">
<a href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a href="{% url 'perms:asset-permission-delete' pk=asset_permission.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 %}
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
{% 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="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
</li>
<li class="active">
<a href="{% url 'perms:asset-permission-user-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Users and user groups' %}
</a>
</li>
<li>
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset gruops' %}</a>
</li>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
<div class="input-group-btn">
<button id="search_btn" type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'User list of ' %} <b>{{ asset_permission.name }}</b></span>
<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">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans 'Name' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Email' %}</th>
<th>{% trans 'Is valid' %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for user in page_obj %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>
{% if user.is_expired and user.is_active %}
<i class="fa fa-times text-danger"></i>
{% else %}
<i class="fa fa-check text-navy"></i>
{% endif %}
</td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group {% if user.inherited %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add user to asset permission' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select user' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for user in users_remain %}
<option value="{{ user.id }}">{{ user.name }}: {{ user.username }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-primary btn-sm">{% trans 'Add' %}</button>
</td>
</tr>
</form>
</tbody>
</table>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Add user group to asset permission' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select user groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for user_group in user_groups_remain %}
<option value="{{ user_group.id }}" id="opt_{{ user_group.id }}">{{ user_group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for user_group in user_groups %}
<tr>
<td ><b class="bdg_user_group" data-gid={{ user_group.id }}>{{ user_group.name }}</b></td>
<td>
<button class="btn btn-danger btn-xs btn_delete_user_group" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
{# function switch_user_status(obj) {#}
{# var status = $(obj).prop('checked');#}
{##}
{# $.ajax({#}
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
{# type: "PUT",#}
{# data: {#}
{# 'is_active': status#}
{# },#}
{# success: function (data, status) {#}
{# console.log(data)#}
{# },#}
{# error: function () {#}
{# console.log('error')#}
{# }#}
{# })#}
{# }#}
$(document).ready(function () {
$('.select2').select2();
});
</script>
{% endblock %}
\ No newline at end of file
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% trans 'Confirm delete' %}</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object.name }}"?</p>
<input type="submit" value="Confirm" />
</form>
</body>
</html>
\ No newline at end of file
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a href="{% url 'users:user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create perm " %} </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 'users:user-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Role' %}</th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Asset group' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=date_expired">{% trans 'Active' %}</a></th>
<th class="text-center"></th>
{% endblock %}
{% block table_body %}
{% for perm in page_obj %}
<tr class="gradeX">
<td class="text-center">
<input type="checkbox" name="checked" value="{{ user.id }}">
</td>
<td class="text-center">
<a href="{% url 'users:user-detail' pk=user.id %}">
{{ user.name }}
</a>
</td>
<td class="text-center">{{ user.username }}</td>
<td class="text-center">{{ user.get_role_display }}</td>
<th class="text-center">35/40</th>
<th class="text-center">20</th>
<th class="text-center">3</th>
<td class="text-center">
<a href="{% url 'perms:perm-user-asset-create' pk=user.id %}" class="btn btn-xs btn-info">{% trans 'Create perm' %}</a>
<a href="{% url 'users:user-delete' pk=user.id %}" class="btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}">{% trans 'Flush' %}</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 %}
# coding:utf-8
from django.conf.urls import url from django.conf.urls import url
import views
app_name = 'perms'
urlpatterns = [
url(r'^asset-permission$', views.AssetPermissionListView.as_view(), name='asset-permission-list'),
url(r'^asset-permission/create$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'),
url(r'^asset-permission/(?P<pk>[0-9]+)/update$', views.AssetPermissionUpdateView.as_view(),
name='asset-permission-update'),
url(r'^asset-permission/(?P<pk>[0-9]+)$', views.AssetPermissionDetailView.as_view(),
name='asset-permission-detail'),
url(r'^asset-permission/(?P<pk>[0-9]+)/delete$', views.AssetPermissionDeleteView.as_view(),
name='asset-permission-delete'),
url(r'^asset-permission/(?P<pk>[0-9]+)/user$', views.AssetPermissionUserListView.as_view(),
name='asset-permission-user-list'),
url(r'^asset-permission/(?P<pk>[0-9]+)/asset$', views.AssetPermissionAssetListView.as_view(),
name='asset-permission-asset-list'),
]
from django.shortcuts import render # ~*~ coding: utf-8 ~*~
# Create your views here. from __future__ import unicode_literals, absolute_import
import functools
from django.utils.translation import ugettext as _
from django.conf import settings
from django.db.models import Q
from django.views.generic import TemplateView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from django.urls import reverse_lazy
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.detail import DetailView, SingleObjectMixin
from common.utils import search_object_attr
from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, Asset, AssetGroup
from .models import AssetPermission
from .forms import AssetPermissionForm
class AssetPermissionListView(AdminUserRequiredMixin, ListView):
model = AssetPermission
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'asset_permission_list'
template_name = 'perms/asset_permission_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Perms'),
'action': _('Asset permission list'),
'keyword': self.keyword,
}
kwargs.update(context)
return super(AssetPermissionListView, self).get_context_data(**kwargs)
def get_queryset(self):
# Todo: Default order by lose asset connection num
self.queryset = super(AssetPermissionListView, self).get_queryset()
self.keyword = keyword = self.request.GET.get('keyword', '')
self.sort = sort = self.request.GET.get('sort', '-date_created')
if keyword:
self.queryset = self.queryset.filter(Q(users__name__contains=keyword) |
Q(users__username__contains=keyword) |
Q(user_groups__name__contains=keyword) |
Q(assets__ip__contains=keyword) |
Q(assets__hostname__contains=keyword) |
Q(system_users__username__icontains=keyword) |
Q(system_users__name__icontains=keyword) |
Q(asset_groups__name__icontains=keyword) |
Q(comment__icontains=keyword) |
Q(name__icontains=keyword)).distinct()
if sort:
self.queryset = self.queryset.order_by(sort)
return self.queryset
class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
model = AssetPermission
form_class = AssetPermissionForm
template_name = 'perms/asset_permission_create_update.html'
success_url = reverse_lazy('perms:asset-permission-list')
def get_context_data(self, **kwargs):
context = {
'app': _('Perms'),
'action': _('Create asset permission'),
}
kwargs.update(context)
return super(AssetPermissionCreateView, self).get_context_data(**kwargs)
def get_success_message(self, cleaned_data):
success_message = _('Create asset permission <a href="%s"> %s </a> successfully.' %
(
reverse_lazy('perms:asset-permission-detail', kwargs={'pk': self.object.pk}),
self.object.name,
))
return success_message
class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
model = AssetPermission
form_class = AssetPermissionForm
template_name = 'perms/asset_permission_create_update.html'
success_message = _('Update asset permission <a href="%s"> %s </a> successfully.')
def get_context_data(self, **kwargs):
context = {
'app': _('Perms'),
'action': _('Update asset permission')
}
kwargs.update(context)
return super(AssetPermissionUpdateView, self).get_context_data(**kwargs)
def get_success_url(self):
success_url = reverse_lazy('perms:asset-permission-detail', kwargs={'pk': self.object.pk})
return success_url
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
template_name = 'perms/asset_permission_detail.html'
context_object_name = 'asset_permission'
model = AssetPermission
def get_context_data(self, **kwargs):
context = {
'app': _('Perms'),
'action': _('Asset permission detail'),
'system_users_remain': [system_user for system_user in SystemUser.objects.all()
if system_user not in self.object.system_users.all()],
'system_users': self.object.system_users.all(),
}
kwargs.update(context)
return super(AssetPermissionDetailView, self).get_context_data(**kwargs)
class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
model = AssetPermission
template_name = 'perms/delete_confirm.html'
success_url = reverse_lazy('perms:asset-permission-list')
class AssetPermissionUserListView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
template_name = 'perms/asset_permission_user_list.html'
context_object_name = 'asset_permission'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetPermission.objects.all())
self.keyword = self.request.GET.get('keyword', '')
return super(AssetPermissionUserListView, self).get(request, *args, **kwargs)
def get_queryset(self):
queryset = self.object.get_granted_users()
if self.keyword:
search_func = functools.partial(search_object_attr, value=self.keyword,
attr_list=['username', 'name', 'email'],
ignore_case=True)
queryset = filter(search_func, queryset)
return queryset
def get_context_data(self, **kwargs):
users_granted = self.get_queryset()
user_groups_granted = self.object.user_groups.all()
context = {
'app': _('Perms'),
'action': _('Asset permission user list'),
'users_remain': [user for user in User.objects.all() if user not in users_granted],
'user_groups': self.object.user_groups.all(),
'user_groups_remain': [user_group for user_group in UserGroup.objects.all()
if user_group not in user_groups_granted],
'keyword': self.keyword,
}
kwargs.update(context)
return super(AssetPermissionUserListView, self).get_context_data(**kwargs)
class AssetPermissionAssetListView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
template_name = 'perms/asset_permission_asset_list.html'
context_object_name = 'asset_permission'
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=AssetPermission.objects.all())
self.keyword = self.request.GET.get('keyword', '')
return super(AssetPermissionAssetListView, self).get(request, *args, **kwargs)
def get_queryset(self):
queryset = self.object.get_granted_assets()
if self.keyword:
search_func = functools.partial(search_object_attr, value=self.keyword,
attr_list=['hostname', 'ip'],
ignore_case=True)
queryset = filter(search_func, queryset)
return queryset
def get_context_data(self, **kwargs):
assets_granted = self.get_queryset()
asset_groups_granted = self.object.user_groups.all()
context = {
'app': _('Perms'),
'action': _('Asset permission asset list'),
'assets_remain': (asset for asset in Asset.objects.all() if asset not in assets_granted),
'asset_groups': self.object.asset_groups.all(),
'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all()
if asset_group not in asset_groups_granted],
'keyword': self.keyword,
}
kwargs.update(context)
return super(AssetPermissionAssetListView, self).get_context_data(**kwargs)
...@@ -38,6 +38,7 @@ th a { ...@@ -38,6 +38,7 @@ th a {
color: white; color: white;
} }
.select2-selection--single,
.select2-selection--multiple { .select2-selection--multiple {
border: 1px solid #e5e6e7 !important; border: 1px solid #e5e6e7 !important;
cursor: text !important; cursor: text !important;
......
body.stop-scrolling {
height: 100%;
overflow: hidden; }
.sweet-overlay {
background-color: black;
/* IE8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
/* IE8 */
background-color: rgba(0, 0, 0, 0.4);
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: none;
z-index: 10000; }
.sweet-alert {
background-color: white;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
width: 478px;
padding: 17px;
border-radius: 5px;
text-align: center;
position: fixed;
left: 50%;
top: 50%;
margin-left: -256px;
margin-top: -200px;
overflow: hidden;
display: none;
z-index: 99999; }
@media all and (max-width: 540px) {
.sweet-alert {
width: auto;
margin-left: 0;
margin-right: 0;
left: 15px;
right: 15px; } }
.sweet-alert h2 {
color: #575757;
font-size: 30px;
text-align: center;
font-weight: 600;
text-transform: none;
position: relative;
margin: 25px 0;
padding: 0;
line-height: 40px;
display: block; }
.sweet-alert p {
color: #797979;
font-size: 16px;
text-align: center;
font-weight: 300;
position: relative;
text-align: inherit;
float: none;
margin: 0;
padding: 0;
line-height: normal; }
.sweet-alert fieldset {
border: none;
position: relative; }
.sweet-alert .sa-error-container {
background-color: #f1f1f1;
margin-left: -17px;
margin-right: -17px;
overflow: hidden;
padding: 0 10px;
max-height: 0;
webkit-transition: padding 0.15s, max-height 0.15s;
transition: padding 0.15s, max-height 0.15s; }
.sweet-alert .sa-error-container.show {
padding: 10px 0;
max-height: 100px;
webkit-transition: padding 0.2s, max-height 0.2s;
transition: padding 0.25s, max-height 0.25s; }
.sweet-alert .sa-error-container .icon {
display: inline-block;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: #ea7d7d;
color: white;
line-height: 24px;
text-align: center;
margin-right: 3px; }
.sweet-alert .sa-error-container p {
display: inline-block; }
.sweet-alert .sa-input-error {
position: absolute;
top: 29px;
right: 26px;
width: 20px;
height: 20px;
opacity: 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transition: all 0.1s;
transition: all 0.1s; }
.sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after {
content: "";
width: 20px;
height: 6px;
background-color: #f06e57;
border-radius: 3px;
position: absolute;
top: 50%;
margin-top: -4px;
left: 50%;
margin-left: -9px; }
.sweet-alert .sa-input-error::before {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg); }
.sweet-alert .sa-input-error::after {
-webkit-transform: rotate(45deg);
transform: rotate(45deg); }
.sweet-alert .sa-input-error.show {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1); }
.sweet-alert input {
width: 100%;
box-sizing: border-box;
border-radius: 3px;
border: 1px solid #d7d7d7;
height: 43px;
margin-top: 10px;
margin-bottom: 17px;
font-size: 18px;
box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06);
padding: 0 12px;
display: none;
-webkit-transition: all 0.3s;
transition: all 0.3s; }
.sweet-alert input:focus {
outline: none;
box-shadow: 0px 0px 3px #c4e6f5;
border: 1px solid #b4dbed; }
.sweet-alert input:focus::-moz-placeholder {
transition: opacity 0.3s 0.03s ease;
opacity: 0.5; }
.sweet-alert input:focus:-ms-input-placeholder {
transition: opacity 0.3s 0.03s ease;
opacity: 0.5; }
.sweet-alert input:focus::-webkit-input-placeholder {
transition: opacity 0.3s 0.03s ease;
opacity: 0.5; }
.sweet-alert input::-moz-placeholder {
color: #bdbdbd; }
.sweet-alert input:-ms-input-placeholder {
color: #bdbdbd; }
.sweet-alert input::-webkit-input-placeholder {
color: #bdbdbd; }
.sweet-alert.show-input input {
display: block; }
.sweet-alert button {
background-color: #AEDEF4;
color: white;
border: none;
box-shadow: none;
font-size: 17px;
font-weight: 500;
-webkit-border-radius: 4px;
border-radius: 5px;
padding: 10px 32px;
margin: 26px 5px 0 5px;
cursor: pointer; }
.sweet-alert button:focus {
outline: none;
box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); }
.sweet-alert button:hover {
background-color: #a1d9f2; }
.sweet-alert button:active {
background-color: #81ccee; }
.sweet-alert button.cancel {
background-color: #D0D0D0; }
.sweet-alert button.cancel:hover {
background-color: #c8c8c8; }
.sweet-alert button.cancel:active {
background-color: #b6b6b6; }
.sweet-alert button.cancel:focus {
box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; }
.sweet-alert button::-moz-focus-inner {
border: 0; }
.sweet-alert[data-has-cancel-button=false] button {
box-shadow: none !important; }
.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] {
padding-bottom: 40px; }
.sweet-alert .sa-icon {
width: 80px;
height: 80px;
border: 4px solid gray;
-webkit-border-radius: 40px;
border-radius: 40px;
border-radius: 50%;
margin: 20px auto;
padding: 0;
position: relative;
box-sizing: content-box; }
.sweet-alert .sa-icon.sa-error {
border-color: #F27474; }
.sweet-alert .sa-icon.sa-error .sa-x-mark {
position: relative;
display: block; }
.sweet-alert .sa-icon.sa-error .sa-line {
position: absolute;
height: 5px;
width: 47px;
background-color: #F27474;
display: block;
top: 37px;
border-radius: 2px; }
.sweet-alert .sa-icon.sa-error .sa-line.sa-left {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
left: 17px; }
.sweet-alert .sa-icon.sa-error .sa-line.sa-right {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
right: 16px; }
.sweet-alert .sa-icon.sa-warning {
border-color: #F8BB86; }
.sweet-alert .sa-icon.sa-warning .sa-body {
position: absolute;
width: 5px;
height: 47px;
left: 50%;
top: 10px;
-webkit-border-radius: 2px;
border-radius: 2px;
margin-left: -2px;
background-color: #F8BB86; }
.sweet-alert .sa-icon.sa-warning .sa-dot {
position: absolute;
width: 7px;
height: 7px;
-webkit-border-radius: 50%;
border-radius: 50%;
margin-left: -3px;
left: 50%;
bottom: 10px;
background-color: #F8BB86; }
.sweet-alert .sa-icon.sa-info {
border-color: #C9DAE1; }
.sweet-alert .sa-icon.sa-info::before {
content: "";
position: absolute;
width: 5px;
height: 29px;
left: 50%;
bottom: 17px;
border-radius: 2px;
margin-left: -2px;
background-color: #C9DAE1; }
.sweet-alert .sa-icon.sa-info::after {
content: "";
position: absolute;
width: 7px;
height: 7px;
border-radius: 50%;
margin-left: -3px;
top: 19px;
background-color: #C9DAE1; }
.sweet-alert .sa-icon.sa-success {
border-color: #A5DC86; }
.sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after {
content: '';
-webkit-border-radius: 40px;
border-radius: 40px;
border-radius: 50%;
position: absolute;
width: 60px;
height: 120px;
background: white;
-webkit-transform: rotate(45deg);
transform: rotate(45deg); }
.sweet-alert .sa-icon.sa-success::before {
-webkit-border-radius: 120px 0 0 120px;
border-radius: 120px 0 0 120px;
top: -7px;
left: -33px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 60px 60px;
transform-origin: 60px 60px; }
.sweet-alert .sa-icon.sa-success::after {
-webkit-border-radius: 0 120px 120px 0;
border-radius: 0 120px 120px 0;
top: -11px;
left: 30px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0px 60px;
transform-origin: 0px 60px; }
.sweet-alert .sa-icon.sa-success .sa-placeholder {
width: 80px;
height: 80px;
border: 4px solid rgba(165, 220, 134, 0.2);
-webkit-border-radius: 40px;
border-radius: 40px;
border-radius: 50%;
box-sizing: content-box;
position: absolute;
left: -4px;
top: -4px;
z-index: 2; }
.sweet-alert .sa-icon.sa-success .sa-fix {
width: 5px;
height: 90px;
background-color: white;
position: absolute;
left: 28px;
top: 8px;
z-index: 1;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg); }
.sweet-alert .sa-icon.sa-success .sa-line {
height: 5px;
background-color: #A5DC86;
display: block;
border-radius: 2px;
position: absolute;
z-index: 2; }
.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
width: 25px;
left: 14px;
top: 46px;
-webkit-transform: rotate(45deg);
transform: rotate(45deg); }
.sweet-alert .sa-icon.sa-success .sa-line.sa-long {
width: 47px;
right: 8px;
top: 38px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg); }
.sweet-alert .sa-icon.sa-custom {
background-size: contain;
border-radius: 0;
border: none;
background-position: center center;
background-repeat: no-repeat; }
/*
* Animations
*/
@-webkit-keyframes showSweetAlert {
0% {
transform: scale(0.7);
-webkit-transform: scale(0.7); }
45% {
transform: scale(1.05);
-webkit-transform: scale(1.05); }
80% {
transform: scale(0.95);
-webkit-transform: scale(0.95); }
100% {
transform: scale(1);
-webkit-transform: scale(1); } }
@keyframes showSweetAlert {
0% {
transform: scale(0.7);
-webkit-transform: scale(0.7); }
45% {
transform: scale(1.05);
-webkit-transform: scale(1.05); }
80% {
transform: scale(0.95);
-webkit-transform: scale(0.95); }
100% {
transform: scale(1);
-webkit-transform: scale(1); } }
@-webkit-keyframes hideSweetAlert {
0% {
transform: scale(1);
-webkit-transform: scale(1); }
100% {
transform: scale(0.5);
-webkit-transform: scale(0.5); } }
@keyframes hideSweetAlert {
0% {
transform: scale(1);
-webkit-transform: scale(1); }
100% {
transform: scale(0.5);
-webkit-transform: scale(0.5); } }
@-webkit-keyframes slideFromTop {
0% {
top: 0%; }
100% {
top: 50%; } }
@keyframes slideFromTop {
0% {
top: 0%; }
100% {
top: 50%; } }
@-webkit-keyframes slideToTop {
0% {
top: 50%; }
100% {
top: 0%; } }
@keyframes slideToTop {
0% {
top: 50%; }
100% {
top: 0%; } }
@-webkit-keyframes slideFromBottom {
0% {
top: 70%; }
100% {
top: 50%; } }
@keyframes slideFromBottom {
0% {
top: 70%; }
100% {
top: 50%; } }
@-webkit-keyframes slideToBottom {
0% {
top: 50%; }
100% {
top: 70%; } }
@keyframes slideToBottom {
0% {
top: 50%; }
100% {
top: 70%; } }
.showSweetAlert[data-animation=pop] {
-webkit-animation: showSweetAlert 0.3s;
animation: showSweetAlert 0.3s; }
.showSweetAlert[data-animation=none] {
-webkit-animation: none;
animation: none; }
.showSweetAlert[data-animation=slide-from-top] {
-webkit-animation: slideFromTop 0.3s;
animation: slideFromTop 0.3s; }
.showSweetAlert[data-animation=slide-from-bottom] {
-webkit-animation: slideFromBottom 0.3s;
animation: slideFromBottom 0.3s; }
.hideSweetAlert[data-animation=pop] {
-webkit-animation: hideSweetAlert 0.2s;
animation: hideSweetAlert 0.2s; }
.hideSweetAlert[data-animation=none] {
-webkit-animation: none;
animation: none; }
.hideSweetAlert[data-animation=slide-from-top] {
-webkit-animation: slideToTop 0.4s;
animation: slideToTop 0.4s; }
.hideSweetAlert[data-animation=slide-from-bottom] {
-webkit-animation: slideToBottom 0.3s;
animation: slideToBottom 0.3s; }
@-webkit-keyframes animateSuccessTip {
0% {
width: 0;
left: 1px;
top: 19px; }
54% {
width: 0;
left: 1px;
top: 19px; }
70% {
width: 50px;
left: -8px;
top: 37px; }
84% {
width: 17px;
left: 21px;
top: 48px; }
100% {
width: 25px;
left: 14px;
top: 45px; } }
@keyframes animateSuccessTip {
0% {
width: 0;
left: 1px;
top: 19px; }
54% {
width: 0;
left: 1px;
top: 19px; }
70% {
width: 50px;
left: -8px;
top: 37px; }
84% {
width: 17px;
left: 21px;
top: 48px; }
100% {
width: 25px;
left: 14px;
top: 45px; } }
@-webkit-keyframes animateSuccessLong {
0% {
width: 0;
right: 46px;
top: 54px; }
65% {
width: 0;
right: 46px;
top: 54px; }
84% {
width: 55px;
right: 0px;
top: 35px; }
100% {
width: 47px;
right: 8px;
top: 38px; } }
@keyframes animateSuccessLong {
0% {
width: 0;
right: 46px;
top: 54px; }
65% {
width: 0;
right: 46px;
top: 54px; }
84% {
width: 55px;
right: 0px;
top: 35px; }
100% {
width: 47px;
right: 8px;
top: 38px; } }
@-webkit-keyframes rotatePlaceholder {
0% {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg); }
5% {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg); }
12% {
transform: rotate(-405deg);
-webkit-transform: rotate(-405deg); }
100% {
transform: rotate(-405deg);
-webkit-transform: rotate(-405deg); } }
@keyframes rotatePlaceholder {
0% {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg); }
5% {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg); }
12% {
transform: rotate(-405deg);
-webkit-transform: rotate(-405deg); }
100% {
transform: rotate(-405deg);
-webkit-transform: rotate(-405deg); } }
.animateSuccessTip {
-webkit-animation: animateSuccessTip 0.75s;
animation: animateSuccessTip 0.75s; }
.animateSuccessLong {
-webkit-animation: animateSuccessLong 0.75s;
animation: animateSuccessLong 0.75s; }
.sa-icon.sa-success.animate::after {
-webkit-animation: rotatePlaceholder 4.25s ease-in;
animation: rotatePlaceholder 4.25s ease-in; }
@-webkit-keyframes animateErrorIcon {
0% {
transform: rotateX(100deg);
-webkit-transform: rotateX(100deg);
opacity: 0; }
100% {
transform: rotateX(0deg);
-webkit-transform: rotateX(0deg);
opacity: 1; } }
@keyframes animateErrorIcon {
0% {
transform: rotateX(100deg);
-webkit-transform: rotateX(100deg);
opacity: 0; }
100% {
transform: rotateX(0deg);
-webkit-transform: rotateX(0deg);
opacity: 1; } }
.animateErrorIcon {
-webkit-animation: animateErrorIcon 0.5s;
animation: animateErrorIcon 0.5s; }
@-webkit-keyframes animateXMark {
0% {
transform: scale(0.4);
-webkit-transform: scale(0.4);
margin-top: 26px;
opacity: 0; }
50% {
transform: scale(0.4);
-webkit-transform: scale(0.4);
margin-top: 26px;
opacity: 0; }
80% {
transform: scale(1.15);
-webkit-transform: scale(1.15);
margin-top: -6px; }
100% {
transform: scale(1);
-webkit-transform: scale(1);
margin-top: 0;
opacity: 1; } }
@keyframes animateXMark {
0% {
transform: scale(0.4);
-webkit-transform: scale(0.4);
margin-top: 26px;
opacity: 0; }
50% {
transform: scale(0.4);
-webkit-transform: scale(0.4);
margin-top: 26px;
opacity: 0; }
80% {
transform: scale(1.15);
-webkit-transform: scale(1.15);
margin-top: -6px; }
100% {
transform: scale(1);
-webkit-transform: scale(1);
margin-top: 0;
opacity: 1; } }
.animateXMark {
-webkit-animation: animateXMark 0.5s;
animation: animateXMark 0.5s; }
@-webkit-keyframes pulseWarning {
0% {
border-color: #F8D486; }
100% {
border-color: #F8BB86; } }
@keyframes pulseWarning {
0% {
border-color: #F8D486; }
100% {
border-color: #F8BB86; } }
.pulseWarning {
-webkit-animation: pulseWarning 0.75s infinite alternate;
animation: pulseWarning 0.75s infinite alternate; }
@-webkit-keyframes pulseWarningIns {
0% {
background-color: #F8D486; }
100% {
background-color: #F8BB86; } }
@keyframes pulseWarningIns {
0% {
background-color: #F8D486; }
100% {
background-color: #F8BB86; } }
.pulseWarningIns {
-webkit-animation: pulseWarningIns 0.75s infinite alternate;
animation: pulseWarningIns 0.75s infinite alternate; }
/* Internet Explorer 9 has some special quirks that are fixed here */
/* The icons are not animated. */
/* This file is automatically merged into sweet-alert.min.js through Gulp */
/* Error icon */
.sweet-alert .sa-icon.sa-error .sa-line.sa-left {
-ms-transform: rotate(45deg) \9; }
.sweet-alert .sa-icon.sa-error .sa-line.sa-right {
-ms-transform: rotate(-45deg) \9; }
/* Success icon */
.sweet-alert .sa-icon.sa-success {
border-color: transparent\9; }
.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
-ms-transform: rotate(45deg) \9; }
.sweet-alert .sa-icon.sa-success .sa-line.sa-long {
-ms-transform: rotate(-45deg) \9; }
.toast-title {
font-weight: 700
}
.toast-message {
-ms-word-wrap: break-word;
word-wrap: break-word
}
.toast-message a, .toast-message label {
color: #fff
}
.toast-message a:hover {
color: #ccc;
text-decoration: none
}
.toast-close-button {
position: relative;
right: -.3em;
top: -.3em;
float: right;
font-size: 20px;
font-weight: 700;
color: #fff;
-webkit-text-shadow: 0 1px 0 #fff;
text-shadow: 0 1px 0 #fff;
opacity: .8;
-ms-filter: alpha(Opacity=80);
filter: alpha(opacity=80)
}
.toast-close-button:focus, .toast-close-button:hover {
color: #000;
text-decoration: none;
cursor: pointer;
opacity: .4;
-ms-filter: alpha(Opacity=40);
filter: alpha(opacity=40)
}
button.toast-close-button {
padding: 0;
cursor: pointer;
background: 0 0;
border: 0;
-webkit-appearance: none
}
.toast-top-center {
top: 0;
right: 0;
width: 100%
}
.toast-bottom-center {
bottom: 0;
right: 0;
width: 100%
}
.toast-top-full-width {
top: 0;
right: 0;
width: 100%
}
.toast-bottom-full-width {
bottom: 0;
right: 0;
width: 100%
}
.toast-top-left {
top: 12px;
left: 12px
}
.toast-top-right {
top: 12px;
right: 12px
}
.toast-bottom-right {
right: 12px;
bottom: 12px
}
.toast-bottom-left {
bottom: 12px;
left: 12px
}
#toast-container {
position: fixed;
z-index: 999999
}
#toast-container * {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box
}
#toast-container > div {
position: relative;
overflow: hidden;
margin: 0 0 6px;
padding: 15px 15px 15px 50px;
width: 300px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-position: 15px center;
background-repeat: no-repeat;
-moz-box-shadow: 0 0 12px #999;
-webkit-box-shadow: 0 0 12px #999;
box-shadow: 0 0 12px #999;
color: #fff;
opacity: .8;
-ms-filter: alpha(Opacity=80);
filter: alpha(opacity=80)
}
#toast-container > :hover {
-moz-box-shadow: 0 0 12px #000;
-webkit-box-shadow: 0 0 12px #000;
box-shadow: 0 0 12px #000;
opacity: 1;
-ms-filter: alpha(Opacity=100);
filter: alpha(opacity=100);
cursor: pointer
}
#toast-container > .toast-info {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=) !important
}
#toast-container > .toast-error {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=) !important
}
#toast-container > .toast-success {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==) !important
}
#toast-container > .toast-warning {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=) !important
}
#toast-container.toast-bottom-center > div, #toast-container.toast-top-center > div {
width: 300px;
margin: auto
}
#toast-container.toast-bottom-full-width > div, #toast-container.toast-top-full-width > div {
width: 96%;
margin: auto
}
.toast {
background-color: #030303
}
.toast-success {
background-color: #51a351
}
.toast-error {
background-color: #bd362f
}
.toast-info {
background-color: #2f96b4
}
.toast-warning {
background-color: #f89406
}
.toast-progress {
position: absolute;
left: 0;
bottom: 0;
height: 4px;
background-color: #000;
opacity: .4;
-ms-filter: alpha(Opacity=40);
filter: alpha(opacity=40)
}
@media all and (max-width: 240px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 11em
}
#toast-container .toast-close-button {
right: -.2em;
top: -.2em
}
}
@media all and (min-width: 241px) and (max-width: 480px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 18em
}
#toast-container .toast-close-button {
right: -.2em;
top: -.2em
}
}
@media all and (min-width: 481px) and (max-width: 768px) {
#toast-container > div {
padding: 15px 15px 15px 50px;
width: 25em
}
}
\ No newline at end of file
[.ShellClassInfo]
IconFile=%SystemRoot%\system32\SHELL32.dll
IconIndex=161
@charset "utf-8";
/*
提示:CSS 样式只允许修改颜色属性,或图片的地址(图片大小要和默认的一致)。border:dotted solid double dashed
*/
*:focus {outline: none;}
/* fade */
.jbox-fade{background-color:#000000;}
/* drag */
.jbox-drag{border:1px dashed #003870;}
/* jbox */
div.jbox {padding:0px;border:none;font-size:12px;}
/* border */
div.jbox .jbox-border{background: none repeat scroll 0 0 #000000;filter:alpha(opacity=20);-moz-opacity:0.2;opacity:0.2;}
/* container */
div.jbox .jbox-container{background-color:#ffffff;border:1px solid #999999;}
/* title-panel */
div.jbox .jbox-title-panel{background:#2f4050;border-bottom:1px solid #CCCCCC;}
div.jbox .jbox-title{font-weight:bold;color:#ffffff;}
div.jbox .jbox-title-icon{background:url(images/jbox-title-icon.gif) no-repeat scroll 3px 5px transparent;}
div.jbox .jbox-close,div.jbox .jbox-close-hover{background:url(images/jbox-close1.gif) no-repeat scroll 0px 0px transparent;}
div.jbox .jbox-close-hover{background-position:-16px 0;}
/* content */
div.jbox .jbox-content{min-height:24px;line-height:18px;color:#444444;}
div.jbox .jbox-content-loading{background-color:#E6E6E6;}
div.jbox .jbox-content-loading-image{background:url(images/jbox-content-loading.gif) no-repeat bottom center;}
/* button-panel */
div.jbox .jbox-button-panel{border-top:1px solid #CCCCCC;background-color: #EEEEEE;}
div.jbox .jbox-bottom-text{text-indent:10px;color:#444444;}
div.jbox .jbox-button{background:url(images/jbox-button2.png) repeat-x transparent;border:#AAAAAA 1px solid;color:#888888;border-radius:3px 3px 3px 3px;margin:1px 7px 0px 0px;height:22px;cursor:default;}
div.jbox .jbox-button-hover{background-position:0px -20px;color:#666666;}
div.jbox .jbox-button-active{background-position:0px -40px;}
div.jbox-warning .jbox .jbox-button-panel{background-color: #FFFFFF;}
/* tip-color */
div.jbox .jbox-tip-color{background-color:#003870;border-color:#003870;border-radius:3px 3px 3px 3px;color:#ffffff;}
/* icons */
div.jbox span.jbox-icon{background:url(images/jbox-icons.png) no-repeat scroll 0 0 transparent;_background:url(images/jbox-icons-ie6.gif) no-repeat scroll 0 0 transparent;}
div.jbox span.jbox-icon-info {background-position:0 0;}
div.jbox span.jbox-icon-question {background-position:-36px 0;}
div.jbox span.jbox-icon-success {background-position:-72px 0;}
div.jbox span.jbox-icon-warning {background-position:-108px 0;}
div.jbox span.jbox-icon-error {background-position:-144px 0;}
div.jbox span.jbox-icon-none {display: none; overflow:hidden;}
div.jbox span.jbox-icon-loading {background:url(images/jbox-loading1.gif) no-repeat scroll 0 0 transparent;}
\ No newline at end of file
[.ShellClassInfo]
IconFile=%SystemRoot%\system32\SHELL32.dll
IconIndex=161
@charset "utf-8";
*:focus {outline: none;}
/* fade */
.jbox-fade{background-color:#000000;}
/* drag */
.jbox-drag{border:1px dashed #0097d4;}
/* jbox */
div.jbox {padding:0px;border:none;font-size:12px;}
/* border */
div.jbox .jbox-border{background: none repeat scroll 0 0 #000000;filter:alpha(opacity=20);-moz-opacity:0.2;opacity:0.2;}
/* container */
div.jbox .jbox-container{background-color:#ffffff;border:1px solid #999999;}
/* title-panel */
div.jbox .jbox-title-panel{background: #2f4050;background: -webkit-gradient(linear, left top, left bottom, from(#2f4050), to(#2f4050));background: -moz-linear-gradient(top, #2f4050, #2f4050);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#2f4050', endColorstr='#2f4050');border-bottom:1px solid #999999;}
div.jbox .jbox-title{font-weight:bold;color:#ffffff;}
div.jbox .jbox-title-icon{background:url(images/jbox-title-icon.gif) no-repeat scroll 3px 5px transparent;}
div.jbox .jbox-close,div.jbox .jbox-close-hover{background:url(images/jbox-close1.gif) no-repeat scroll 0px 0px transparent;}
div.jbox .jbox-close-hover{background-position:-16px 0;}
/* content */
div.jbox .jbox-content{min-height:24px;line-height:18px;color:#444444;}
div.jbox .jbox-content-loading{background-color:#E6E6E6;}
div.jbox .jbox-content-loading-image{background:url(images/jbox-content-loading.gif) no-repeat bottom center;}
/* button-panel */
div.jbox .jbox-button-panel{border-top:1px solid #CCCCCC;background-color: #EEEEEE;}
div.jbox .jbox-bottom-text{text-indent:10px;color:#444444;}
div.jbox .jbox-button{background: #0097d4;background: -webkit-gradient(linear, left top, left bottom, from(#2f4050), to(#2f4050));background: -moz-linear-gradient(top, #2f4050, #2f4050);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#2f4050', endColorstr='#2f4050');border:#004b6a 1px solid;color:#fff;border-radius:3px 3px 3px 3px;margin:1px 7px 0px 0px;height:22px;cursor:default;}
div.jbox .jbox-button-hover{background: #0097d4;background: -webkit-gradient(linear, left top, left bottom, from(#0097d4), to(#005b7f));background: -moz-linear-gradient(top, #0097d4, #005b7f);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0097d4', endColorstr='#005b7f');}
div.jbox .jbox-button-active{background: -webkit-gradient(linear, left top, left bottom, from(#005b7f), to(#0097d4));background: -moz-linear-gradient(top, #005b7f, #0097d4);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#005b7f', endColorstr='#0097d4');}
div.jbox-warning .jbox .jbox-button-panel{background-color: #FFFFFF;}
/* tip-color */
div.jbox .jbox-tip-color{background: #0097d4;background: -webkit-gradient(linear, left top, left bottom, from(#0097d4), to(#005b7f));background: -moz-linear-gradient(top, #0097d4, #005b7f);filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0097d4', endColorstr='#005b7f');border-color:#004b6a;border-radius:3px 3px 3px 3px;color:#fff;}
/* icons */
div.jbox span.jbox-icon{background:url(images/jbox-icons.png) no-repeat scroll 0 0 transparent;_background:url(images/jbox-icons-ie6.gif) no-repeat scroll 0 0 transparent;}
div.jbox span.jbox-icon-info {background-position:0 0;}
div.jbox span.jbox-icon-question {background-position:-36px 0;}
div.jbox span.jbox-icon-success {background-position:-72px 0;}
div.jbox span.jbox-icon-warning {background-position:-108px 0;}
div.jbox span.jbox-icon-error {background-position:-144px 0;}
div.jbox span.jbox-icon-none {display: none; overflow:hidden;}
div.jbox span.jbox-icon-loading {background:url(images/jbox-loading1.gif) no-repeat scroll 0 0 transparent;}
\ No newline at end of file

/* jBox 全局设置 */
var jBoxConfig = {};
jBoxConfig.defaults = {
id: null, /* 在页面中的唯一id,如果为null则自动生成随机id,一个id只会显示一个jBox */
top: '15%', /* 窗口离顶部的距离,可以是百分比或像素(如 '100px') */
border: 5, /* 窗口的外边框像素大小,必须是0以上的整数 */
opacity: 0.1, /* 窗口隔离层的透明度,如果设置为0,则不显示隔离层 */
timeout: 0, /* 窗口显示多少毫秒后自动关闭,如果设置为0,则不自动关闭 */
showType: 'fade', /* 窗口显示的类型,可选值有:show、fade、slide */
showSpeed: 'fast', /* 窗口显示的速度,可选值有:'slow'、'fast'、表示毫秒的整数 */
showIcon: true, /* 是否显示窗口标题的图标,true显示,false不显示,或自定义的CSS样式类名(以为图标为背景) */
showClose: true, /* 是否显示窗口右上角的关闭按钮 */
draggable: true, /* 是否可以拖动窗口 */
dragLimit: true, /* 在可以拖动窗口的情况下,是否限制在可视范围 */
dragClone: false, /* 在可以拖动窗口的情况下,鼠标按下时窗口是否克隆窗口 */
persistent: true, /* 在显示隔离层的情况下,点击隔离层时,是否坚持窗口不关闭 */
showScrolling: true, /* 是否显示浏览的滚动条 */
ajaxData: {}, /* 在窗口内容使用get:或post:前缀标识的情况下,ajax post的数据,例如:{ id: 1 } 或 "id=1" */
iframeScrolling: 'auto', /* 在窗口内容使用iframe:前缀标识的情况下,iframe的scrolling属性值,可选值有:'auto'、'yes'、'no' */
title: 'jBox', /* 窗口的标题 */
width: 350, /* 窗口的宽度,值为'auto'或表示像素的整数 */
height: 'auto', /* 窗口的高度,值为'auto'或表示像素的整数 */
bottomText: '', /* 窗口的按钮左边的内容,当没有按钮时此设置无效 */
buttons: { '确定': 'ok' }, /* 窗口的按钮 */
buttonsFocus: 0, /* 表示第几个按钮为默认按钮,索引从0开始 */
loaded: function (h) { }, /* 窗口加载完成后执行的函数,需要注意的是,如果是ajax或iframe也是要等加载完http请求才算窗口加载完成,参数h表示窗口内容的jQuery对象 */
submit: function (v, h, f) { return true; }, /* 点击窗口按钮后的回调函数,返回true时表示关闭窗口,参数有三个,v表示所点的按钮的返回值,h表示窗口内容的jQuery对象,f表示窗口内容里的form表单键值 */
closed: function () { } /* 窗口关闭后执行的函数 */
};
jBoxConfig.stateDefaults = {
content: '', /* 状态的内容,不支持前缀标识 */
buttons: { '确定': 'ok' }, /* 状态的按钮 */
buttonsFocus: 0, /* 表示第几个按钮为默认按钮,索引从0开始 */
submit: function (v, h, f) { return true; } /* 点击状态按钮后的回调函数,返回true时表示关闭窗口,参数有三个,v表示所点的按钮的返回值,h表示窗口内容的jQuery对象,f表示窗口内容里的form表单键值 */
};
jBoxConfig.tipDefaults = {
content: '', /* 提示的内容,不支持前缀标识 */
icon: 'info', /* 提示的图标,可选值有'info'、'success'、'warning'、'error'、'loading',默认值为'info',当为'loading'时,timeout值会被设置为0,表示不会自动关闭。 */
top: '40%', /* 提示离顶部的距离,可以是百分比或像素(如 '100px') */
width: 'auto', /* 提示的高度,值为'auto'或表示像素的整数 */
height: 'auto', /* 提示的高度,值为'auto'或表示像素的整数 */
opacity: 0, /* 窗口隔离层的透明度,如果设置为0,则不显示隔离层 */
timeout: 3000, /* 提示显示多少毫秒后自动关闭,必须是大于0的整数 */
closed: function () { } /* 提示关闭后执行的函数 */
};
jBoxConfig.messagerDefaults = {
content: '', /* 信息的内容,不支持前缀标识 */
title: 'jBox', /* 信息的标题 */
icon: 'none', /* 信息图标,值为'none'时为不显示图标,可选值有'none'、'info'、'question'、'success'、'warning'、'error' */
width: 350, /* 信息的高度,值为'auto'或表示像素的整数 */
height: 'auto', /* 信息的高度,值为'auto'或表示像素的整数 */
timeout: 3000, /* 信息显示多少毫秒后自动关闭,如果设置为0,则不自动关闭 */
showType: 'slide', /* 信息显示的类型,可选值有:show、fade、slide */
showSpeed: 600, /* 信息显示的速度,可选值有:'slow'、'fast'、表示毫秒的整数 */
border: 0, /* 信息的外边框像素大小,必须是0以上的整数 */
buttons: {}, /* 信息的按钮 */
buttonsFocus: 0, /* 表示第几个按钮为默认按钮,索引从0开始 */
loaded: function (h) { }, /* 窗口加载完成后执行的函数,参数h表示窗口内容的jQuery对象 */
submit: function (v, h, f) { return true; }, /* 点击信息按钮后的回调函数,返回true时表示关闭窗口,参数有三个,v表示所点的按钮的返回值,h表示窗口内容的jQuery对象,f表示窗口内容里的form表单键值 */
closed: function () { } /* 信息关闭后执行的函数 */
};
jBoxConfig.languageDefaults = {
close: '关闭', /* 窗口右上角关闭按钮提示 */
ok: '确定', /* $.jBox.prompt() 系列方法的“确定”按钮文字 */
yes: '是', /* $.jBox.warning() 方法的“是”按钮文字 */
no: '否', /* $.jBox.warning() 方法的“否”按钮文字 */
cancel: '取消' /* $.jBox.confirm() 和 $.jBox.warning() 方法的“取消”按钮文字 */
};
$.jBox.setDefaults(jBoxConfig);
/*!
* jQuery Migrate - v1.1.1 - 2013-02-16
* https://github.com/jquery/jquery-migrate
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
*/
(function(s,p,i){var D={};s.migrateWarnings=[];if(!s.migrateMute&&p.console&&console.log){console.log("JQMIGRATE: Logging is active")}if(s.migrateTrace===i){s.migrateTrace=true}s.migrateReset=function(){D={};s.migrateWarnings.length=0};function h(G){if(!D[G]){D[G]=true;s.migrateWarnings.push(G);if(p.console&&console.warn&&!s.migrateMute){console.warn("JQMIGRATE: "+G);if(s.migrateTrace&&console.trace){console.trace()}}}}function a(I,K,H,J){if(Object.defineProperty){try{Object.defineProperty(I,K,{configurable:true,enumerable:true,get:function(){h(J);return H},set:function(L){h(J);H=L}});return}catch(G){}}s._definePropertyBroken=true;I[K]=H}if(document.compatMode==="BackCompat"){h("jQuery is not compatible with Quirks Mode")}var f=s("<input/>",{size:1}).attr("size")&&s.attrFn,x=s.attr,w=s.attrHooks.value&&s.attrHooks.value.get||function(){return null},j=s.attrHooks.value&&s.attrHooks.value.set||function(){return i},t=/^(?:input|button)$/i,y=/^[238]$/,B=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,k=/^(?:checked|selected)$/i;a(s,"attrFn",f||{},"jQuery.attrFn is deprecated");s.attr=function(K,I,L,J){var H=I.toLowerCase(),G=K&&K.nodeType;if(J){if(x.length<4){h("jQuery.fn.attr( props, pass ) is deprecated")}if(K&&!y.test(G)&&(f?I in f:s.isFunction(s.fn[I]))){return s(K)[I](L)}}if(I==="type"&&L!==i&&t.test(K.nodeName)&&K.parentNode){h("Can't change the 'type' of an input or button in IE 6/7/8")}if(!s.attrHooks[H]&&B.test(H)){s.attrHooks[H]={get:function(N,M){var P,O=s.prop(N,M);return O===true||typeof O!=="boolean"&&(P=N.getAttributeNode(M))&&P.nodeValue!==false?M.toLowerCase():i},set:function(N,P,M){var O;if(P===false){s.removeAttr(N,M)}else{O=s.propFix[M]||M;if(O in N){N[O]=true}N.setAttribute(M,M.toLowerCase())}return M}};if(k.test(H)){h("jQuery.fn.attr('"+H+"') may use property instead of attribute")
}}return x.call(s,K,I,L)};s.attrHooks.value={get:function(H,G){var I=(H.nodeName||"").toLowerCase();if(I==="button"){return w.apply(this,arguments)}if(I!=="input"&&I!=="option"){h("jQuery.fn.attr('value') no longer gets properties")}return G in H?H.value:null},set:function(G,H){var I=(G.nodeName||"").toLowerCase();if(I==="button"){return j.apply(this,arguments)}if(I!=="input"&&I!=="option"){h("jQuery.fn.attr('value', val) no longer sets properties")}G.value=H}};var q,E,z=s.fn.init,A=s.parseJSON,v=/^(?:[^<]*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;s.fn.init=function(G,J,I){var H;if(G&&typeof G==="string"&&!s.isPlainObject(J)&&(H=v.exec(G))&&H[1]){if(G.charAt(0)!=="<"){h("$(html) HTML strings must start with '<' character")}if(J&&J.context){J=J.context}if(s.parseHTML){return z.call(this,s.parseHTML(s.trim(G),J,true),J,I)}}return z.apply(this,arguments)};s.fn.init.prototype=s.fn;s.parseJSON=function(G){if(!G&&G!==null){h("jQuery.parseJSON requires a valid JSON string");return null}return A.apply(this,arguments)};s.uaMatch=function(H){H=H.toLowerCase();var G=/(chrome)[ \/]([\w.]+)/.exec(H)||/(webkit)[ \/]([\w.]+)/.exec(H)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(H)||/(msie) ([\w.]+)/.exec(H)||H.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(H)||[];return{browser:G[1]||"",version:G[2]||"0"}};if(!s.browser){q=s.uaMatch(navigator.userAgent);E={};if(q.browser){E[q.browser]=true;E.version=q.version}if(E.chrome){E.webkit=true}else{if(E.webkit){E.safari=true}}s.browser=E}a(s,"browser",s.browser,"jQuery.browser is deprecated");s.sub=function(){function G(J,K){return new G.fn.init(J,K)}s.extend(true,G,this);G.superclass=this;G.fn=G.prototype=this();G.fn.constructor=G;G.sub=this.sub;G.fn.init=function I(J,K){if(K&&K instanceof s&&!(K instanceof G)){K=G(K)}return s.fn.init.call(this,J,K,H)};G.fn.init.prototype=G.fn;var H=G(document);h("jQuery.sub() is deprecated");return G};s.ajaxSetup({converters:{"text json":s.parseJSON}});var n=s.fn.data;s.fn.data=function(I){var H,G,J=this[0];if(J&&I==="events"&&arguments.length===1){H=s.data(J,I);
G=s._data(J,I);if((H===i||H===G)&&G!==i){h("Use of jQuery.fn.data('events') is deprecated");return G}}return n.apply(this,arguments)};var o=/\/(java|ecma)script/i,u=s.fn.andSelf||s.fn.addBack;s.fn.andSelf=function(){h("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");return u.apply(this,arguments)};if(!s.clean){s.clean=function(G,H,N,J){H=H||document;H=!H.nodeType&&H[0]||H;H=H.ownerDocument||H;h("jQuery.clean() is deprecated");var K,I,L,O,M=[];s.merge(M,s.buildFragment(G,H).childNodes);if(N){L=function(P){if(!P.type||o.test(P.type)){return J?J.push(P.parentNode?P.parentNode.removeChild(P):P):N.appendChild(P)}};for(K=0;(I=M[K])!=null;K++){if(!(s.nodeName(I,"script")&&L(I))){N.appendChild(I);if(typeof I.getElementsByTagName!=="undefined"){O=s.grep(s.merge([],I.getElementsByTagName("script")),L);M.splice.apply(M,[K+1,0].concat(O));K+=O.length}}}}return M}}var c=s.event.add,b=s.event.remove,g=s.event.trigger,r=s.fn.toggle,d=s.fn.live,m=s.fn.die,C="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",e=new RegExp("\\b(?:"+C+")\\b"),F=/(?:^|\s)hover(\.\S+|)\b/,l=function(G){if(typeof(G)!=="string"||s.event.special.hover){return G}if(F.test(G)){h("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'")}return G&&G.replace(F,"mouseenter$1 mouseleave$1")};if(s.event.props&&s.event.props[0]!=="attrChange"){s.event.props.unshift("attrChange","attrName","relatedNode","srcElement")}if(s.event.dispatch){a(s.event,"handle",s.event.dispatch,"jQuery.event.handle is undocumented and deprecated")}s.event.add=function(J,H,I,K,G){if(J!==document&&e.test(H)){h("AJAX events should be attached to document: "+H)}c.call(this,J,l(H||""),I,K,G)};s.event.remove=function(K,I,J,G,H){b.call(this,K,l(I)||"",J,G,H)};s.fn.error=function(){var G=Array.prototype.slice.call(arguments,0);h("jQuery.fn.error() is deprecated");G.splice(0,0,"error");if(arguments.length){return this.bind.apply(this,G)}this.triggerHandler.apply(this,G);return this};s.fn.toggle=function(K,I){if(!s.isFunction(K)||!s.isFunction(I)){return r.apply(this,arguments)
}h("jQuery.fn.toggle(handler, handler...) is deprecated");var H=arguments,G=K.guid||s.guid++,J=0,L=function(M){var N=(s._data(this,"lastToggle"+K.guid)||0)%J;s._data(this,"lastToggle"+K.guid,N+1);M.preventDefault();return H[N].apply(this,arguments)||false};L.guid=G;while(J<H.length){H[J++].guid=G}return this.click(L)};s.fn.live=function(G,I,H){h("jQuery.fn.live() is deprecated");if(d){return d.apply(this,arguments)}s(this.context).on(G,this.selector,I,H);return this};s.fn.die=function(G,H){h("jQuery.fn.die() is deprecated");if(m){return m.apply(this,arguments)}s(this.context).off(G,this.selector||"**",H);return this};s.event.trigger=function(I,J,H,G){if(!H&&!e.test(I)){h("Global events are undocumented and deprecated")}return g.call(this,I,J,H||document,G)};s.each(C.split("|"),function(H,G){s.event.special[G]={setup:function(){var I=this;if(I!==document){s.event.add(document,G+"."+s.guid,function(){s.event.trigger(G,null,I,true)});s._data(this,G,s.guid++)}return false},teardown:function(){if(this!==document){s.event.remove(document,G+"."+s._data(this,G))}return false}}})})(jQuery,window);
\ No newline at end of file
/*
* jQuery jBox 2.3
* http://www.kudystudio.com
* Author: kudy chen (kudychen@gmail.com)
*
* Copyright 2011, kudy studio
* Dual licensed under the MIT or GPL Version 3 licenses.
*
* Last Modified: 2011-11-11
*/
;eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('(8(a){a.7=8(b,c){c=a.1n({},a.7.17,c);c.1M=c.1V>9;c.1p=c.1p||1q;c.1A=c.1A||1q;5(b==1y){b=\'\'};5(c.W<9){c.W=9};5(c.1t==1y){c.1t=\'51\'+2U.52(2U.3i()*4Z)};6 d=(a.1U.2e&&3u(a.1U.3a)<3r);6 e=a(\'#\'+c.1t);5(e.1I>9){c.1k=a.7.17.1k++;e.16({1k:c.1k});e.10(\'#4\').16({1k:c.1k+1h});1j e};6 f={2g:\'\',1x:\'\',1e:\'\',2j:b.50==53};5(!f.2j){b=b+\'\';6 N=b.56();5(N.1X(\'1t:\')==9)f.1x=\'4t\';1b 5(N.1X(\'4C:\')==9)f.1x=\'35\';1b 5(N.1X(\'57:\')==9)f.1x=\'30\';1b 5(N.1X(\'1F:\')==9)f.1x=\'2w\';1b 5(N.1X(\'1e:\')==9)f.1x=\'3h\';1b{b=\'1e:\'+b;f.1x=\'3h\'};b=b.54(b.1X(":")+1h,b.1I)};5(!c.1p&&!c.1A&&!c.4s){a(a.1U.2e?\'1e\':\'1z\').3c(\'11\',\'2a:2l;1f-27:55;\')};6 g=!c.1p&&!(c.1o==1y);6 h=f.1x==\'35\'||f.1x==\'30\'||f.1x==\'2w\';6 i=1L c.14==\'36\'?(c.14-4Y)+\'19\':"4R%";6 j=[];j.X(\'<Z 1t="\'+c.1t+\'" 1a="4-\'+(c.1p?\'1v\':(c.1A?\'3l\':\'1z\'))+\'">\');5(c.1M){5((d&&a(\'1F\').1I>9)||a(\'4S, 4P\').1I>9){j.X(\'<1F 1t="4-24" 1a="4-24" 3y="3M:3X" 11="1D:2R;1s:1B;z-3t:-1;"></1F>\')}1b{5(d){a(\'3Z\').16(\'3L\',\'2l\')};j.X(\'<Z 1t="4-24" 1a="4-24" 11="1s:1B;"></Z>\')}};j.X(\'<Z 1t="4-3m" 1a="4-3m" 11="14:1c;Y:1c;4Q-4x:#4T;1s:1B;z-3t:45;4W:1d;"></Z>\');5(c.1Y){j.X(\'<Z 1t="4-47" 1a="4-47" 11="1s:1B;z-3t:45;1D:1d;"></Z>\')};j.X(\'<Z 1t="4" 1a="4" 11="1s:1B;14:1m;Y:1m;">\');j.X(\'<Z 1a="4-2W-1o 4-1o-23" 11="Y:2s;1D:1d;"></Z>\');j.X(\'<Z 1a="4-2W-1l 4-1l-23" 11="Y:2s;1f:2Z 0 2Z 0;1D:1d;"></Z>\');j.X(\'<4p W="0" 4X="0" 4U="0" 11="1E:1c;1f:1c;W:1d;">\');5(c.W>9){j.X(\'<2n>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;W-3d:\'+c.W+\'19 0 0 0;14:\'+c.W+\'19;Y:\'+c.W+\'19;"></1u>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;Y:\'+c.W+\'19;2a: 2l;"></1u>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;W-3d:0 \'+c.W+\'19 0 0;14:\'+c.W+\'19;Y:\'+c.W+\'19;"></1u>\');j.X(\'</2n>\')};j.X(\'<2n>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;"></1u>\');j.X(\'<1u 4V="18" 11="1E:1c;1f:1c;W:1d;">\');j.X(\'<Z 1a="4-4v" 11="14:1m; Y:1m;">\');j.X(\'<a 1a="4-1J" 1o="\'+a.7.1S.1J+\'" 58="$(21).2x(\\\'4-1J-2E\\\');" 5l="$(21).2I(\\\'4-1J-2E\\\');" 11="1s:1B; 1D:2R; 4w:5m; 18:\'+(4D+c.W)+\'19; 27:\'+(4D+c.W)+\'19; 14:4z; Y:4z;\'+(c.34?\'\':\'1D:1d;\')+\'"></a>\');5(g){j.X(\'<Z 1a="4-1o-23" 11="Y:2s;">\');j.X(\'<Z 1a="4-1o\'+(c.2L==1i?\' 4-1o-12\':(c.2L==1q?\'\':\' \'+c.2L))+\'" 11="3W:1g; 14:\'+i+\'; 3j-Y:\'+(a.1U.2e?5j:5k)+\'19; 1f-1g:\'+(c.2L?5n:2X)+\'19;2a:2l;1T-2a:5q;5r-1K:1K-5o;">\'+(c.1o==\'\'?\'&5p;\':c.1o)+\'</Z>\');j.X(\'</Z>\')};j.X(\'<Z 1t="4-2T"></Z></Z>\');j.X(\'</Z>\');j.X(\'</1u>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;"></1u>\');j.X(\'</2n>\');5(c.W>9){j.X(\'<2n>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;W-3d:0 0 0 \'+c.W+\'19; 14:\'+c.W+\'19; Y:\'+c.W+\'19;"></1u>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;Y:\'+c.W+\'19;2a: 2l;"></1u>\');j.X(\'<1u 1a="4-W" 11="1E:1c;1f:1c;W:1d;W-3d:0 0 \'+c.W+\'19 0; 14:\'+c.W+\'19; Y:\'+c.W+\'19;"></1u>\');j.X(\'</2n>\')};j.X(\'</4p>\');j.X(\'</Z>\');j.X(\'</Z>\');6 k=\'<1F 2h="4-1F" 1t="4-1F" 14="2v%" Y="2v%" 5i="0" 5b="0" 5c="0" 59="\'+c.4r+\'"></1F>\';6 l=a(2f);6 m=a(1H.1z);6 n=a(j.2m(\'\')).5a(m);6 o=n.2r(\'#4\');6 p=n.2r(\'#4-24\');6 q=n.2r(\'#4-3m\');5(!f.2j){3H(f.1x){1R"4t":f.1e=a(\'#\'+b).1e();1K;1R"35":1R"30":f.1e=\'\';f.2g=b;1K;1R"3h":f.1e=b;1K;1R"2w":f.1e=k;5(b.1X(\'#\')==-1h){f.2g=b+(b.1X(\'?\')==-1h?\'?39\':\'&39\')+2U.3i()}1b{6 N=b.5d(\'#\');f.2g=N[9]+(N[9].1X(\'?\')==-1h?\'?39\':\'&39\')+2U.3i()+\'#\'+N[1h]};1K};b={5g:{13:f.1e,1C:c.1C,2o:c.2o,1W:c.1W}}};6 r=[];6 s=o.10(\'.4-2W-1o\').3N(1i);6 t=o.10(\'.4-2W-1l\').3N(1i);6 u=a.1U.2e?\'3j-Y:3V;1f:1c 3O 1c 3O;\':\'1f:1c 2N 1c 2N;\';a.2C(b,8(N,O){5(f.2j){O=a.1n({},a.7.2O,O)};b[N]=O;5(O.1C==1y){O.1C={}};6 P=1q;a.2C(O.1C,8(T,U){P=1i});6 Q=\'1m\';5(1L c.Y==\'36\'){Q=c.Y;5(g){Q=Q-s};5(P){Q=Q-t};Q=(Q-1h)+\'19\'};6 R=\'\';6 S=\'2s\';5(!f.2j&&h){6 T=c.Y;5(1L c.Y==\'36\'){5(g){T=T-s};5(P){T=T-t};S=((T/2X)*1N)+\'19\';T=(T-1h)+\'19\'};R=[\'<Z 1t="4-13-2B" 1a="4-13-2B" 11="2P-Y:5h;Y:\'+T+\'; 1T-2k:42;">\',\'<Z 1a="4-13-2B-5e" 11="1D:2R; 1E:1m; 14:5f; Y:3V; 1f-18: \'+S+\';"></Z>\',\'</Z>\'].2m(\'\')};r.X(\'<Z 1t="4-1G-\'+N+\'" 1a="4-1G" 11="1D:1d;">\');r.X(\'<Z 11="2P-14:3o;14:\'+(1L c.14==\'36\'?c.14+\'19\':\'1m\')+\'; Y:\'+Q+\';">\'+R+\'<Z 1t="4-13" 1a="4-13" 11="Y:\'+Q+\';2a:2l;2a-y:1m;">\'+O.13+\'</Z></Z>\');r.X(\'<Z 1a="4-1l-23" 11="Y:2s;1f:2Z 0 2Z 0;1T-2k: 27;\'+(P?\'\':\'1D:1d;\')+\'">\');5(!c.1p){r.X(\'<26 1a="4-29-1T" 11="3W:1g;1D:2R;3j-Y:2s;"></26>\')};a.2C(O.1C,8(T,U){r.X(\'<1l 1a="4-1l" 31="\'+U+\'" 11="\'+u+\'">\'+T+\'</1l>\')});r.X(\'</Z></Z>\')});o.10(\'#4-2T\').1e(r.2m(\'\')).2r(\'.4-1G:3k\').16(\'1D\',\'2R\');5(h){6 N=o.10(\'#4-13\').16({1s:(d)?"1B":"32",1g:-4H})};a.2C(b,8(N,O){6 P=o.10(\'#4-1G-\'+N);P.2r(\'.4-1l-23\').2r(\'1l\').2c(8(){6 Q=P.10(\'#4-13\');6 R=O.1C[a(21).1T()];6 S={};a.2C(o.10(\'#4-2T :4h\').4M(),8(U,V){5(S[V.2h]===1y){S[V.2h]=V.31}1b 5(1L S[V.2h]==4L){S[V.2h].X(V.31)}1b{S[V.2h]=[S[V.2h],V.31]}});6 T=O.1W(R,Q,S);5(T===1y||T){I()}}).1P(\'2t\',8(){a(21).2x(\'4-1l-3x\')}).1P(\'4A\',8(){a(21).2I(\'4-1l-3x\')}).1P(\'4G\',8(){a(21).2x(\'4-1l-2E\')}).1P(\'4O\',8(){a(21).2I(\'4-1l-3x\').2I(\'4-1l-2E\')});P.10(\'.4-1l-23 1l:2V(\'+O.2o+\')\').2x(\'4-1l-1O\')});6 v=8(){n.16({18:l.3e()});5(c.1A){o.16({1s:(d)?"1B":"32",27:1h,29:1h})}};6 w=8(){6 N=l.14();1j 1H.1z.3I<N?N:1H.1z.3I};6 x=8(){6 N=l.Y();1j 1H.1z.3C<N?N:1H.1z.3C};6 y=8(){5(!c.1M){1j};5(c.4q){6 N=9;n.2x(\'4-25\');6 O=4K(8(){n.4J(\'4-25\');5(N++>1h){4I(O);n.2I(\'4-25\')}},4N)}1b{I()}};6 z=8(N){5(c.1p||c.1A){1j 1q};6 O=(2f.4f)?4f.4g:N.4g;5(O==4F){I()};5(O==5Z){6 P=a(\':4h:5Y:2p\',n);6 Q=!N.4e&&N.1r==P[P.1I-1h];6 R=N.4e&&N.1r==P[9];5(Q||R){38(8(){5(!P)1j;6 S=P[R===1i?P.1I-1h:9];5(S)S.1O()},2G);1j 1q}}};6 A=8(){5(c.1M){p.16({1s:"1B",Y:c.1p?x():l.Y(),14:d?l.14():"2v%",18:9,1g:9,27:9,29:9})}};6 B=8(){5(c.1A){o.16({1s:(d)?"1B":"32",27:1h,29:1h})}1b{q.16({18:c.18});o.16({1s:"1B",18:q.3f().18+(c.1p?l.3e():9),1g:((l.14()-o.3S())/1N)})};5((c.1M&&!c.1p)||(!c.1M&&!c.1p&&!c.1A)){n.16({1s:(d)?"1B":"32",Y:c.1M?l.Y():9,14:"2v%",18:(d)?l.3e():9,1g:9,27:9,29:9})};A()};6 C=8(){c.1k=a.7.17.1k++;n.16({1k:c.1k});o.16({1k:c.1k+1h})};6 D=8(){c.1k=a.7.17.1k++;n.16({1k:c.1k});o.16({1D:"1d",1k:c.1k+1h});5(c.1M){p.16({1D:"1d",1k:c.1k,1V:c.1V})}};6 E=8(N){6 O=N.1w;O.1r.10(\'1F\').2K();5(c.22){O.1r.2u().16({1g:O.1r.16(\'1g\'),18:O.1r.16(\'18\'),61:-1N,60:-1N,14:O.1r.14()+1N,Y:O.1r.Y()+1N}).1Z()};1j 1q};6 F=8(N){6 O=N.1w;6 P=O.49+N.4c-O.43;6 Q=O.4y+N.48-O.4a;5(c.4o){6 R=1h;6 S=1H.46.3C-N.1w.1r.Y()-1h;6 T=1h;6 U=1H.46.3I-N.1w.1r.14()-1h;5(Q<R)Q=R+(c.22?1N:9);5(Q>S)Q=S-(c.22?1N:9);5(P<T)P=T+(c.22?1N:9);5(P>U)P=U-(c.22?1N:9)};5(c.22){O.1r.2u().16({1g:P,18:Q})}1b{O.1r.16({1g:P,18:Q})};1j 1q};6 G=8(N){a(1H).2i(\'.1Y\');5(c.22){6 O=N.1w.1r.2u().2K();N.1w.1r.16({1g:O.16(\'1g\'),18:O.16(\'18\')}).10(\'1F\').1Z()}1b{N.1w.1r.10(\'1F\').1Z()};1j 1q};6 H=8(N){6 O=N.1w.1r.1s();6 P={1r:N.1w.1r,43:N.4c,4a:N.48,49:O.1g,4y:O.18};a(1H).1P(\'2t.1Y\',P,E).1P(\'5V.1Y\',P,F).1P(\'4A.1Y\',P,G)};6 I=8(){5(!c.1p&&!c.1A){5(a(\'.4-1z\').1I==1h){a(a.1U.2e?\'1e\':\'1z\').5U(\'11\')};J()}1b{5(c.1p){6 1v=a(1H.1z).1w(\'1v\');5(1v&&1v.2F==1i){q.16(\'18\',1v.33.18);6 N=q.3f().18+l.3e();5(N==o.3f().18){J()}1b{o.10(\'#4-13\').1e(1v.33.13.5X(2X)).5W().16({1g:((l.14()-o.3S())/1N)}).41({18:N,1V:0.1},3J,J)}}1b{o.41({18:\'-=62\',1V:9},3J,J)}}1b{3H(c.2J){1R\'3D\':o.4b(c.20,J);1K;1R\'24\':o.3P(c.20,J);1K;1R\'1Z\':3R:o.2K(c.20,J);1K}}}};6 J=8(){l.2i(\'3U\',A);5(c.1Y&&!c.1p&&!c.1A){o.10(\'.4-1o-23\').2i(\'2t\',H)};5(f.1x!=\'2w\'){o.10(\'#4-1F\').3c({\'3y\':\'3M:3X\'})};o.1e(\'\').3F();5(d&&!c.1p){m.2i(\'3T\',v)};5(c.1M){p.3P(\'37\',8(){p.2i(\'2c\',y).2i(\'2t\',C).1e(\'\').3F()})};n.2i(\'3Y 3K\',z).1e(\'\').3F();5(d&&c.1M){a(\'3Z\').16(\'3L\',\'2p\')};5(1L c.2H==\'8\'){c.2H()}};6 K=8(){5(c.1Q>9){o.1w(\'3B\',2f.38(I,c.1Q));5(c.1A){o.2E(8(){2f.63(o.1w(\'3B\'))},8(){o.1w(\'3B\',2f.38(I,c.1Q))})}}};6 L=8(){5(1L c.2Y==\'8\'){c.2Y(o.10(\'.4-1G:2p\').10(\'.4-13\'))}};5(!f.2j){3H(f.1x){1R"35":1R"30":a.64({1x:f.1x,2g:f.2g,1w:c.3g==1y?{}:c.3g,5B:\'1e\',5A:1q,2y:8(N,O){o.10(\'#4-13\').16({1s:"3Q"}).1e(N).1Z().2u().2K();L()},2z:8(){o.10(\'#4-13-2B\').1e(\'<Z 11="1f-18:3o;1f-29:3o;1T-2k:42;">5z 5C.</Z>\')}});1K;1R"2w":o.10(\'#4-1F\').3c({\'3y\':f.2g}).1P("5F",8(N){a(21).5E().16({1s:"3Q"}).1Z().2u().2K();o.10(\'#4-2T .4-1G:3k .4-1l-1O\').1O();L()});1K;3R:o.10(\'#4-13\').1Z();1K}};B();D();5(d&&!c.1p){l.3T(v)};5(c.1M){p.2c(y)};l.3U(A);n.1P(\'3Y 3K\',z);o.10(\'.4-1J\').2c(I);5(c.1M){p.4u(\'37\')};6 M=\'1Z\';5(c.2J==\'3D\'){M=\'44\'}1b 5(c.2J==\'24\'){M=\'4u\'};5(c.1A){o[M](c.20,K)}1b{6 1v=a(1H.1z).1w(\'1v\');5(1v&&1v.2F==1i){a(1H.1z).1w(\'1v\',{2F:1q,33:{}});o.16(\'1D\',\'\')}1b{5(!f.2j&&h){o[M](c.20)}1b{o[M](c.20,L);}}};5(!c.1p){o.10(\'.4-29-1T\').1e(c.4E)}1b{o.10(\'.4-4v,.4-13\').2x(\'4-1v-4x\')};5(f.1x!=\'2w\'){o.10(\'#4-2T .4-1G:3k .4-1l-1O\').1O()}1b{o.1O()};5(!c.1A){K()};n.1P(\'2t\',C);5(c.1Y&&!c.1p&&!c.1A){o.10(\'.4-1o-23\').1P(\'2t\',{1r:o},H).16(\'4w\',\'5D\')};1j n};a.7.3a=2.3;a.7.17={1t:3A,18:"15%",1k:5u,W:2X,1V:0.1,1Q:9,2J:\'24\',20:\'37\',2L:1i,34:1i,1Y:1i,4o:1i,22:1q,4q:1i,4s:1i,3g:{},4r:\'1m\',1o:\'7\',14:3p,Y:\'1m\',4E:\'\',1C:{\'3z\':\'2b\'},2o:9,2Y:8(b){},1W:8(b,c,d){1j 1i},2H:8(){}};a.7.2O={13:\'\',1C:{\'3z\':\'2b\'},2o:9,1W:8(b,c,d){1j 1i}};a.7.2Q={13:\'\',12:\'28\',18:\'40%\',14:\'1m\',Y:\'1m\',1V:9,1Q:4B,2H:8(){}};a.7.2A={13:\'\',1o:\'7\',12:\'1d\',14:3p,Y:\'1m\',1Q:4B,2J:\'3D\',20:5t,W:9,1C:{},2o:9,2Y:8(){},1W:8(b,c,d){1j 1i},2H:8(){}};a.7.1S={1J:\'5s\',2b:\'3z\',3n:\'5v\',3q:\'5y\',2S:\'5x\'};a.7.5w=8(b){a.7.17=a.1n({},a.7.17,b.17);a.7.2O=a.1n({},a.7.2O,b.2O);a.7.2Q=a.1n({},a.7.2Q,b.2Q);a.7.2A=a.1n({},a.7.2A,b.2A);a.7.1S=a.1n({},a.7.1S,b.1S)};a.7.2D=8(){1j a(\'.4-1z\').2V(a(\'.4-1z\').1I-1h)};a.7.5P=8(b){6 c=(1L b==\'3v\')?a(\'#\'+b):a.7.2D();1j c.10(\'#4-1F\').4C(9)};a.7.5O=8(){1j a.7.3b().10(\'.4-13\').1e()};a.7.5N=8(b){1j a.7.3b().10(\'.4-13\').1e(b)};a.7.3b=8(b){5(b==1y){1j a.7.2D().10(\'.4-1G:2p\')}1b{1j a.7.2D().10(\'#4-1G-\'+b)}};a.7.5Q=8(){1j a.7.3b().3c(\'1t\').5T(\'4-1G-\',\'\')};a.7.3w=8(b,c){6 d=a.7.2D();5(d!=1y&&d!=3A){6 e;b=b||1q;d.10(\'.4-1G\').4b(\'37\');5(1L b==\'3v\'){e=d.10(\'#4-1G-\'+b)}1b{e=b?d.10(\'.4-1G:2p\').2F():d.10(\'.4-1G:2p\').2u()};e.44(3p,8(){2f.38(8(){e.10(\'.4-1l-1O\').1O();5(c!=1y){e.10(\'.4-13\').1e(c)}},5S)})}};a.7.5R=8(b){a.7.3w(1i,b)};a.7.5I=8(b){a.7.3w(1q,b)};a.7.1J=8(b,c){b=b||1q;c=c||\'1z\';5(1L b==\'3v\'){a(\'#\'+b).10(\'.4-1J\').2c()}1b{6 d=a(\'.4-\'+c);5(b){5H(6 e=9,l=d.1I;e<l;++e){d.2V(e).10(\'.4-1J\').2c()}}1b{5(d.1I>9){d.2V(d.1I-1h).10(\'.4-1J\').2c()}}}};a.7.5G=8(b,c,d,e,f){6 17={13:b,1o:c,14:d,Y:e};f=a.1n({},17,f);f=a.1n({},a.7.17,f);a.7(f.13,f)};a.7.2d=8(b,c,d,e){6 17={13:b,1o:c,12:d,1C:3s(\'({ "\'+a.7.1S.2b+\'": "2b" })\')};e=a.1n({},17,e);e=a.1n({},a.7.17,e);5(e.W<9){e.W=9};5(e.12!=\'28\'&&e.12!=\'25\'&&e.12!=\'2y\'&&e.12!=\'2z\'&&e.12!=\'3G\'){1f=\'\';e.12=\'1d\'};6 f=e.1o==1y?2G:4j;6 g=e.12==\'1d\'?\'Y:1m;\':\'2P-Y:2M;\'+((a.1U.2e&&3u(a.1U.3a)<3r)?\'Y:1m !4l;Y:2v%;4n:2M;\':\'Y:1m;\');6 h=[];h.X(\'1e:\');h.X(\'<Z 11="1E:2N;\'+g+\'1f-1g:\'+(e.12==\'1d\'?9:4m)+\'19;1T-2k:1g;">\');h.X(\'<26 1a="4-12 4-12-\'+e.12+\'" 11="1s:1B; 18:\'+(f+e.W)+\'19;1g:\'+(2G+e.W)+\'19; 14:2q; Y:2q;"></26>\');h.X(e.13);h.X(\'</Z>\');e.13=h.2m(\'\');a.7(e.13,e)};a.7.5J=8(b,c,d){a.7.2d(b,c,\'1d\',d)};a.7.28=8(b,c,d){a.7.2d(b,c,\'28\',d)};a.7.2y=8(b,c,d){a.7.2d(b,c,\'2y\',d)};a.7.2z=8(b,c,d){a.7.2d(b,c,\'2z\',d)};a.7.5M=8(b,c,d,e){6 17={1C:3s(\'({ "\'+a.7.1S.2b+\'": "2b", "\'+a.7.1S.2S+\'": "2S" })\')};5(d!=1y&&1L d==\'8\'){17.1W=d}1b{17.1W=8(f,g,h){1j 1i}};e=a.1n({},17,e);a.7.2d(b,c,\'3G\',e)};a.7.25=8(b,c,d,e){6 17={1C:3s(\'({ "\'+a.7.1S.3n+\'": "3n", "\'+a.7.1S.3q+\'": "3q", "\'+a.7.1S.2S+\'": "2S" })\')};5(d!=1y&&1L d==\'8\'){17.1W=d}1b{17.1W=8(f,g,h){1j 1i}};e=a.1n({},17,e);a.7.2d(b,c,\'25\',e)};a.7.1v=8(b,c,d){6 17={13:b,12:c,1V:9,W:9,34:1q,1C:{},1p:1i};5(17.12==\'2B\'){17.1Q=9;17.1V=0.1};d=a.1n({},17,d);d=a.1n({},a.7.2Q,d);d=a.1n({},a.7.17,d);5(d.1Q<9){d.1Q=9};5(d.W<9){d.W=9};5(d.12!=\'28\'&&d.12!=\'25\'&&d.12!=\'2y\'&&d.12!=\'2z\'&&d.12!=\'2B\'){d.12=\'28\'};6 e=[];e.X(\'1e:\');e.X(\'<Z 11="2P-Y:5L;Y:1m;1E:2N;1f-1g:2M;1f-18:1c;1T-2k:1g;">\');e.X(\'<26 1a="4-12 4-12-\'+d.12+\'" 11="1s:1B;18:\'+(4d+d.W)+\'19;1g:\'+(4d+d.W)+\'19; 14:2q; Y:2q;"></26>\');e.X(d.13);e.X(\'</Z>\');d.13=e.2m(\'\');5(a(\'.4-1v\').1I>9){a(1H.1z).1w(\'1v\',{2F:1i,33:d});a.7.4k()};5(d.3E!=1y){a(\'#\'+d.3E).1O();18.$(\'#\'+d.3E).1O()};a.7(d.13,d)};a.7.4k=8(){a.7.1J(1q,\'1v\')};a.7.3l=8(b,c,d,e){a.7.4i();6 17={13:b,1o:c,1Q:(d==1y?a.7.2A.1Q:d),1V:9,34:1i,1Y:1q,1A:1i};e=a.1n({},17,e);e=a.1n({},a.7.2A,e);6 f=a.1n({},a.7.17,{});f.1o=3A;e=a.1n({},f,e);5(e.W<9){e.W=9};5(e.12!=\'28\'&&e.12!=\'25\'&&e.12!=\'2y\'&&e.12!=\'2z\'&&e.12!=\'3G\'){1f=\'\';e.12=\'1d\'};6 g=e.1o==1y?2G:4j;6 h=e.12==\'1d\'?\'Y:1m;\':\'2P-Y:2M;\'+((a.1U.2e&&3u(a.1U.3a)<3r)?\'Y:1m !4l;Y:2v%;4n:2M;\':\'Y:1m;\');6 i=[];i.X(\'1e:\');i.X(\'<Z 11="1E:2N;\'+h+\'1f-1g:\'+(e.12==\'1d\'?9:4m)+\'19;1T-2k:1g;">\');i.X(\'<26 1a="4-12 4-12-\'+e.12+\'" 11="1s:1B; 18:\'+(g+e.W)+\'19;1g:\'+(2G+e.W)+\'19; 14:2q; Y:2q;"></26>\');i.X(e.13);i.X(\'</Z>\');e.13=i.2m(\'\');a.7(e.13,e)};a.7.4i=8(){a.7.1J(1q,\'3l\')};2f.7=a.7})(5K);',62,377,'||||jbox|if|var|jBox|function|0x0|||||||||||||||||||||||||||||||||||||||||||||||||border|push|height|div|find|style|icon|content|width||css|defaults|top|px|class|else|0px|none|html|padding|left|0x1|true|return|zIndex|button|auto|extend|title|isTip|false|target|position|id|td|tip|data|type|undefined|body|isMessager|absolute|buttons|display|margin|iframe|state|document|length|close|break|typeof|showFade|0x2|focus|bind|timeout|case|languageDefaults|text|browser|opacity|submit|indexOf|draggable|show|showSpeed|this|dragClone|panel|fade|warning|span|right|info|bottom|overflow|ok|click|prompt|msie|window|url|name|unbind|isObject|align|hidden|join|tr|buttonsFocus|visible|32px|children|25px|mousedown|prev|100|IFRAME|addClass|success|error|messagerDefaults|loading|each|getBox|hover|next|0xa|closed|removeClass|showType|hide|showIcon|30px|10px|stateDefaults|min|tipDefaults|block|cancel|states|Math|eq|help|0x5|loaded|5px|POST|value|fixed|options|showClose|GET|number|fast|setTimeout|___t|version|getState|attr|radius|scrollTop|offset|ajaxData|HTML|random|line|first|messager|temp|yes|50px|0x15e|no|0x7|eval|index|parseInt|string|goToState|active|src|确定|null|autoClosing|clientHeight|slide|focusId|remove|question|switch|clientWidth|0x1f4|keypress|visibility|about|outerHeight|6px|fadeOut|static|default|outerWidth|scroll|resize|19px|float|blank|keydown|select||animate|center|startX|slideDown|1984|documentElement|drag|pageY|startLeft|startY|slideUp|pageX|0x4|shiftKey|event|keyCode|input|closeMessager|0x23|closeTip|important|0x28|_height|dragLimit|table|persistent|iframeScrolling|showScrolling|ID|fadeIn|container|cursor|color|startTop|15px|mouseup|0xbb8|get|0x6|bottomText|0x1b|mouseover|0x2710|clearInterval|toggleClass|setInterval|Array|serializeArray|0x64|mouseout|applet|background|90|object|ff3300|cellspacing|valign|fdisplay|cellpadding|0x32|0xf4240|constructor|jBox_|floor|Object|substring|17px|toLowerCase|post|onmouseover|scrolling|appendTo|marginwidth|frameborder|split|image|220px|state0|70px|marginheight|0x19|0x18|onmouseout|pointer|0x12|all|nbsp|ellipsis|word|关闭|0x258|0x7c0|是|setDefaults|取消|否|Loading|cache|dataType|Error|move|parent|load|open|for|prevState|alert|jQuery|18px|confirm|setContent|getContent|getIframe|getStateName|nextState|0x14|replace|removeAttr|mousemove|end|substr|enabled|0x9|marginTop|marginLeft|200|clearTimeout|ajax'.split('|'),0,{}));
\ No newline at end of file
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
var checked=false; var checked=false;
function check_all(form) { function check_all(form) {
var checkboxes = document.getElementById(form); var checkboxes = document.getElementById(form);
if (checked == false) { if (checked === false) {
checked = true checked = true;
} else { } else {
checked = false checked = false;
} }
for (var i = 0; i < checkboxes.elements.length; i++) { for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox") { if (checkboxes.elements[i].type == "checkbox") {
...@@ -51,13 +51,13 @@ function GetRowData(row){ ...@@ -51,13 +51,13 @@ function GetRowData(row){
//此函数用于在多选提交时至少要选择一行 //此函数用于在多选提交时至少要选择一行
function GetTableDataBox() { function GetTableDataBox() {
var tabProduct = document.getElementById("editable"); var tabProduct = document.getElementById("editable");
var tableData = new Array(); var tableData = [];
var returnData = new Array(); var returnData = [];
var checkboxes = document.getElementById("contents_form"); var checkboxes = document.getElementById("contents_form");
var id_list = new Array(); var id_list = [];
len = checkboxes.elements.length; len = checkboxes.elements.length;
for (var i=0; i < len; i++) { for (var i=0; i < len; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") { if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked === true && checkboxes.elements[i].value != "checkall") {
id_list.push(i); id_list.push(i);
} }
} }
...@@ -67,7 +67,7 @@ function GetTableDataBox() { ...@@ -67,7 +67,7 @@ function GetTableDataBox() {
tableData.push(GetRowData(tabProduct.rows[id_list[i]])); tableData.push(GetRowData(tabProduct.rows[id_list[i]]));
} }
if (id_list.length == 0){ if (id_list.length === 0){
alert('请至少选择一行!'); alert('请至少选择一行!');
} }
returnData.push(tableData); returnData.push(tableData);
...@@ -77,7 +77,7 @@ function GetTableDataBox() { ...@@ -77,7 +77,7 @@ function GetTableDataBox() {
function move(from, to, from_o, to_o) { function move(from, to, from_o, to_o) {
$("#" + from + " option").each(function () { $("#" + from + " option").each(function () {
if ($(this).prop("selected") == true) { if ($(this).prop("selected") === true) {
$("#" + to).append(this); $("#" + to).append(this);
if( typeof from_o !== 'undefined'){ if( typeof from_o !== 'undefined'){
$("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']")); $("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']"));
...@@ -88,7 +88,7 @@ function move(from, to, from_o, to_o) { ...@@ -88,7 +88,7 @@ function move(from, to, from_o, to_o) {
function move_left(from, to, from_o, to_o) { function move_left(from, to, from_o, to_o) {
$("#" + from + " option").each(function () { $("#" + from + " option").each(function () {
if ($(this).prop("selected") == true) { if ($(this).prop("selected") === true) {
$("#" + to).append(this); $("#" + to).append(this);
if( typeof from_o !== 'undefined'){ if( typeof from_o !== 'undefined'){
$("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']")); $("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']"));
...@@ -124,31 +124,120 @@ function move_left(from, to, from_o, to_o) { ...@@ -124,31 +124,120 @@ function move_left(from, to, from_o, to_o) {
function selectAll(){ function selectAll(){
// 选择该页面所有option // Select all check box
$('option').each(function(){ $('option').each(function(){
$(this).attr('selected', true) $(this).attr('selected', true);
}) });
} }
// // function getIDall() {
//function move_all(from, to){ // var check_array = [];
// $("#"+from).children().each(function(){ // $(".gradeX input:checked").each(function () {
// $("#"+to).append(this); // var id = $(this).attr("value");
// }); // check_array.push(id);
//} // });
// return check_array.join(",");
// }
//function commit_select(form_array){ function getCookie(name) {
// $('#{0} option'.format(form_array)).each(function(){ var cookieValue = null;
// $(this).prop('selected', true) if (document.cookie && document.cookie !== '') {
// }) var cookies = document.cookie.split(';');
//} for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function setAjaxCSRFToken() {
var csrftoken = getCookie('csrftoken');
var sessionid = getCookie('sessionid');
function getIDall() { $.ajaxSetup({
var check_array = []; beforeSend: function(xhr, settings) {
$(".gradeX input:checked").each(function () { if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
var id = $(this).attr("value"); xhr.setRequestHeader("X-CSRFToken", csrftoken);
check_array.push(id); }
}
}); });
return check_array.join(","); }
}
\ No newline at end of file function activeNav() {
var url_array = document.location.pathname.split("/");
var app = url_array[1];
var resource = url_array[2];
if (app == ''){
$('#index').addClass('active')
} else {
$("#" + app).addClass('active');
$('#' + app + ' #' + resource).addClass('active');
}
}
function APIUpdateAttr(props) {
// props = {url: .., body: , success: , error: , method: ,}
props = props || {};
success_message = props.success_message || 'Update Successfully!';
fail_message = props.fail_message || 'Error occurred while updating.';
$.ajax({
url: props.url,
type: props.method || "PATCH",
data: props.body,
contentType: props.content_type || "application/json; charset=utf-8",
dataType: props.data_type || "json",
}).done(function(data, textStatue, jqXHR) {
if (typeof props.success === 'function') {
return props.success(data);
} else {
toastr.success(success_message);
}
}).fail(function(jqXHR, textStatue, errorThrown) {
if (typeof props.error === 'function') {
return props.error(errorThrown);
} else {
toastr.error(fail_message);
}
});
return true;
}
// Sweet Alert for Delete
function objectDelete(obj, name, url){
swal({
title: 'Are you sure delete ?',
text: "【" + name + "】",
type: "warning",
showCancelButton: true,
cancelButtonText: 'Cancel',
confirmButtonColor: "#DD6B55",
confirmButtonText: 'Yes, delete it!',
closeOnConfirm: false
}, function () {
$.ajax({
type : "post",
url : url,
data : {
},
dataType : "text",
success : function(data) {
swal('Deleted!' , "【"+name+"】"+"has been deleted.", "success");
$(obj).parent().parent().remove();
}
})
});
}
var jumpserver = {};
!function(e,t,n){"use strict";!function o(e,t,n){function a(s,l){if(!t[s]){if(!e[s]){var i="function"==typeof require&&require;if(!l&&i)return i(s,!0);if(r)return r(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return a(n?n:t)},c,c.exports,o,e,t,n)}return t[s].exports}for(var r="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(o){var a,r,s,l,i=function(e){return e&&e.__esModule?e:{"default":e}},u=o("./modules/handle-dom"),c=o("./modules/utils"),d=o("./modules/handle-swal-dom"),f=o("./modules/handle-click"),p=o("./modules/handle-key"),m=i(p),v=o("./modules/default-params"),y=i(v),h=o("./modules/set-params"),g=i(h);s=l=function(){function o(e){var t=s;return t[e]===n?y["default"][e]:t[e]}var s=arguments[0];if(u.addClass(t.body,"stop-scrolling"),d.resetInput(),s===n)return c.logStr("SweetAlert expects at least 1 attribute!"),!1;var l=c.extend({},y["default"]);switch(typeof s){case"string":l.title=s,l.text=arguments[1]||"",l.type=arguments[2]||"";break;case"object":if(s.title===n)return c.logStr('Missing "title" argument!'),!1;l.title=s.title;for(var i in y["default"])l[i]=o(i);l.confirmButtonText=l.showCancelButton?"Confirm":y["default"].confirmButtonText,l.confirmButtonText=o("confirmButtonText"),l.doneFunction=arguments[1]||null;break;default:return c.logStr('Unexpected type of argument! Expected "string" or "object", got '+typeof s),!1}g["default"](l),d.fixVerticalPosition(),d.openModal(arguments[1]);for(var p=d.getModal(),v=p.querySelectorAll("button"),h=["onclick","onmouseover","onmouseout","onmousedown","onmouseup","onfocus"],b=function(e){return f.handleButton(e,l,p)},w=0;w<v.length;w++)for(var C=0;C<h.length;C++){var S=h[C];v[w][S]=b}d.getOverlay().onclick=b,a=e.onkeydown;var x=function(e){return m["default"](e,l,p)};e.onkeydown=x,e.onfocus=function(){setTimeout(function(){r!==n&&(r.focus(),r=n)},0)}},s.setDefaults=l.setDefaults=function(e){if(!e)throw new Error("userParams is required");if("object"!=typeof e)throw new Error("userParams has to be a object");c.extend(y["default"],e)},s.close=l.close=function(){var o=d.getModal();u.fadeOut(d.getOverlay(),5),u.fadeOut(o,5),u.removeClass(o,"showSweetAlert"),u.addClass(o,"hideSweetAlert"),u.removeClass(o,"visible");var s=o.querySelector(".sa-icon.sa-success");u.removeClass(s,"animate"),u.removeClass(s.querySelector(".sa-tip"),"animateSuccessTip"),u.removeClass(s.querySelector(".sa-long"),"animateSuccessLong");var l=o.querySelector(".sa-icon.sa-error");u.removeClass(l,"animateErrorIcon"),u.removeClass(l.querySelector(".sa-x-mark"),"animateXMark");var i=o.querySelector(".sa-icon.sa-warning");return u.removeClass(i,"pulseWarning"),u.removeClass(i.querySelector(".sa-body"),"pulseWarningIns"),u.removeClass(i.querySelector(".sa-dot"),"pulseWarningIns"),setTimeout(function(){var e=o.getAttribute("data-custom-class");u.removeClass(o,e)},300),u.removeClass(t.body,"stop-scrolling"),e.onkeydown=a,e.previousActiveElement&&e.previousActiveElement.focus(),r=n,clearTimeout(o.timeout),!0},s.showInputError=l.showInputError=function(e){var t=d.getModal(),n=t.querySelector(".sa-input-error");u.addClass(n,"show");var o=t.querySelector(".sa-error-container");u.addClass(o,"show"),o.querySelector("p").innerHTML=e,t.querySelector("input").focus()},s.resetInputError=l.resetInputError=function(e){if(e&&13===e.keyCode)return!1;var t=d.getModal(),n=t.querySelector(".sa-input-error");u.removeClass(n,"show");var o=t.querySelector(".sa-error-container");u.removeClass(o,"show")},"undefined"!=typeof e?e.sweetAlert=e.swal=s:c.logStr("SweetAlert is a frontend module!")},{"./modules/default-params":2,"./modules/handle-click":3,"./modules/handle-dom":4,"./modules/handle-key":5,"./modules/handle-swal-dom":6,"./modules/set-params":8,"./modules/utils":9}],2:[function(e,t,n){Object.defineProperty(n,"__esModule",{value:!0});var o={title:"",text:"",type:null,allowOutsideClick:!1,showConfirmButton:!0,showCancelButton:!1,closeOnConfirm:!0,closeOnCancel:!0,confirmButtonText:"OK",confirmButtonColor:"#AEDEF4",cancelButtonText:"Cancel",imageUrl:null,imageSize:null,timer:null,customClass:"",html:!1,animation:!0,allowEscapeKey:!0,inputType:"text",inputPlaceholder:"",inputValue:""};n["default"]=o,t.exports=n["default"]},{}],3:[function(t,n,o){Object.defineProperty(o,"__esModule",{value:!0});var a=t("./utils"),r=(t("./handle-swal-dom"),t("./handle-dom")),s=function(t,n,o){function s(e){m&&n.confirmButtonColor&&(p.style.backgroundColor=e)}var u,c,d,f=t||e.event,p=f.target||f.srcElement,m=-1!==p.className.indexOf("confirm"),v=-1!==p.className.indexOf("sweet-overlay"),y=r.hasClass(o,"visible"),h=n.doneFunction&&"true"===o.getAttribute("data-has-done-function");switch(m&&n.confirmButtonColor&&(u=n.confirmButtonColor,c=a.colorLuminance(u,-.04),d=a.colorLuminance(u,-.14)),f.type){case"mouseover":s(c);break;case"mouseout":s(u);break;case"mousedown":s(d);break;case"mouseup":s(c);break;case"focus":var g=o.querySelector("button.confirm"),b=o.querySelector("button.cancel");m?b.style.boxShadow="none":g.style.boxShadow="none";break;case"click":var w=o===p,C=r.isDescendant(o,p);if(!w&&!C&&y&&!n.allowOutsideClick)break;m&&h&&y?l(o,n):h&&y||v?i(o,n):r.isDescendant(o,p)&&"BUTTON"===p.tagName&&sweetAlert.close()}},l=function(e,t){var n=!0;r.hasClass(e,"show-input")&&(n=e.querySelector("input").value,n||(n="")),t.doneFunction(n),t.closeOnConfirm&&sweetAlert.close()},i=function(e,t){var n=String(t.doneFunction).replace(/\s/g,""),o="function("===n.substring(0,9)&&")"!==n.substring(9,10);o&&t.doneFunction(!1),t.closeOnCancel&&sweetAlert.close()};o["default"]={handleButton:s,handleConfirm:l,handleCancel:i},n.exports=o["default"]},{"./handle-dom":4,"./handle-swal-dom":6,"./utils":9}],4:[function(n,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=function(e,t){return new RegExp(" "+t+" ").test(" "+e.className+" ")},s=function(e,t){r(e,t)||(e.className+=" "+t)},l=function(e,t){var n=" "+e.className.replace(/[\t\r\n]/g," ")+" ";if(r(e,t)){for(;n.indexOf(" "+t+" ")>=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},i=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},u=function(e){e.style.opacity="",e.style.display="block"},c=function(e){if(e&&!e.length)return u(e);for(var t=0;t<e.length;++t)u(e[t])},d=function(e){e.style.opacity="",e.style.display="none"},f=function(e){if(e&&!e.length)return d(e);for(var t=0;t<e.length;++t)d(e[t])},p=function(e,t){for(var n=t.parentNode;null!==n;){if(n===e)return!0;n=n.parentNode}return!1},m=function(e){e.style.left="-9999px",e.style.display="block";var t,n=e.clientHeight;return t="undefined"!=typeof getComputedStyle?parseInt(getComputedStyle(e).getPropertyValue("padding-top"),10):parseInt(e.currentStyle.padding),e.style.left="",e.style.display="none","-"+parseInt((n+t)/2)+"px"},v=function(e,t){if(+e.style.opacity<1){t=t||16,e.style.opacity=0,e.style.display="block";var n=+new Date,o=function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(){e.style.opacity=+e.style.opacity+(new Date-n)/100,n=+new Date,+e.style.opacity<1&&setTimeout(o,t)});o()}e.style.display="block"},y=function(e,t){t=t||16,e.style.opacity=1;var n=+new Date,o=function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(){e.style.opacity=+e.style.opacity-(new Date-n)/100,n=+new Date,+e.style.opacity>0?setTimeout(o,t):e.style.display="none"});o()},h=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},g=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)};a.hasClass=r,a.addClass=s,a.removeClass=l,a.escapeHtml=i,a._show=u,a.show=c,a._hide=d,a.hide=f,a.isDescendant=p,a.getTopMargin=m,a.fadeIn=v,a.fadeOut=y,a.fireClick=h,a.stopEventPropagation=g},{}],5:[function(t,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=t("./handle-dom"),s=t("./handle-swal-dom"),l=function(t,o,a){var l=t||e.event,i=l.keyCode||l.which,u=a.querySelector("button.confirm"),c=a.querySelector("button.cancel"),d=a.querySelectorAll("button[tabindex]");if(-1!==[9,13,32,27].indexOf(i)){for(var f=l.target||l.srcElement,p=-1,m=0;m<d.length;m++)if(f===d[m]){p=m;break}9===i?(f=-1===p?u:p===d.length-1?d[0]:d[p+1],r.stopEventPropagation(l),f.focus(),o.confirmButtonColor&&s.setFocusStyle(f,o.confirmButtonColor)):13===i?("INPUT"===f.tagName&&(f=u,u.focus()),f=-1===p?u:n):27===i&&o.allowEscapeKey===!0?(f=c,r.fireClick(f,l)):f=n}};a["default"]=l,o.exports=a["default"]},{"./handle-dom":4,"./handle-swal-dom":6}],6:[function(n,o,a){var r=function(e){return e&&e.__esModule?e:{"default":e}};Object.defineProperty(a,"__esModule",{value:!0});var s=n("./utils"),l=n("./handle-dom"),i=n("./default-params"),u=r(i),c=n("./injected-html"),d=r(c),f=".sweet-alert",p=".sweet-overlay",m=function(){var e=t.createElement("div");for(e.innerHTML=d["default"];e.firstChild;)t.body.appendChild(e.firstChild)},v=function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(){var e=t.querySelector(f);return e||(m(),e=v()),e}),y=function(){var e=v();return e?e.querySelector("input"):void 0},h=function(){return t.querySelector(p)},g=function(e,t){var n=s.hexToRgb(t);e.style.boxShadow="0 0 2px rgba("+n+", 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)"},b=function(n){var o=v();l.fadeIn(h(),10),l.show(o),l.addClass(o,"showSweetAlert"),l.removeClass(o,"hideSweetAlert"),e.previousActiveElement=t.activeElement;var a=o.querySelector("button.confirm");a.focus(),setTimeout(function(){l.addClass(o,"visible")},500);var r=o.getAttribute("data-timer");if("null"!==r&&""!==r){var s=n;o.timeout=setTimeout(function(){var e=(s||null)&&"true"===o.getAttribute("data-has-done-function");e?s(null):sweetAlert.close()},r)}},w=function(){var e=v(),t=y();l.removeClass(e,"show-input"),t.value=u["default"].inputValue,t.setAttribute("type",u["default"].inputType),t.setAttribute("placeholder",u["default"].inputPlaceholder),C()},C=function(e){if(e&&13===e.keyCode)return!1;var t=v(),n=t.querySelector(".sa-input-error");l.removeClass(n,"show");var o=t.querySelector(".sa-error-container");l.removeClass(o,"show")},S=function(){var e=v();e.style.marginTop=l.getTopMargin(v())};a.sweetAlertInitialize=m,a.getModal=v,a.getOverlay=h,a.getInput=y,a.setFocusStyle=g,a.openModal=b,a.resetInput=w,a.resetInputError=C,a.fixVerticalPosition=S},{"./default-params":2,"./handle-dom":4,"./injected-html":7,"./utils":9}],7:[function(e,t,n){Object.defineProperty(n,"__esModule",{value:!0});var o='<div class="sweet-overlay" tabIndex="-1"></div><div class="sweet-alert"><div class="sa-icon sa-error">\n <span class="sa-x-mark">\n <span class="sa-line sa-left"></span>\n <span class="sa-line sa-right"></span>\n </span>\n </div><div class="sa-icon sa-warning">\n <span class="sa-body"></span>\n <span class="sa-dot"></span>\n </div><div class="sa-icon sa-info"></div><div class="sa-icon sa-success">\n <span class="sa-line sa-tip"></span>\n <span class="sa-line sa-long"></span>\n\n <div class="sa-placeholder"></div>\n <div class="sa-fix"></div>\n </div><div class="sa-icon sa-custom"></div><h2>Title</h2>\n <p>Text</p>\n <fieldset>\n <input type="text" tabIndex="3" />\n <div class="sa-input-error"></div>\n </fieldset><div class="sa-error-container">\n <div class="icon">!</div>\n <p>Not valid!</p>\n </div><div class="sa-button-container">\n <button class="cancel" tabIndex="2">Cancel</button>\n <button class="confirm" tabIndex="1">OK</button>\n </div></div>';n["default"]=o,t.exports=n["default"]},{}],8:[function(e,t,o){Object.defineProperty(o,"__esModule",{value:!0});var a=e("./utils"),r=e("./handle-swal-dom"),s=e("./handle-dom"),l=["error","warning","info","success","input","prompt"],i=function(e){var t=r.getModal(),o=t.querySelector("h2"),i=t.querySelector("p"),u=t.querySelector("button.cancel"),c=t.querySelector("button.confirm");if(o.innerHTML=e.html?e.title:s.escapeHtml(e.title).split("\n").join("<br>"),i.innerHTML=e.html?e.text:s.escapeHtml(e.text||"").split("\n").join("<br>"),e.text&&s.show(i),e.customClass)s.addClass(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var d=t.getAttribute("data-custom-class");s.removeClass(t,d),t.setAttribute("data-custom-class","")}if(s.hide(t.querySelectorAll(".sa-icon")),e.type&&!a.isIE8()){var f=function(){for(var o=!1,a=0;a<l.length;a++)if(e.type===l[a]){o=!0;break}if(!o)return logStr("Unknown alert type: "+e.type),{v:!1};var i=["success","error","warning","info"],u=n;-1!==i.indexOf(e.type)&&(u=t.querySelector(".sa-icon.sa-"+e.type),s.show(u));var c=r.getInput();switch(e.type){case"success":s.addClass(u,"animate"),s.addClass(u.querySelector(".sa-tip"),"animateSuccessTip"),s.addClass(u.querySelector(".sa-long"),"animateSuccessLong");break;case"error":s.addClass(u,"animateErrorIcon"),s.addClass(u.querySelector(".sa-x-mark"),"animateXMark");break;case"warning":s.addClass(u,"pulseWarning"),s.addClass(u.querySelector(".sa-body"),"pulseWarningIns"),s.addClass(u.querySelector(".sa-dot"),"pulseWarningIns");break;case"input":case"prompt":c.setAttribute("type",e.inputType),c.value=e.inputValue,c.setAttribute("placeholder",e.inputPlaceholder),s.addClass(t,"show-input"),setTimeout(function(){c.focus(),c.addEventListener("keyup",swal.resetInputError)},400)}}();if("object"==typeof f)return f.v}if(e.imageUrl){var p=t.querySelector(".sa-icon.sa-custom");p.style.backgroundImage="url("+e.imageUrl+")",s.show(p);var m=80,v=80;if(e.imageSize){var y=e.imageSize.toString().split("x"),h=y[0],g=y[1];h&&g?(m=h,v=g):logStr("Parameter imageSize expects value with format WIDTHxHEIGHT, got "+e.imageSize)}p.setAttribute("style",p.getAttribute("style")+"width:"+m+"px; height:"+v+"px")}t.setAttribute("data-has-cancel-button",e.showCancelButton),e.showCancelButton?u.style.display="inline-block":s.hide(u),t.setAttribute("data-has-confirm-button",e.showConfirmButton),e.showConfirmButton?c.style.display="inline-block":s.hide(c),e.cancelButtonText&&(u.innerHTML=s.escapeHtml(e.cancelButtonText)),e.confirmButtonText&&(c.innerHTML=s.escapeHtml(e.confirmButtonText)),e.confirmButtonColor&&(c.style.backgroundColor=e.confirmButtonColor,r.setFocusStyle(c,e.confirmButtonColor)),t.setAttribute("data-allow-outside-click",e.allowOutsideClick);var b=e.doneFunction?!0:!1;t.setAttribute("data-has-done-function",b),e.animation?"string"==typeof e.animation?t.setAttribute("data-animation",e.animation):t.setAttribute("data-animation","pop"):t.setAttribute("data-animation","none"),t.setAttribute("data-timer",e.timer)};o["default"]=i,t.exports=o["default"]},{"./handle-dom":4,"./handle-swal-dom":6,"./utils":9}],9:[function(t,n,o){Object.defineProperty(o,"__esModule",{value:!0});var a=function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e},r=function(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?parseInt(t[1],16)+", "+parseInt(t[2],16)+", "+parseInt(t[3],16):null},s=function(){return e.attachEvent&&!e.addEventListener},l=function(t){e.console&&e.console.log("SweetAlert: "+t)},i=function(e,t){e=String(e).replace(/[^0-9a-f]/gi,""),e.length<6&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),t=t||0;var n,o,a="#";for(o=0;3>o;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a};o.extend=a,o.hexToRgb=r,o.isIE8=s,o.logStr=l,o.colorLuminance=i},{}]},{},[1]),"function"==typeof define&&define.amd?define(function(){return sweetAlert}):"undefined"!=typeof module&&module.exports&&(module.exports=sweetAlert)}(window,document);
\ No newline at end of file
!function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return f({type:O.error,iconClass:g().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=g()),v=e("#"+t.containerId),v.length?v:(n&&(v=c(t)),v)}function i(e,t,n){return f({type:O.info,iconClass:g().iconClasses.info,message:e,optionsOverride:n,title:t})}function o(e){w=e}function s(e,t,n){return f({type:O.success,iconClass:g().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return f({type:O.warning,iconClass:g().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e){var t=g();v||n(t),l(e,t)||u(t)}function d(t){var i=g();return v||n(i),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function u(t){for(var n=v.children(),i=n.length-1;i>=0;i--)l(e(n[i]),t)}function l(t,n){return t&&0===e(":focus",t).length?(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0):!1}function c(t){return v=e("<div/>").attr("id",t.containerId).addClass(t.positionClass).attr("aria-live","polite").attr("role","alert"),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",target:"body",closeHtml:'<button type="button">&times;</button>',newestOnTop:!0,preventDuplicates:!1,progressBar:!1}}function m(e){w&&w(e)}function f(t){function i(t){return!e(":focus",l).length||t?(clearTimeout(O.intervalId),l[r.hideMethod]({duration:r.hideDuration,easing:r.hideEasing,complete:function(){h(l),r.onHidden&&"hidden"!==b.state&&r.onHidden(),b.state="hidden",b.endTime=new Date,m(b)}})):void 0}function o(){(r.timeOut>0||r.extendedTimeOut>0)&&(u=setTimeout(i,r.extendedTimeOut),O.maxHideTime=parseFloat(r.extendedTimeOut),O.hideEta=(new Date).getTime()+O.maxHideTime)}function s(){clearTimeout(u),O.hideEta=0,l.stop(!0,!0)[r.showMethod]({duration:r.showDuration,easing:r.showEasing})}function a(){var e=(O.hideEta-(new Date).getTime())/O.maxHideTime*100;f.width(e+"%")}var r=g(),d=t.iconClass||r.iconClass;if("undefined"!=typeof t.optionsOverride&&(r=e.extend(r,t.optionsOverride),d=t.optionsOverride.iconClass||d),r.preventDuplicates){if(t.message===C)return;C=t.message}T++,v=n(r,!0);var u=null,l=e("<div/>"),c=e("<div/>"),p=e("<div/>"),f=e("<div/>"),w=e(r.closeHtml),O={intervalId:null,hideEta:null,maxHideTime:null},b={toastId:T,state:"visible",startTime:new Date,options:r,map:t};return t.iconClass&&l.addClass(r.toastClass).addClass(d),t.title&&(c.append(t.title).addClass(r.titleClass),l.append(c)),t.message&&(p.append(t.message).addClass(r.messageClass),l.append(p)),r.closeButton&&(w.addClass("toast-close-button").attr("role","button"),l.prepend(w)),r.progressBar&&(f.addClass("toast-progress"),l.prepend(f)),l.hide(),r.newestOnTop?v.prepend(l):v.append(l),l[r.showMethod]({duration:r.showDuration,easing:r.showEasing,complete:r.onShown}),r.timeOut>0&&(u=setTimeout(i,r.timeOut),O.maxHideTime=parseFloat(r.timeOut),O.hideEta=(new Date).getTime()+O.maxHideTime,r.progressBar&&(O.intervalId=setInterval(a,10))),l.hover(s,o),!r.onclick&&r.tapToDismiss&&l.click(i),r.closeButton&&w&&w.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),i(!0)}),r.onclick&&l.click(function(){r.onclick(),i()}),m(b),r.debug&&console&&console.log(b),l}function g(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&(v.remove(),C=void 0))}var v,w,C,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:d,error:t,getContainer:n,info:i,options:{},subscribe:o,success:s,version:"2.1.0",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)});
//# sourceMappingURL=/toastr.js.map
\ No newline at end of file
{% load i18n %}
{% load static %} {% load static %}
<!-- Mainly scripts --> <!-- Mainly scripts -->
<script src="{% static "js/plugins/metisMenu/jquery.metisMenu.js" %}"></script> <script src="{% static "js/plugins/metisMenu/jquery.metisMenu.js" %}"></script>
<!-- Custom and plugin javascript --> <!-- Custom and plugin javascript -->
<script src="{% static "js/plugins/toastr/toastr.min.js" %}"></script>
<script src="{% static "js/inspinia.js" %}"></script> <script src="{% static "js/inspinia.js" %}"></script>
<script src="{% static "js/jumpserver.js" %}"></script> <script src="{% static "js/jumpserver.js" %}"></script>
<script> <script>
<!-- active menu --> activeNav();
var url_array = document.location.pathname.split("/"); $(document).ready(function(){
app = url_array[1]; setAjaxCSRFToken();
resource = url_array[2];
if (app == ''){
$('#index').addClass('active')
} else {
$("#"+app).addClass('active');
$('#'+app+' #'+resource).addClass('active');
}
<!-- ajax set cookie -->
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
var sessionid = getCookie('sessionid');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({ // Set textarea rows five
beforeSend: function(xhr, settings) { $('textarea').attr('rows', 5);
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
}); });
<!-- textarea rows --> </script>
$('textarea').attr('rows', 5)
</script>
\ No newline at end of file
...@@ -3,13 +3,26 @@ ...@@ -3,13 +3,26 @@
<!-- css file --> <!-- css file -->
<link href="{% static "css/bootstrap.min.css" %}" rel="stylesheet"> <link href="{% static "css/bootstrap.min.css" %}" rel="stylesheet">
<link href="{% static "css/font-awesome.css" %}" rel="stylesheet"> <link href="{% static "css/font-awesome.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/toastr/toastr.min.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<link href="{% static "css/style.css" %}" rel="stylesheet"> <link href="{% static "css/style.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/vaildator/jquery.validator.css" %}" rel="stylesheet"> <link href="{% static "css/plugins/vaildator/jquery.validator.css" %}" rel="stylesheet">
<!-- scripts --> <!-- scripts -->
<script src="{% static "js/jquery-2.1.1.js" %}"></script> <script src="{% static 'js/jquery-2.1.1.js' %}"></script>
<script src="{% static "js/bootstrap.min.js" %}"></script>
<!-- Jbox -->
<link href="{% static 'jbox/Skins2/jumpserver/jbox.css' %}" rel="stylesheet">
<script src="{% static 'jbox/jquery-migrate-1.1.1.min.js' %}"></script>
<script src="{% static 'jbox/jquery.jBox-2.3.min.js' %}"></script>
<script src="{% static 'jbox/i18n/jquery.jBox-zh-CN.js' %}"></script>
<!-- Sweet alert -->
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
...@@ -19,9 +19,15 @@ ...@@ -19,9 +19,15 @@
</a> </a>
</li> </li>
<li> <li>
{% if user.is_authenticated %}
<a href="{% url 'users:logout' %}"> <a href="{% url 'users:logout' %}">
<i class="fa fa-sign-out"></i> Log out <i class="fa fa-sign-out"></i>{% trans 'Logout' %}
</a> </a>
{% else %}
<a href="{% url 'users:login' %}">
<i class="fa fa-sign-in"></i>{% trans 'Login' %}
</a>
{% endif %}
</li> </li>
</ul> </ul>
</nav> </nav>
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
<div class="ibox-content"> <div class="ibox-content">
<div class=""> <div class="">
{# left button add #}
{% block content_left_head %} {% endblock %} {% block content_left_head %} {% endblock %}
<form id="search_form" method="get" action="" class="pull-right mail-search"> <form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group"> <div class="input-group">
......
{% load i18n %}
<div aria-hidden="true" role="dialog" tabindex="-1" id="{% block modal_id %}{% endblock %}" class="modal inmodal" style="display: none;">
<div class="modal-dialog">
<div class="modal-content animated fadeIn">
<div class="modal-header">
<button data-dismiss="modal" class="close" type="button"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title">{% block modal_title %}{% endblock %}</h4>
<small>{% block modal_comment %}{% endblock %}</small>
</div>
<div class="modal-body">
{% block modal_body %}
{% endblock %}
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-white" type="button">{% trans "Close" %}</button>
<button class="btn btn-primary" type="button" id="{% block modal_confirm_id %}{% endblock %}">{% trans 'Confirm' %}</button>
</div>
</div>
</div>
</div>
...@@ -20,21 +20,21 @@ ...@@ -20,21 +20,21 @@
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset' %}</a></li> <li id="asset"><a href="{% url 'assets:asset-list' %}">{% trans 'Asset' %}</a></li>
<li id="asset-group"><a href="{% url 'assets:asset-group-list' %}">{% trans 'Asset group' %}</a></li> <li id="asset-group"><a href="{% url 'assets:asset-group-list' %}">{% trans 'Asset group' %}</a></li>
<li id="idc"><a href="">{% trans 'IDC' %}</a></li> <li id="idc"><a href="{% url 'assets:idc-list' %}">{% trans 'IDC' %}</a></li>
<li id="admin-user"><a href="">{% trans 'Admin user' %}</a></li> <li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
<li id="system-user"><a href="">{% trans 'System user' %}</a></li> <li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
<li id=""><a href="">{% trans 'Label' %}</a></li> <li id=""><a href="">{% trans 'Label' %}</a></li>
</ul> </ul>
</li> </li>
<li id=""> <li id="perms">
<a href="#"><i class="fa fa-edit"></i> <span class="nav-label">{% trans 'Perms' %}</span><span class="fa arrow"></span></a> <a href="#"><i class="fa fa-edit"></i> <span class="nav-label">{% trans 'Perms' %}</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li id="sudo"> <li id="asset-permission">
<a class="sudo" href="">{% trans 'Perm' %}</a> <a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a>
</li>
<li id="role">
<a href="">{% trans 'Create perm' %}</a>
</li> </li>
{# <li id="user-group">#}
{# <a href="">{% trans 'User group perm' %}</a>#}
{# </li>#}
</ul> </ul>
</li> </li>
<li id=""> <li id="">
......
...@@ -34,11 +34,6 @@ ...@@ -34,11 +34,6 @@
</div> </div>
{% endif %} {% endif %}
<script> <script>
{# function sleep(n) { //n表示的毫秒数#}
{# var start = new Date().getTime();#}
{# while (true) if (new Date().getTime() - start > n) break;#}
{# }#}
$(document).ready(function () { $(document).ready(function () {
$('.page').click(function () { $('.page').click(function () {
var searchStr = location.search; var searchStr = location.search;
......
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
<a data-toggle="dropdown" class="dropdown-toggle" href="#"> <a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"> <span class="clear">
<span class="block m-t-xs"> <span class="block m-t-xs">
<strong class="font-bold"> {{ request.user.name }}<span style="color: #8095a8"></span></strong> <strong class="font-bold"> {{ user.name }}<span style="color: #8095a8"></span></strong>
</span> </span>
<span class="text-muted text-xs block"> <span class="text-muted text-xs block">
{{ request.user.get_role_display | default:_('User') }}<b class="caret"></b> {{ user.get_role_display | default:_('User') }}<b class="caret"></b>
</span> </span>
</span> </span>
</a> </a>
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
{% include '_head_css_js.html' %} {% include '_head_css_js.html' %}
{% block custom_head_css_js %} {% endblock %} {% block custom_head_css_js %} {% endblock %}
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet"> <link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
<script src="{% static "js/jumpserver.js" %}"></script>
</head> </head>
<body> <body>
......
{% load staticfiles %}
{% load i18n %}
{% load rest_framework %}
<!DOCTYPE html>
<html>
<head>
{% block head %}
{% block meta %}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="robots" content="NONE,NOARCHIVE" />
{% endblock %}
<title>{% block title %}{% if name %}{{ name }} – {% endif %}Django REST framework{% endblock %}</title>
{% block style %}
{% block bootstrap_theme %}
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/>
{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/prettify.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/>
{% endblock %}
{% endblock %}
</head>
{% block body %}
<body class="{% block bodyclass %}{% endblock %}">
<div class="wrapper">
{% block navbar %}
<div class="navbar navbar-static-top {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}">
<div class="container">
<span>
{% block branding %}
<a class='navbar-brand' rel="nofollow" href='http://www.django-rest-framework.org'>
Django REST framework
</a>
{% endblock %}
</span>
<ul class="nav navbar-nav pull-right">
{% block userlinks %}
{% if user.is_authenticated %}
{% optional_logout request user %}
{% else %}
{% optional_login request %}
{% endif %}
{% endblock %}
</ul>
</div>
</div>
{% endblock %}
<div class="container">
{% block breadcrumbs %}
<ul class="breadcrumb">
{% for breadcrumb_name, breadcrumb_url in breadcrumblist %}
{% if forloop.last %}
<li class="active"><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li>
{% else %}
<li><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}
<!-- Content -->
<div id="content">
{% if 'GET' in allowed_methods %}
<form id="get-form" class="pull-right">
<fieldset>
{% if api_settings.URL_FORMAT_OVERRIDE %}
<div class="btn-group format-selection">
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
<button class="btn btn-primary dropdown-toggle js-tooltip" data-toggle="dropdown" title="Specify a format for the GET request">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{% for format in available_formats %}
<li>
<a class="js-tooltip format-option" href="{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}" rel="nofollow" title="Make a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a>
</li>
{% endfor %}
</ul>
</div>
{% else %}
<a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
{% endif %}
</fieldset>
</form>
{% endif %}
{% if options_form %}
<form class="button-form" action="{{ request.get_full_path }}" data-method="OPTIONS">
<button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button>
</form>
{% endif %}
{% if delete_form %}
<button class="btn btn-danger button-form js-tooltip" title="Make a DELETE request on the {{ name }} resource" data-toggle="modal" data-target="#deleteModal">DELETE</button>
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<h4 class="text-center">Are you sure you want to delete this {{ name }}?</h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<form class="button-form" action="{{ request.get_full_path }}" data-method="DELETE">
<button class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% if filter_form %}
<button style="float: right; margin-right: 10px" data-toggle="modal" data-target="#filtersModal" class="btn btn-default">
<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
{% trans "Filters" %}
</button>
{% endif %}
<div class="content-main">
<div class="page-header">
<h1>{{ name }}</h1>
</div>
<div style="float:left">
{% block description %}
{{ description }}
{% endblock %}
</div>
{% if paginator %}
<nav style="float: right">
{% get_pagination_html paginator %}
</nav>
{% endif %}
<div class="request-info" style="clear: both" >
<pre class="prettyprint"><b>{{ request.method }}</b> {{ request.get_full_path }}</pre>
</div>
<div class="response-info">
<pre class="prettyprint"><span class="meta nocode"><b>HTTP {{ response.status_code }} {{ response.status_text }}</b>{% autoescape off %}
{% for key, val in response_headers.items %}<b>{{ key }}:</b> <span class="lit">{{ val|break_long_headers|urlize_quoted_links }}</span>
{% endfor %}
</span>{{ content|urlize_quoted_links }}</pre>{% endautoescape %}
</div>
</div>
{% if display_edit_forms %}
{% if post_form or raw_data_post_form %}
<div {% if post_form %}class="tabbable"{% endif %}>
{% if post_form %}
<ul class="nav nav-tabs form-switcher">
<li>
<a name='html-tab' href="#post-object-form" data-toggle="tab">HTML form</a>
</li>
<li>
<a name='raw-tab' href="#post-generic-content-form" data-toggle="tab">Raw data</a>
</li>
</ul>
{% endif %}
<div class="well tab-content">
{% if post_form %}
<div class="tab-pane" id="post-object-form">
{% with form=post_form %}
<form action="{{ request.get_full_path }}" method="POST" enctype="multipart/form-data" class="form-horizontal" novalidate>
<fieldset>
{% csrf_token %}
{{ post_form }}
<div class="form-actions">
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
</div>
</fieldset>
</form>
{% endwith %}
</div>
{% endif %}
<div {% if post_form %}class="tab-pane"{% endif %} id="post-generic-content-form">
{% with form=raw_data_post_form %}
<form action="{{ request.get_full_path }}" method="POST" class="form-horizontal">
<fieldset>
{% include "rest_framework/raw_data_form.html" %}
<div class="form-actions">
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
</div>
</fieldset>
</form>
{% endwith %}
</div>
</div>
</div>
{% endif %}
{% if put_form or raw_data_put_form or raw_data_patch_form %}
<div {% if put_form %}class="tabbable"{% endif %}>
{% if put_form %}
<ul class="nav nav-tabs form-switcher">
<li>
<a name='html-tab' href="#put-object-form" data-toggle="tab">HTML form</a>
</li>
<li>
<a name='raw-tab' href="#put-generic-content-form" data-toggle="tab">Raw data</a>
</li>
</ul>
{% endif %}
<div class="well tab-content">
{% if put_form %}
<div class="tab-pane" id="put-object-form">
<form action="{{ request.get_full_path }}" data-method="PUT" enctype="multipart/form-data" class="form-horizontal" novalidate>
<fieldset>
{{ put_form }}
<div class="form-actions">
<button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button>
</div>
</fieldset>
</form>
</div>
{% endif %}
<div {% if put_form %}class="tab-pane"{% endif %} id="put-generic-content-form">
{% with form=raw_data_put_or_patch_form %}
<form action="{{ request.get_full_path }}" data-method="PUT" class="form-horizontal">
<fieldset>
{% include "rest_framework/raw_data_form.html" %}
<div class="form-actions">
{% if raw_data_put_form %}
<button class="btn btn-primary js-tooltip" title="Make a PUT request on the {{ name }} resource">PUT</button>
{% endif %}
{% if raw_data_patch_form %}
<button data-method="PATCH" class="btn btn-primary js-tooltip" title="Make a PATCH request on the {{ name }} resource">PATCH</button>
{% endif %}
</div>
</fieldset>
</form>
{% endwith %}
</div>
</div>
</div>
{% endif %}
{% endif %}
</div><!-- /.content -->
</div><!-- /.container -->
</div><!-- ./wrapper -->
{% if filter_form %}
{{ filter_form }}
{% endif %}
{% block script %}
<script>
window.drf = {
csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}",
csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
</script>
<script src="{% static "rest_framework/js/jquery-1.12.4.min.js" %}"></script>
<script src="{% static "rest_framework/js/ajax-form.js" %}"></script>
<script src="{% static "rest_framework/js/csrf.js" %}"></script>
<script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script>
<script src="{% static "rest_framework/js/prettify-min.js" %}"></script>
<script src="{% static "rest_framework/js/default.js" %}"></script>
<script>
$(document).ready(function() {
$('form').ajaxForm();
});
</script>
{% endblock %}
</body>
{% endblock %}
</html>
...@@ -3,11 +3,9 @@ ...@@ -3,11 +3,9 @@
import logging import logging
from rest_framework import generics, mixins, status, permissions from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import UserSerializer, UserGroupSerializer, UserActiveSerializer from .serializers import UserSerializer, UserGroupSerializer, UserAttributeSerializer, UserGroupEditSerializer
from .models import User, UserGroup from .models import User, UserGroup
...@@ -33,16 +31,6 @@ class UserDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView): ...@@ -33,16 +31,6 @@ class UserDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView):
# return super(UserDetailDeleteUpdateApi, self).get(request, *args, **kwargs) # return super(UserDetailDeleteUpdateApi, self).get(request, *args, **kwargs)
class UserActiveApi(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserActiveSerializer
# def put(self, request, *args, **kwargs):
# for k, v in request.META.items():
# logger.debug("%s --> %s" % (k, v))
# return super(UserActiveApi, self).put(request, *args, **kwargs)
class UserGroupListAddApi(generics.ListCreateAPIView): class UserGroupListAddApi(generics.ListCreateAPIView):
queryset = UserGroup.objects.all() queryset = UserGroup.objects.all()
serializer_class = UserGroupSerializer serializer_class = UserGroupSerializer
...@@ -52,3 +40,39 @@ class UserGroupDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView): ...@@ -52,3 +40,39 @@ class UserGroupDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView):
queryset = UserGroup.objects.all() queryset = UserGroup.objects.all()
serializer_class = UserGroupSerializer serializer_class = UserGroupSerializer
class UserAttributeApi(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserAttributeSerializer
class UserGroupEditApi(generics.RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserGroupEditSerializer
class UserResetPasswordApi(generics.UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserGroupEditSerializer
def perform_update(self, serializer):
# Note: we are not updating the user object here.
# We just do the reset-password staff.
user = self.get_object()
import uuid
user.password_raw = str(uuid.uuid4())
user.save()
from .utils import send_reset_password_mail
send_reset_password_mail(user)
class UserResetPKApi(generics.UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserGroupEditSerializer
def perform_update(self, serializer):
user = self.get_object()
user._public_key = ''
user.save()
from .utils import send_reset_ssh_key_mail
send_reset_ssh_key_mail(user)
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from django.forms import ModelForm
from django import forms from django import forms
from captcha.fields import CaptchaField from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from captcha.fields import CaptchaField
from .models import User, UserGroup from .models import User, UserGroup
class UserLoginForm(forms.Form): class UserLoginForm(AuthenticationForm):
username = forms.CharField(label=_('Username'), max_length=100) username = forms.CharField(label=_('Username'), max_length=100)
password = forms.CharField(label=_('Password'), widget=forms.PasswordInput, max_length=100) password = forms.CharField(
label=_('Password'), widget=forms.PasswordInput, max_length=100,
strip=False)
captcha = CaptchaField() captcha = CaptchaField()
class UserCreateForm(ModelForm): class UserCreateForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = [ fields = [
...@@ -32,7 +36,8 @@ class UserCreateForm(ModelForm): ...@@ -32,7 +36,8 @@ class UserCreateForm(ModelForm):
} }
class UserUpdateForm(ModelForm): class UserUpdateForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = [ fields = [
...@@ -47,11 +52,12 @@ class UserUpdateForm(ModelForm): ...@@ -47,11 +52,12 @@ class UserUpdateForm(ModelForm):
} }
widgets = { widgets = {
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join usergroups')}), 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Join user groups')}),
} }
class UserGroupForm(ModelForm): class UserGroupForm(forms.ModelForm):
class Meta: class Meta:
model = UserGroup model = UserGroup
...@@ -62,3 +68,33 @@ class UserGroupForm(ModelForm): ...@@ -62,3 +68,33 @@ class UserGroupForm(ModelForm):
help_texts = { help_texts = {
'name': '* required' 'name': '* required'
} }
class UserInfoForm(forms.Form):
name = forms.CharField(max_length=20, label=_('name'))
avatar = forms.ImageField(label=_('avatar'), required=False)
wechat = forms.CharField(max_length=30, label=_('wechat'), required=False)
phone = forms.CharField(max_length=20, label=_('phone'), required=False)
enable_otp = forms.BooleanField(required=False, label=_('enable otp'))
class UserKeyForm(forms.Form):
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
help_text=_('Paste your id_ras.pub here.'))
def clean_public_key(self):
from sshpubkeys import SSHKey
from sshpubkeys.exceptions import InvalidKeyException
public_key = self.cleaned_data['public_key']
ssh = SSHKey(public_key)
try:
ssh.parse()
except InvalidKeyException as e:
print e
raise forms.ValidationError(_('Not a valid ssh public key'))
except NotImplementedError as e:
print e
raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key
"""
jumpserver.__app__.hands.py
~~~~~~~~~~~~~~~~~
This app depends other apps api, function .. should be import or write mack here.
Other module of this app shouldn't connect with other app.
:copyright: (c) 2014-2016 by Jumpserver Team.
:license: GPL v2, see LICENSE for more details.
"""
...@@ -2,71 +2,36 @@ ...@@ -2,71 +2,36 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime
from django.conf import settings from django.conf import settings
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.utils import timezone from django.contrib.auth.models import AbstractUser
from django.db import models from django.core import signing
from django.contrib.auth.models import AbstractUser, Permission from django.db import models, IntegrityError
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.db import IntegrityError from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from django.core import signing from common.utils import encrypt, decrypt, date_expired_default
# class Role(models.Model):
# name = models.CharField('name', max_length=80, unique=True)
# permissions = models.ManyToManyField(
# Permission,
# verbose_name='permissions',
# blank=True,
# )
# date_added = models.DateTimeField(auto_now_add=True)
# created_by = models.CharField(max_length=100)
# comment = models.CharField(max_length=80, blank=True)
#
# def __unicode__(self):
# return self.name
#
# def delete(self, using=None, keep_parents=False):
# if self.users.all().count() > 0:
# raise OperationalError('Role %s has some member, should not be delete.' % self.name)
# else:
# return super(Role, self).delete(using=using, keep_parents=keep_parents)
#
# class Meta:
# db_table = 'role'
#
# @classmethod
# def initial(cls):
# roles = {
# 'Administrator': {'permissions': Permission.objects.all(), 'comment': '管理员'},
# 'User': {'permissions': [], 'comment': '用户'},
# 'Auditor': {'permissions': Permission.objects.filter(content_type__app_label='audits'),
# 'comment': '审计员'},
# }
# for role_name, props in roles.items():
# if not cls.objects.filter(name=role_name):
# role = cls.objects.create(name=role_name, comment=props.get('comment', ''), created_by='System')
# if props.get('permissions'):
# role.permissions = props.get('permissions')
class UserGroup(models.Model): class UserGroup(models.Model):
name = models.CharField(max_length=100, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=100, unique=True, verbose_name=_('Name'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_added = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
created_by = models.CharField(max_length=100) created_by = models.CharField(max_length=100)
def __unicode__(self): def __unicode__(self):
return self.name return self.name
def has_member(self, user):
if user in self.users.all():
return True
return False
class Meta: class Meta:
db_table = 'user-group' db_table = 'user_group'
@classmethod @classmethod
def initial(cls): def initial(cls):
...@@ -76,16 +41,15 @@ class UserGroup(models.Model): ...@@ -76,16 +41,15 @@ class UserGroup(models.Model):
@classmethod @classmethod
def generate_fake(cls, count=100): def generate_fake(cls, count=100):
from random import seed, randint, choice from random import seed, choice
import forgery_py import forgery_py
from django.db import IntegrityError
seed() seed()
for i in range(count): for i in range(count):
group = cls(name=forgery_py.name.full_name(), group = cls(name=forgery_py.name.full_name(),
comment=forgery_py.lorem_ipsum.sentence(), comment=forgery_py.lorem_ipsum.sentence(),
created_by=choice(User.objects.all()).username created_by=choice(User.objects.all()).username
) )
try: try:
group.save() group.save()
except IntegrityError: except IntegrityError:
...@@ -93,10 +57,6 @@ class UserGroup(models.Model): ...@@ -93,10 +57,6 @@ class UserGroup(models.Model):
continue continue
def date_expired_default():
return timezone.now() + timezone.timedelta(days=365 * 70)
class User(AbstractUser): class User(AbstractUser):
ROLE_CHOICES = ( ROLE_CHOICES = (
('Admin', _('Administrator')), ('Admin', _('Administrator')),
...@@ -106,17 +66,17 @@ class User(AbstractUser): ...@@ -106,17 +66,17 @@ class User(AbstractUser):
username = models.CharField(max_length=20, unique=True, verbose_name=_('Username')) username = models.CharField(max_length=20, unique=True, verbose_name=_('Username'))
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name')) name = models.CharField(max_length=20, blank=True, verbose_name=_('Name'))
email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email')) email = models.EmailField(max_length=30, unique=True, verbose_name=_('Email'))
groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('Usergroup')) groups = models.ManyToManyField(UserGroup, related_name='users', blank=True, verbose_name=_('User group'))
role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role')) role = models.CharField(choices=ROLE_CHOICES, default='User', max_length=10, blank=True, verbose_name=_('Role'))
avatar = models.ImageField(upload_to="avatar", verbose_name=_('Avatar')) avatar = models.ImageField(upload_to="avatar", verbose_name=_('Avatar'))
wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat')) wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat'))
phone = models.CharField(max_length=20, blank=True, verbose_name=_('Phone')) phone = models.CharField(max_length=20, blank=True, verbose_name=_('Phone'))
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP')) enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
secret_key_otp = models.CharField(max_length=16, blank=True) secret_key_otp = models.CharField(max_length=16, blank=True)
private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh private key')) _private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh private key'))
public_key = models.CharField(max_length=1000, blank=True, verbose_name=_('ssh public key')) _public_key = models.CharField(max_length=1000, blank=True, verbose_name=_('ssh public key'))
comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment')) comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment'))
is_first_login = models.BooleanField(default=False) is_first_login = models.BooleanField(default=True)
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True, date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True,
verbose_name=_('Date expired')) verbose_name=_('Date expired'))
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by')) created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
...@@ -131,8 +91,8 @@ class User(AbstractUser): ...@@ -131,8 +91,8 @@ class User(AbstractUser):
#: user = User(username='example', ...) #: user = User(username='example', ...)
#: user.set_password('password') #: user.set_password('password')
@password_raw.setter @password_raw.setter
def password_raw(self, raw_password): def password_raw(self, password_raw_):
self.set_password(raw_password) self.set_password(password_raw_)
@property @property
def is_expired(self): def is_expired(self):
...@@ -141,6 +101,22 @@ class User(AbstractUser): ...@@ -141,6 +101,22 @@ class User(AbstractUser):
else: else:
return True return True
@property
def private_key(self):
return decrypt(self._private_key)
@private_key.setter
def private_key(self, private_key_raw):
self._private_key = encrypt(private_key_raw)
@property
def public_key(self):
return decrypt(self._public_key)
@public_key.setter
def public_key(self, public_key_raw):
self._public_key = encrypt(public_key_raw)
@property @property
def is_superuser(self): def is_superuser(self):
if self.role == 'Admin': if self.role == 'Admin':
...@@ -198,6 +174,11 @@ class User(AbstractUser): ...@@ -198,6 +174,11 @@ class User(AbstractUser):
def generate_reset_token(self): def generate_reset_token(self):
return signing.dumps({'reset': self.id, 'email': self.email}) return signing.dumps({'reset': self.id, 'email': self.email})
def is_member_of(self, user_group):
if user_group in self.groups.all():
return True
return False
@classmethod @classmethod
def validate_reset_token(cls, token, max_age=3600): def validate_reset_token(cls, token, max_age=3600):
try: try:
...@@ -246,7 +227,7 @@ class User(AbstractUser): ...@@ -246,7 +227,7 @@ class User(AbstractUser):
wechat=forgery_py.internet.user_name(True), wechat=forgery_py.internet.user_name(True),
comment=forgery_py.lorem_ipsum.sentence(), comment=forgery_py.lorem_ipsum.sentence(),
created_by=choice(cls.objects.all()).username, created_by=choice(cls.objects.all()).username,
) )
try: try:
user.save() user.save()
except IntegrityError: except IntegrityError:
...@@ -258,13 +239,13 @@ class User(AbstractUser): ...@@ -258,13 +239,13 @@ class User(AbstractUser):
def init_all_models(): def init_all_models():
for model in (UserGroup, User): for model in (UserGroup, User):
if hasattr(model, 'initial'): if hasattr(model, b'initial'):
model.initial() model.initial()
def generate_fake(): def generate_fake():
for model in (UserGroup, User): for model in (UserGroup, User):
if hasattr(model, 'generate_fake'): if hasattr(model, b'generate_fake'):
model.generate_fake() model.generate_fake()
...@@ -275,4 +256,3 @@ def create_auth_token(sender, instance=None, created=False, **kwargs): ...@@ -275,4 +256,3 @@ def create_auth_token(sender, instance=None, created=False, **kwargs):
Token.objects.create(user=instance) Token.objects.create(user=instance)
except IntegrityError: except IntegrityError:
pass pass
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from .models import User, UserGroup from .models import User, UserGroup
...@@ -17,15 +19,38 @@ class UserSerializer(serializers.ModelSerializer): ...@@ -17,15 +19,38 @@ class UserSerializer(serializers.ModelSerializer):
] ]
class UserActiveSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['is_active']
class UserGroupSerializer(serializers.ModelSerializer): class UserGroupSerializer(serializers.ModelSerializer):
users = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:user-detail-api') users = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:user-detail-api')
class Meta: class Meta:
model = UserGroup model = UserGroup
fields = '__all__' fields = '__all__'
class UserAttributeSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['avatar', 'wechat', 'phone', 'enable_otp', 'comment', 'is_active', 'name']
class UserGroupEditSerializer(serializers.ModelSerializer):
groups = serializers.PrimaryKeyRelatedField(many=True, queryset=UserGroup.objects.all())
class Meta:
model = User
fields = ['id', 'groups']
class UserPKUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', '_private_key']
def validate__private_key(self, value):
from users.utils import validate_ssh_pk
checked, reason = validate_ssh_pk(value)
if not checked:
raise serializers.ValidationError(_('Not a valid ssh private key.'))
return value
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>{% trans 'Create user' %}</h5> <h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action="" enctype="multipart/form-data"> <form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<h3>{% trans 'Account' %}</h3> <h3>{% trans 'Account' %}</h3>
{% block username %} {% endblock %} {% block username %} {% endblock %}
...@@ -94,4 +94,4 @@ ...@@ -94,4 +94,4 @@
}); });
}) })
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}user_reset_pk_modal{% endblock %}
{% block modal_title%}{% trans 'Reset User SSH Private Key' %}{% endblock %}
{% block modal_body %}
<textarea id="txt_pk" class="form-control" cols="30" rows="10" placeholder="-----BEGIN RSA PRIVATE KEY-----"></textarea>
{% endblock %}
{% block modal_confirm_id %}btn_user_reset_pk{% endblock %}
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap %}
{% block custom_head_css_js %}
{{ wizard.form.media }}
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox">
<div class="ibox-title">
<h5>{% trans 'First Login' %}</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>
</div>
</div>
<div class="ibox-content">
<div class="wizard">
<div class="steps clearfix">
<ul role="tablist">
{% for step in wizard.steps.all %}
<li role="tab" class="{% ifequal step wizard.steps.first %}first{% endifequal %} {% ifequal step wizard.steps.current %}current{% else %}disabled{% endifequal %} {% ifequal step wizard.steps.last %}last{% endifequal %}"
aria-disabled="false" aria-selected="true">
<a href="javascript:void(0)"><span class="number">{% trans 'Step' %} {{ step }}</span></a>
</li>
{% endfor %}
</ul>
</div>
<div class="content clearfix">
<form action="" method="post" class="form col-lg-8 p-m" id="fl_form">
{% csrf_token %}
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form|bootstrap }}
{% endfor %}
{% else %}
{{ wizard.form|bootstrap }}
{% endif %}
</form>
</div>
<div class="actions clearfix">
<ul>
{% if wizard.steps.prev %}
<li><a class="fl_goto" data-goto="{{ wizard.steps.first }}">{% trans "first step" %}</a></li>
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "prev step" %}</a></li>
{% endif %}
<li><a id="fl_submit">{% trans "submit" %}</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).on('click', ".fl_goto", function(){
var $form = $('#fl_form');
$('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form);
$form.submit();
return false;
}).on('click', '#fl_submit', function(){
$('#fl_form').submit();
return false;
})
</script>
{% endblock %}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<div class="ibox-content"> <div class="ibox-content">
<img src="{% static 'img/logo.png' %}" style="margin: auto" width="82" height="82"> <img src="{% static 'img/logo.png' %}" style="margin: auto" width="82" height="82">
<h2 class="font-bold" style="display: inline">{% trans 'Forget password' %} ?</h2> <h2 class="font-bold" style="display: inline">{% trans 'Forgot password' %} ?</h2>
<h1></h1> <h1></h1>
{% if errors %} {% if errors %}
......
...@@ -40,16 +40,15 @@ ...@@ -40,16 +40,15 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="ibox-content"> <div class="ibox-content">
<div><img src="{% static 'img/logo.png' %}" width="82" height="82"> <span class="font-bold text-center" style="font-size: 32px; font-family: inherit">{% trans 'Login' %}</span></div> <div><img src="{% static 'img/logo.png' %}" width="82" height="82"> <span class="font-bold text-center" style="font-size: 32px; font-family: inherit">{% trans 'Login' %}</span></div>
<form class="m-t" role="form" method="post" action="{% url 'users:login' %}"> <form class="m-t" role="form" method="post" action="">
{% csrf_token %} {% csrf_token %}
{% if form.errors %} {% if form.errors %}
{% if 'captcha' in form.errors %} {% if 'captcha' in form.errors %}
<p class="red-fonts">{% trans 'Captcha invalid' %}</p> <p class="red-fonts">{% trans 'Captcha invalid' %}</p>
{% else %}
<p class="red-fonts">{{ form.non_field_errors.as_text }}</p>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if errors %}
<p class="red-fonts">{{ errors }}</p>
{% endif %}
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" name="{{ form.username.html_name }}" placeholder="{% trans 'Username' %}" required=""> <input type="text" class="form-control" name="{{ form.username.html_name }}" placeholder="{% trans 'Username' %}" required="">
</div> </div>
...@@ -61,8 +60,8 @@ ...@@ -61,8 +60,8 @@
</div> </div>
<button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Login' %}</button> <button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Login' %}</button>
<a href="{% url 'users:forget-password' %}"> <a href="{% url 'users:forgot-password' %}">
<small>Forgot password?</small> <small>{% trans 'Forgot password' %}?</small>
</a> </a>
<p class="text-muted text-center"> <p class="text-muted text-center">
...@@ -84,7 +83,4 @@ ...@@ -84,7 +83,4 @@
</div> </div>
</div> </div>
</body> </body>
</html> </html>
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet"> <link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script> <script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
...@@ -19,26 +21,13 @@ ...@@ -19,26 +21,13 @@
</li> </li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User assets' %}</a></li> <li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User assets' %}</a></li>
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User log' %}</a></li> <li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'User log' %}</a></li>
<div class="" style="float: right">
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" id="keyword" name="keyword"
value="{{ keyword }}" placeholder="Search">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
{% trans 'Search' %}
</button>
</div>
</div>
</form>
</div>
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
<div class="col-sm-7" style="padding-left: 0px;"> <div class="col-sm-7" style="padding-left: 0">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label"><b>{{ user.name }}</b></span> <span class="label"><b>{{ user_object.name }}</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -47,10 +36,6 @@ ...@@ -47,10 +36,6 @@
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user"> <ul class="dropdown-menu dropdown-user">
<li><a href="#"></a>
</li>
<li><a href="#"></a>
</li>
</ul> </ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
...@@ -62,63 +47,63 @@ ...@@ -62,63 +47,63 @@
<tbody> <tbody>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <td colspan="2">
<img src="{{ user | user_avatar_url }}" class="img-circle" width="64" height="64"> <img src="{{ user_object | user_avatar_url }}" class="img-circle" width="64" height="64">
</td> </td>
</tr> </tr>
<tr> <tr>
<td width="20%">{% trans 'Name' %}:</td> <td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ user.name }}</b></td> <td><b>{{ user_object.name }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Username' %}:</td> <td>{% trans 'Username' %}:</td>
<td><b>{{ user.username }}</b></td> <td><b>{{ user_object.username }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Email' %}:</td> <td>{% trans 'Email' %}:</td>
<td><b>{{ user.email }}</b></td> <td><b>{{ user_object.email }}</b></td>
</tr> </tr>
{% if user.phone %} {% if user_object.phone %}
<tr> <tr>
<td>{% trans 'Phone' %}:</td> <td>{% trans 'Phone' %}:</td>
<td><b>{{ user.phone }}</b></td> <td><b>{{ user_object.phone }}</b></td>
</tr> </tr>
{% endif %} {% endif %}
{% if user.wechat %} {% if user_object.wechat %}
<tr> <tr>
<td>{% trans 'Wechat' %}:</td> <td>{% trans 'Wechat' %}:</td>
<td><b>{{ user.wechat }}</b></td> <td><b>{{ user_object.wechat }}</b></td>
</tr> </tr>
{% endif %} {% endif %}
<tr> <tr>
<td>{% trans 'Role' %}:</td> <td>{% trans 'Role' %}:</td>
<td><b>{{ user.get_role_display }}</b></td> <td><b>{{ user_object.get_role_display }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Date expired' %}:</td> <td>{% trans 'Date expired' %}:</td>
<td><b>{{ user.date_expired|date:"Y-m-j H:i:s" }}</b></td> <td><b>{{ user_object.date_expired|date:"Y-m-j H:i:s" }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Created by' %}:</td> <td>{% trans 'Created by' %}:</td>
<td><b>{{ user.created_by }}</b></td> <td><b>{{ user_object.created_by }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Date joined' %}:</td> <td>{% trans 'Date joined' %}:</td>
<td><b>{{ user.date_joined|date:"Y-m-j H:i:s" }}</b></td> <td><b>{{ user_object.date_joined|date:"Y-m-j H:i:s" }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Last login' %}:</td> <td>{% trans 'Last login' %}:</td>
<td><b>{{ user.last_login|date:"Y-m-j H:i:s" }}</b></td> <td><b>{{ user_object.last_login|date:"Y-m-j H:i:s" }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Comment' %}:</td> <td>{% trans 'Comment' %}:</td>
<td><b>{{ user.comment }}</b></td> <td><b>{{ user_object.comment }}</b></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-5" style="padding-left: 0px;"> <div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %} <i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
...@@ -127,11 +112,11 @@ ...@@ -127,11 +112,11 @@
<table class="table"> <table class="table">
<tbody> <tbody>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td width="50%">Active:</td> <td width="50%">{% trans 'Active' %}:</td>
<td><span style="float: right"> <td><span class="pull-right">
<div class="switch"> <div class="switch">
<div class="onoffswitch"> <div class="onoffswitch">
<input type="checkbox" {% if user.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active" onchange="switch_user_status(this)"> <input type="checkbox" {% if user_object.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
<label class="onoffswitch-label" for="is_active"> <label class="onoffswitch-label" for="is_active">
<span class="onoffswitch-inner"></span> <span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span> <span class="onoffswitch-switch"></span>
...@@ -141,13 +126,13 @@ ...@@ -141,13 +126,13 @@
</span></td> </span></td>
</tr> </tr>
<tr> <tr>
<td>二次验证:</td> <td>{% trans 'Enable OTP' %}:</td>
<td><span style="float: right"> <td><span class="pull-right">
<div class="switch"> <div class="switch">
<div class="onoffswitch"> <div class="onoffswitch">
<input type="checkbox" class="onoffswitch-checkbox" <input type="checkbox" class="onoffswitch-checkbox" {% if user_object.enable_otp %} checked {% endif %}
id="example2"> id="enable_otp">
<label class="onoffswitch-label" for="example2"> <label class="onoffswitch-label" for="enable_otp">
<span class="onoffswitch-inner"></span> <span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span> <span class="onoffswitch-switch"></span>
</label> </label>
...@@ -158,16 +143,16 @@ ...@@ -158,16 +143,16 @@
<tr> <tr>
<td>{% trans 'Reset password' %}:</td> <td>{% trans 'Reset password' %}:</td>
<td> <td>
<span style="float: right"> <span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button> <button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Reset' %}</button>
</span> </span>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Reset ssh key' %}:</td> <td>{% trans 'Reset ssh key' %}:</td>
<td> <td>
<span style="float: right"> <span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" style="width: 54px;">{% trans 'Reset' %}</button> <button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Reset' %}</button>
</span> </span>
</td> </td>
</tr> </tr>
...@@ -178,34 +163,34 @@ ...@@ -178,34 +163,34 @@
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Usergroup' %} <i class="fa fa-info-circle"></i> {% trans 'User group' %}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<table class="table"> <table class="table group_edit">
<tbody> <tbody>
<form> <form>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select usergroups' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Join user groups' %}" id="slct_groups" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %} {% for group in groups %}
<option value="{{ group.id }}">{{ group.name }}</option> <option value="{{ group.id }}" id="opt_{{ group.id }}">{{ group.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small">{% trans 'Add' %}</button> <button type="button" class="btn btn-info btn-small" id="btn_add_user_group">{% trans 'Join' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
{% for group in user.groups.all %} {% for group in user_object.groups.all %}
<tr> <tr>
<td ><b>{{ group.name }}</b></td> <td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
<td> <td>
<button class="btn btn-danger btn-sm" type="button" style="float: right;"><i class="fa fa-minus"></i></button> <button class="btn btn-danger pull-right btn-sm btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
...@@ -218,30 +203,128 @@ ...@@ -218,30 +203,128 @@
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function switch_user_status(obj) { jumpserver.selected_groups = {};
var status = $(obj).prop('checked'); function updateUserGroups(user_groups) {
var the_url = "{% url 'users:user-group-edit-api' pk=user_object.id%}";
var body = {
id: {{ user_object.id }},
groups: Object.assign([], user_groups)
};
var success = function(data) {
// remove all the selected groups from select > option and rendered ul element;
$('.select2-selection__rendered').empty();
$('#slct_groups').val('');
$.map(jumpserver.selected_groups, function(group_name, index){
$('#opt_' + index).remove();
// change tr html of user groups.
$('.group_edit tbody').append(
'<tr>' +
'<td><b class="bdg_user_group" data-gid="' + index + '">' + group_name + '</b></td>' +
'<td><button class="btn btn-danger btn-sm pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>' +
'</tr>'
)
});
// clear jumpserver.selected_groups
jumpserver.selected_groups = {};
toastr.success('{% trans "UserGroup Update Success!" %}')
};
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, method: 'PUT'});
$.ajax({ }
url: "{% url 'users:user-active-api' pk=user.id %}", $(document).ready(function () {
type: "PUT", $('.select2').select2()
data: { .on('select2:select', function(evt) {
'is_active': status var data = evt.params.data;
}, jumpserver.selected_groups[data.id] = data.text;
success: function (data, status) { }).on('select2:unselect', function(evt) {
console.log(data) var data = evt.params.data;
}, delete jumpserver.selected_groups[data.id]
error: function () { })
console.log('error') }).on('click', '#is_active', function(){
} var the_url = "{% url 'users:user-patch-api' pk=user_object.id %}";
}) var checked = !$(this).prop('checked');
} var body = {'is_active': checked };
$(document).ready(function () { var success = '{% trans "Update Successfully!" %}';
$('.select2').select2(); APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success_message: success});
}) }).on('click', '#enable_otp', function(){
</script> var the_url = "{% url 'users:user-patch-api' pk=user_object.id %}";
{% endblock %} var checked = !$(this).prop('checked');
\ No newline at end of file var body = {'enable_otp': checked };
var success = '{% trans "Update Successfully!" %}';
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success_message: success});
}).on('click', '#btn_add_user_group', function(){
if (Object.keys(jumpserver.selected_groups).length === 0) {
return false;
}
var user_groups = $('.bdg_user_group').map(function(){
return $(this).data('gid');
}).get();
$.map(jumpserver.selected_groups, function(value, index){
user_groups.push(parseInt(index));
$('#opt_' + index).remove();
});
updateUserGroups(user_groups)
}).on('click', '.btn_delete_user_group', function(){
var $this = $(this);
var $tr = $this.closest('tr');
var $badge = $tr.find('.bdg_user_group');
var gid = $badge.data('gid');
var group_name = $badge.html() || $badge.text();
$('#slct_groups').append(
'<option value="' + gid + '" id="opt_' + gid + '">' + group_name + '</option>'
);
$tr.remove();
var user_groups = $('.bdg_user_group').map(function(){
return $(this).data('gid');
}).get();
updateUserGroups(user_groups)
}).on('click', '#btn_reset_password', function(){
function doReset() {
var the_url = '{% url "users:user-reset-password-api" pk=user_object.id %}';
var body = {};
var success = function() {
var msg = "{% trans 'E-mail sent successfully. An e-mail has been sent to the user\'s mailbox.' %}";
swal("{% trans 'Password-Reset' %}", msg, "success");
}
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will reset the user\'s password.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function () {
doReset();
}
);
}).on('click', '#btn_reset_pk', function(){
function doReset() {
var the_url = '{% url "users:user-reset-pk-api" pk=user_object.id %}';
var body = {};
var success = function() {
var msg = "{% trans 'The reset-ssh-public-key E-mail has been sent successfully. Please inform the user to update his new ssh public key.' %}";
swal("{% trans 'SSH-Public-Key Reset' %}", msg, "success");
}
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will reset the user\'s public key.' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function () {
doReset();
}
);
});
</script>
{% endblock %}
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action="" > <form method="post" class="form-horizontal" action="" >
{% csrf_token %} {% csrf_token %}
{{ form.name|bootstrap_horizontal }} {{ form.name|bootstrap_horizontal }}
......
...@@ -12,14 +12,14 @@ ...@@ -12,14 +12,14 @@
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=name">{% trans 'Name' %}</a></th> <th class="text-center"><a href="{% url 'users:user-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=username">{% trans 'Username' %}</a></th> <th class="text-center"><a href="{% url 'users:user-list' %}?sort=username">{% trans 'Username' %}</a></th>
<th class="text-center">{% trans 'Role' %}</th> <th class="text-center">{% trans 'Role' %}</th>
<th class="text-center">{% trans 'Usergroup' %}</th> <th class="text-center">{% trans 'User group' %}</th>
<th class="text-center">{% trans 'Asset num' %}</th> <th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center"><a href="{% url 'users:user-list' %}?sort=date_expired">{% trans 'Active' %}</a></th> <th class="text-center"><a href="{% url 'users:user-list' %}?sort=date_expired">{% trans 'Active' %}</a></th>
<th class="text-center"></th> <th class="text-center"></th>
{% endblock %} {% endblock %}
{% block table_body %} {% block table_body %}
{% for user in user_list %} {% for user in object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center"> <td class="text-center">
<input type="checkbox" name="checked" value="{{ user.id }}"> <input type="checkbox" name="checked" value="{{ user.id }}">
...@@ -34,15 +34,16 @@ ...@@ -34,15 +34,16 @@
<td class="text-center" title="{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"> {{ user.groups.all|join_queryset_attr:"name" }} </td> <td class="text-center" title="{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"> {{ user.groups.all|join_queryset_attr:"name" }} </td>
<th class="text-center">{{ user.name }}</th> <th class="text-center">{{ user.name }}</th>
<td class="text-center"> <td class="text-center">
{% if user.is_expired %} {% if user.is_expired and user.is_active %}
<i class="fa fa-times text-danger"></i> <i class="fa fa-times text-danger"></i>
{% else %} {% else %}
<i class="fa fa-check text-navy"></i> <i class="fa fa-check text-navy"></i>
{% endif %} {% endif %}
</td> </td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'users:user-update' pk=user.id %}" class="btn btn-xs btn-info">{% trans 'Edit' %}</a> <a href="{% url 'users:user-update' pk=user.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
<a href="{% url 'users:user-delete' pk=user.id %}" class="btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}">{% trans 'Delete' %}</a> <!--<a href="{% url 'users:user-delete' pk=user.id %}" class="btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}">{% trans 'Delete' %}</a>-->
<a onclick="obj_del(this,'{{ user.name }}','{% url 'users:user-delete' user.id %}')" class="btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}">{% trans 'Delete' %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends 'users/_user.html' %} {% extends 'users/_user.html' %}
{% load i18n %} {% load i18n %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block username %} {% block username %}
<div class="form-group"> <div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label> <label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
...@@ -16,4 +17,4 @@ ...@@ -16,4 +17,4 @@
<input id="password" name="password" type="password" class="form-control"> <input id="password" name="password" type="password" class="form-control">
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
\ No newline at end of file
from django.conf.urls import url, include from django.conf.urls import url
from django.contrib.auth import views as auth_views
from django.urls import reverse_lazy
import views import views
import api import api
...@@ -10,13 +8,16 @@ app_name = 'users' ...@@ -10,13 +8,16 @@ app_name = 'users'
urlpatterns = [ urlpatterns = [
url(r'^login$', views.UserLoginView.as_view(), name='login'), url(r'^login$', views.UserLoginView.as_view(), name='login'),
url(r'^logout$', views.UserLogoutView.as_view(), name='logout'), url(r'^logout$', views.UserLogoutView.as_view(), name='logout'),
url(r'^password/forget$', views.UserForgetPasswordView.as_view(), name='forget-password'), url(r'^password/forgot$', views.UserForgotPasswordView.as_view(), name='forgot-password'),
url(r'^password/forget/sendmail-success$', url(r'^password/forgot/sendmail-success$',
views.UserForgetPasswordSendmailSuccessView.as_view(), name='forget-password-sendmail-success'), views.UserForgotPasswordSendmailSuccessView.as_view(), name='forgot-password-sendmail-success'),
url(r'^password/reset$', views.UserResetPasswordView.as_view(), name='reset-password'), url(r'^password/reset$', views.UserResetPasswordView.as_view(), name='reset-password'),
url(r'^password/reset/success$', views.UserResetPasswordSuccessView.as_view(), name='reset-password-success'), url(r'^password/reset/success$', views.UserResetPasswordSuccessView.as_view(),
name='reset-password-success'),
url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user$', views.UserListView.as_view(), name='user-list'),
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'), url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
url(r'^user/(?P<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'), url(r'^user/(?P<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),
url(r'^user/(?P<pk>[0-9]+)/delete$', views.UserDeleteView.as_view(), name='user-delete'), url(r'^user/(?P<pk>[0-9]+)/delete$', views.UserDeleteView.as_view(), name='user-delete'),
...@@ -30,8 +31,15 @@ urlpatterns = [ ...@@ -30,8 +31,15 @@ urlpatterns = [
urlpatterns += [ urlpatterns += [
url(r'^v1/users$', api.UserListAddApi.as_view(), name='user-list-api'), url(r'^v1/users$', api.UserListAddApi.as_view(), name='user-list-api'),
url(r'^v1/users/(?P<pk>[0-9]+)$', api.UserDetailDeleteUpdateApi.as_view(), name='user-detail-api'), url(r'^v1/users/(?P<pk>[0-9]+)$',
url(r'^v1/users/(?P<pk>[0-9]+)/active$', api.UserActiveApi.as_view(), name='user-active-api'), api.UserDetailDeleteUpdateApi.as_view(), name='user-detail-api'),
url(r'^v1/usergroups$', api.UserGroupListAddApi.as_view(), name='user-group-list-api'), url(r'^v1/users/(?P<pk>[0-9]+)/patch$',
url(r'^v1/usergroups/(?P<pk>[0-9]+)$', api.UserGroupDetailDeleteUpdateApi.as_view(), name='user-group-detail-api'), api.UserAttributeApi.as_view(), name='user-patch-api'),
url(r'^v1/users/(?P<pk>\d+)/reset-password/$', api.UserResetPasswordApi.as_view(), name='user-reset-password-api'),
url(r'^v1/users/(?P<pk>\d+)/reset-pk/$', api.UserResetPKApi.as_view(), name='user-reset-pk-api'),
url(r'^v1/user-groups$', api.UserGroupListAddApi.as_view(), name='user-group-list-api'),
url(r'^v1/user-groups/(?P<pk>[0-9]+)$',
api.UserGroupDetailDeleteUpdateApi.as_view(), name='user-group-detail-api'),
url(r'^v1/user-groups/(?P<pk>[0-9]+)/edit$',
api.UserGroupEditApi.as_view(), name='user-group-edit-api'),
] ]
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
from __future__ import unicode_literals from __future__ import unicode_literals
import os
import logging import logging
import os
import re
from paramiko.rsakey import RSAKey from django.conf import settings
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from paramiko.rsakey import RSAKey
from common.tasks import send_mail_async from common.tasks import send_mail_async
from common.utils import reverse from common.utils import reverse
from users.models import User
try: try:
...@@ -86,7 +87,7 @@ def user_add_success_next(user): ...@@ -86,7 +87,7 @@ def user_add_success_next(user):
'name': user.name, 'name': user.name,
'rest_password_url': reverse('users:reset-password', external=True), 'rest_password_url': reverse('users:reset-password', external=True),
'rest_password_token': user.generate_reset_token(), 'rest_password_token': user.generate_reset_token(),
'forget_password_url': reverse('users:forget-password', external=True), 'forget_password_url': reverse('users:forgot-password', external=True),
'email': user.email, 'email': user.email,
'login_url': reverse('users:login', external=True), 'login_url': reverse('users:login', external=True),
} }
...@@ -117,13 +118,88 @@ def send_reset_password_mail(user): ...@@ -117,13 +118,88 @@ def send_reset_password_mail(user):
'name': user.name, 'name': user.name,
'rest_password_url': reverse('users:reset-password', external=True), 'rest_password_url': reverse('users:reset-password', external=True),
'rest_password_token': user.generate_reset_token(), 'rest_password_token': user.generate_reset_token(),
'forget_password_url': reverse('users:forget-password', external=True), 'forget_password_url': reverse('users:forgot-password', external=True),
'email': user.email, 'email': user.email,
'login_url': reverse('users:login', external=True), 'login_url': reverse('users:login', external=True),
} }
if settings.DEBUG:
logger.debug(message)
send_mail_async.delay(subject, message, recipient_list, html_message=message)
def send_reset_ssh_key_mail(user):
subject = _('SSH Key Reset')
recipient_list = [user.email]
message = _("""
Hello %(name)s:
</br>
Your ssh public key has been reset by site administrator.
Please login and reset your ssh public key.
</br>
<a href="%(login_url)s">Login direct</a>
</br>
""") % {
'name': user.name,
'login_url': reverse('users:login', external=True),
}
if settings.DEBUG:
logger.debug(message)
send_mail_async.delay(subject, message, recipient_list, html_message=message) send_mail_async.delay(subject, message, recipient_list, html_message=message)
def validate_ssh_pk(text):
"""
Expects a SSH private key as string.
Returns a boolean and a error message.
If the text is parsed as private key successfully,
(True,'') is returned. Otherwise,
(False, <message describing the error>) is returned.
from https://github.com/githubnemo/SSH-private-key-validator/blob/master/validate.py
"""
if not text:
return False, 'No text given'
startPattern = re.compile("^-----BEGIN [A-Z]+ PRIVATE KEY-----")
optionPattern = re.compile("^.+: .+")
contentPattern = re.compile("^([a-zA-Z0-9+/]{64}|[a-zA-Z0-9+/]{1,64}[=]{0,2})$")
endPattern = re.compile("^-----END [A-Z]+ PRIVATE KEY-----")
def contentState(text):
for i in range(0, len(text)):
line = text[i]
if endPattern.match(line):
if i == len(text) - 1 or len(text[i + 1]) == 0:
return True, ''
else:
return False, 'At end but content coming'
elif not contentPattern.match(line):
return False, 'Wrong string in content section'
return False, 'No content or missing end line'
def optionState(text):
for i in range(0, len(text)):
line = text[i]
if line[-1:] == '\\':
return optionState(text[i + 2:])
if not optionPattern.match(line):
return contentState(text[i + 1:])
return False, 'Expected option, found nothing'
def startState(text):
if len(text) == 0 or not startPattern.match(text[0]):
return False, 'Header is wrong'
return optionState(text[1:])
return startState([n.strip() for n in text.splitlines()])
...@@ -2,67 +2,69 @@ ...@@ -2,67 +2,69 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import logging from django.conf import settings
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.shortcuts import get_object_or_404, reverse, render, Http404, redirect from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy from django.contrib.messages.views import SuccessMessageMixin
from django.utils.translation import ugettext as _ from django.core.files.storage import default_storage
from django.db.models import Q from django.db.models import Q
from django.views.generic.base import View, TemplateView from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, reverse, redirect
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from django.urls import reverse_lazy
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic.base import TemplateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView, ProcessFormView, FormView from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.contrib.messages.views import SuccessMessageMixin
from django.conf import settings
from django.http import HttpResponseRedirect
from django.contrib.auth import views as auth_view, authenticate, login, logout
from common.utils import get_object_or_none from formtools.wizard.views import SessionWizardView
from common.utils import get_object_or_none, get_logger
from .models import User, UserGroup from .models import User, UserGroup
from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm
from .utils import AdminUserRequiredMixin, ssh_key_gen, user_add_success_next, send_reset_password_mail from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail
logger = logging.getLogger('jumpserver.users.views') logger = get_logger(__name__)
@method_decorator(sensitive_post_parameters(), name='dispatch')
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(never_cache, name='dispatch')
class UserLoginView(FormView): class UserLoginView(FormView):
template_name = 'users/login.html' template_name = 'users/login.html'
form_class = UserLoginForm form_class = UserLoginForm
redirect_field_name = 'next' redirect_field_name = 'next'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if self.request.user.is_staff: if request.user.is_staff:
return redirect(request.POST.get(self.redirect_field_name, reverse('index'))) return redirect(self.get_success_url())
# Todo: Django have bug, lose context issue: https://github.com/django/django/pull/7202 return super(UserLoginView, self).get(request, *args, **kwargs)
# so we jump it and use origin method render_to_response
# return super(UserLoginView, self).get(request, *args, **kwargs)
return self.render_to_response(self.get_context_data(**kwargs))
def post(self, request, *args, **kwargs):
form = self.get_form()
if not form.is_valid():
return self.form_invalid(form)
username = form['username'].value() def form_valid(self, form):
password = form['password'].value() auth_login(self.request, form.get_user())
return redirect(self.get_success_url())
user = authenticate(username=username, password=password) def get_success_url(self):
if user is None: if self.request.user.is_first_login:
kwargs.update({'errors': _('Username or password invalid')}) return reverse('users:user-first-login')
return self.get(request, *args, **kwargs)
login(request, user) return self.request.POST.get(
return redirect(request.GET.get(self.redirect_field_name, reverse('index'))) self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, reverse('index')))
@method_decorator(never_cache, name='dispatch')
class UserLogoutView(TemplateView): class UserLogoutView(TemplateView):
template_name = 'common/flash_message_standalone.html' template_name = 'common/flash_message_standalone.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
logout(request) auth_logout(request)
return super(UserLogoutView, self).get(request) return super(UserLogoutView, self).get(request)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
...@@ -80,7 +82,7 @@ class UserListView(AdminUserRequiredMixin, ListView): ...@@ -80,7 +82,7 @@ class UserListView(AdminUserRequiredMixin, ListView):
model = User model = User
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'user_list' context_object_name = 'user_list'
template_name = 'users/user_list.html' template_name = 'users/asset_permission_list.html'
ordering = '-date_joined' ordering = '-date_joined'
def get_queryset(self): def get_queryset(self):
...@@ -90,7 +92,6 @@ class UserListView(AdminUserRequiredMixin, ListView): ...@@ -90,7 +92,6 @@ class UserListView(AdminUserRequiredMixin, ListView):
if keyword: if keyword:
self.queryset = self.queryset.filter(Q(username__icontains=keyword) | self.queryset = self.queryset.filter(Q(username__icontains=keyword) |
Q(name__icontains=keyword)) Q(name__icontains=keyword))
if sort: if sort:
self.queryset = self.queryset.order_by(sort) self.queryset = self.queryset.order_by(sort)
return self.queryset return self.queryset
...@@ -106,7 +107,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): ...@@ -106,7 +107,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
form_class = UserCreateForm form_class = UserCreateForm
template_name = 'users/user_create.html' template_name = 'users/user_create.html'
success_url = reverse_lazy('users:user-list') success_url = reverse_lazy('users:user-list')
success_message = _('Create user<a href="%s">%s</a> success.') success_message = _('Create user <a href="%s">%s</a> successfully.')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(UserCreateView, self).get_context_data(**kwargs) context = super(UserCreateView, self).get_context_data(**kwargs)
...@@ -150,7 +151,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView): ...@@ -150,7 +151,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(UserUpdateView, self).get_context_data(**kwargs) context = super(UserUpdateView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('Edit user')}) context.update({'app': _('Users'), 'action': _('Update user')})
return context return context
...@@ -159,14 +160,28 @@ class UserDeleteView(AdminUserRequiredMixin, DeleteView): ...@@ -159,14 +160,28 @@ class UserDeleteView(AdminUserRequiredMixin, DeleteView):
success_url = reverse_lazy('users:user-list') success_url = reverse_lazy('users:user-list')
template_name = 'users/user_delete_confirm.html' template_name = 'users/user_delete_confirm.html'
def delete(self, request, *args, **kwargs):
"""
Calls the delete() method on the fetched object and then
redirects to the success URL.
"""
self.object = self.get_object()
success_url = self.get_success_url()
if self.object.name == "admin" or self.object.id == request.session.get('_auth_user_id'):
pass
else:
self.object.delete()
return HttpResponseRedirect(success_url)
class UserDetailView(AdminUserRequiredMixin, DetailView): class UserDetailView(AdminUserRequiredMixin, DetailView):
model = User model = User
template_name = 'users/user_detail.html' template_name = 'users/user_detail.html'
context_object_name = "user" context_object_name = "user_object"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
groups = [group for group in UserGroup.objects.iterator() if group not in self.object.groups.iterator()] groups = UserGroup.objects.exclude(id__in=self.object.groups.all())
context = {'app': _('Users'), 'action': _('User detail'), 'groups': groups} context = {'app': _('Users'), 'action': _('User detail'), 'groups': groups}
kwargs.update(context) kwargs.update(context)
return super(UserDetailView, self).get_context_data(**kwargs) return super(UserDetailView, self).get_context_data(**kwargs)
...@@ -177,7 +192,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView): ...@@ -177,7 +192,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView):
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
context_object_name = 'user_group_list' context_object_name = 'user_group_list'
template_name = 'users/user_group_list.html' template_name = 'users/user_group_list.html'
ordering = '-date_added' ordering = '-date_created'
def get_queryset(self): def get_queryset(self):
self.queryset = super(UserGroupListView, self).get_queryset() self.queryset = super(UserGroupListView, self).get_queryset()
...@@ -192,7 +207,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView): ...@@ -192,7 +207,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(UserGroupListView, self).get_context_data(**kwargs) context = super(UserGroupListView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('Usergroup list'), 'keyword': self.keyword}) context.update({'app': _('Users'), 'action': _('User group list'), 'keyword': self.keyword})
return context return context
...@@ -230,20 +245,20 @@ class UserGroupDeleteView(DeleteView): ...@@ -230,20 +245,20 @@ class UserGroupDeleteView(DeleteView):
pass pass
class UserForgetPasswordView(TemplateView): class UserForgotPasswordView(TemplateView):
template_name = 'users/forget_password.html' template_name = 'users/forgot_password.html'
def post(self, request, *args, **kwargs): def post(self, request):
email = request.POST.get('email') email = request.POST.get('email')
user = get_object_or_none(User, email=email) user = get_object_or_none(User, email=email)
if not user: if not user:
return self.get(request, errors=_('Email address invalid, input again')) return self.get(request, errors=_('Email address invalid, input again'))
else: else:
send_reset_password_mail(user) send_reset_password_mail(user)
return HttpResponseRedirect(reverse('users:forget-password-sendmail-success')) return HttpResponseRedirect(reverse('users:forgot-password-sendmail-success'))
class UserForgetPasswordSendmailSuccessView(TemplateView): class UserForgotPasswordSendmailSuccessView(TemplateView):
template_name = 'common/flash_message_standalone.html' template_name = 'common/flash_message_standalone.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
...@@ -253,7 +268,7 @@ class UserForgetPasswordSendmailSuccessView(TemplateView): ...@@ -253,7 +268,7 @@ class UserForgetPasswordSendmailSuccessView(TemplateView):
'redirect_url': reverse('users:login'), 'redirect_url': reverse('users:login'),
} }
kwargs.update(context) kwargs.update(context)
return super(UserForgetPasswordSendmailSuccessView, self).get_context_data(**kwargs) return super(UserForgotPasswordSendmailSuccessView, self).get_context_data(**kwargs)
class UserResetPasswordSuccessView(TemplateView): class UserResetPasswordSuccessView(TemplateView):
...@@ -295,3 +310,42 @@ class UserResetPasswordView(TemplateView): ...@@ -295,3 +310,42 @@ class UserResetPasswordView(TemplateView):
user.reset_password(password) user.reset_password(password)
return HttpResponseRedirect(reverse('users:reset-password-success')) return HttpResponseRedirect(reverse('users:reset-password-success'))
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
template_name = 'users/first_login.html'
form_list = [UserInfoForm, UserKeyForm]
file_storage = default_storage
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and not request.user.is_first_login:
return redirect(reverse('index'))
return super(UserFirstLoginView, self).dispatch(request, *args, **kwargs)
def done(self, form_list, form_dict, **kwargs):
user = self.request.user
for form in form_list:
for field in form:
if field.value():
setattr(user, field.name, field.value())
if field.name == 'enable_otp':
user.enable_otp = field.value()
user.is_first_login = False
user.save()
return redirect(reverse('index'))
def get_context_data(self, **kwargs):
context = super(UserFirstLoginView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('First Login')})
return context
def get_form_initial(self, step):
user = self.request.user
if step == '0':
return {
'name': user.name or user.username,
'enable_otp': user.enable_otp or True,
'wechat': user.wechat or '',
'phone': user.phone or ''
}
return super(UserFirstLoginView, self).get_form_initial(step)
...@@ -71,16 +71,12 @@ ...@@ -71,16 +71,12 @@
<row name="is_active" null="0" autoincrement="0"> <row name="is_active" null="0" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>0</default></row> <default>0</default></row>
<row name="enable_2FA" null="1" autoincrement="0"> <row name="enable_otp" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>0</default></row> <default>0</default></row>
<row name="secret_key_2FA" null="1" autoincrement="0">
<datatype>CHAR</datatype>
<default>NULL</default></row>
<row name="role" null="1" autoincrement="0"> <row name="role" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="role" row="id" /> <default>NULL</default></row>
</row>
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -106,7 +102,7 @@ ...@@ -106,7 +102,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="227" y="430" name="role"> <table x="205" y="363" name="role">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -120,7 +116,7 @@ ...@@ -120,7 +116,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="399" y="102" name="usergroup"> <table x="399" y="102" name="user_group">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -130,7 +126,7 @@ ...@@ -130,7 +126,7 @@
<row name="comment" null="1" autoincrement="0"> <row name="comment" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
...@@ -140,13 +136,13 @@ ...@@ -140,13 +136,13 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="159" y="181" name="user_usergroup"> <table x="165" y="151" name="user_user_group">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="usergroup_id" null="1" autoincrement="0"> <row name="usergroup_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="usergroup" row="id" /> <default>NULL</default><relation table="user_group" row="id" />
</row> </row>
<row name="user_id" null="1" autoincrement="0"> <row name="user_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -156,7 +152,7 @@ ...@@ -156,7 +152,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="220" y="587" name="permission"> <table x="201" y="486" name="permission">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -188,7 +184,7 @@ ...@@ -188,7 +184,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="26" y="426" name="role_permission"> <table x="3" y="364" name="role_permission">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -231,7 +227,7 @@ ...@@ -231,7 +227,7 @@
<default>NULL</default></row> <default>NULL</default></row>
<row name="admin_user" null="1" autoincrement="0"> <row name="admin_user" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="adminuser" row="id" /> <default>NULL</default><relation table="admin_user" row="id" />
</row> </row>
<row name="idc" null="1" autoincrement="0"> <row name="idc" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -242,7 +238,7 @@ ...@@ -242,7 +238,7 @@
<default>NULL</default></row> <default>NULL</default></row>
<row name="type" null="1" autoincrement="0"> <row name="type" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="assetextend" row="id" /> <default>NULL</default><relation table="asset_extend" row="id" />
</row> </row>
<row name="brand" null="1" autoincrement="0"> <row name="brand" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
...@@ -264,7 +260,7 @@ ...@@ -264,7 +260,7 @@
<default>NULL</default></row> <default>NULL</default></row>
<row name="env" null="1" autoincrement="0"> <row name="env" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="assetextend" row="id" /> <default>NULL</default><relation table="asset_extend" row="id" />
</row> </row>
<row name="cpu" null="1" autoincrement="0"> <row name="cpu" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
...@@ -284,14 +280,14 @@ ...@@ -284,14 +280,14 @@
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<key type="PRIMARY" name=""> <key type="PRIMARY" name="">
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1278" y="684" name="assetextend"> <table x="1301" y="687" name="asset_extend">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -305,7 +301,7 @@ ...@@ -305,7 +301,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1274" y="387" name="idc"> <table x="1294" y="379" name="idc">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -336,14 +332,14 @@ ...@@ -336,14 +332,14 @@
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<key type="PRIMARY" name=""> <key type="PRIMARY" name="">
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1269" y="220" name="assetlabel"> <table x="1269" y="220" name="asset_label">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -361,7 +357,7 @@ ...@@ -361,7 +357,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1080" y="102" name="assetgroup"> <table x="1080" y="102" name="asset_group">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -374,20 +370,20 @@ ...@@ -374,20 +370,20 @@
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<key type="PRIMARY" name=""> <key type="PRIMARY" name="">
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1261" y="101" name="asset_assetgroup"> <table x="1261" y="101" name="asset_asset_group">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="assetgroup_id" null="1" autoincrement="0"> <row name="asset_group_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="assetgroup" row="id" /> <default>NULL</default><relation table="asset_group" row="id" />
</row> </row>
<row name="asset_id" null="1" autoincrement="0"> <row name="asset_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -397,7 +393,7 @@ ...@@ -397,7 +393,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1272" y="806" name="adminuser"> <table x="1289" y="806" name="admin_user">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -419,7 +415,7 @@ ...@@ -419,7 +415,7 @@
<row name="auto_update" null="1" autoincrement="0"> <row name="auto_update" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="create_by" null="1" autoincrement="0"> <row name="create_by" null="1" autoincrement="0">
...@@ -432,7 +428,7 @@ ...@@ -432,7 +428,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="732" y="571" name="sysuser"> <table x="720" y="571" name="system_user">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -481,20 +477,20 @@ ...@@ -481,20 +477,20 @@
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>CHAR</datatype> <datatype>CHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>DATETIME</datatype> <datatype>DATETIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<key type="PRIMARY" name=""> <key type="PRIMARY" name="">
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="873" y="572" name="asset_sysuser"> <table x="873" y="572" name="asset_system_user">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="sysuser_id" null="1" autoincrement="0"> <row name="system_user_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="sysuser" row="id" /> <default>NULL</default><relation table="system_user" row="id" />
</row> </row>
<row name="asset_id" null="1" autoincrement="0"> <row name="asset_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -504,7 +500,7 @@ ...@@ -504,7 +500,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="870" y="743" name="taskhistory"> <table x="878" y="743" name="task_history">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -534,7 +530,7 @@ ...@@ -534,7 +530,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="1081" y="917" name="task"> <table x="1079" y="918" name="task">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -567,20 +563,20 @@ ...@@ -567,20 +563,20 @@
<row name="created_by" null="1" autoincrement="0"> <row name="created_by" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="date_added" null="1" autoincrement="0"> <row name="date_created" null="1" autoincrement="0">
<datatype>TIME</datatype> <datatype>TIME</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<key type="PRIMARY" name=""> <key type="PRIMARY" name="">
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="560" y="184" name="usergroup_perm"> <table x="560" y="184" name="user_group_perm">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="usergroup_id" null="1" autoincrement="0"> <row name="user_group_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="usergroup" row="id" /> <default>NULL</default><relation table="user_group" row="id" />
</row> </row>
<row name="perm_id" null="1" autoincrement="0"> <row name="perm_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -590,7 +586,7 @@ ...@@ -590,7 +586,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="566" y="407" name="user_perm"> <table x="560" y="361" name="user_perm">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -606,13 +602,13 @@ ...@@ -606,13 +602,13 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="868" y="184" name="assetgroup_perm"> <table x="868" y="184" name="asset_group_perm">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="assetgroup_id" null="1" autoincrement="0"> <row name="asset_group_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="assetgroup" row="id" /> <default>NULL</default><relation table="asset_group" row="id" />
</row> </row>
<row name="perm_id" null="1" autoincrement="0"> <row name="perm_id" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
...@@ -638,11 +634,11 @@ ...@@ -638,11 +634,11 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="300" y="770" name="loginlog"> <table x="300" y="770" name="login_log">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="user_name" null="1" autoincrement="0"> <row name="username" null="1" autoincrement="0">
<datatype>VARCHAR</datatype> <datatype>VARCHAR</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="login_type" null="1" autoincrement="0"> <row name="login_type" null="1" autoincrement="0">
...@@ -667,7 +663,7 @@ ...@@ -667,7 +663,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="139" y="772" name="adminlog"> <table x="139" y="772" name="admin_log">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -693,7 +689,7 @@ ...@@ -693,7 +689,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="460" y="769" name="proxylog"> <table x="435" y="806" name="proxy_log">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
...@@ -734,13 +730,13 @@ ...@@ -734,13 +730,13 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="575" y="575" name="commandlog"> <table x="567" y="575" name="commandlog">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
<row name="proxy_log" null="1" autoincrement="0"> <row name="proxy_log" null="1" autoincrement="0">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default><relation table="proxylog" row="id" /> <default>NULL</default><relation table="proxy_log" row="id" />
</row> </row>
<row name="date_start" null="1" autoincrement="0"> <row name="date_start" null="1" autoincrement="0">
<datatype>DATE</datatype> <datatype>DATE</datatype>
...@@ -752,7 +748,7 @@ ...@@ -752,7 +748,7 @@
<part>id</part> <part>id</part>
</key> </key>
</table> </table>
<table x="600" y="754" name="notice"> <table x="585" y="786" name="notice">
<row name="id" null="1" autoincrement="1"> <row name="id" null="1" autoincrement="1">
<datatype>INTEGER</datatype> <datatype>INTEGER</datatype>
<default>NULL</default></row> <default>NULL</default></row>
......
...@@ -17,3 +17,5 @@ paramiko==2.0.2 ...@@ -17,3 +17,5 @@ paramiko==2.0.2
celery==3.1.23 celery==3.1.23
ansible==2.1.1.0 ansible==2.1.1.0
django-simple-captcha==0.5.2 django-simple-captcha==0.5.2
django-formtools==1.0
sshpubkeys==2.2.0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment