Commit bbf5e285 authored by BaiJiangJie's avatar BaiJiangJie

Merge branch 'bugfix' of github.com:jumpserver/jumpserver into bugfix

parents 003601bb 7bf1555c
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django import forms from django import forms
from django.core.exceptions import ValidationError
import re
from orgs.mixins import OrgModelForm from orgs.mixins import OrgModelForm
from ..models import CommandFilter, CommandFilterRule from ..models import CommandFilter, CommandFilterRule
...@@ -15,6 +17,8 @@ class CommandFilterForm(OrgModelForm): ...@@ -15,6 +17,8 @@ class CommandFilterForm(OrgModelForm):
class CommandFilterRuleForm(OrgModelForm): class CommandFilterRuleForm(OrgModelForm):
invalid_pattern = re.compile(r'[\.\*\+\[\\\?\{\}\^\$\|\(\)\#\<\>]')
class Meta: class Meta:
model = CommandFilterRule model = CommandFilterRule
fields = [ fields = [
...@@ -25,3 +29,11 @@ class CommandFilterRuleForm(OrgModelForm): ...@@ -25,3 +29,11 @@ class CommandFilterRuleForm(OrgModelForm):
'placeholder': 'eg:\r\nreboot\r\nrm -rf' '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
# -*- 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'},
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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',
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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'),
),
]
# -*- 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),
]
# 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')},
),
]
# 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')},
),
]
# Generated by Django 2.1.7 on 2019-06-24 13:08 # Generated by Django 2.1.7 on 2019-06-24 13:08
import common.fields.model
from django.db import migrations from django.db import migrations
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import re
from rest_framework import serializers from rest_framework import serializers
from common.fields import ChoiceDisplayField from common.fields import ChoiceDisplayField
...@@ -20,8 +21,16 @@ class CommandFilterSerializer(BulkOrgResourceModelSerializer): ...@@ -20,8 +21,16 @@ class CommandFilterSerializer(BulkOrgResourceModelSerializer):
class CommandFilterRuleSerializer(BulkOrgResourceModelSerializer): class CommandFilterRuleSerializer(BulkOrgResourceModelSerializer):
serializer_choice_field = ChoiceDisplayField serializer_choice_field = ChoiceDisplayField
invalid_pattern = re.compile(r'[\.\*\+\[\\\?\{\}\^\$\|\(\)\#\<\>]')
class Meta: class Meta:
model = CommandFilterRule model = CommandFilterRule
fields = '__all__' fields = '__all__'
list_serializer_class = AdaptedBulkListSerializer 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
# -*- coding: utf-8 -*-
#
from .models import *
from .serializers import *
from .api import *
from .views import *
# -*- 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
\ No newline at end of file
# -*- 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()
# coding: utf-8 # -*- coding: utf-8 -*-
#
from django.db import models
from django.http import JsonResponse from rest_framework.utils import html
from django.utils import timezone from rest_framework.settings import api_settings
from django.core.cache import cache from rest_framework.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from rest_framework.fields import SkipField
from django.contrib import messages
from rest_framework.utils import html __all__ = ['BulkSerializerMixin', 'BulkListSerializerMixin']
from rest_framework.settings import api_settings
from rest_framework.exceptions import ValidationError
from rest_framework.fields import SkipField class BulkSerializerMixin(object):
"""
from .const import KEY_CACHE_RESOURCES_ID Become rest_framework_bulk not support uuid as a primary key
so rewrite it. https://github.com/miki725/django-rest-framework-bulk/issues/66
"""
class NoDeleteQuerySet(models.query.QuerySet): def to_internal_value(self, data):
from rest_framework_bulk import BulkListSerializer
def delete(self): ret = super(BulkSerializerMixin, self).to_internal_value(data)
return self.update(is_discard=True, discard_time=timezone.now())
id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
if self.context.get('view'):
class NoDeleteManager(models.Manager): request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')
# add update_lookup_field field back to validated data
def get_all(self): # since super by default strips out read-only fields
return NoDeleteQuerySet(self.model, using=self._db) # hence id will no longer be present in validated_data
if all((isinstance(self.root, BulkListSerializer),
def get_queryset(self): id_attr,
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=False) request_method in ('PUT', 'PATCH'))):
id_field = self.fields[id_attr]
def get_deleted(self): if data.get("id"):
return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=True) id_value = id_field.to_internal_value(data.get("id"))
else:
id_value = id_field.to_internal_value(data.get("pk"))
class NoDeleteModelMixin(models.Model): ret[id_attr] = id_value
is_discard = models.BooleanField(verbose_name=_("is discard"), default=False)
discard_time = models.DateTimeField(verbose_name=_("discard time"), null=True, blank=True) return ret
objects = NoDeleteManager()
class BulkListSerializerMixin(object):
class Meta: """
abstract = True Become rest_framework_bulk doing bulk update raise Exception:
'QuerySet' object has no attribute 'pk' when doing bulk update
def delete(self): so rewrite it .
self.is_discard = True https://github.com/miki725/django-rest-framework-bulk/issues/68
self.discard_time = timezone.now() """
return self.save()
def to_internal_value(self, data):
"""
class JSONResponseMixin(object): List of dicts of native values <- List of dicts of primitive datatypes.
"""JSON mixin""" """
@staticmethod if html.is_html_input(data):
def render_json_response(context): data = html.parse_html_list(data)
return JsonResponse(context)
if not isinstance(data, list):
message = self.error_messages['not_a_list'].format(
class IDInFilterMixin(object): input_type=type(data).__name__
def filter_queryset(self, queryset): )
queryset = super(IDInFilterMixin, self).filter_queryset(queryset) raise ValidationError({
id_list = self.request.query_params.get('id__in') api_settings.NON_FIELD_ERRORS_KEY: [message]
if id_list: }, code='not_a_list')
import json
try: if not self.allow_empty and len(data) == 0:
ids = json.loads(id_list) if self.parent and self.partial:
except Exception as e: raise SkipField()
return queryset
if isinstance(ids, list): message = self.error_messages['empty']
queryset = queryset.filter(id__in=ids) raise ValidationError({
return queryset api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='empty')
class IDInCacheFilterMixin(object): ret = []
errors = []
def filter_queryset(self, queryset):
queryset = super(IDInCacheFilterMixin, self).filter_queryset(queryset) for item in data:
spm = self.request.query_params.get('spm') try:
cache_key = KEY_CACHE_RESOURCES_ID.format(spm) # prepare child serializer to only handle one instance
resources_id = cache.get(cache_key) if 'id' in item.keys():
if resources_id and isinstance(resources_id, list): self.child.instance = self.instance.get(id=item['id']) if self.instance else None
queryset = queryset.filter(id__in=resources_id) if 'pk' in item.keys():
return queryset self.child.instance = self.instance.get(id=item['pk']) if self.instance else None
self.child.initial_data = item
class IDExportFilterMixin(object): # raw
def filter_queryset(self, queryset): validated = self.child.run_validation(item)
# 下载导入模版 except ValidationError as exc:
if self.request.query_params.get('template') == 'import': errors.append(exc.detail)
return [] else:
else: ret.append(validated)
return super(IDExportFilterMixin, self).filter_queryset(queryset) errors.append({})
if any(errors):
class BulkSerializerMixin(object): raise ValidationError(errors)
"""
Become rest_framework_bulk not support uuid as a primary key return ret
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
# -*- 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 = { ...@@ -301,10 +301,10 @@ LOGGING = {
'handlers': ['gunicorn_console', 'gunicorn_file'], 'handlers': ['gunicorn_console', 'gunicorn_file'],
'level': 'INFO', 'level': 'INFO',
}, },
# 'django.db': { 'django.db': {
# 'handlers': ['console', 'file'], 'handlers': ['console', 'file'],
# 'level': 'DEBUG' 'level': 'DEBUG'
# } }
} }
} }
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
...@@ -86,7 +86,7 @@ msgstr "运行参数" ...@@ -86,7 +86,7 @@ msgstr "运行参数"
#: assets/templates/assets/system_user_list.html:55 audits/models.py:19 #: 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:41
#: audits/templates/audits/ftp_log_list.html:71 #: 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_create_update.html:45
#: perms/templates/perms/asset_permission_list.html:48 #: perms/templates/perms/asset_permission_list.html:48
#: perms/templates/perms/asset_permission_list.html:117 #: perms/templates/perms/asset_permission_list.html:117
...@@ -115,8 +115,8 @@ msgstr "资产" ...@@ -115,8 +115,8 @@ msgstr "资产"
#: assets/models/user.py:160 assets/templates/assets/user_asset_list.html:172 #: 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/models.py:20 audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:72 #: audits/templates/audits/ftp_log_list.html:72
#: perms/forms/asset_permission.py:53 perms/models/asset_permission.py:55 #: perms/forms/asset_permission.py:74 perms/models/asset_permission.py:87
#: perms/models/asset_permission.py:76 #: perms/models/asset_permission.py:104
#: perms/templates/perms/asset_permission_detail.html:140 #: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:50 #: perms/templates/perms/asset_permission_list.html:50
#: perms/templates/perms/asset_permission_list.html:71 #: perms/templates/perms/asset_permission_list.html:71
...@@ -149,7 +149,7 @@ msgstr "系统用户" ...@@ -149,7 +149,7 @@ msgstr "系统用户"
#: assets/templates/assets/system_user_detail.html:58 #: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:51 ops/models/adhoc.py:37 #: 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 #: 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/models/base.py:35
#: perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:45 #: perms/templates/perms/asset_permission_list.html:45
...@@ -215,10 +215,10 @@ msgstr "参数" ...@@ -215,10 +215,10 @@ msgstr "参数"
#: assets/templates/assets/domain_detail.html:72 #: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_detail.html:100
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:14 #: 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/asset_permission_detail.html:98
#: perms/templates/perms/remote_app_permission_detail.html:90 #: 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 #: users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:106 #: xpack/plugins/change_auth_plan/models.py:106
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
...@@ -238,7 +238,7 @@ msgstr "创建者" ...@@ -238,7 +238,7 @@ msgstr "创建者"
#: assets/templates/assets/domain_detail.html:68 #: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:96 #: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64 #: 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/models/base.py:42
#: perms/templates/perms/asset_permission_detail.html:94 #: perms/templates/perms/asset_permission_detail.html:94
#: perms/templates/perms/remote_app_permission_detail.html:86 #: perms/templates/perms/remote_app_permission_detail.html:86
...@@ -274,7 +274,7 @@ msgstr "创建日期" ...@@ -274,7 +274,7 @@ msgstr "创建日期"
#: assets/templates/assets/system_user_detail.html:104 #: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:59 #: assets/templates/assets/system_user_list.html:59
#: assets/templates/assets/user_asset_list.html:175 ops/models/adhoc.py:43 #: 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/models/base.py:43
#: perms/templates/perms/asset_permission_detail.html:102 #: perms/templates/perms/asset_permission_detail.html:102
#: perms/templates/perms/remote_app_permission_detail.html:94 #: perms/templates/perms/remote_app_permission_detail.html:94
...@@ -440,7 +440,6 @@ msgstr "详情" ...@@ -440,7 +440,6 @@ msgstr "详情"
#: users/templates/users/user_group_list.html:20 #: users/templates/users/user_group_list.html:20
#: users/templates/users/user_group_list.html:70 #: users/templates/users/user_group_list.html:70
#: users/templates/users/user_list.html:20 #: 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_list.html:99
#: users/templates/users/user_profile.html:177 #: users/templates/users/user_profile.html:177
#: users/templates/users/user_profile.html:187 #: users/templates/users/user_profile.html:187
...@@ -481,7 +480,6 @@ msgstr "更新" ...@@ -481,7 +480,6 @@ msgstr "更新"
#: users/templates/users/user_detail.html:30 #: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32 #: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:72 #: users/templates/users/user_group_list.html:72
#: users/templates/users/user_list.html:104
#: users/templates/users/user_list.html:108 #: 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_detail.html:33
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57
...@@ -529,8 +527,7 @@ msgstr "创建远程应用" ...@@ -529,8 +527,7 @@ msgstr "创建远程应用"
#: audits/templates/audits/operate_log_list.html:67 #: 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/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 #: 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/forms/asset_permission.py:21 perms/models/asset_permission.py:27
#: perms/models/asset_permission.py:57
#: perms/templates/perms/asset_permission_create_update.html:50 #: perms/templates/perms/asset_permission_create_update.html:50
#: perms/templates/perms/asset_permission_list.html:52 #: perms/templates/perms/asset_permission_list.html:52
#: perms/templates/perms/asset_permission_list.html:126 #: perms/templates/perms/asset_permission_list.html:126
...@@ -552,7 +549,7 @@ msgstr "动作" ...@@ -552,7 +549,7 @@ msgstr "动作"
#: applications/templates/applications/user_remote_app_list.html:57 #: applications/templates/applications/user_remote_app_list.html:57
#: assets/templates/assets/user_asset_list.html:100 perms/const.py:19 #: 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" msgid "Connect"
msgstr "连接" msgstr "连接"
...@@ -591,11 +588,11 @@ msgstr "请选择需要更新的资产" ...@@ -591,11 +588,11 @@ msgstr "请选择需要更新的资产"
msgid "You can't update the root node name" msgid "You can't update the root node name"
msgstr "不能修改根节点名称" msgstr "不能修改根节点名称"
#: assets/api/node.py:281 #: assets/api/node.py:283
msgid "Update node asset hardware information: {}" msgid "Update node asset hardware information: {}"
msgstr "更新节点资产硬件信息: {}" msgstr "更新节点资产硬件信息: {}"
#: assets/api/node.py:295 #: assets/api/node.py:297
msgid "Test if the assets under the node are connectable: {}" msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}" msgstr "测试节点下资产是否可连接: {}"
...@@ -622,7 +619,7 @@ msgstr "未知" ...@@ -622,7 +619,7 @@ msgstr "未知"
#: assets/templates/assets/asset_detail.html:194 #: assets/templates/assets/asset_detail.html:194
#: assets/templates/assets/asset_detail.html:202 #: assets/templates/assets/asset_detail.html:202
#: assets/templates/assets/system_user_assets.html:83 #: 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 #: xpack/plugins/change_auth_plan/models.py:72
msgid "Nodes" msgid "Nodes"
msgstr "节点" msgstr "节点"
...@@ -656,8 +653,8 @@ 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:64 assets/forms/asset.py:86 assets/forms/asset.py:99
#: assets/forms/asset.py:134 assets/models/node.py:248 #: assets/forms/asset.py:134 assets/models/node.py:248
#: assets/templates/assets/asset_create.html:42 #: assets/templates/assets/asset_create.html:42
#: perms/forms/asset_permission.py:50 perms/forms/asset_permission.py:60 #: perms/forms/asset_permission.py:71 perms/forms/asset_permission.py:79
#: perms/models/asset_permission.py:74 #: perms/models/asset_permission.py:102
#: perms/templates/perms/asset_permission_list.html:49 #: perms/templates/perms/asset_permission_list.html:49
#: perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_list.html:70
#: perms/templates/perms/asset_permission_list.html:120 #: perms/templates/perms/asset_permission_list.html:120
...@@ -695,6 +692,10 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域, ...@@ -695,6 +692,10 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
msgid "Select assets" msgid "Select assets"
msgstr "选择资产" 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 #: assets/forms/domain.py:51
msgid "Password should not contain special characters" msgid "Password should not contain special characters"
msgstr "不能包含特殊字符" msgstr "不能包含特殊字符"
...@@ -1000,7 +1001,7 @@ msgid "Operator" ...@@ -1000,7 +1001,7 @@ msgid "Operator"
msgstr "运营商" msgstr "运营商"
#: assets/models/cluster.py:36 assets/models/group.py:34 #: assets/models/cluster.py:36 assets/models/group.py:34
#: perms/utils/asset_permission.py:67 #: perms/utils/asset_permission.py:106
msgid "Default" msgid "Default"
msgstr "默认" msgstr "默认"
...@@ -1112,7 +1113,7 @@ msgstr "默认资产组" ...@@ -1112,7 +1113,7 @@ msgstr "默认资产组"
#: audits/templates/audits/password_change_log_list.html:50 #: audits/templates/audits/password_change_log_list.html:50
#: ops/templates/ops/command_execution_list.html:35 #: ops/templates/ops/command_execution_list.html:35
#: ops/templates/ops/command_execution_list.html:60 #: 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/models/base.py:36
#: perms/templates/perms/asset_permission_create_update.html:41 #: perms/templates/perms/asset_permission_create_update.html:41
#: perms/templates/perms/asset_permission_list.html:46 #: perms/templates/perms/asset_permission_list.html:46
...@@ -1124,9 +1125,9 @@ msgstr "默认资产组" ...@@ -1124,9 +1125,9 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33 #: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:301 #: 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_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/forms.py:26
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113 #: xpack/plugins/orgs/templates/orgs/org_detail.html:113
#: xpack/plugins/orgs/templates/orgs/org_list.html:14 #: xpack/plugins/orgs/templates/orgs/org_list.html:14
...@@ -1205,26 +1206,25 @@ msgstr "登录模式" ...@@ -1205,26 +1206,25 @@ msgstr "登录模式"
msgid "%(value)s is not an even number" msgid "%(value)s is not an even number"
msgstr "%(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/serializers/asset_user.py:30 assets/serializers/system_user.py:30
#: assets/templates/assets/_asset_user_list.html:18 #: assets/templates/assets/_asset_user_list.html:18
msgid "Connectivity" msgid "Connectivity"
msgstr "连接" msgstr "连接"
#: assets/serializers/asset.py:45 assets/serializers/asset.py:155 #: assets/serializers/asset.py:44 assets/templates/assets/asset_create.html:24
#: assets/templates/assets/asset_create.html:24
msgid "Protocols" msgid "Protocols"
msgstr "协议组" msgstr "协议组"
#: assets/serializers/asset.py:73 #: assets/serializers/asset.py:72
msgid "Hardware info" msgid "Hardware info"
msgstr "硬件信息" msgstr "硬件信息"
#: assets/serializers/asset.py:74 orgs/mixins.py:192 #: assets/serializers/asset.py:73 orgs/mixins.py:192
msgid "Org name" msgid "Org name"
msgstr "组织名称" msgstr "组织名称"
#: assets/serializers/asset.py:92 #: assets/serializers/asset.py:91
msgid "Protocol duplicate: {}" msgid "Protocol duplicate: {}"
msgstr "协议重复: {}" msgstr "协议重复: {}"
...@@ -1710,7 +1710,7 @@ msgstr "创建日期" ...@@ -1710,7 +1710,7 @@ msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:154 #: assets/templates/assets/asset_detail.html:154
#: assets/templates/assets/user_asset_list.html:46 #: 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_create_update.html:55
#: perms/templates/perms/asset_permission_detail.html:120 #: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/remote_app_permission_create_update.html:54 #: perms/templates/perms/remote_app_permission_create_update.html:54
...@@ -2056,10 +2056,6 @@ msgstr "批量更新资产" ...@@ -2056,10 +2056,6 @@ msgstr "批量更新资产"
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:347
msgid "already exists"
msgstr "已经存在"
#: assets/views/cmd_filter.py:32 #: assets/views/cmd_filter.py:32
msgid "Command filter list" msgid "Command filter list"
msgstr "命令过滤器列表" msgstr "命令过滤器列表"
...@@ -2557,8 +2553,8 @@ msgstr "欢迎回来,请输入用户名和密码登录" ...@@ -2557,8 +2553,8 @@ msgstr "欢迎回来,请输入用户名和密码登录"
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:172 users/views/user.py:555 #: authentication/views/login.py:172 users/views/user.py:412
#: users/views/user.py:580 #: users/views/user.py:437
msgid "MFA code invalid, or ntp sync server time" msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确,或者服务器端时间不对" msgstr "MFA验证码不正确,或者服务器端时间不对"
...@@ -3000,11 +2996,11 @@ msgstr "命令执行" ...@@ -3000,11 +2996,11 @@ msgstr "命令执行"
msgid "Organization" msgid "Organization"
msgstr "组织" 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" msgid "All"
msgstr "全部" msgstr "全部"
#: perms/const.py:20 perms/models/asset_permission.py:46 #: perms/const.py:20 perms/models/asset_permission.py:47
msgid "Upload file" msgid "Upload file"
msgstr "上传文件" msgstr "上传文件"
...@@ -3012,8 +3008,8 @@ msgstr "上传文件" ...@@ -3012,8 +3008,8 @@ msgstr "上传文件"
msgid "Download file" msgid "Download file"
msgstr "下载文件" msgstr "下载文件"
#: perms/forms/asset_permission.py:44 perms/forms/remote_app_permission.py:34 #: perms/forms/asset_permission.py:65 perms/forms/remote_app_permission.py:34
#: perms/models/asset_permission.py:75 perms/models/base.py:37 #: 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:47
#: perms/templates/perms/asset_permission_list.html:67 #: perms/templates/perms/asset_permission_list.html:67
#: perms/templates/perms/asset_permission_list.html:114 #: perms/templates/perms/asset_permission_list.html:114
...@@ -3026,30 +3022,34 @@ msgstr "下载文件" ...@@ -3026,30 +3022,34 @@ msgstr "下载文件"
msgid "User group" msgid "User group"
msgstr "用户组" msgstr "用户组"
#: perms/forms/asset_permission.py:63 #: perms/forms/asset_permission.py:82
msgid "" msgid ""
"Tips: The RDP protocol does not support separate controls for uploading or " "Tips: The RDP protocol does not support separate controls for uploading or "
"downloading files" "downloading files"
msgstr "提示:RDP 协议不支持单独控制上传或下载文件" 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" msgid "User or group at least one required"
msgstr "用户和用户组至少选一个" msgstr "用户和用户组至少选一个"
#: perms/forms/asset_permission.py:82 #: perms/forms/asset_permission.py:101
msgid "Asset or group at least one required" msgid "Asset or group at least one required"
msgstr "资产和节点至少选一个" msgstr "资产和节点至少选一个"
#: perms/models/asset_permission.py:47 #: perms/models/asset_permission.py:49
msgid "Upload download" msgid "Upload download"
msgstr "上传下载" 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 #: templates/_nav.html:44
msgid "Asset permission" msgid "Asset permission"
msgstr "资产授权" 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/asset_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:82 #: perms/templates/perms/remote_app_permission_detail.html:82
#: users/models/user.py:102 users/templates/users/user_detail.html:107 #: users/models/user.py:102 users/templates/users/user_detail.html:107
...@@ -3199,8 +3199,8 @@ msgid "Add user group to this permission" ...@@ -3199,8 +3199,8 @@ msgid "Add user group to this permission"
msgstr "添加用户组" msgstr "添加用户组"
#: perms/views/asset_permission.py:34 perms/views/asset_permission.py:65 #: 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:82 perms/views/asset_permission.py:99
#: perms/views/asset_permission.py:134 perms/views/asset_permission.py:167 #: 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:33
#: perms/views/remote_app_permission.py:49 #: perms/views/remote_app_permission.py:49
#: perms/views/remote_app_permission.py:65 #: perms/views/remote_app_permission.py:65
...@@ -3219,19 +3219,19 @@ msgstr "资产授权列表" ...@@ -3219,19 +3219,19 @@ msgstr "资产授权列表"
msgid "Create asset permission" msgid "Create asset permission"
msgstr "创建权限规则" msgstr "创建权限规则"
#: perms/views/asset_permission.py:82 #: perms/views/asset_permission.py:83
msgid "Update asset permission" msgid "Update asset permission"
msgstr "更新资产授权" msgstr "更新资产授权"
#: perms/views/asset_permission.py:98 #: perms/views/asset_permission.py:100
msgid "Asset permission detail" msgid "Asset permission detail"
msgstr "资产授权详情" msgstr "资产授权详情"
#: perms/views/asset_permission.py:135 #: perms/views/asset_permission.py:137
msgid "Asset permission user list" msgid "Asset permission user list"
msgstr "资产授权用户列表" msgstr "资产授权用户列表"
#: perms/views/asset_permission.py:168 #: perms/views/asset_permission.py:170
msgid "Asset permission asset list" msgid "Asset permission asset list"
msgstr "资产授权资产列表" msgstr "资产授权资产列表"
...@@ -3828,7 +3828,7 @@ msgstr "商业支持" ...@@ -3828,7 +3828,7 @@ msgstr "商业支持"
#: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57 #: 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" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
...@@ -3923,13 +3923,13 @@ msgstr "" ...@@ -3923,13 +3923,13 @@ msgstr ""
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:45 #: 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/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/login.py:154 users/views/user.py:68 users/views/user.py:85
#: users/views/user.py:131 users/views/user.py:211 users/views/user.py:374 #: users/views/user.py:129 users/views/user.py:209 users/views/user.py:231
#: users/views/user.py:426 users/views/user.py:467 #: users/views/user.py:283 users/views/user.py:324
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:71 #: templates/_nav.html:13 users/views/user.py:69
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
...@@ -4369,11 +4369,11 @@ msgid "" ...@@ -4369,11 +4369,11 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}" "You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端" 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." msgid "You do not have permission."
msgstr "你没有权限" msgstr "你没有权限"
#: users/api/user.py:221 #: users/api/user.py:186
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置" msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
...@@ -4405,7 +4405,7 @@ msgstr "添加到用户组" ...@@ -4405,7 +4405,7 @@ msgstr "添加到用户组"
msgid "Public key should not be the same as your old one." msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同" 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" msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法" msgstr "ssh密钥不合法"
...@@ -4532,7 +4532,7 @@ msgid "Date password last updated" ...@@ -4532,7 +4532,7 @@ msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:139 users/templates/users/user_update.html:22 #: 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" msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码" msgstr "用户认证源来自 {}, 请去相应系统修改密码"
...@@ -4569,10 +4569,12 @@ msgid "Avatar url" ...@@ -4569,10 +4569,12 @@ msgid "Avatar url"
msgstr "头像路径" msgstr "头像路径"
#: users/serializers/v1.py:46 #: users/serializers/v1.py:46
#, fuzzy msgid "Role limit to {}"
#| msgid "Password does not match" msgstr "角色只能为 {}"
#: users/serializers/v1.py:54
msgid "Password does not match security rules" msgid "Password does not match security rules"
msgstr "密码不一致" msgstr "密码不满足安全规则"
#: users/serializers_v2/user.py:36 #: users/serializers_v2/user.py:36
msgid "name not unique" msgid "name not unique"
...@@ -4624,7 +4626,7 @@ msgid "Import users" ...@@ -4624,7 +4626,7 @@ msgid "Import users"
msgstr "导入用户" msgstr "导入用户"
#: users/templates/users/_user_update_modal.html:4 #: 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" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
...@@ -4762,12 +4764,12 @@ msgid "Very strong" ...@@ -4762,12 +4764,12 @@ msgid "Very strong"
msgstr "很强" msgstr "很强"
#: users/templates/users/user_create.html:4 #: 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" msgid "Create user"
msgstr "创建用户" msgstr "创建用户"
#: users/templates/users/user_detail.html:19 #: 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" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -4967,8 +4969,7 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接 ...@@ -4967,8 +4969,7 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接
msgid "Administrator Settings force MFA login" msgid "Administrator Settings force MFA login"
msgstr "管理员设置强制使用MFA登录" msgstr "管理员设置强制使用MFA登录"
#: users/templates/users/user_profile.html:120 users/views/user.py:248 #: users/templates/users/user_profile.html:120
#: users/views/user.py:303
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
...@@ -5243,7 +5244,7 @@ msgstr "Token错误或失效" ...@@ -5243,7 +5244,7 @@ msgstr "Token错误或失效"
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" 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" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" msgstr "* 您的密码不符合要求"
...@@ -5251,51 +5252,47 @@ msgstr "* 您的密码不符合要求" ...@@ -5251,51 +5252,47 @@ msgstr "* 您的密码不符合要求"
msgid "First login" msgid "First login"
msgstr "首次登录" msgstr "首次登录"
#: users/views/user.py:163 #: users/views/user.py:161
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:191 #: users/views/user.py:189
msgid "Bulk update user" msgid "Bulk update user"
msgstr "批量更新用户" msgstr "批量更新用户"
#: users/views/user.py:278 #: users/views/user.py:232
msgid "Invalid file."
msgstr "文件不合法"
#: users/views/user.py:375
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:408 #: users/views/user.py:265
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:427 #: users/views/user.py:284
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:468 #: users/views/user.py:325
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#: users/views/user.py:510 #: users/views/user.py:367
msgid "Password invalid" msgid "Password invalid"
msgstr "用户名或密码无效" msgstr "用户名或密码无效"
#: users/views/user.py:610 #: users/views/user.py:467
msgid "MFA enable success" msgid "MFA enable success"
msgstr "MFA 绑定成功" msgstr "MFA 绑定成功"
#: users/views/user.py:611 #: users/views/user.py:468
msgid "MFA enable success, return login page" msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面" msgstr "MFA 绑定成功,返回到登录页面"
#: users/views/user.py:613 #: users/views/user.py:470
msgid "MFA disable success" msgid "MFA disable success"
msgstr "MFA 解绑成功" msgstr "MFA 解绑成功"
#: users/views/user.py:614 #: users/views/user.py:471
msgid "MFA disable success, return login page" msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面" msgstr "MFA 解绑成功,返回登录页面"
...@@ -5783,10 +5780,8 @@ msgid "Restore default failed." ...@@ -5783,10 +5780,8 @@ msgid "Restore default failed."
msgstr "恢复默认失败!" msgstr "恢复默认失败!"
#: xpack/plugins/interface/views.py:24 #: xpack/plugins/interface/views.py:24
#, fuzzy
#| msgid "Interval"
msgid "Interface" msgid "Interface"
msgstr "间隔" msgstr "界面"
#: xpack/plugins/interface/views.py:51 #: xpack/plugins/interface/views.py:51
msgid "It is already in the default setting state!" msgid "It is already in the default setting state!"
...@@ -5946,6 +5941,12 @@ msgstr "密码匣子" ...@@ -5946,6 +5941,12 @@ msgstr "密码匣子"
msgid "vault create" msgid "vault create"
msgstr "创建" msgstr "创建"
#~ msgid "already exists"
#~ msgstr "已经存在"
#~ msgid "Invalid file."
#~ msgstr "文件不合法"
#~ msgid "Refresh all node assets amount" #~ msgid "Refresh all node assets amount"
#~ msgstr "刷新所有节点资产数量" #~ msgstr "刷新所有节点资产数量"
......
...@@ -10,7 +10,7 @@ from rest_framework.pagination import LimitOffsetPagination ...@@ -10,7 +10,7 @@ from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsOrgAdmin from common.permissions import IsOrgAdmin
from common.utils import get_object_or_none from common.utils import get_object_or_none
from ..models import AssetPermission, Action from ..models import AssetPermission
from ..hands import ( from ..hands import (
User, UserGroup, Asset, Node, SystemUser, User, UserGroup, Asset, Node, SystemUser,
) )
......
...@@ -21,7 +21,7 @@ from ..utils import ( ...@@ -21,7 +21,7 @@ from ..utils import (
from ..hands import User, Asset, Node, SystemUser, NodeSerializer from ..hands import User, Asset, Node, SystemUser, NodeSerializer
from .. import serializers, const from .. import serializers, const
from ..mixins import AssetsFilterMixin from ..mixins import AssetsFilterMixin
from ..models import ActionFlag from ..models import Action
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -423,7 +423,7 @@ class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView): ...@@ -423,7 +423,7 @@ class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView):
return Response({'msg': False}, status=403) return Response({'msg': False}, status=403)
action = granted_system_users[su] action = granted_system_users[su]
choices = ActionFlag.value_to_choices(action) choices = Action.value_to_choices(action)
if action_name not in choices: if action_name not in choices:
return Response({'msg': False}, status=403) return Response({'msg': False}, status=403)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.utils.translation import ugettext_lazy as _ UNGROUPED_NODE_ID = "00000000-0000-0000-0000-000000000002"
__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"
...@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
from orgs.mixins import OrgModelForm from orgs.mixins import OrgModelForm
from orgs.utils import current_org from orgs.utils import current_org
from assets.models import Asset, Node from assets.models import Asset, Node
from ..models import AssetPermission, ActionFlag from ..models import AssetPermission, Action
__all__ = [ __all__ = [
'AssetPermissionForm', 'AssetPermissionForm',
...@@ -16,20 +16,20 @@ __all__ = [ ...@@ -16,20 +16,20 @@ __all__ = [
class ActionField(forms.MultipleChoiceField): class ActionField(forms.MultipleChoiceField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['choices'] = ActionFlag.CHOICES kwargs['choices'] = Action.CHOICES
kwargs['initial'] = ActionFlag.ALL kwargs['initial'] = Action.ALL
kwargs['label'] = _("Action") kwargs['label'] = _("Action")
kwargs['widget'] = forms.CheckboxSelectMultiple() kwargs['widget'] = forms.CheckboxSelectMultiple()
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def to_python(self, value): def to_python(self, value):
value = super().to_python(value) value = super().to_python(value)
return ActionFlag.choices_to_value(value) return Action.choices_to_value(value)
def prepare_value(self, value): def prepare_value(self, value):
if value is None: if value is None:
return value return value
value = ActionFlag.value_to_choices(value) value = Action.value_to_choices(value)
return value return value
......
...@@ -4,14 +4,6 @@ from django.db import migrations, models ...@@ -4,14 +4,6 @@ from django.db import migrations, models
import uuid 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): class Migration(migrations.Migration):
dependencies = [ dependencies = [
...@@ -29,5 +21,4 @@ class Migration(migrations.Migration): ...@@ -29,5 +21,4 @@ class Migration(migrations.Migration):
'verbose_name': 'Action', 'verbose_name': 'Action',
}, },
), ),
migrations.RunPython(add_default_actions)
] ]
...@@ -3,18 +3,6 @@ ...@@ -3,18 +3,6 @@
from django.db import migrations, models 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): class Migration(migrations.Migration):
dependencies = [ dependencies = [
...@@ -27,5 +15,4 @@ class Migration(migrations.Migration): ...@@ -27,5 +15,4 @@ class Migration(migrations.Migration):
name='actions', name='actions',
field=models.ManyToManyField(blank=True, related_name='permissions', to='perms.Action', verbose_name='Action'), 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 ...@@ -6,21 +6,22 @@ from functools import reduce
def migrate_old_actions(apps, schema_editor): def migrate_old_actions(apps, schema_editor):
from orgs.utils import set_to_root_org from orgs.utils import set_to_root_org
from ..models import ActionFlag
set_to_root_org() set_to_root_org()
perm_model = apps.get_model('perms', 'AssetPermission') perm_model = apps.get_model('perms', 'AssetPermission')
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
perms = perm_model.objects.using(db_alias).all() perms = perm_model.objects.using(db_alias).all()
actions_map = { actions_map = {
"all": ActionFlag.ALL, "all": 0b11111111,
"connect": ActionFlag.CONNECT, "connect": 0b00000001,
"upload_file": ActionFlag.UPLOAD, "upload_file": 0b00000010,
"download_file": ActionFlag.DOWNLOAD, "download_file": 0b00000100,
} }
for perm in perms: for perm in perms:
actions = perm.actions.all() 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) new_action = reduce(lambda x, y: x | y, new_actions)
perm.action = new_action perm.action = new_action
perm.save() perm.save()
......
...@@ -19,4 +19,5 @@ class Migration(migrations.Migration): ...@@ -19,4 +19,5 @@ class Migration(migrations.Migration):
old_name='action', old_name='action',
new_name='actions', new_name='actions',
), ),
migrations.DeleteModel(name='Action'),
] ]
...@@ -4,37 +4,18 @@ from functools import reduce ...@@ -4,37 +4,18 @@ from functools import reduce
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ 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 orgs.mixins import OrgModelMixin
from ..const import PERMS_ACTION_NAME_CHOICES, PERMS_ACTION_NAME_ALL
from .base import BasePermission from .base import BasePermission
__all__ = [ __all__ = [
'Action', 'AssetPermission', 'NodePermission', 'ActionFlag' 'AssetPermission', 'NodePermission', 'Action',
] ]
class Action(models.Model): class Action:
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:
CONNECT = 0b00000001 CONNECT = 0b00000001
UPLOAD = 0b00000010 UPLOAD = 0b00000010
DOWNLOAD = 0b00000100 DOWNLOAD = 0b00000100
...@@ -74,6 +55,8 @@ class ActionFlag: ...@@ -74,6 +55,8 @@ class ActionFlag:
x = cls.NAME_MAP_REVERSE.get(x, 0) x = cls.NAME_MAP_REVERSE.get(x, 0)
y = cls.NAME_MAP_REVERSE.get(y, 0) y = cls.NAME_MAP_REVERSE.get(y, 0)
return x | y return x | y
if not value:
return None
return reduce(to_choices, value) return reduce(to_choices, value)
@classmethod @classmethod
...@@ -86,7 +69,7 @@ class AssetPermission(BasePermission): ...@@ -86,7 +69,7 @@ class AssetPermission(BasePermission):
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes")) 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")) 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.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: class Meta:
unique_together = [('org_id', 'name')] unique_together = [('org_id', 'name')]
......
...@@ -5,36 +5,38 @@ from rest_framework import serializers ...@@ -5,36 +5,38 @@ from rest_framework import serializers
from common.fields import StringManyToManyField from common.fields import StringManyToManyField
from orgs.mixins import BulkOrgResourceModelSerializer from orgs.mixins import BulkOrgResourceModelSerializer
from perms.models import AssetPermission, ActionFlag from perms.models import AssetPermission, Action
__all__ = [ __all__ = [
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer', 'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer', 'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
'ActionField', 'ActionsField',
] ]
class ActionField(serializers.MultipleChoiceField): class ActionsField(serializers.MultipleChoiceField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['choices'] = ActionFlag.CHOICES kwargs['choices'] = Action.CHOICES
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def to_representation(self, value): def to_representation(self, value):
return ActionFlag.value_to_choices(value) return Action.value_to_choices(value)
def to_internal_value(self, data): 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): def to_representation(self, value):
values = super().to_representation(value) values = super().to_representation(value)
choices = dict(ActionFlag.CHOICES) choices = dict(Action.CHOICES)
return [choices.get(i) for i in values] return [choices.get(i) for i in values]
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer): class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
actions = ActionField() actions = ActionsField(required=False, allow_null=True)
class Meta: class Meta:
model = AssetPermission model = AssetPermission
...@@ -47,7 +49,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer): ...@@ -47,7 +49,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
assets = StringManyToManyField(many=True, read_only=True) assets = StringManyToManyField(many=True, read_only=True)
nodes = StringManyToManyField(many=True, read_only=True) nodes = StringManyToManyField(many=True, read_only=True)
system_users = StringManyToManyField(many=True, read_only=True) system_users = StringManyToManyField(many=True, read_only=True)
actions = ActionDisplayField() actions = ActionsDisplayField()
is_valid = serializers.BooleanField() is_valid = serializers.BooleanField()
is_expired = serializers.BooleanField() is_expired = serializers.BooleanField()
......
...@@ -6,7 +6,7 @@ from rest_framework import serializers ...@@ -6,7 +6,7 @@ from rest_framework import serializers
from assets.models import Node, SystemUser from assets.models import Node, SystemUser
from assets.serializers import AssetSerializer from assets.serializers import AssetSerializer
from .asset_permission import ActionField from .asset_permission import ActionsField
__all__ = [ __all__ = [
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer', 'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
...@@ -19,7 +19,7 @@ class AssetSystemUserSerializer(serializers.ModelSerializer): ...@@ -19,7 +19,7 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
""" """
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少 查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
""" """
actions = ActionField(read_only=True) actions = ActionsField(read_only=True)
class Meta: class Meta:
model = SystemUser model = SystemUser
...@@ -115,4 +115,4 @@ class GrantedNodeSerializer(serializers.ModelSerializer): ...@@ -115,4 +115,4 @@ class GrantedNodeSerializer(serializers.ModelSerializer):
class ActionsSerializer(serializers.Serializer): class ActionsSerializer(serializers.Serializer):
actions = ActionField(read_only=True) actions = ActionsField(read_only=True)
\ No newline at end of file
...@@ -6,7 +6,7 @@ from django.db import transaction ...@@ -6,7 +6,7 @@ from django.db import transaction
from common.utils import get_logger from common.utils import get_logger
from .utils import AssetPermissionUtil from .utils import AssetPermissionUtil
from .models import AssetPermission, Action from .models import AssetPermission
logger = get_logger(__file__) logger = get_logger(__file__)
......
...@@ -17,7 +17,7 @@ from orgs.utils import set_to_root_org ...@@ -17,7 +17,7 @@ from orgs.utils import set_to_root_org
from common.utils import get_logger from common.utils import get_logger
from common.tree import TreeNode from common.tree import TreeNode
from .. import const from .. import const
from ..models import AssetPermission, Action, ActionFlag from ..models import AssetPermission, Action
from ..hands import Node, Asset from ..hands import Node, Asset
from assets.utils import NodeUtil from assets.utils import NodeUtil
...@@ -569,7 +569,7 @@ def parse_asset_to_tree_node(node, asset, system_users): ...@@ -569,7 +569,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
'protocol': system_user.protocol, 'protocol': system_user.protocol,
'priority': system_user.priority, 'priority': system_user.priority,
'login_mode': system_user.login_mode, 'login_mode': system_user.login_mode,
'actions': [ActionFlag.value_to_choices(action)], 'actions': [Action.value_to_choices(action)],
}) })
data = { data = {
'id': str(asset.id), 'id': str(asset.id),
......
...@@ -10,10 +10,9 @@ from django.conf import settings ...@@ -10,10 +10,9 @@ from django.conf import settings
from common.permissions import PermissionsMixin, IsOrgAdmin from common.permissions import PermissionsMixin, IsOrgAdmin
from orgs.utils import current_org from orgs.utils import current_org
from perms.hands import Node, Asset, SystemUser, User, UserGroup from perms.hands import Node, Asset, SystemUser, UserGroup
from perms.models import AssetPermission, Action from perms.models import AssetPermission
from perms.forms import AssetPermissionForm from perms.forms import AssetPermissionForm
from perms.const import PERMS_ACTION_NAME_ALL
__all__ = [ __all__ = [
......
...@@ -77,6 +77,7 @@ def monkey_patch_settings(sender, **kwargs): ...@@ -77,6 +77,7 @@ def monkey_patch_settings(sender, **kwargs):
@receiver(django_ready) @receiver(django_ready)
def auto_generate_terminal_host_key(sender, **kwargs): def auto_generate_terminal_host_key(sender, **kwargs):
try: try:
print("Auto gen host key")
if Setting.objects.filter(name='TERMINAL_HOST_KEY').exists(): if Setting.objects.filter(name='TERMINAL_HOST_KEY').exists():
return return
private_key, public_key = ssh_key_gen() private_key, public_key = ssh_key_gen()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment