merge master
|
@ -1,6 +1,7 @@
|
|||
.DS_Store
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.swp
|
||||
env
|
||||
env*
|
||||
dist
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from rest_framework import serializers
|
||||
from .models import (
|
||||
AssetGroup,Asset,IDC,AssetExtend
|
||||
)
|
||||
from rest_framework import viewsets,serializers
|
||||
from rest_framework import viewsets, serializers
|
||||
|
||||
from .models import AssetGroup, Asset, IDC, AssetExtend
|
||||
|
||||
|
||||
class AssetGroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = AssetGroup
|
||||
#exclude = [
|
||||
#'password', 'first_name', 'last_name', 'secret_key_otp',
|
||||
#'private_key', 'public_key', 'avatar',
|
||||
#]
|
||||
# exclude = [
|
||||
# 'password', 'first_name', 'last_name', 'secret_key_otp',
|
||||
# 'private_key', 'public_key', 'avatar',
|
||||
# ]
|
||||
|
||||
|
||||
class AssetSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Asset
|
||||
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
|
||||
# fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
|
||||
|
||||
|
||||
class IDCSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = IDC
|
||||
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
|
||||
# fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
|
||||
|
||||
|
||||
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()
|
||||
serializer_class = AssetGroupSerializer
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# coding:utf-8
|
||||
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 _
|
||||
|
||||
|
||||
|
@ -11,16 +11,17 @@ class AssetForm(forms.ModelForm):
|
|||
|
||||
fields = [
|
||||
"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"
|
||||
]
|
||||
|
||||
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):
|
||||
# See AdminUserForm comment same it
|
||||
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
|
||||
label=_('Asset'),
|
||||
required=False,
|
||||
|
@ -45,14 +46,169 @@ class AssetGroupForm(forms.ModelForm):
|
|||
fields = [
|
||||
"name", "comment"
|
||||
]
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
}
|
||||
|
||||
|
||||
class IdcForm(forms.ModelForm):
|
||||
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 Meta:
|
||||
model = IDC
|
||||
fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'network', 'comment']
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': 'Name'}),
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'network': forms.Textarea(
|
||||
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',
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
"""
|
||||
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
|
|
@ -1,181 +0,0 @@
|
|||
# -*- 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 @@
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from django.db import models
|
||||
import logging
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import encrypt, decrypt
|
||||
|
||||
|
||||
class AssetGroup(models.Model):
|
||||
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
|
||||
|
@ -16,6 +19,8 @@ class AssetGroup(models.Model):
|
|||
class Meta:
|
||||
db_table = 'asset_group'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IDC(models.Model):
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
|
@ -24,7 +29,7 @@ class IDC(models.Model):
|
|||
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
|
||||
address = models.CharField(max_length=128, blank=True, verbose_name=_("Address"))
|
||||
network = models.TextField(blank=True, verbose_name=_('Network'))
|
||||
date_added = models.DateField(auto_now=True, null=True, verbose_name=_('Date added'))
|
||||
date_created = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added'))
|
||||
operator = models.CharField(max_length=32, blank=True, verbose_name=_('Operator'))
|
||||
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
|
@ -35,87 +40,253 @@ class IDC(models.Model):
|
|||
class Meta:
|
||||
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):
|
||||
key = models.CharField(max_length=64, verbose_name=_('KEY'))
|
||||
value = models.CharField(max_length=64, verbose_name=_('VALUE'))
|
||||
created_by = models.CharField(max_length=32, blank=True, verbose_name=_("Created by"))
|
||||
date_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'))
|
||||
|
||||
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:
|
||||
db_table = 'assetextend'
|
||||
db_table = 'asset_extend'
|
||||
|
||||
|
||||
class AdminUser(models.Model):
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_('Password'))
|
||||
private_key = models.CharField(max_length=4096, null=True, blank=True, verbose_name=_('SSH private key'))
|
||||
is_default = models.BooleanField(default=False, verbose_name=_('As default'))
|
||||
_password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
|
||||
_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'))
|
||||
as_default = models.BooleanField(default=False, verbose_name=_('As default'))
|
||||
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):
|
||||
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 = '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 SystemUser(models.Model):
|
||||
PROTOCOL_CHOICES = (
|
||||
('ssh', 'ssh'),
|
||||
)
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
_password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
|
||||
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'))
|
||||
_public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
|
||||
as_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'))
|
||||
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'))
|
||||
sudo = models.TextField(max_length=4096, default='/user/bin/whoami', verbose_name=_('Sudo'))
|
||||
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
||||
home = models.CharField(max_length=64, blank=True, verbose_name=_('Home'))
|
||||
uid = models.IntegerField(null=True, blank=True, verbose_name=_('Uid'))
|
||||
date_created = models.DateTimeField(auto_now=True)
|
||||
created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
|
||||
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):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
db_table = 'adminuser'
|
||||
db_table = 'asset_group'
|
||||
|
||||
@classmethod
|
||||
def initial(cls):
|
||||
asset_group = cls(name=_('Default'), commont=_('Default asset group'))
|
||||
asset_group.save()
|
||||
|
||||
class SysUser(models.Model):
|
||||
PROTOCOL_CHOICES = (
|
||||
('ssh', 'ssh'),
|
||||
('telnet', 'telnet'),
|
||||
)
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_('Password'))
|
||||
protocol = models.CharField(max_length=16, default='ssh', verbose_name=_('Protocol'))
|
||||
private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key'))
|
||||
public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
|
||||
is_default = models.BooleanField(default=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(max_length=4096, blank=True, verbose_name=_('Sudo'))
|
||||
shell = models.CharField(max_length=64, blank=True, verbose_name=_('Shell'))
|
||||
home = models.CharField(max_length=64, blank=True, verbose_name=_('Home'))
|
||||
uid = models.IntegerField(blank=True, verbose_name=_('Uid'))
|
||||
date_added = models.DateTimeField(auto_now=True, null=True, verbose_name=_('Date added'))
|
||||
create_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by'))
|
||||
comment = models.CharField(max_length=128, blank=True, verbose_name=_('Comment'))
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100):
|
||||
from random import seed
|
||||
import forgery_py
|
||||
from django.db import IntegrityError
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
db_table = 'sysuser'
|
||||
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):
|
||||
ip = models.CharField(max_length=32, verbose_name=_('IP'))
|
||||
other_ip = models.CharField(max_length=255, blank=True, verbose_name=_('Other IP'))
|
||||
remote_card_ip = models.CharField(max_length=16, blank=True, verbose_name=_('Remote card IP'))
|
||||
hostname = models.CharField(max_length=128, unique=True, blank=True, verbose_name=_('Hostname'))
|
||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||
groups = models.ManyToManyField(AssetGroup, blank=True, verbose_name=_('Asset groups'))
|
||||
username = models.CharField(max_length=16, blank=True, verbose_name=_('Admin user'))
|
||||
password = models.CharField(max_length=256, blank=True, verbose_name=_("Admin password"))
|
||||
admin_user = models.ForeignKey(AdminUser, null=True, on_delete=models.SET_NULL, verbose_name=_("Admin User"))
|
||||
sys_user = models.ManyToManyField(SysUser, verbose_name=_("Sys User"))
|
||||
idc = models.ForeignKey(IDC, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('IDC'))
|
||||
mac_addr = models.CharField(max_length=20, blank=True, verbose_name=_("Mac address"))
|
||||
brand = models.CharField(max_length=64, blank=True, verbose_name=_('Brand'))
|
||||
cpu = models.CharField(max_length=64, blank=True, verbose_name=_('CPU'))
|
||||
memory = models.CharField(max_length=128, blank=True, verbose_name=_('Memory'))
|
||||
disk = models.CharField(max_length=1024, blank=True, verbose_name=_('Disk'))
|
||||
os = models.CharField(max_length=128, blank=True, verbose_name=_('OS'))
|
||||
cabinet_no = models.CharField(max_length=32, blank=True, verbose_name=_('Cabinet number'))
|
||||
ip = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('IP'))
|
||||
other_ip = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('Other IP'))
|
||||
remote_card_ip = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Remote card IP'))
|
||||
hostname = models.CharField(max_length=128, unique=True, null=True, blank=True, verbose_name=_('Hostname'))
|
||||
port = models.IntegerField(null=True, blank=True, verbose_name=_('Port'))
|
||||
groups = models.ManyToManyField(AssetGroup, related_name='assets', verbose_name=_('Asset groups'))
|
||||
username = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Admin user'))
|
||||
password = models.CharField(max_length=256, null=True, blank=True, verbose_name=_("Admin password"))
|
||||
admin_user = models.ForeignKey(AdminUser, null=True, related_name='assets',
|
||||
on_delete=models.SET_NULL, verbose_name=_("Admin user"))
|
||||
system_user = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User"))
|
||||
idc = models.ForeignKey(IDC, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('IDC'))
|
||||
mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address"))
|
||||
brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand'))
|
||||
cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU'))
|
||||
memory = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Memory'))
|
||||
disk = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk'))
|
||||
os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS'))
|
||||
cabinet_no = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Cabinet number'))
|
||||
cabinet_pos = models.IntegerField(null=True, blank=True, verbose_name=_('Cabinet position'))
|
||||
number = models.CharField(max_length=32, blank=True, verbose_name=_('Asset number'))
|
||||
status = models.ForeignKey(AssetExtend, null=True, blank=True,
|
||||
|
@ -127,11 +298,11 @@ class Asset(models.Model):
|
|||
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'))
|
||||
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(max_length=128, blank=True, verbose_name=_('Comment'))
|
||||
date_created = models.DateTimeField(auto_now=True, null=True, blank=True, verbose_name=_('Date added'))
|
||||
comment = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
|
||||
|
||||
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):
|
||||
pass
|
||||
|
@ -140,13 +311,32 @@ class Asset(models.Model):
|
|||
db_table = 'asset'
|
||||
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):
|
||||
key = models.CharField(max_length=64, verbose_name=_('KEY'))
|
||||
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'))
|
||||
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'))
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -155,3 +345,7 @@ class Label(models.Model):
|
|||
class Meta:
|
||||
db_table = 'label'
|
||||
|
||||
|
||||
def generate_fake():
|
||||
for cls in (Asset, AssetGroup, IDC):
|
||||
cls.generate_fake()
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,220 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,41 @@
|
|||
{% 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 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
<td class="text-navy">备注</td>
|
||||
|
|
|
@ -27,22 +27,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="" >
|
||||
<form method="post" class="form-horizontal" action="" >
|
||||
{% csrf_token %}
|
||||
{{ form.name|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 }}
|
||||
|
||||
<div class="form-group">
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
{% 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 %}
|
|
@ -27,10 +27,10 @@
|
|||
</a>
|
||||
</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">
|
||||
<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-delete' pk=asset_group.id %}" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
|
||||
<a href="{% url 'assets:asset-group-update' pk=asset_group.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{% 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>
|
|
@ -0,0 +1,61 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,70 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,135 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,136 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,95 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,188 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,43 @@
|
|||
{% 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
|
|||
app_name = 'assets'
|
||||
|
||||
urlpatterns = [
|
||||
# Resource asset url
|
||||
url(r'^$', views.AssetListView.as_view(), name='asset-index'),
|
||||
url(r'^asset$', views.AssetListView.as_view(), name='asset-list'),
|
||||
url(r'^asset/create$', views.AssetCreateView.as_view(), name='asset-create'),
|
||||
url(r'^asset/(?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'),
|
||||
|
||||
# Resource asset group url
|
||||
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/(?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]+)/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)),
|
||||
]
|
||||
|
|
|
@ -1,23 +1,4 @@
|
|||
# ~*~ 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 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.generic import TemplateView, ListView
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
||||
from django.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.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 .forms import AssetForm, AssetGroupForm
|
||||
from .utils import AdminUserRequiredMixin
|
||||
from .models import Asset, AssetGroup, IDC, AssetExtend, AdminUser, SystemUser
|
||||
from .forms import AssetForm, AssetGroupForm, IDCForm, AdminUserForm, SystemUserForm
|
||||
from .hands import AdminUserRequiredMixin
|
||||
|
||||
|
||||
class AssetCreateView(CreateView):
|
||||
|
@ -50,12 +49,14 @@ class AssetDetailView(DetailView):
|
|||
template_name = 'assets/asset_detail.html'
|
||||
|
||||
|
||||
class AssetGroupCreateView(CreateView):
|
||||
class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = AssetGroup
|
||||
form_class = AssetGroupForm
|
||||
template_name = 'assets/asset_group_create.html'
|
||||
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):
|
||||
context = {
|
||||
'app': _('Assets'),
|
||||
|
@ -70,25 +71,57 @@ class AssetGroupCreateView(CreateView):
|
|||
return super(AssetGroupCreateView, self).form_valid(form)
|
||||
|
||||
|
||||
class AssetGroupListView(ListView):
|
||||
class AssetGroupListView(AdminUserRequiredMixin, ListView):
|
||||
model = AssetGroup
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
context_object_name = 'asset_group_list'
|
||||
template_name = 'assets/asset_group_list.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Assets'),
|
||||
'action': _('Asset group list')
|
||||
'action': _('Asset group list'),
|
||||
'keyword': self.request.GET.get('keyword', '')
|
||||
}
|
||||
kwargs.update(context)
|
||||
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):
|
||||
pass
|
||||
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 AssetGroupUpdateView(UpdateView):
|
||||
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()
|
||||
|
||||
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
|
||||
form_class = AssetGroupForm
|
||||
template_name = 'assets/asset_group_create.html'
|
||||
|
@ -104,5 +137,313 @@ class AssetGroupUpdateView(UpdateView):
|
|||
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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
# 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
|
||||
|
||||
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
#
|
||||
|
||||
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.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):
|
||||
|
@ -21,3 +27,76 @@ def get_object_or_none(model, **kwargs):
|
|||
except model.DoesNotExist:
|
||||
obj = None
|
||||
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)
|
||||
|
|
|
@ -1 +1 @@
|
|||
[{"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]}}]
|
|
@ -108,6 +108,7 @@ TEMPLATES = [
|
|||
# WSGI_APPLICATION = 'jumpserver.wsgi.application'
|
||||
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('index')
|
||||
LOGIN_URL = reverse_lazy('users:login')
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
||||
|
@ -227,7 +228,7 @@ USE_L10N = True
|
|||
USE_TZ = True
|
||||
|
||||
# I18N translation
|
||||
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'),]
|
||||
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'), ]
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
||||
|
@ -313,3 +314,5 @@ CAPTCHA_IMAGE_SIZE = (75, 33)
|
|||
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
|
|||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -25,6 +24,7 @@ urlpatterns = [
|
|||
url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'),
|
||||
url(r'^(api/)?users/', include('users.urls')),
|
||||
url(r'^assets/', include('assets.urls')),
|
||||
url(r'^perms/', include('perms.urls')),
|
||||
url(r'^terminal/', include('webterminal.urls')),
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# ~*~ 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',
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# ~*~ 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
|
||||
|
||||
|
|
@ -1,5 +1,70 @@
|
|||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
import functools
|
||||
|
||||
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.
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,96 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,220 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,73 @@
|
|||
{% 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 %}
|
||||
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
{% 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 %}
|
|
@ -0,0 +1,15 @@
|
|||
{% 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>
|
|
@ -0,0 +1,66 @@
|
|||
{% 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 %}
|
||||
|
||||
|
|
@ -1 +1,22 @@
|
|||
# coding:utf-8
|
||||
|
||||
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'),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,3 +1,190 @@
|
|||
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)
|
||||
|
|
After Width: | Height: | Size: 338 B |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 6.4 KiB |
|
@ -38,6 +38,7 @@ th a {
|
|||
color: white;
|
||||
}
|
||||
|
||||
.select2-selection--single,
|
||||
.select2-selection--multiple {
|
||||
border: 1px solid #e5e6e7 !important;
|
||||
cursor: text !important;
|
||||
|
|
|
@ -0,0 +1,715 @@
|
|||
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; }
|
|
@ -0,0 +1,222 @@
|
|||
.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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
[.ShellClassInfo]
|
||||
IconFile=%SystemRoot%\system32\SHELL32.dll
|
||||
IconIndex=161
|
After Width: | Height: | Size: 338 B |
After Width: | Height: | Size: 314 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 791 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 73 B |
|
@ -0,0 +1,43 @@
|
|||
@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;}
|
|
@ -0,0 +1,3 @@
|
|||
[.ShellClassInfo]
|
||||
IconFile=%SystemRoot%\system32\SHELL32.dll
|
||||
IconIndex=161
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 791 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 73 B |
|
@ -0,0 +1,41 @@
|
|||
@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;}
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
/* 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);
|
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* 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);
|
|
@ -4,10 +4,10 @@
|
|||
var checked=false;
|
||||
function check_all(form) {
|
||||
var checkboxes = document.getElementById(form);
|
||||
if (checked == false) {
|
||||
checked = true
|
||||
if (checked === false) {
|
||||
checked = true;
|
||||
} else {
|
||||
checked = false
|
||||
checked = false;
|
||||
}
|
||||
for (var i = 0; i < checkboxes.elements.length; i++) {
|
||||
if (checkboxes.elements[i].type == "checkbox") {
|
||||
|
@ -51,13 +51,13 @@ function GetRowData(row){
|
|||
//此函数用于在多选提交时至少要选择一行
|
||||
function GetTableDataBox() {
|
||||
var tabProduct = document.getElementById("editable");
|
||||
var tableData = new Array();
|
||||
var returnData = new Array();
|
||||
var tableData = [];
|
||||
var returnData = [];
|
||||
var checkboxes = document.getElementById("contents_form");
|
||||
var id_list = new Array();
|
||||
var id_list = [];
|
||||
len = checkboxes.elements.length;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ function GetTableDataBox() {
|
|||
tableData.push(GetRowData(tabProduct.rows[id_list[i]]));
|
||||
}
|
||||
|
||||
if (id_list.length == 0){
|
||||
if (id_list.length === 0){
|
||||
alert('请至少选择一行!');
|
||||
}
|
||||
returnData.push(tableData);
|
||||
|
@ -77,7 +77,7 @@ function GetTableDataBox() {
|
|||
|
||||
function move(from, to, from_o, to_o) {
|
||||
$("#" + from + " option").each(function () {
|
||||
if ($(this).prop("selected") == true) {
|
||||
if ($(this).prop("selected") === true) {
|
||||
$("#" + to).append(this);
|
||||
if( typeof from_o !== 'undefined'){
|
||||
$("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']"));
|
||||
|
@ -88,7 +88,7 @@ function move(from, to, from_o, to_o) {
|
|||
|
||||
function move_left(from, to, from_o, to_o) {
|
||||
$("#" + from + " option").each(function () {
|
||||
if ($(this).prop("selected") == true) {
|
||||
if ($(this).prop("selected") === true) {
|
||||
$("#" + to).append(this);
|
||||
if( typeof from_o !== 'undefined'){
|
||||
$("#"+to_o).append($("#"+from_o +" option[value='"+this.value+"']"));
|
||||
|
@ -124,31 +124,120 @@ function move_left(from, to, from_o, to_o) {
|
|||
|
||||
|
||||
function selectAll(){
|
||||
// 选择该页面所有option
|
||||
// Select all check box
|
||||
$('option').each(function(){
|
||||
$(this).attr('selected', true)
|
||||
})
|
||||
$(this).attr('selected', true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//function move_all(from, to){
|
||||
// $("#"+from).children().each(function(){
|
||||
// $("#"+to).append(this);
|
||||
// });
|
||||
//}
|
||||
// function getIDall() {
|
||||
// var check_array = [];
|
||||
// $(".gradeX input:checked").each(function () {
|
||||
// var id = $(this).attr("value");
|
||||
// check_array.push(id);
|
||||
// });
|
||||
// return check_array.join(",");
|
||||
// }
|
||||
|
||||
//function commit_select(form_array){
|
||||
// $('#{0} option'.format(form_array)).each(function(){
|
||||
// $(this).prop('selected', true)
|
||||
// })
|
||||
//}
|
||||
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;
|
||||
}
|
||||
|
||||
function getIDall() {
|
||||
var check_array = [];
|
||||
$(".gradeX input:checked").each(function () {
|
||||
var id = $(this).attr("value");
|
||||
check_array.push(id);
|
||||
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');
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
});
|
||||
return check_array.join(",");
|
||||
}
|
||||
}
|
||||
|
||||
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 = {};
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
!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">×</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
|
|
@ -1,56 +1,19 @@
|
|||
{% load i18n %}
|
||||
{% load static %}
|
||||
<!-- Mainly scripts -->
|
||||
<script src="{% static "js/plugins/metisMenu/jquery.metisMenu.js" %}"></script>
|
||||
|
||||
<!-- 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/jumpserver.js" %}"></script>
|
||||
|
||||
<script>
|
||||
<!-- active menu -->
|
||||
var url_array = document.location.pathname.split("/");
|
||||
app = url_array[1];
|
||||
resource = url_array[2];
|
||||
if (app == ''){
|
||||
$('#index').addClass('active')
|
||||
} else {
|
||||
$("#"+app).addClass('active');
|
||||
$('#'+app+' #'+resource).addClass('active');
|
||||
}
|
||||
activeNav();
|
||||
$(document).ready(function(){
|
||||
setAjaxCSRFToken();
|
||||
|
||||
<!-- 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({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
// Set textarea rows five
|
||||
$('textarea').attr('rows', 5);
|
||||
});
|
||||
|
||||
<!-- textarea rows -->
|
||||
$('textarea').attr('rows', 5)
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -3,13 +3,26 @@
|
|||
<!-- css file -->
|
||||
<link href="{% static "css/bootstrap.min.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/plugins/vaildator/jquery.validator.css" %}" rel="stylesheet">
|
||||
|
||||
|
||||
|
||||
<!-- scripts -->
|
||||
<script src="{% static "js/jquery-2.1.1.js" %}"></script>
|
||||
<script src="{% static "js/bootstrap.min.js" %}"></script>
|
||||
<script src="{% static 'js/jquery-2.1.1.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 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'users:logout' %}">
|
||||
<i class="fa fa-sign-out"></i> Log out
|
||||
<i class="fa fa-sign-out"></i>{% trans 'Logout' %}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'users:login' %}">
|
||||
<i class="fa fa-sign-in"></i>{% trans 'Login' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
<div class="ibox-content">
|
||||
<div class="">
|
||||
{# left button add #}
|
||||
{% block content_left_head %} {% endblock %}
|
||||
<form id="search_form" method="get" action="" class="pull-right mail-search">
|
||||
<div class="input-group">
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{% 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 @@
|
|||
<ul class="nav nav-second-level">
|
||||
<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="idc"><a href="">{% trans 'IDC' %}</a></li>
|
||||
<li id="admin-user"><a href="">{% trans 'Admin user' %}</a></li>
|
||||
<li id="system-user"><a href="">{% trans 'System user' %}</a></li>
|
||||
<li id="idc"><a href="{% url 'assets:idc-list' %}">{% trans 'IDC' %}</a></li>
|
||||
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin 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>
|
||||
</ul>
|
||||
</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>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="sudo">
|
||||
<a class="sudo" href="">{% trans 'Perm' %}</a>
|
||||
</li>
|
||||
<li id="role">
|
||||
<a href="">{% trans 'Create perm' %}</a>
|
||||
<li id="asset-permission">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
{# <li id="user-group">#}
|
||||
{# <a href="">{% trans 'User group perm' %}</a>#}
|
||||
{# </li>#}
|
||||
</ul>
|
||||
</li>
|
||||
<li id="">
|
||||
|
|
|
@ -34,11 +34,6 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
<script>
|
||||
{# function sleep(n) { //n表示的毫秒数#}
|
||||
{# var start = new Date().getTime();#}
|
||||
{# while (true) if (new Date().getTime() - start > n) break;#}
|
||||
{# }#}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.page').click(function () {
|
||||
var searchStr = location.search;
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="clear">
|
||||
<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 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>
|
||||
</a>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
{% include '_head_css_js.html' %}
|
||||
{% block custom_head_css_js %} {% endblock %}
|
||||
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/jumpserver.js" %}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
{% 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 @@
|
|||
|
||||
import logging
|
||||
|
||||
from rest_framework import generics, mixins, status, permissions
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import generics
|
||||
|
||||
from .serializers import UserSerializer, UserGroupSerializer, UserActiveSerializer
|
||||
from .serializers import UserSerializer, UserGroupSerializer, UserAttributeSerializer, UserGroupEditSerializer
|
||||
from .models import User, UserGroup
|
||||
|
||||
|
||||
|
@ -33,16 +31,6 @@ class UserDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView):
|
|||
# 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):
|
||||
queryset = UserGroup.objects.all()
|
||||
serializer_class = UserGroupSerializer
|
||||
|
@ -52,3 +40,39 @@ class UserGroupDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView):
|
|||
queryset = UserGroup.objects.all()
|
||||
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)
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from django.forms import ModelForm
|
||||
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 captcha.fields import CaptchaField
|
||||
|
||||
from .models import User, UserGroup
|
||||
|
||||
|
||||
class UserLoginForm(forms.Form):
|
||||
class UserLoginForm(AuthenticationForm):
|
||||
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()
|
||||
|
||||
|
||||
class UserCreateForm(ModelForm):
|
||||
class UserCreateForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
|
@ -32,7 +36,8 @@ class UserCreateForm(ModelForm):
|
|||
}
|
||||
|
||||
|
||||
class UserUpdateForm(ModelForm):
|
||||
class UserUpdateForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
|
@ -47,11 +52,12 @@ class UserUpdateForm(ModelForm):
|
|||
}
|
||||
|
||||
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:
|
||||
model = UserGroup
|
||||
|
||||
|
@ -62,3 +68,33 @@ class UserGroupForm(ModelForm):
|
|||
help_texts = {
|
||||
'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
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
"""
|
||||
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 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser, Permission
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core import signing
|
||||
from django.db import models, IntegrityError
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.db import IntegrityError
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from django.core import signing
|
||||
|
||||
# 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')
|
||||
from common.utils import encrypt, decrypt, date_expired_default
|
||||
|
||||
|
||||
class UserGroup(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True, verbose_name=_('Name'))
|
||||
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)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def has_member(self, user):
|
||||
if user in self.users.all():
|
||||
return True
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
db_table = 'user-group'
|
||||
db_table = 'user_group'
|
||||
|
||||
@classmethod
|
||||
def initial(cls):
|
||||
|
@ -76,16 +41,15 @@ class UserGroup(models.Model):
|
|||
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100):
|
||||
from random import seed, randint, choice
|
||||
from random import seed, choice
|
||||
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=choice(User.objects.all()).username
|
||||
)
|
||||
)
|
||||
try:
|
||||
group.save()
|
||||
except IntegrityError:
|
||||
|
@ -93,10 +57,6 @@ class UserGroup(models.Model):
|
|||
continue
|
||||
|
||||
|
||||
def date_expired_default():
|
||||
return timezone.now() + timezone.timedelta(days=365 * 70)
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
ROLE_CHOICES = (
|
||||
('Admin', _('Administrator')),
|
||||
|
@ -106,17 +66,17 @@ class User(AbstractUser):
|
|||
username = models.CharField(max_length=20, unique=True, verbose_name=_('Username'))
|
||||
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name'))
|
||||
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'))
|
||||
avatar = models.ImageField(upload_to="avatar", verbose_name=_('Avatar'))
|
||||
wechat = models.CharField(max_length=30, blank=True, verbose_name=_('Wechat'))
|
||||
phone = models.CharField(max_length=20, blank=True, verbose_name=_('Phone'))
|
||||
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
|
||||
secret_key_otp = models.CharField(max_length=16, blank=True)
|
||||
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'))
|
||||
_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'))
|
||||
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,
|
||||
verbose_name=_('Date expired'))
|
||||
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
|
||||
|
@ -131,8 +91,8 @@ class User(AbstractUser):
|
|||
#: user = User(username='example', ...)
|
||||
#: user.set_password('password')
|
||||
@password_raw.setter
|
||||
def password_raw(self, raw_password):
|
||||
self.set_password(raw_password)
|
||||
def password_raw(self, password_raw_):
|
||||
self.set_password(password_raw_)
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
|
@ -141,6 +101,22 @@ class User(AbstractUser):
|
|||
else:
|
||||
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
|
||||
def is_superuser(self):
|
||||
if self.role == 'Admin':
|
||||
|
@ -198,6 +174,11 @@ class User(AbstractUser):
|
|||
def generate_reset_token(self):
|
||||
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
|
||||
def validate_reset_token(cls, token, max_age=3600):
|
||||
try:
|
||||
|
@ -246,7 +227,7 @@ class User(AbstractUser):
|
|||
wechat=forgery_py.internet.user_name(True),
|
||||
comment=forgery_py.lorem_ipsum.sentence(),
|
||||
created_by=choice(cls.objects.all()).username,
|
||||
)
|
||||
)
|
||||
try:
|
||||
user.save()
|
||||
except IntegrityError:
|
||||
|
@ -258,13 +239,13 @@ class User(AbstractUser):
|
|||
|
||||
def init_all_models():
|
||||
for model in (UserGroup, User):
|
||||
if hasattr(model, 'initial'):
|
||||
if hasattr(model, b'initial'):
|
||||
model.initial()
|
||||
|
||||
|
||||
def generate_fake():
|
||||
for model in (UserGroup, User):
|
||||
if hasattr(model, 'generate_fake'):
|
||||
if hasattr(model, b'generate_fake'):
|
||||
model.generate_fake()
|
||||
|
||||
|
||||
|
@ -275,4 +256,3 @@ def create_auth_token(sender, instance=None, created=False, **kwargs):
|
|||
Token.objects.create(user=instance)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import User, UserGroup
|
||||
|
@ -17,15 +19,38 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class UserActiveSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['is_active']
|
||||
|
||||
|
||||
class UserGroupSerializer(serializers.ModelSerializer):
|
||||
users = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='users:user-detail-api')
|
||||
|
||||
class Meta:
|
||||
model = UserGroup
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
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
|
||||
|
|