mirror of https://github.com/jumpserver/jumpserver
Merge branch 'bugfix' of github.com:jumpserver/jumpserver into bugfix
commit
bbf5e28571
|
@ -1,6 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
import re
|
||||
|
||||
from orgs.mixins import OrgModelForm
|
||||
from ..models import CommandFilter, CommandFilterRule
|
||||
|
@ -15,6 +17,8 @@ class CommandFilterForm(OrgModelForm):
|
|||
|
||||
|
||||
class CommandFilterRuleForm(OrgModelForm):
|
||||
invalid_pattern = re.compile(r'[\.\*\+\[\\\?\{\}\^\$\|\(\)\#\<\>]')
|
||||
|
||||
class Meta:
|
||||
model = CommandFilterRule
|
||||
fields = [
|
||||
|
@ -25,3 +29,11 @@ class CommandFilterRuleForm(OrgModelForm):
|
|||
'placeholder': 'eg:\r\nreboot\r\nrm -rf'
|
||||
}),
|
||||
}
|
||||
|
||||
def clean_content(self):
|
||||
content = self.cleaned_data.get("content")
|
||||
if self.invalid_pattern.search(content):
|
||||
invalid_char = self.invalid_pattern.pattern.replace('\\', '')
|
||||
msg = _("Content should not be contain: {}").format(invalid_char)
|
||||
raise ValidationError(msg)
|
||||
return content
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-01-05 10:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='adminuser',
|
||||
options={'ordering': ['name'], 'verbose_name': 'Admin user'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='asset',
|
||||
options={'verbose_name': 'Asset'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='assetgroup',
|
||||
options={'ordering': ['name'], 'verbose_name': 'Asset group'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='cluster',
|
||||
options={'ordering': ['name'], 'verbose_name': 'Cluster'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='systemuser',
|
||||
options={'ordering': ['name'], 'verbose_name': 'System user'},
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-01-09 15:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import assets.models.asset
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0002_auto_20180105_1807'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='cluster',
|
||||
field=models.ForeignKey(default=assets.models.asset.default_cluster, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='assets', to='assets.Cluster', verbose_name='Cluster'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-01-25 04:18
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0003_auto_20180109_2331'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetgroup',
|
||||
name='created_by',
|
||||
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by'),
|
||||
),
|
||||
]
|
|
@ -1,40 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-01-26 08:37
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0004_auto_20180125_1218'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Label',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('value', models.CharField(max_length=128, verbose_name='Value')),
|
||||
('category', models.CharField(choices=[('S', 'System'), ('U', 'User')], default='U', max_length=128, verbose_name='Category')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
|
||||
('comment', models.TextField(blank=True, null=True, verbose_name='Comment')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'assets_label',
|
||||
},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='label',
|
||||
unique_together=set([('name', 'value')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='labels',
|
||||
field=models.ManyToManyField(blank=True, related_name='assets', to='assets.Label', verbose_name='Labels'),
|
||||
),
|
||||
]
|
|
@ -1,39 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-01-30 07:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0005_auto_20180126_1637'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='cabinet_no',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='cabinet_pos',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='env',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='remote_card_ip',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='status',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='type',
|
||||
),
|
||||
]
|
|
@ -1,60 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-02-25 10:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import assets.models.asset
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0006_auto_20180130_1502'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Node',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('key', models.CharField(max_length=64, unique=True, verbose_name='Key')),
|
||||
('value', models.CharField(max_length=128, unique=True, verbose_name='Value')),
|
||||
('child_mark', models.IntegerField(default=0)),
|
||||
('date_create', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='cluster',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='groups',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='systemuser',
|
||||
name='cluster',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='admin_user',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='assets.AdminUser', verbose_name='Admin user'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='protocol',
|
||||
field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp')], default='ssh', max_length=16, verbose_name='Protocol'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='nodes',
|
||||
field=models.ManyToManyField(default=assets.models.asset.default_node, related_name='assets', to='assets.Node', verbose_name='Nodes'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='nodes',
|
||||
field=models.ManyToManyField(blank=True, to='assets.Node', verbose_name='Nodes'),
|
||||
),
|
||||
]
|
|
@ -1,40 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-03-06 10:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0007_auto_20180225_1815'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='created_by',
|
||||
field=models.CharField(max_length=128, null=True, verbose_name='Created by'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=128, verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='platform',
|
||||
field=models.CharField(choices=[('Linux', 'Linux'), ('Unix', 'Unix'), ('MacOS', 'MacOS'), ('BSD', 'BSD'), ('Windows', 'Windows'), ('Other', 'Other')], default='Linux', max_length=128, verbose_name='Platform'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='created_by',
|
||||
field=models.CharField(max_length=128, null=True, verbose_name='Created by'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=128, verbose_name='Username'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-03-07 04:12
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0008_auto_20180306_1804'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='node',
|
||||
name='value',
|
||||
field=models.CharField(max_length=128, verbose_name='Value'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-03-07 09:49
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0009_auto_20180307_1212'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='node',
|
||||
name='value',
|
||||
field=models.CharField(max_length=128, unique=True, verbose_name='Value'),
|
||||
),
|
||||
]
|
|
@ -1,55 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-03-26 01:57
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import assets.models.utils
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0010_auto_20180307_1749'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Domain',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Gateway',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||
('username', models.CharField(max_length=128, verbose_name='Username')),
|
||||
('_password', models.CharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||
('_private_key', models.TextField(blank=True, max_length=4096, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key')),
|
||||
('_public_key', models.TextField(blank=True, max_length=4096, verbose_name='SSH public key')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True)),
|
||||
('date_updated', models.DateTimeField(auto_now=True)),
|
||||
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
|
||||
('ip', models.GenericIPAddressField(db_index=True, verbose_name='IP')),
|
||||
('port', models.IntegerField(default=22, verbose_name='Port')),
|
||||
('protocol', models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp')], default='ssh', max_length=16, verbose_name='Protocol')),
|
||||
('comment', models.CharField(blank=True, max_length=128, null=True, verbose_name='Comment')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
|
||||
('domain', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Domain', verbose_name='Domain')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='domain',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assets', to='assets.Domain', verbose_name='Domain'),
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-04-04 05:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0011_auto_20180326_0957'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='domain',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assets', to='assets.Domain', verbose_name='Domain'),
|
||||
),
|
||||
]
|
|
@ -1,25 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-04-11 03:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0012_auto_20180404_1302'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='assets',
|
||||
field=models.ManyToManyField(blank=True, to='assets.Asset', verbose_name='Assets'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='sudo',
|
||||
field=models.TextField(default='/bin/whoami', verbose_name='Sudo'),
|
||||
),
|
||||
]
|
|
@ -1,31 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-04-27 04:45
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0013_auto_20180411_1135'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_-]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gateway',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_-]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_-]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
]
|
|
@ -1,31 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-05-10 04:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0014_auto_20180427_1245'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gateway',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='username',
|
||||
field=models.CharField(max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-05-11 04:03
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0015_auto_20180510_1235'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='node',
|
||||
name='value',
|
||||
field=models.CharField(max_length=128, verbose_name='Value'),
|
||||
),
|
||||
]
|
|
@ -1,58 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-07-02 06:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_win_to_ssh_protocol(apps, schema_editor):
|
||||
asset_model = apps.get_model("assets", "Asset")
|
||||
db_alias = schema_editor.connection.alias
|
||||
asset_model.objects.using(db_alias).filter(platform__startswith='Win').update(protocol='rdp')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0016_auto_20180511_1203'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='protocol',
|
||||
field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)')], default='ssh', max_length=128, verbose_name='Protocol'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='login_mode',
|
||||
field=models.CharField(choices=[('auto', 'Automatic login'), ('manual', 'Manually login')], default='auto', max_length=10, verbose_name='Login mode'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='username',
|
||||
field=models.CharField(blank=True, max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='platform',
|
||||
field=models.CharField(choices=[('Linux', 'Linux'), ('Unix', 'Unix'), ('MacOS', 'MacOS'), ('BSD', 'BSD'), ('Windows', 'Windows'), ('Windows2016', 'Windows(2016)'), ('Other', 'Other')], default='Linux', max_length=128, verbose_name='Platform'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gateway',
|
||||
name='username',
|
||||
field=models.CharField(blank=True, max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='protocol',
|
||||
field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)')], default='ssh', max_length=16, verbose_name='Protocol'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='username',
|
||||
field=models.CharField(blank=True, max_length=32, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username'),
|
||||
),
|
||||
migrations.RunPython(migrate_win_to_ssh_protocol),
|
||||
]
|
|
@ -1,84 +0,0 @@
|
|||
# Generated by Django 2.0.7 on 2018-08-07 03:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0017_auto_20180702_1415'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='adminuser',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='gateway',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='label',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='node',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='hostname',
|
||||
field=models.CharField(max_length=128, verbose_name='Hostname'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gateway',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='adminuser',
|
||||
unique_together={('name', 'org_id')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='asset',
|
||||
unique_together={('org_id', 'hostname')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='gateway',
|
||||
unique_together={('name', 'org_id')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='systemuser',
|
||||
unique_together={('name', 'org_id')},
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# Generated by Django 2.0.7 on 2018-08-16 05:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0018_auto_20180807_1116'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='cpu_vcpus',
|
||||
field=models.IntegerField(null=True, verbose_name='CPU vcpus'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='label',
|
||||
unique_together={('name', 'value', 'org_id')},
|
||||
),
|
||||
]
|
|
@ -1,6 +1,5 @@
|
|||
# Generated by Django 2.1.7 on 2019-06-24 13:08
|
||||
|
||||
import common.fields.model
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import re
|
||||
from rest_framework import serializers
|
||||
|
||||
from common.fields import ChoiceDisplayField
|
||||
|
@ -20,8 +21,16 @@ class CommandFilterSerializer(BulkOrgResourceModelSerializer):
|
|||
|
||||
class CommandFilterRuleSerializer(BulkOrgResourceModelSerializer):
|
||||
serializer_choice_field = ChoiceDisplayField
|
||||
invalid_pattern = re.compile(r'[\.\*\+\[\\\?\{\}\^\$\|\(\)\#\<\>]')
|
||||
|
||||
class Meta:
|
||||
model = CommandFilterRule
|
||||
fields = '__all__'
|
||||
list_serializer_class = AdaptedBulkListSerializer
|
||||
|
||||
def validate_content(self, content):
|
||||
if self.invalid_pattern.search(content):
|
||||
invalid_char = self.invalid_pattern.pattern.replace('\\', '')
|
||||
msg = _("Content should not be contain: {}").format(invalid_char)
|
||||
raise serializers.ValidationError(msg)
|
||||
return content
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from django.db import models
|
||||
from django.http import JsonResponse
|
||||
from django.utils import timezone
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
from rest_framework.utils import html
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import SkipField
|
||||
|
||||
from .const import KEY_CACHE_RESOURCES_ID
|
||||
|
||||
|
||||
class NoDeleteQuerySet(models.query.QuerySet):
|
||||
|
||||
def delete(self):
|
||||
return self.update(is_discard=True, discard_time=timezone.now())
|
||||
|
||||
|
||||
class NoDeleteManager(models.Manager):
|
||||
|
||||
def get_all(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db)
|
||||
|
||||
def get_queryset(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=False)
|
||||
|
||||
def get_deleted(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=True)
|
||||
|
||||
|
||||
class NoDeleteModelMixin(models.Model):
|
||||
is_discard = models.BooleanField(verbose_name=_("is discard"), default=False)
|
||||
discard_time = models.DateTimeField(verbose_name=_("discard time"), null=True, blank=True)
|
||||
|
||||
objects = NoDeleteManager()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def delete(self):
|
||||
self.is_discard = True
|
||||
self.discard_time = timezone.now()
|
||||
return self.save()
|
||||
|
||||
|
||||
class JSONResponseMixin(object):
|
||||
"""JSON mixin"""
|
||||
@staticmethod
|
||||
def render_json_response(context):
|
||||
return JsonResponse(context)
|
||||
|
||||
|
||||
class IDInFilterMixin(object):
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super(IDInFilterMixin, self).filter_queryset(queryset)
|
||||
id_list = self.request.query_params.get('id__in')
|
||||
if id_list:
|
||||
import json
|
||||
try:
|
||||
ids = json.loads(id_list)
|
||||
except Exception as e:
|
||||
return queryset
|
||||
if isinstance(ids, list):
|
||||
queryset = queryset.filter(id__in=ids)
|
||||
return queryset
|
||||
|
||||
|
||||
class IDInCacheFilterMixin(object):
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super(IDInCacheFilterMixin, self).filter_queryset(queryset)
|
||||
spm = self.request.query_params.get('spm')
|
||||
cache_key = KEY_CACHE_RESOURCES_ID.format(spm)
|
||||
resources_id = cache.get(cache_key)
|
||||
if resources_id and isinstance(resources_id, list):
|
||||
queryset = queryset.filter(id__in=resources_id)
|
||||
return queryset
|
||||
|
||||
|
||||
class IDExportFilterMixin(object):
|
||||
def filter_queryset(self, queryset):
|
||||
# 下载导入模版
|
||||
if self.request.query_params.get('template') == 'import':
|
||||
return []
|
||||
else:
|
||||
return super(IDExportFilterMixin, self).filter_queryset(queryset)
|
||||
|
||||
|
||||
class BulkSerializerMixin(object):
|
||||
"""
|
||||
Become rest_framework_bulk not support uuid as a primary key
|
||||
so rewrite it. https://github.com/miki725/django-rest-framework-bulk/issues/66
|
||||
"""
|
||||
def to_internal_value(self, data):
|
||||
from rest_framework_bulk import BulkListSerializer
|
||||
ret = super(BulkSerializerMixin, self).to_internal_value(data)
|
||||
|
||||
id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
|
||||
if self.context.get('view'):
|
||||
request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')
|
||||
# add update_lookup_field field back to validated data
|
||||
# since super by default strips out read-only fields
|
||||
# hence id will no longer be present in validated_data
|
||||
if all((isinstance(self.root, BulkListSerializer),
|
||||
id_attr,
|
||||
request_method in ('PUT', 'PATCH'))):
|
||||
id_field = self.fields[id_attr]
|
||||
if data.get("id"):
|
||||
id_value = id_field.to_internal_value(data.get("id"))
|
||||
else:
|
||||
id_value = id_field.to_internal_value(data.get("pk"))
|
||||
ret[id_attr] = id_value
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class BulkListSerializerMixin(object):
|
||||
"""
|
||||
Become rest_framework_bulk doing bulk update raise Exception:
|
||||
'QuerySet' object has no attribute 'pk' when doing bulk update
|
||||
so rewrite it .
|
||||
https://github.com/miki725/django-rest-framework-bulk/issues/68
|
||||
"""
|
||||
|
||||
def to_internal_value(self, data):
|
||||
"""
|
||||
List of dicts of native values <- List of dicts of primitive datatypes.
|
||||
"""
|
||||
if html.is_html_input(data):
|
||||
data = html.parse_html_list(data)
|
||||
|
||||
if not isinstance(data, list):
|
||||
message = self.error_messages['not_a_list'].format(
|
||||
input_type=type(data).__name__
|
||||
)
|
||||
raise ValidationError({
|
||||
api_settings.NON_FIELD_ERRORS_KEY: [message]
|
||||
}, code='not_a_list')
|
||||
|
||||
if not self.allow_empty and len(data) == 0:
|
||||
if self.parent and self.partial:
|
||||
raise SkipField()
|
||||
|
||||
message = self.error_messages['empty']
|
||||
raise ValidationError({
|
||||
api_settings.NON_FIELD_ERRORS_KEY: [message]
|
||||
}, code='empty')
|
||||
|
||||
ret = []
|
||||
errors = []
|
||||
|
||||
for item in data:
|
||||
try:
|
||||
# prepare child serializer to only handle one instance
|
||||
if 'id' in item.keys():
|
||||
self.child.instance = self.instance.get(id=item['id']) if self.instance else None
|
||||
if 'pk' in item.keys():
|
||||
self.child.instance = self.instance.get(id=item['pk']) if self.instance else None
|
||||
|
||||
self.child.initial_data = item
|
||||
# raw
|
||||
validated = self.child.run_validation(item)
|
||||
except ValidationError as exc:
|
||||
errors.append(exc.detail)
|
||||
else:
|
||||
ret.append(validated)
|
||||
errors.append({})
|
||||
|
||||
if any(errors):
|
||||
raise ValidationError(errors)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class DatetimeSearchMixin:
|
||||
date_format = '%Y-%m-%d'
|
||||
date_from = date_to = None
|
||||
|
||||
def get_date_range(self):
|
||||
date_from_s = self.request.GET.get('date_from')
|
||||
date_to_s = self.request.GET.get('date_to')
|
||||
|
||||
if date_from_s:
|
||||
date_from = timezone.datetime.strptime(date_from_s, self.date_format)
|
||||
tz = timezone.get_current_timezone()
|
||||
self.date_from = tz.localize(date_from)
|
||||
else:
|
||||
self.date_from = timezone.now() - timezone.timedelta(7)
|
||||
|
||||
if date_to_s:
|
||||
date_to = timezone.datetime.strptime(
|
||||
date_to_s + ' 23:59:59', self.date_format + ' %H:%M:%S'
|
||||
)
|
||||
self.date_to = date_to.replace(
|
||||
tzinfo=timezone.get_current_timezone()
|
||||
)
|
||||
else:
|
||||
self.date_to = timezone.now()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.get_date_range()
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ApiMessageMixin:
|
||||
success_message = _("%(name)s was %(action)s successfully")
|
||||
_action_map = {"create": _("create"), "update": _("update")}
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
if not isinstance(cleaned_data, dict):
|
||||
return ''
|
||||
data = {k: v for k, v in cleaned_data.items()}
|
||||
action = getattr(self, "action", "create")
|
||||
data["action"] = self._action_map.get(action)
|
||||
try:
|
||||
message = self.success_message % data
|
||||
except:
|
||||
message = ''
|
||||
return message
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
resp = super().dispatch(request, *args, **kwargs)
|
||||
if request.method.lower() in ("get", "delete", "patch"):
|
||||
return resp
|
||||
if resp.status_code >= 400:
|
||||
return resp
|
||||
message = self.get_success_message(resp.data)
|
||||
if message:
|
||||
messages.success(request, message)
|
||||
return resp
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from .models import *
|
||||
from .serializers import *
|
||||
from .api import *
|
||||
from .views import *
|
|
@ -0,0 +1,84 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.http import JsonResponse
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
|
||||
from ..const import KEY_CACHE_RESOURCES_ID
|
||||
|
||||
__all__ = [
|
||||
"JSONResponseMixin", "IDInCacheFilterMixin", "IDExportFilterMixin",
|
||||
"IDInFilterMixin", "ApiMessageMixin"
|
||||
]
|
||||
|
||||
|
||||
class JSONResponseMixin(object):
|
||||
"""JSON mixin"""
|
||||
@staticmethod
|
||||
def render_json_response(context):
|
||||
return JsonResponse(context)
|
||||
|
||||
|
||||
class IDInFilterMixin(object):
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super(IDInFilterMixin, self).filter_queryset(queryset)
|
||||
id_list = self.request.query_params.get('id__in')
|
||||
if id_list:
|
||||
import json
|
||||
try:
|
||||
ids = json.loads(id_list)
|
||||
except Exception as e:
|
||||
return queryset
|
||||
if isinstance(ids, list):
|
||||
queryset = queryset.filter(id__in=ids)
|
||||
return queryset
|
||||
|
||||
|
||||
class IDInCacheFilterMixin(object):
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super(IDInCacheFilterMixin, self).filter_queryset(queryset)
|
||||
spm = self.request.query_params.get('spm')
|
||||
cache_key = KEY_CACHE_RESOURCES_ID.format(spm)
|
||||
resources_id = cache.get(cache_key)
|
||||
if resources_id and isinstance(resources_id, list):
|
||||
queryset = queryset.filter(id__in=resources_id)
|
||||
return queryset
|
||||
|
||||
|
||||
class IDExportFilterMixin(object):
|
||||
def filter_queryset(self, queryset):
|
||||
# 下载导入模版
|
||||
if self.request.query_params.get('template') == 'import':
|
||||
return []
|
||||
else:
|
||||
return super(IDExportFilterMixin, self).filter_queryset(queryset)
|
||||
|
||||
|
||||
class ApiMessageMixin:
|
||||
success_message = _("%(name)s was %(action)s successfully")
|
||||
_action_map = {"create": _("create"), "update": _("update")}
|
||||
|
||||
def get_success_message(self, cleaned_data):
|
||||
if not isinstance(cleaned_data, dict):
|
||||
return ''
|
||||
data = {k: v for k, v in cleaned_data.items()}
|
||||
action = getattr(self, "action", "create")
|
||||
data["action"] = self._action_map.get(action)
|
||||
try:
|
||||
message = self.success_message % data
|
||||
except:
|
||||
message = ''
|
||||
return message
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
resp = super().dispatch(request, *args, **kwargs)
|
||||
if request.method.lower() in ("get", "delete", "patch"):
|
||||
return resp
|
||||
if resp.status_code >= 400:
|
||||
return resp
|
||||
message = self.get_success_message(resp.data)
|
||||
if message:
|
||||
messages.success(request, message)
|
||||
return resp
|
|
@ -0,0 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
__all__ = ["NoDeleteManager", "NoDeleteModelMixin", "NoDeleteQuerySet"]
|
||||
|
||||
|
||||
class NoDeleteQuerySet(models.query.QuerySet):
|
||||
|
||||
def delete(self):
|
||||
return self.update(is_discard=True, discard_time=timezone.now())
|
||||
|
||||
|
||||
class NoDeleteManager(models.Manager):
|
||||
|
||||
def get_all(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db)
|
||||
|
||||
def get_queryset(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=False)
|
||||
|
||||
def get_deleted(self):
|
||||
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=True)
|
||||
|
||||
|
||||
class NoDeleteModelMixin(models.Model):
|
||||
is_discard = models.BooleanField(verbose_name=_("is discard"), default=False)
|
||||
discard_time = models.DateTimeField(verbose_name=_("discard time"), null=True, blank=True)
|
||||
|
||||
objects = NoDeleteManager()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def delete(self):
|
||||
self.is_discard = True
|
||||
self.discard_time = timezone.now()
|
||||
return self.save()
|
|
@ -0,0 +1,95 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from rest_framework.utils import html
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import SkipField
|
||||
|
||||
__all__ = ['BulkSerializerMixin', 'BulkListSerializerMixin']
|
||||
|
||||
|
||||
class BulkSerializerMixin(object):
|
||||
"""
|
||||
Become rest_framework_bulk not support uuid as a primary key
|
||||
so rewrite it. https://github.com/miki725/django-rest-framework-bulk/issues/66
|
||||
"""
|
||||
def to_internal_value(self, data):
|
||||
from rest_framework_bulk import BulkListSerializer
|
||||
ret = super(BulkSerializerMixin, self).to_internal_value(data)
|
||||
|
||||
id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
|
||||
if self.context.get('view'):
|
||||
request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')
|
||||
# add update_lookup_field field back to validated data
|
||||
# since super by default strips out read-only fields
|
||||
# hence id will no longer be present in validated_data
|
||||
if all((isinstance(self.root, BulkListSerializer),
|
||||
id_attr,
|
||||
request_method in ('PUT', 'PATCH'))):
|
||||
id_field = self.fields[id_attr]
|
||||
if data.get("id"):
|
||||
id_value = id_field.to_internal_value(data.get("id"))
|
||||
else:
|
||||
id_value = id_field.to_internal_value(data.get("pk"))
|
||||
ret[id_attr] = id_value
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class BulkListSerializerMixin(object):
|
||||
"""
|
||||
Become rest_framework_bulk doing bulk update raise Exception:
|
||||
'QuerySet' object has no attribute 'pk' when doing bulk update
|
||||
so rewrite it .
|
||||
https://github.com/miki725/django-rest-framework-bulk/issues/68
|
||||
"""
|
||||
|
||||
def to_internal_value(self, data):
|
||||
"""
|
||||
List of dicts of native values <- List of dicts of primitive datatypes.
|
||||
"""
|
||||
if html.is_html_input(data):
|
||||
data = html.parse_html_list(data)
|
||||
|
||||
if not isinstance(data, list):
|
||||
message = self.error_messages['not_a_list'].format(
|
||||
input_type=type(data).__name__
|
||||
)
|
||||
raise ValidationError({
|
||||
api_settings.NON_FIELD_ERRORS_KEY: [message]
|
||||
}, code='not_a_list')
|
||||
|
||||
if not self.allow_empty and len(data) == 0:
|
||||
if self.parent and self.partial:
|
||||
raise SkipField()
|
||||
|
||||
message = self.error_messages['empty']
|
||||
raise ValidationError({
|
||||
api_settings.NON_FIELD_ERRORS_KEY: [message]
|
||||
}, code='empty')
|
||||
|
||||
ret = []
|
||||
errors = []
|
||||
|
||||
for item in data:
|
||||
try:
|
||||
# prepare child serializer to only handle one instance
|
||||
if 'id' in item.keys():
|
||||
self.child.instance = self.instance.get(id=item['id']) if self.instance else None
|
||||
if 'pk' in item.keys():
|
||||
self.child.instance = self.instance.get(id=item['pk']) if self.instance else None
|
||||
|
||||
self.child.initial_data = item
|
||||
# raw
|
||||
validated = self.child.run_validation(item)
|
||||
except ValidationError as exc:
|
||||
errors.append(exc.detail)
|
||||
else:
|
||||
ret.append(validated)
|
||||
errors.append({})
|
||||
|
||||
if any(errors):
|
||||
raise ValidationError(errors)
|
||||
|
||||
return ret
|
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# coding: utf-8
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
__all__ = ["DatetimeSearchMixin"]
|
||||
|
||||
|
||||
class DatetimeSearchMixin:
|
||||
date_format = '%Y-%m-%d'
|
||||
date_from = date_to = None
|
||||
|
||||
def get_date_range(self):
|
||||
date_from_s = self.request.GET.get('date_from')
|
||||
date_to_s = self.request.GET.get('date_to')
|
||||
|
||||
if date_from_s:
|
||||
date_from = timezone.datetime.strptime(date_from_s, self.date_format)
|
||||
tz = timezone.get_current_timezone()
|
||||
self.date_from = tz.localize(date_from)
|
||||
else:
|
||||
self.date_from = timezone.now() - timezone.timedelta(7)
|
||||
|
||||
if date_to_s:
|
||||
date_to = timezone.datetime.strptime(
|
||||
date_to_s + ' 23:59:59', self.date_format + ' %H:%M:%S'
|
||||
)
|
||||
self.date_to = date_to.replace(
|
||||
tzinfo=timezone.get_current_timezone()
|
||||
)
|
||||
else:
|
||||
self.date_to = timezone.now()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.get_date_range()
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
|
@ -301,10 +301,10 @@ LOGGING = {
|
|||
'handlers': ['gunicorn_console', 'gunicorn_file'],
|
||||
'level': 'INFO',
|
||||
},
|
||||
# 'django.db': {
|
||||
# 'handlers': ['console', 'file'],
|
||||
# 'level': 'DEBUG'
|
||||
# }
|
||||
'django.db': {
|
||||
'handlers': ['console', 'file'],
|
||||
'level': 'DEBUG'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Jumpserver 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-06-28 20:08+0800\n"
|
||||
"POT-Creation-Date: 2019-07-02 14:47+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
||||
|
@ -86,7 +86,7 @@ msgstr "运行参数"
|
|||
#: assets/templates/assets/system_user_list.html:55 audits/models.py:19
|
||||
#: audits/templates/audits/ftp_log_list.html:41
|
||||
#: audits/templates/audits/ftp_log_list.html:71
|
||||
#: perms/forms/asset_permission.py:47 perms/models/asset_permission.py:53
|
||||
#: perms/forms/asset_permission.py:68 perms/models/asset_permission.py:85
|
||||
#: perms/templates/perms/asset_permission_create_update.html:45
|
||||
#: perms/templates/perms/asset_permission_list.html:48
|
||||
#: perms/templates/perms/asset_permission_list.html:117
|
||||
|
@ -115,8 +115,8 @@ msgstr "资产"
|
|||
#: assets/models/user.py:160 assets/templates/assets/user_asset_list.html:172
|
||||
#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49
|
||||
#: audits/templates/audits/ftp_log_list.html:72
|
||||
#: perms/forms/asset_permission.py:53 perms/models/asset_permission.py:55
|
||||
#: perms/models/asset_permission.py:76
|
||||
#: perms/forms/asset_permission.py:74 perms/models/asset_permission.py:87
|
||||
#: perms/models/asset_permission.py:104
|
||||
#: perms/templates/perms/asset_permission_detail.html:140
|
||||
#: perms/templates/perms/asset_permission_list.html:50
|
||||
#: perms/templates/perms/asset_permission_list.html:71
|
||||
|
@ -149,7 +149,7 @@ msgstr "系统用户"
|
|||
#: assets/templates/assets/system_user_detail.html:58
|
||||
#: assets/templates/assets/system_user_list.html:51 ops/models/adhoc.py:37
|
||||
#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27
|
||||
#: orgs/models.py:11 perms/models/asset_permission.py:22
|
||||
#: orgs/models.py:11 perms/models/asset_permission.py:23
|
||||
#: perms/models/base.py:35
|
||||
#: perms/templates/perms/asset_permission_detail.html:62
|
||||
#: perms/templates/perms/asset_permission_list.html:45
|
||||
|
@ -215,10 +215,10 @@ msgstr "参数"
|
|||
#: assets/templates/assets/domain_detail.html:72
|
||||
#: assets/templates/assets/system_user_detail.html:100
|
||||
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:14
|
||||
#: perms/models/asset_permission.py:79 perms/models/base.py:41
|
||||
#: perms/models/asset_permission.py:107 perms/models/base.py:41
|
||||
#: perms/templates/perms/asset_permission_detail.html:98
|
||||
#: perms/templates/perms/remote_app_permission_detail.html:90
|
||||
#: users/models/user.py:105 users/serializers/v1.py:99
|
||||
#: users/models/user.py:105 users/serializers/v1.py:107
|
||||
#: users/templates/users/user_detail.html:111
|
||||
#: xpack/plugins/change_auth_plan/models.py:106
|
||||
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
|
||||
|
@ -238,7 +238,7 @@ msgstr "创建者"
|
|||
#: assets/templates/assets/domain_detail.html:68
|
||||
#: assets/templates/assets/system_user_detail.html:96
|
||||
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64
|
||||
#: orgs/models.py:15 perms/models/asset_permission.py:80
|
||||
#: orgs/models.py:15 perms/models/asset_permission.py:108
|
||||
#: perms/models/base.py:42
|
||||
#: perms/templates/perms/asset_permission_detail.html:94
|
||||
#: perms/templates/perms/remote_app_permission_detail.html:86
|
||||
|
@ -274,7 +274,7 @@ msgstr "创建日期"
|
|||
#: assets/templates/assets/system_user_detail.html:104
|
||||
#: assets/templates/assets/system_user_list.html:59
|
||||
#: assets/templates/assets/user_asset_list.html:175 ops/models/adhoc.py:43
|
||||
#: orgs/models.py:16 perms/models/asset_permission.py:81
|
||||
#: orgs/models.py:16 perms/models/asset_permission.py:109
|
||||
#: perms/models/base.py:43
|
||||
#: perms/templates/perms/asset_permission_detail.html:102
|
||||
#: perms/templates/perms/remote_app_permission_detail.html:94
|
||||
|
@ -440,7 +440,6 @@ msgstr "详情"
|
|||
#: users/templates/users/user_group_list.html:20
|
||||
#: users/templates/users/user_group_list.html:70
|
||||
#: users/templates/users/user_list.html:20
|
||||
#: users/templates/users/user_list.html:96
|
||||
#: users/templates/users/user_list.html:99
|
||||
#: users/templates/users/user_profile.html:177
|
||||
#: users/templates/users/user_profile.html:187
|
||||
|
@ -481,7 +480,6 @@ msgstr "更新"
|
|||
#: users/templates/users/user_detail.html:30
|
||||
#: users/templates/users/user_group_detail.html:32
|
||||
#: users/templates/users/user_group_list.html:72
|
||||
#: users/templates/users/user_list.html:104
|
||||
#: users/templates/users/user_list.html:108
|
||||
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33
|
||||
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57
|
||||
|
@ -529,8 +527,7 @@ msgstr "创建远程应用"
|
|||
#: audits/templates/audits/operate_log_list.html:67
|
||||
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
|
||||
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34
|
||||
#: perms/forms/asset_permission.py:56 perms/models/asset_permission.py:26
|
||||
#: perms/models/asset_permission.py:57
|
||||
#: perms/forms/asset_permission.py:21 perms/models/asset_permission.py:27
|
||||
#: perms/templates/perms/asset_permission_create_update.html:50
|
||||
#: perms/templates/perms/asset_permission_list.html:52
|
||||
#: perms/templates/perms/asset_permission_list.html:126
|
||||
|
@ -552,7 +549,7 @@ msgstr "动作"
|
|||
|
||||
#: applications/templates/applications/user_remote_app_list.html:57
|
||||
#: assets/templates/assets/user_asset_list.html:100 perms/const.py:19
|
||||
#: perms/models/asset_permission.py:45
|
||||
#: perms/models/asset_permission.py:46
|
||||
msgid "Connect"
|
||||
msgstr "连接"
|
||||
|
||||
|
@ -591,11 +588,11 @@ msgstr "请选择需要更新的资产"
|
|||
msgid "You can't update the root node name"
|
||||
msgstr "不能修改根节点名称"
|
||||
|
||||
#: assets/api/node.py:281
|
||||
#: assets/api/node.py:283
|
||||
msgid "Update node asset hardware information: {}"
|
||||
msgstr "更新节点资产硬件信息: {}"
|
||||
|
||||
#: assets/api/node.py:295
|
||||
#: assets/api/node.py:297
|
||||
msgid "Test if the assets under the node are connectable: {}"
|
||||
msgstr "测试节点下资产是否可连接: {}"
|
||||
|
||||
|
@ -622,7 +619,7 @@ msgstr "未知"
|
|||
#: assets/templates/assets/asset_detail.html:194
|
||||
#: assets/templates/assets/asset_detail.html:202
|
||||
#: assets/templates/assets/system_user_assets.html:83
|
||||
#: perms/models/asset_permission.py:54
|
||||
#: perms/models/asset_permission.py:86
|
||||
#: xpack/plugins/change_auth_plan/models.py:72
|
||||
msgid "Nodes"
|
||||
msgstr "节点"
|
||||
|
@ -656,8 +653,8 @@ msgstr "网域"
|
|||
#: assets/forms/asset.py:64 assets/forms/asset.py:86 assets/forms/asset.py:99
|
||||
#: assets/forms/asset.py:134 assets/models/node.py:248
|
||||
#: assets/templates/assets/asset_create.html:42
|
||||
#: perms/forms/asset_permission.py:50 perms/forms/asset_permission.py:60
|
||||
#: perms/models/asset_permission.py:74
|
||||
#: perms/forms/asset_permission.py:71 perms/forms/asset_permission.py:79
|
||||
#: perms/models/asset_permission.py:102
|
||||
#: perms/templates/perms/asset_permission_list.html:49
|
||||
#: perms/templates/perms/asset_permission_list.html:70
|
||||
#: perms/templates/perms/asset_permission_list.html:120
|
||||
|
@ -695,6 +692,10 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
|
|||
msgid "Select assets"
|
||||
msgstr "选择资产"
|
||||
|
||||
#: assets/forms/cmd_filter.py:37 assets/serializers/cmd_filter.py:34
|
||||
msgid "Content should not be contain: {}"
|
||||
msgstr "内容不能包含: {}"
|
||||
|
||||
#: assets/forms/domain.py:51
|
||||
msgid "Password should not contain special characters"
|
||||
msgstr "不能包含特殊字符"
|
||||
|
@ -1000,7 +1001,7 @@ msgid "Operator"
|
|||
msgstr "运营商"
|
||||
|
||||
#: assets/models/cluster.py:36 assets/models/group.py:34
|
||||
#: perms/utils/asset_permission.py:67
|
||||
#: perms/utils/asset_permission.py:106
|
||||
msgid "Default"
|
||||
msgstr "默认"
|
||||
|
||||
|
@ -1112,7 +1113,7 @@ msgstr "默认资产组"
|
|||
#: audits/templates/audits/password_change_log_list.html:50
|
||||
#: ops/templates/ops/command_execution_list.html:35
|
||||
#: ops/templates/ops/command_execution_list.html:60
|
||||
#: perms/forms/asset_permission.py:41 perms/forms/remote_app_permission.py:31
|
||||
#: perms/forms/asset_permission.py:62 perms/forms/remote_app_permission.py:31
|
||||
#: perms/models/base.py:36
|
||||
#: perms/templates/perms/asset_permission_create_update.html:41
|
||||
#: perms/templates/perms/asset_permission_list.html:46
|
||||
|
@ -1124,9 +1125,9 @@ msgstr "默认资产组"
|
|||
#: terminal/templates/terminal/command_list.html:72
|
||||
#: terminal/templates/terminal/session_list.html:33
|
||||
#: terminal/templates/terminal/session_list.html:71 users/forms.py:301
|
||||
#: users/models/user.py:38 users/models/user.py:431 users/serializers/v1.py:88
|
||||
#: users/models/user.py:38 users/models/user.py:431 users/serializers/v1.py:96
|
||||
#: users/templates/users/user_group_detail.html:78
|
||||
#: users/templates/users/user_group_list.html:36 users/views/user.py:407
|
||||
#: users/templates/users/user_group_list.html:36 users/views/user.py:264
|
||||
#: xpack/plugins/orgs/forms.py:26
|
||||
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
|
||||
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
|
||||
|
@ -1205,26 +1206,25 @@ msgstr "登录模式"
|
|||
msgid "%(value)s is not an even number"
|
||||
msgstr "%(value)s is not an even number"
|
||||
|
||||
#: assets/serializers/admin_user.py:36 assets/serializers/asset.py:47
|
||||
#: assets/serializers/admin_user.py:36 assets/serializers/asset.py:46
|
||||
#: assets/serializers/asset_user.py:30 assets/serializers/system_user.py:30
|
||||
#: assets/templates/assets/_asset_user_list.html:18
|
||||
msgid "Connectivity"
|
||||
msgstr "连接"
|
||||
|
||||
#: assets/serializers/asset.py:45 assets/serializers/asset.py:155
|
||||
#: assets/templates/assets/asset_create.html:24
|
||||
#: assets/serializers/asset.py:44 assets/templates/assets/asset_create.html:24
|
||||
msgid "Protocols"
|
||||
msgstr "协议组"
|
||||
|
||||
#: assets/serializers/asset.py:73
|
||||
#: assets/serializers/asset.py:72
|
||||
msgid "Hardware info"
|
||||
msgstr "硬件信息"
|
||||
|
||||
#: assets/serializers/asset.py:74 orgs/mixins.py:192
|
||||
#: assets/serializers/asset.py:73 orgs/mixins.py:192
|
||||
msgid "Org name"
|
||||
msgstr "组织名称"
|
||||
|
||||
#: assets/serializers/asset.py:92
|
||||
#: assets/serializers/asset.py:91
|
||||
msgid "Protocol duplicate: {}"
|
||||
msgstr "协议重复: {}"
|
||||
|
||||
|
@ -1710,7 +1710,7 @@ msgstr "创建日期"
|
|||
|
||||
#: assets/templates/assets/asset_detail.html:154
|
||||
#: assets/templates/assets/user_asset_list.html:46
|
||||
#: perms/models/asset_permission.py:77 perms/models/base.py:38
|
||||
#: perms/models/asset_permission.py:105 perms/models/base.py:38
|
||||
#: perms/templates/perms/asset_permission_create_update.html:55
|
||||
#: perms/templates/perms/asset_permission_detail.html:120
|
||||
#: perms/templates/perms/remote_app_permission_create_update.html:54
|
||||
|
@ -2056,10 +2056,6 @@ msgstr "批量更新资产"
|
|||
msgid "Update asset"
|
||||
msgstr "更新资产"
|
||||
|
||||
#: assets/views/asset.py:347
|
||||
msgid "already exists"
|
||||
msgstr "已经存在"
|
||||
|
||||
#: assets/views/cmd_filter.py:32
|
||||
msgid "Command filter list"
|
||||
msgstr "命令过滤器列表"
|
||||
|
@ -2557,8 +2553,8 @@ msgstr "欢迎回来,请输入用户名和密码登录"
|
|||
msgid "Please enable cookies and try again."
|
||||
msgstr "设置你的浏览器支持cookie"
|
||||
|
||||
#: authentication/views/login.py:172 users/views/user.py:555
|
||||
#: users/views/user.py:580
|
||||
#: authentication/views/login.py:172 users/views/user.py:412
|
||||
#: users/views/user.py:437
|
||||
msgid "MFA code invalid, or ntp sync server time"
|
||||
msgstr "MFA验证码不正确,或者服务器端时间不对"
|
||||
|
||||
|
@ -3000,11 +2996,11 @@ msgstr "命令执行"
|
|||
msgid "Organization"
|
||||
msgstr "组织"
|
||||
|
||||
#: perms/const.py:18 perms/models/asset_permission.py:44 settings/forms.py:143
|
||||
#: perms/const.py:18 perms/models/asset_permission.py:45 settings/forms.py:143
|
||||
msgid "All"
|
||||
msgstr "全部"
|
||||
|
||||
#: perms/const.py:20 perms/models/asset_permission.py:46
|
||||
#: perms/const.py:20 perms/models/asset_permission.py:47
|
||||
msgid "Upload file"
|
||||
msgstr "上传文件"
|
||||
|
||||
|
@ -3012,8 +3008,8 @@ msgstr "上传文件"
|
|||
msgid "Download file"
|
||||
msgstr "下载文件"
|
||||
|
||||
#: perms/forms/asset_permission.py:44 perms/forms/remote_app_permission.py:34
|
||||
#: perms/models/asset_permission.py:75 perms/models/base.py:37
|
||||
#: perms/forms/asset_permission.py:65 perms/forms/remote_app_permission.py:34
|
||||
#: perms/models/asset_permission.py:103 perms/models/base.py:37
|
||||
#: perms/templates/perms/asset_permission_list.html:47
|
||||
#: perms/templates/perms/asset_permission_list.html:67
|
||||
#: perms/templates/perms/asset_permission_list.html:114
|
||||
|
@ -3026,30 +3022,34 @@ msgstr "下载文件"
|
|||
msgid "User group"
|
||||
msgstr "用户组"
|
||||
|
||||
#: perms/forms/asset_permission.py:63
|
||||
#: perms/forms/asset_permission.py:82
|
||||
msgid ""
|
||||
"Tips: The RDP protocol does not support separate controls for uploading or "
|
||||
"downloading files"
|
||||
msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
|
||||
|
||||
#: perms/forms/asset_permission.py:73 perms/forms/remote_app_permission.py:47
|
||||
#: perms/forms/asset_permission.py:92 perms/forms/remote_app_permission.py:47
|
||||
msgid "User or group at least one required"
|
||||
msgstr "用户和用户组至少选一个"
|
||||
|
||||
#: perms/forms/asset_permission.py:82
|
||||
#: perms/forms/asset_permission.py:101
|
||||
msgid "Asset or group at least one required"
|
||||
msgstr "资产和节点至少选一个"
|
||||
|
||||
#: perms/models/asset_permission.py:47
|
||||
#: perms/models/asset_permission.py:49
|
||||
msgid "Upload download"
|
||||
msgstr "上传下载"
|
||||
|
||||
#: perms/models/asset_permission.py:61 perms/models/asset_permission.py:87
|
||||
#: perms/models/asset_permission.py:89
|
||||
msgid "Actions"
|
||||
msgstr "动作"
|
||||
|
||||
#: perms/models/asset_permission.py:93 perms/models/asset_permission.py:115
|
||||
#: templates/_nav.html:44
|
||||
msgid "Asset permission"
|
||||
msgstr "资产授权"
|
||||
|
||||
#: perms/models/asset_permission.py:78 perms/models/base.py:40
|
||||
#: perms/models/asset_permission.py:106 perms/models/base.py:40
|
||||
#: perms/templates/perms/asset_permission_detail.html:90
|
||||
#: perms/templates/perms/remote_app_permission_detail.html:82
|
||||
#: users/models/user.py:102 users/templates/users/user_detail.html:107
|
||||
|
@ -3199,8 +3199,8 @@ msgid "Add user group to this permission"
|
|||
msgstr "添加用户组"
|
||||
|
||||
#: perms/views/asset_permission.py:34 perms/views/asset_permission.py:65
|
||||
#: perms/views/asset_permission.py:81 perms/views/asset_permission.py:97
|
||||
#: perms/views/asset_permission.py:134 perms/views/asset_permission.py:167
|
||||
#: perms/views/asset_permission.py:82 perms/views/asset_permission.py:99
|
||||
#: perms/views/asset_permission.py:136 perms/views/asset_permission.py:169
|
||||
#: perms/views/remote_app_permission.py:33
|
||||
#: perms/views/remote_app_permission.py:49
|
||||
#: perms/views/remote_app_permission.py:65
|
||||
|
@ -3219,19 +3219,19 @@ msgstr "资产授权列表"
|
|||
msgid "Create asset permission"
|
||||
msgstr "创建权限规则"
|
||||
|
||||
#: perms/views/asset_permission.py:82
|
||||
#: perms/views/asset_permission.py:83
|
||||
msgid "Update asset permission"
|
||||
msgstr "更新资产授权"
|
||||
|
||||
#: perms/views/asset_permission.py:98
|
||||
#: perms/views/asset_permission.py:100
|
||||
msgid "Asset permission detail"
|
||||
msgstr "资产授权详情"
|
||||
|
||||
#: perms/views/asset_permission.py:135
|
||||
#: perms/views/asset_permission.py:137
|
||||
msgid "Asset permission user list"
|
||||
msgstr "资产授权用户列表"
|
||||
|
||||
#: perms/views/asset_permission.py:168
|
||||
#: perms/views/asset_permission.py:170
|
||||
msgid "Asset permission asset list"
|
||||
msgstr "资产授权资产列表"
|
||||
|
||||
|
@ -3828,7 +3828,7 @@ msgstr "商业支持"
|
|||
#: users/templates/users/user_profile.html:17
|
||||
#: users/templates/users/user_profile_update.html:37
|
||||
#: users/templates/users/user_profile_update.html:57
|
||||
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:388
|
||||
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:245
|
||||
msgid "Profile"
|
||||
msgstr "个人信息"
|
||||
|
||||
|
@ -3923,13 +3923,13 @@ msgstr ""
|
|||
|
||||
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:45
|
||||
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:96
|
||||
#: users/views/login.py:154 users/views/user.py:70 users/views/user.py:87
|
||||
#: users/views/user.py:131 users/views/user.py:211 users/views/user.py:374
|
||||
#: users/views/user.py:426 users/views/user.py:467
|
||||
#: users/views/login.py:154 users/views/user.py:68 users/views/user.py:85
|
||||
#: users/views/user.py:129 users/views/user.py:209 users/views/user.py:231
|
||||
#: users/views/user.py:283 users/views/user.py:324
|
||||
msgid "Users"
|
||||
msgstr "用户管理"
|
||||
|
||||
#: templates/_nav.html:13 users/views/user.py:71
|
||||
#: templates/_nav.html:13 users/views/user.py:69
|
||||
msgid "User list"
|
||||
msgstr "用户列表"
|
||||
|
||||
|
@ -4369,11 +4369,11 @@ msgid ""
|
|||
"You should use your ssh client tools connect terminal: {} <br /> <br />{}"
|
||||
msgstr "你可以使用ssh客户端工具连接终端"
|
||||
|
||||
#: users/api/user.py:79 users/api/user.py:90 users/api/user.py:116
|
||||
#: users/api/user.py:93
|
||||
msgid "You do not have permission."
|
||||
msgstr "你没有权限"
|
||||
|
||||
#: users/api/user.py:221
|
||||
#: users/api/user.py:186
|
||||
msgid "Could not reset self otp, use profile reset instead"
|
||||
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
|
||||
|
||||
|
@ -4405,7 +4405,7 @@ msgstr "添加到用户组"
|
|||
msgid "Public key should not be the same as your old one."
|
||||
msgstr "不能和原来的密钥相同"
|
||||
|
||||
#: users/forms.py:90 users/forms.py:237 users/serializers/v1.py:74
|
||||
#: users/forms.py:90 users/forms.py:237 users/serializers/v1.py:82
|
||||
msgid "Not a valid ssh public key"
|
||||
msgstr "ssh密钥不合法"
|
||||
|
||||
|
@ -4532,7 +4532,7 @@ msgid "Date password last updated"
|
|||
msgstr "最后更新密码日期"
|
||||
|
||||
#: users/models/user.py:139 users/templates/users/user_update.html:22
|
||||
#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:439
|
||||
#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:296
|
||||
msgid "User auth from {}, go there change password"
|
||||
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
|
||||
|
||||
|
@ -4569,10 +4569,12 @@ msgid "Avatar url"
|
|||
msgstr "头像路径"
|
||||
|
||||
#: users/serializers/v1.py:46
|
||||
#, fuzzy
|
||||
#| msgid "Password does not match"
|
||||
msgid "Role limit to {}"
|
||||
msgstr "角色只能为 {}"
|
||||
|
||||
#: users/serializers/v1.py:54
|
||||
msgid "Password does not match security rules"
|
||||
msgstr "密码不一致"
|
||||
msgstr "密码不满足安全规则"
|
||||
|
||||
#: users/serializers_v2/user.py:36
|
||||
msgid "name not unique"
|
||||
|
@ -4624,7 +4626,7 @@ msgid "Import users"
|
|||
msgstr "导入用户"
|
||||
|
||||
#: users/templates/users/_user_update_modal.html:4
|
||||
#: users/templates/users/user_update.html:4 users/views/user.py:132
|
||||
#: users/templates/users/user_update.html:4 users/views/user.py:130
|
||||
msgid "Update user"
|
||||
msgstr "更新用户"
|
||||
|
||||
|
@ -4762,12 +4764,12 @@ msgid "Very strong"
|
|||
msgstr "很强"
|
||||
|
||||
#: users/templates/users/user_create.html:4
|
||||
#: users/templates/users/user_list.html:28 users/views/user.py:88
|
||||
#: users/templates/users/user_list.html:28 users/views/user.py:86
|
||||
msgid "Create user"
|
||||
msgstr "创建用户"
|
||||
|
||||
#: users/templates/users/user_detail.html:19
|
||||
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:212
|
||||
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:210
|
||||
msgid "User detail"
|
||||
msgstr "用户详情"
|
||||
|
||||
|
@ -4967,8 +4969,7 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接
|
|||
msgid "Administrator Settings force MFA login"
|
||||
msgstr "管理员设置强制使用MFA登录"
|
||||
|
||||
#: users/templates/users/user_profile.html:120 users/views/user.py:248
|
||||
#: users/views/user.py:303
|
||||
#: users/templates/users/user_profile.html:120
|
||||
msgid "User groups"
|
||||
msgstr "用户组"
|
||||
|
||||
|
@ -5243,7 +5244,7 @@ msgstr "Token错误或失效"
|
|||
msgid "Password not same"
|
||||
msgstr "密码不一致"
|
||||
|
||||
#: users/views/login.py:114 users/views/user.py:146 users/views/user.py:449
|
||||
#: users/views/login.py:114 users/views/user.py:144 users/views/user.py:306
|
||||
msgid "* Your password does not meet the requirements"
|
||||
msgstr "* 您的密码不符合要求"
|
||||
|
||||
|
@ -5251,51 +5252,47 @@ msgstr "* 您的密码不符合要求"
|
|||
msgid "First login"
|
||||
msgstr "首次登录"
|
||||
|
||||
#: users/views/user.py:163
|
||||
#: users/views/user.py:161
|
||||
msgid "Bulk update user success"
|
||||
msgstr "批量更新用户成功"
|
||||
|
||||
#: users/views/user.py:191
|
||||
#: users/views/user.py:189
|
||||
msgid "Bulk update user"
|
||||
msgstr "批量更新用户"
|
||||
|
||||
#: users/views/user.py:278
|
||||
msgid "Invalid file."
|
||||
msgstr "文件不合法"
|
||||
|
||||
#: users/views/user.py:375
|
||||
#: users/views/user.py:232
|
||||
msgid "User granted assets"
|
||||
msgstr "用户授权资产"
|
||||
|
||||
#: users/views/user.py:408
|
||||
#: users/views/user.py:265
|
||||
msgid "Profile setting"
|
||||
msgstr "个人信息设置"
|
||||
|
||||
#: users/views/user.py:427
|
||||
#: users/views/user.py:284
|
||||
msgid "Password update"
|
||||
msgstr "密码更新"
|
||||
|
||||
#: users/views/user.py:468
|
||||
#: users/views/user.py:325
|
||||
msgid "Public key update"
|
||||
msgstr "密钥更新"
|
||||
|
||||
#: users/views/user.py:510
|
||||
#: users/views/user.py:367
|
||||
msgid "Password invalid"
|
||||
msgstr "用户名或密码无效"
|
||||
|
||||
#: users/views/user.py:610
|
||||
#: users/views/user.py:467
|
||||
msgid "MFA enable success"
|
||||
msgstr "MFA 绑定成功"
|
||||
|
||||
#: users/views/user.py:611
|
||||
#: users/views/user.py:468
|
||||
msgid "MFA enable success, return login page"
|
||||
msgstr "MFA 绑定成功,返回到登录页面"
|
||||
|
||||
#: users/views/user.py:613
|
||||
#: users/views/user.py:470
|
||||
msgid "MFA disable success"
|
||||
msgstr "MFA 解绑成功"
|
||||
|
||||
#: users/views/user.py:614
|
||||
#: users/views/user.py:471
|
||||
msgid "MFA disable success, return login page"
|
||||
msgstr "MFA 解绑成功,返回登录页面"
|
||||
|
||||
|
@ -5783,10 +5780,8 @@ msgid "Restore default failed."
|
|||
msgstr "恢复默认失败!"
|
||||
|
||||
#: xpack/plugins/interface/views.py:24
|
||||
#, fuzzy
|
||||
#| msgid "Interval"
|
||||
msgid "Interface"
|
||||
msgstr "间隔"
|
||||
msgstr "界面"
|
||||
|
||||
#: xpack/plugins/interface/views.py:51
|
||||
msgid "It is already in the default setting state!"
|
||||
|
@ -5946,6 +5941,12 @@ msgstr "密码匣子"
|
|||
msgid "vault create"
|
||||
msgstr "创建"
|
||||
|
||||
#~ msgid "already exists"
|
||||
#~ msgstr "已经存在"
|
||||
|
||||
#~ msgid "Invalid file."
|
||||
#~ msgstr "文件不合法"
|
||||
|
||||
#~ msgid "Refresh all node assets amount"
|
||||
#~ msgstr "刷新所有节点资产数量"
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework.pagination import LimitOffsetPagination
|
|||
|
||||
from common.permissions import IsOrgAdmin
|
||||
from common.utils import get_object_or_none
|
||||
from ..models import AssetPermission, Action
|
||||
from ..models import AssetPermission
|
||||
from ..hands import (
|
||||
User, UserGroup, Asset, Node, SystemUser,
|
||||
)
|
||||
|
|
|
@ -21,7 +21,7 @@ from ..utils import (
|
|||
from ..hands import User, Asset, Node, SystemUser, NodeSerializer
|
||||
from .. import serializers, const
|
||||
from ..mixins import AssetsFilterMixin
|
||||
from ..models import ActionFlag
|
||||
from ..models import Action
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
@ -423,7 +423,7 @@ class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView):
|
|||
return Response({'msg': False}, status=403)
|
||||
|
||||
action = granted_system_users[su]
|
||||
choices = ActionFlag.value_to_choices(action)
|
||||
choices = Action.value_to_choices(action)
|
||||
if action_name not in choices:
|
||||
return Response({'msg': False}, status=403)
|
||||
|
||||
|
|
|
@ -1,24 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
__all__ = [
|
||||
'PERMS_ACTION_NAME_ALL', 'PERMS_ACTION_NAME_CONNECT',
|
||||
'PERMS_ACTION_NAME_DOWNLOAD_FILE', 'PERMS_ACTION_NAME_UPLOAD_FILE',
|
||||
'PERMS_ACTION_NAME_CHOICES'
|
||||
]
|
||||
|
||||
PERMS_ACTION_NAME_ALL = 'all'
|
||||
PERMS_ACTION_NAME_CONNECT = 'connect'
|
||||
PERMS_ACTION_NAME_UPLOAD_FILE = 'upload_file'
|
||||
PERMS_ACTION_NAME_DOWNLOAD_FILE = 'download_file'
|
||||
|
||||
PERMS_ACTION_NAME_CHOICES = (
|
||||
(PERMS_ACTION_NAME_ALL, _('All')),
|
||||
(PERMS_ACTION_NAME_CONNECT, _('Connect')),
|
||||
(PERMS_ACTION_NAME_UPLOAD_FILE, _('Upload file')),
|
||||
(PERMS_ACTION_NAME_DOWNLOAD_FILE, _('Download file')),
|
||||
)
|
||||
|
||||
UNGROUPED_NODE_ID = "00000000-0000-0000-0000-000000000000"
|
||||
UNGROUPED_NODE_ID = "00000000-0000-0000-0000-000000000002"
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from orgs.mixins import OrgModelForm
|
||||
from orgs.utils import current_org
|
||||
from assets.models import Asset, Node
|
||||
from ..models import AssetPermission, ActionFlag
|
||||
from ..models import AssetPermission, Action
|
||||
|
||||
__all__ = [
|
||||
'AssetPermissionForm',
|
||||
|
@ -16,20 +16,20 @@ __all__ = [
|
|||
|
||||
class ActionField(forms.MultipleChoiceField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['choices'] = ActionFlag.CHOICES
|
||||
kwargs['initial'] = ActionFlag.ALL
|
||||
kwargs['choices'] = Action.CHOICES
|
||||
kwargs['initial'] = Action.ALL
|
||||
kwargs['label'] = _("Action")
|
||||
kwargs['widget'] = forms.CheckboxSelectMultiple()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def to_python(self, value):
|
||||
value = super().to_python(value)
|
||||
return ActionFlag.choices_to_value(value)
|
||||
return Action.choices_to_value(value)
|
||||
|
||||
def prepare_value(self, value):
|
||||
if value is None:
|
||||
return value
|
||||
value = ActionFlag.value_to_choices(value)
|
||||
value = Action.value_to_choices(value)
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
@ -4,14 +4,6 @@ from django.db import migrations, models
|
|||
import uuid
|
||||
|
||||
|
||||
def add_default_actions(apps, schema_editor):
|
||||
from ..const import PERMS_ACTION_NAME_CHOICES
|
||||
action_model = apps.get_model('perms', 'Action')
|
||||
db_alias = schema_editor.connection.alias
|
||||
for action, _ in PERMS_ACTION_NAME_CHOICES:
|
||||
action_model.objects.using(db_alias).update_or_create(name=action)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
|
@ -29,5 +21,4 @@ class Migration(migrations.Migration):
|
|||
'verbose_name': 'Action',
|
||||
},
|
||||
),
|
||||
migrations.RunPython(add_default_actions)
|
||||
]
|
||||
|
|
|
@ -3,18 +3,6 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
def set_default_action_to_existing_perms(apps, schema_editor):
|
||||
from orgs.utils import set_to_root_org
|
||||
from ..models import Action
|
||||
set_to_root_org()
|
||||
perm_model = apps.get_model('perms', 'AssetPermission')
|
||||
db_alias = schema_editor.connection.alias
|
||||
perms = perm_model.objects.using(db_alias).all()
|
||||
default_action = Action.get_action_all()
|
||||
for perm in perms:
|
||||
perm.actions.add(default_action.id)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
|
@ -27,5 +15,4 @@ class Migration(migrations.Migration):
|
|||
name='actions',
|
||||
field=models.ManyToManyField(blank=True, related_name='permissions', to='perms.Action', verbose_name='Action'),
|
||||
),
|
||||
migrations.RunPython(set_default_action_to_existing_perms)
|
||||
]
|
||||
|
|
|
@ -6,21 +6,22 @@ from functools import reduce
|
|||
|
||||
def migrate_old_actions(apps, schema_editor):
|
||||
from orgs.utils import set_to_root_org
|
||||
from ..models import ActionFlag
|
||||
set_to_root_org()
|
||||
perm_model = apps.get_model('perms', 'AssetPermission')
|
||||
db_alias = schema_editor.connection.alias
|
||||
perms = perm_model.objects.using(db_alias).all()
|
||||
actions_map = {
|
||||
"all": ActionFlag.ALL,
|
||||
"connect": ActionFlag.CONNECT,
|
||||
"upload_file": ActionFlag.UPLOAD,
|
||||
"download_file": ActionFlag.DOWNLOAD,
|
||||
"all": 0b11111111,
|
||||
"connect": 0b00000001,
|
||||
"upload_file": 0b00000010,
|
||||
"download_file": 0b00000100,
|
||||
}
|
||||
|
||||
for perm in perms:
|
||||
actions = perm.actions.all()
|
||||
new_actions = [actions_map.get(action.name, ActionFlag.ALL) for action in actions]
|
||||
if not actions:
|
||||
continue
|
||||
new_actions = [actions_map.get(action.name, 0b11111111) for action in actions]
|
||||
new_action = reduce(lambda x, y: x | y, new_actions)
|
||||
perm.action = new_action
|
||||
perm.save()
|
||||
|
|
|
@ -19,4 +19,5 @@ class Migration(migrations.Migration):
|
|||
old_name='action',
|
||||
new_name='actions',
|
||||
),
|
||||
migrations.DeleteModel(name='Action'),
|
||||
]
|
||||
|
|
|
@ -4,37 +4,18 @@ from functools import reduce
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import date_expired_default, set_or_append_attr_bulk
|
||||
from common.utils import date_expired_default
|
||||
from orgs.mixins import OrgModelMixin
|
||||
|
||||
from ..const import PERMS_ACTION_NAME_CHOICES, PERMS_ACTION_NAME_ALL
|
||||
from .base import BasePermission
|
||||
|
||||
|
||||
__all__ = [
|
||||
'Action', 'AssetPermission', 'NodePermission', 'ActionFlag'
|
||||
'AssetPermission', 'NodePermission', 'Action',
|
||||
]
|
||||
|
||||
|
||||
class Action(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(
|
||||
max_length=128, unique=True, choices=PERMS_ACTION_NAME_CHOICES,
|
||||
verbose_name=_('Name')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Action')
|
||||
|
||||
def __str__(self):
|
||||
return self.get_name_display()
|
||||
|
||||
@classmethod
|
||||
def get_action_all(cls):
|
||||
return cls.objects.get(name=PERMS_ACTION_NAME_ALL)
|
||||
|
||||
|
||||
class ActionFlag:
|
||||
class Action:
|
||||
CONNECT = 0b00000001
|
||||
UPLOAD = 0b00000010
|
||||
DOWNLOAD = 0b00000100
|
||||
|
@ -74,6 +55,8 @@ class ActionFlag:
|
|||
x = cls.NAME_MAP_REVERSE.get(x, 0)
|
||||
y = cls.NAME_MAP_REVERSE.get(y, 0)
|
||||
return x | y
|
||||
if not value:
|
||||
return None
|
||||
return reduce(to_choices, value)
|
||||
|
||||
@classmethod
|
||||
|
@ -86,7 +69,7 @@ class AssetPermission(BasePermission):
|
|||
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
|
||||
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
|
||||
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
|
||||
actions = models.IntegerField(choices=ActionFlag.DB_CHOICES, default=ActionFlag.ALL, verbose_name=_("Actions"))
|
||||
actions = models.IntegerField(choices=Action.DB_CHOICES, default=Action.ALL, verbose_name=_("Actions"))
|
||||
|
||||
class Meta:
|
||||
unique_together = [('org_id', 'name')]
|
||||
|
|
|
@ -5,36 +5,38 @@ from rest_framework import serializers
|
|||
|
||||
from common.fields import StringManyToManyField
|
||||
from orgs.mixins import BulkOrgResourceModelSerializer
|
||||
from perms.models import AssetPermission, ActionFlag
|
||||
from perms.models import AssetPermission, Action
|
||||
|
||||
__all__ = [
|
||||
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
|
||||
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
|
||||
'ActionField',
|
||||
'ActionsField',
|
||||
]
|
||||
|
||||
|
||||
class ActionField(serializers.MultipleChoiceField):
|
||||
class ActionsField(serializers.MultipleChoiceField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['choices'] = ActionFlag.CHOICES
|
||||
kwargs['choices'] = Action.CHOICES
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def to_representation(self, value):
|
||||
return ActionFlag.value_to_choices(value)
|
||||
return Action.value_to_choices(value)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return ActionFlag.choices_to_value(data)
|
||||
if data is None:
|
||||
return data
|
||||
return Action.choices_to_value(data)
|
||||
|
||||
|
||||
class ActionDisplayField(ActionField):
|
||||
class ActionsDisplayField(ActionsField):
|
||||
def to_representation(self, value):
|
||||
values = super().to_representation(value)
|
||||
choices = dict(ActionFlag.CHOICES)
|
||||
choices = dict(Action.CHOICES)
|
||||
return [choices.get(i) for i in values]
|
||||
|
||||
|
||||
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
|
||||
actions = ActionField()
|
||||
actions = ActionsField(required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = AssetPermission
|
||||
|
@ -47,7 +49,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
|
|||
assets = StringManyToManyField(many=True, read_only=True)
|
||||
nodes = StringManyToManyField(many=True, read_only=True)
|
||||
system_users = StringManyToManyField(many=True, read_only=True)
|
||||
actions = ActionDisplayField()
|
||||
actions = ActionsDisplayField()
|
||||
is_valid = serializers.BooleanField()
|
||||
is_expired = serializers.BooleanField()
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from rest_framework import serializers
|
|||
from assets.models import Node, SystemUser
|
||||
from assets.serializers import AssetSerializer
|
||||
|
||||
from .asset_permission import ActionField
|
||||
from .asset_permission import ActionsField
|
||||
|
||||
__all__ = [
|
||||
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
|
||||
|
@ -19,7 +19,7 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
|
|||
"""
|
||||
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
|
||||
"""
|
||||
actions = ActionField(read_only=True)
|
||||
actions = ActionsField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
|
@ -115,4 +115,4 @@ class GrantedNodeSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class ActionsSerializer(serializers.Serializer):
|
||||
actions = ActionField(read_only=True)
|
||||
actions = ActionsField(read_only=True)
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db import transaction
|
|||
|
||||
from common.utils import get_logger
|
||||
from .utils import AssetPermissionUtil
|
||||
from .models import AssetPermission, Action
|
||||
from .models import AssetPermission
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
|
|
@ -17,7 +17,7 @@ from orgs.utils import set_to_root_org
|
|||
from common.utils import get_logger
|
||||
from common.tree import TreeNode
|
||||
from .. import const
|
||||
from ..models import AssetPermission, Action, ActionFlag
|
||||
from ..models import AssetPermission, Action
|
||||
from ..hands import Node, Asset
|
||||
from assets.utils import NodeUtil
|
||||
|
||||
|
@ -569,7 +569,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
|
|||
'protocol': system_user.protocol,
|
||||
'priority': system_user.priority,
|
||||
'login_mode': system_user.login_mode,
|
||||
'actions': [ActionFlag.value_to_choices(action)],
|
||||
'actions': [Action.value_to_choices(action)],
|
||||
})
|
||||
data = {
|
||||
'id': str(asset.id),
|
||||
|
|
|
@ -10,10 +10,9 @@ from django.conf import settings
|
|||
|
||||
from common.permissions import PermissionsMixin, IsOrgAdmin
|
||||
from orgs.utils import current_org
|
||||
from perms.hands import Node, Asset, SystemUser, User, UserGroup
|
||||
from perms.models import AssetPermission, Action
|
||||
from perms.hands import Node, Asset, SystemUser, UserGroup
|
||||
from perms.models import AssetPermission
|
||||
from perms.forms import AssetPermissionForm
|
||||
from perms.const import PERMS_ACTION_NAME_ALL
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -77,6 +77,7 @@ def monkey_patch_settings(sender, **kwargs):
|
|||
@receiver(django_ready)
|
||||
def auto_generate_terminal_host_key(sender, **kwargs):
|
||||
try:
|
||||
print("Auto gen host key")
|
||||
if Setting.objects.filter(name='TERMINAL_HOST_KEY').exists():
|
||||
return
|
||||
private_key, public_key = ssh_key_gen()
|
||||
|
|
Loading…
Reference in New Issue