Commit 8e9b3f13 authored by ibuler's avatar ibuler

[Update] 修改permission actions

parents 48ba1993 320b17c8
...@@ -112,12 +112,16 @@ class NodeChildrenAsTreeApi(generics.ListAPIView): ...@@ -112,12 +112,16 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
is_root = False is_root = False
def get_queryset(self): def get_queryset(self):
self.check_need_refresh_nodes()
node_key = self.request.query_params.get('key') node_key = self.request.query_params.get('key')
util = NodeUtil() util = NodeUtil()
# 是否包含自己
with_self = False
if not node_key: if not node_key:
node_key = Node.root().key node_key = Node.root().key
with_self = True
self.node = util.get_node_by_key(node_key) self.node = util.get_node_by_key(node_key)
queryset = self.node.get_children(with_self=True) queryset = self.node.get_children(with_self=with_self)
queryset = [node.as_tree_node() for node in queryset] queryset = [node.as_tree_node() for node in queryset]
queryset = sorted(queryset) queryset = sorted(queryset)
return queryset return queryset
...@@ -133,14 +137,11 @@ class NodeChildrenAsTreeApi(generics.ListAPIView): ...@@ -133,14 +137,11 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
def filter_queryset(self, queryset): def filter_queryset(self, queryset):
queryset = self.filter_assets(queryset) queryset = self.filter_assets(queryset)
queryset = self.filter_refresh_nodes(queryset)
return queryset return queryset
def filter_refresh_nodes(self, queryset): def check_need_refresh_nodes(self):
if self.request.query_params.get('refresh', '0') == '1': if self.request.query_params.get('refresh', '0') == '1':
Node.expire_nodes_assets_amount() Node.refresh_nodes()
Node.expire_nodes_full_value()
return queryset
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
......
...@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _ ...@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from common.utils import get_logger from common.utils import get_logger
from orgs.mixins import OrgModelForm from orgs.mixins import OrgModelForm
from ..models import Asset, Protocol from ..models import Asset, Protocol, Node
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -33,6 +33,12 @@ class ProtocolForm(forms.ModelForm): ...@@ -33,6 +33,12 @@ class ProtocolForm(forms.ModelForm):
class AssetCreateForm(OrgModelForm): class AssetCreateForm(OrgModelForm):
PROTOCOL_CHOICES = Protocol.PROTOCOL_CHOICES PROTOCOL_CHOICES = Protocol.PROTOCOL_CHOICES
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.data:
nodes_field = self.fields['nodes']
nodes_field._queryset = Node.get_queryset()
class Meta: class Meta:
model = Asset model = Asset
fields = [ fields = [
......
...@@ -186,9 +186,6 @@ class FullValueMixin: ...@@ -186,9 +186,6 @@ class FullValueMixin:
def expire_nodes_full_value(cls, nodes=None): def expire_nodes_full_value(cls, nodes=None):
key = cls._full_value_cache_key.format('*') key = cls._full_value_cache_key.format('*')
cache.delete_pattern(key+'*') cache.delete_pattern(key+'*')
from ..utils import NodeUtil
util = NodeUtil()
util.set_full_value()
class AssetsAmountMixin: class AssetsAmountMixin:
...@@ -216,7 +213,7 @@ class AssetsAmountMixin: ...@@ -216,7 +213,7 @@ class AssetsAmountMixin:
def assets_amount(self, value): def assets_amount(self, value):
self._assets_amount = value self._assets_amount = value
cache_key = self._assets_amount_cache_key.format(self.key) cache_key = self._assets_amount_cache_key.format(self.key)
cache.set(cache_key, value, 3600 * 24) cache.set(cache_key, value)
def expire_assets_amount(self): def expire_assets_amount(self):
ancestor_keys = self.get_ancestor_keys(with_self=True) ancestor_keys = self.get_ancestor_keys(with_self=True)
...@@ -226,11 +223,15 @@ class AssetsAmountMixin: ...@@ -226,11 +223,15 @@ class AssetsAmountMixin:
@classmethod @classmethod
def expire_nodes_assets_amount(cls, nodes=None): def expire_nodes_assets_amount(cls, nodes=None):
from ..utils import NodeUtil
key = cls._assets_amount_cache_key.format('*') key = cls._assets_amount_cache_key.format('*')
cache.delete_pattern(key) cache.delete_pattern(key)
@classmethod
def refresh_nodes(cls):
from ..utils import NodeUtil
util = NodeUtil(with_assets_amount=True) util = NodeUtil(with_assets_amount=True)
util.set_assets_amount() util.set_assets_amount()
util.set_full_value()
class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin): class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
...@@ -375,9 +376,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin): ...@@ -375,9 +376,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
def as_tree_node(self): def as_tree_node(self):
from common.tree import TreeNode from common.tree import TreeNode
from ..serializers import NodeSerializer
name = '{} ({})'.format(self.value, self.assets_amount) name = '{} ({})'.format(self.value, self.assets_amount)
node_serializer = NodeSerializer(instance=self)
data = { data = {
'id': self.key, 'id': self.key,
'name': name, 'name': name,
...@@ -386,7 +385,12 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin): ...@@ -386,7 +385,12 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
'isParent': True, 'isParent': True,
'open': self.is_root(), 'open': self.is_root(),
'meta': { 'meta': {
'node': node_serializer.data, 'node': {
"id": self.id,
"name": self.name,
"value": self.value,
"key": self.key,
},
'type': 'node' 'type': 'node'
} }
} }
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from rest_framework import serializers from rest_framework import serializers
from django.utils.translation import ugettext as _
from orgs.mixins import BulkOrgResourceModelSerializer from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import Asset, Node from ..models import Asset, Node
...@@ -25,11 +26,11 @@ class NodeSerializer(BulkOrgResourceModelSerializer): ...@@ -25,11 +26,11 @@ class NodeSerializer(BulkOrgResourceModelSerializer):
def validate_value(self, data): def validate_value(self, data):
instance = self.instance if self.instance else Node.root() instance = self.instance if self.instance else Node.root()
children = instance.parent.get_children().exclude(key=instance.key) children = instance.parent.get_children()
values = [child.value for child in children] children_values = [node.value for node in children if node != instance]
if data in values: if data in children_values:
raise serializers.ValidationError( raise serializers.ValidationError(
'The same level node name cannot be the same' _('The same level node name cannot be the same')
) )
return data return data
......
...@@ -67,6 +67,7 @@ function initTable2() { ...@@ -67,6 +67,7 @@ function initTable2() {
columns: [ columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" } {data: "id"}, {data: "hostname" }, {data: "ip" }
], ],
lengthMenu: [[10, 25, 50], [10, 25, 50]],
pageLength: 10 pageLength: 10
}; };
asset_table2 = jumpserver.initServerSideDataTable(options); asset_table2 = jumpserver.initServerSideDataTable(options);
......
This diff is collapsed.
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
# #
import time
from django.db.models import Prefetch from django.db.models import Prefetch
from common.utils import get_object_or_none, get_logger from common.utils import get_object_or_none, get_logger
...@@ -56,9 +57,11 @@ class NodeUtil: ...@@ -56,9 +57,11 @@ class NodeUtil:
def get_all_nodes(self): def get_all_nodes(self):
all_nodes = Node.objects.all() all_nodes = Node.objects.all()
if self.with_assets_amount: if self.with_assets_amount:
now = time.time()
all_nodes = all_nodes.prefetch_related( all_nodes = all_nodes.prefetch_related(
Prefetch('assets', queryset=Asset.objects.all().only('id')) Prefetch('assets', queryset=Asset.objects.all().only('id'))
) )
all_nodes = list(all_nodes)
for node in all_nodes: for node in all_nodes:
node._assets = set(node.assets.all()) node._assets = set(node.assets.all())
all_nodes = sorted(all_nodes, key=self.sorted_by) all_nodes = sorted(all_nodes, key=self.sorted_by)
......
...@@ -130,16 +130,13 @@ def get_short_uuid_str(): ...@@ -130,16 +130,13 @@ def get_short_uuid_str():
def is_uuid(seq): def is_uuid(seq):
if isinstance(seq, str): if isinstance(seq, uuid.UUID):
if UUID_PATTERN.match(seq): return True
return True elif isinstance(seq, str) and UUID_PATTERN.match(seq):
else:
return False
else:
for s in seq:
if not is_uuid(s):
return False
return True return True
elif isinstance(seq, (list, tuple)):
all([is_uuid(x) for x in seq])
return False
def get_request_ip(request): def get_request_ip(request):
......
...@@ -399,7 +399,7 @@ REST_FRAMEWORK = { ...@@ -399,7 +399,7 @@ REST_FRAMEWORK = {
'ORDERING_PARAM': "order", 'ORDERING_PARAM': "order",
'SEARCH_PARAM': "search", 'SEARCH_PARAM': "search",
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z', 'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'], 'DATETIME_INPUT_FORMATS': ['iso-8601', '%Y-%m-%d %H:%M:%S %z'],
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
# 'PAGE_SIZE': 15 # 'PAGE_SIZE': 15
} }
......
This diff is collapsed.
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from assets.models import Node from assets.models import Node
from orgs.utils import set_current_org, current_org from orgs.utils import set_current_org, current_org, get_current_org
...@@ -4,7 +4,8 @@ import traceback ...@@ -4,7 +4,8 @@ import traceback
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 django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.forms import ModelForm from django import forms
from django.core.exceptions import ValidationError
from django.http.response import HttpResponseForbidden from django.http.response import HttpResponseForbidden
from rest_framework import serializers from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator from rest_framework.validators import UniqueTogetherValidator
...@@ -101,6 +102,26 @@ class OrgModelMixin(models.Model): ...@@ -101,6 +102,26 @@ class OrgModelMixin(models.Model):
else: else:
return name return name
def validate_unique(self, exclude=None):
"""
Check unique constraints on the model and raise ValidationError if any
failed.
Form 提交时会使用这个检验
"""
self.org_id = current_org.id if current_org.is_real() else ''
if exclude and 'org_id' in exclude:
exclude.remove('org_id')
unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
errors = self._perform_unique_checks(unique_checks)
date_errors = self._perform_date_checks(date_checks)
for k, v in date_errors.items():
errors.setdefault(k, []).extend(v)
if errors:
raise ValidationError(errors)
class Meta: class Meta:
abstract = True abstract = True
...@@ -123,11 +144,9 @@ class RootOrgViewMixin: ...@@ -123,11 +144,9 @@ class RootOrgViewMixin:
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class OrgModelForm(ModelForm): class OrgModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# if 'initial' not in kwargs:
# return
for name, field in self.fields.items(): for name, field in self.fields.items():
if not hasattr(field, 'queryset'): if not hasattr(field, 'queryset'):
continue continue
......
...@@ -6,7 +6,7 @@ from django.db.models.signals import post_save ...@@ -6,7 +6,7 @@ from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from .models import Organization from .models import Organization
from .hands import set_current_org, current_org, Node from .hands import set_current_org, current_org, Node, get_current_org
from perms.models import AssetPermission from perms.models import AssetPermission
from users.models import UserGroup from users.models import UserGroup
...@@ -14,7 +14,7 @@ from users.models import UserGroup ...@@ -14,7 +14,7 @@ from users.models import UserGroup
@receiver(post_save, sender=Organization) @receiver(post_save, sender=Organization)
def on_org_create_or_update(sender, instance=None, created=False, **kwargs): def on_org_create_or_update(sender, instance=None, created=False, **kwargs):
if instance: if instance:
old_org = current_org old_org = get_current_org()
set_current_org(instance) set_current_org(instance)
node_root = Node.root() node_root = Node.root()
if node_root.value != instance.name: if node_root.value != instance.name:
......
...@@ -20,16 +20,10 @@ from .. import serializers ...@@ -20,16 +20,10 @@ from .. import serializers
__all__ = [ __all__ = [
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi', 'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi', 'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
'AssetPermissionAddAssetApi', 'ActionViewSet', 'AssetPermissionAddAssetApi',
] ]
class ActionViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Action.objects.all()
serializer_class = serializers.ActionSerializer
permission_classes = (IsOrgAdmin,)
class AssetPermissionViewSet(viewsets.ModelViewSet): class AssetPermissionViewSet(viewsets.ModelViewSet):
""" """
资产授权列表的增删改查api 资产授权列表的增删改查api
......
...@@ -14,7 +14,6 @@ from rest_framework.pagination import LimitOffsetPagination ...@@ -14,7 +14,6 @@ from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsValidUser, IsOrgAdminOrAppUser from common.permissions import IsValidUser, IsOrgAdminOrAppUser
from common.tree import TreeNodeSerializer from common.tree import TreeNodeSerializer
from common.utils import get_logger from common.utils import get_logger
from orgs.utils import set_to_root_org
from ..utils import ( from ..utils import (
AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node, AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node,
check_system_user_action, RemoteAppPermissionUtil, check_system_user_action, RemoteAppPermissionUtil,
...@@ -515,6 +514,7 @@ class ValidateUserRemoteAppPermissionApi(APIView): ...@@ -515,6 +514,7 @@ class ValidateUserRemoteAppPermissionApi(APIView):
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.change_org_if_need(request, kwargs)
user_id = request.query_params.get('user_id', '') user_id = request.query_params.get('user_id', '')
remote_app_id = request.query_params.get('remote_app_id', '') remote_app_id = request.query_params.get('remote_app_id', '')
user = get_object_or_404(User, id=user_id) user = get_object_or_404(User, id=user_id)
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from functools import reduce
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -18,17 +19,22 @@ class AssetPermissionForm(OrgModelForm): ...@@ -18,17 +19,22 @@ class AssetPermissionForm(OrgModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
users_field = self.fields.get('users') users_field = self.fields.get('users')
if hasattr(users_field, 'queryset'): users_field.queryset = current_org.get_org_users()
users_field.queryset = current_org.get_org_users()
assets_field = self.fields.get('assets')
# 前端渲染优化, 防止过多资产 # 前端渲染优化, 防止过多资产
if not self.data: if not self.data:
instance = kwargs.get('instance') instance = kwargs.get('instance')
assets_field = self.fields['assets']
if instance: if instance:
assets_field.queryset = instance.assets.all() assets_field.queryset = instance.assets.all()
else: else:
assets_field.queryset = Asset.objects.none() assets_field.queryset = Asset.objects.none()
nodes_field = self.fields['nodes']
nodes_field._queryset = Node.get_queryset()
def clean_action(self):
actions = self.cleaned_data.get("action")
return reduce(lambda x, y: x | y, actions)
class Meta: class Meta:
model = AssetPermission model = AssetPermission
...@@ -51,16 +57,14 @@ class AssetPermissionForm(OrgModelForm): ...@@ -51,16 +57,14 @@ class AssetPermissionForm(OrgModelForm):
'system_users': forms.SelectMultiple( 'system_users': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('System user')} attrs={'class': 'select2', 'data-placeholder': _('System user')}
), ),
'actions': forms.SelectMultiple( 'action': forms.CheckboxSelectMultiple()
attrs={'class': 'select2', 'data-placeholder': _('Action')}
)
} }
labels = { labels = {
'nodes': _("Node"), 'nodes': _("Node"),
} }
help_texts = { help_texts = {
'actions': _('Tips: The RDP protocol does not support separate ' 'action': _('Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files') 'controls for uploading or downloading files')
} }
def clean_user_groups(self): def clean_user_groups(self):
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-25 10:15
from __future__ import unicode_literals
import common.utils
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('users', '0004_auto_20180125_1218'),
('assets', '0007_auto_20180225_1815'),
('perms', '0002_auto_20171228_0025'),
]
operations = [
migrations.CreateModel(
name='NodePermission',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('date_expired', models.DateTimeField(default=common.utils.date_expired_default, verbose_name='Date expired')),
('created_by', models.CharField(blank=True, max_length=128, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Node', verbose_name='Node')),
('system_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser', verbose_name='System user')),
('user_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.UserGroup', verbose_name='User group')),
],
options={
'verbose_name': 'Asset permission',
},
),
migrations.AlterUniqueTogether(
name='nodepermission',
unique_together=set([('node', 'user_group', 'system_user')]),
),
]
# -*- 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
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('assets', '0013_auto_20180411_1135'),
('perms', '0003_auto_20180225_1815'),
]
operations = [
migrations.RemoveField(
model_name='assetpermission',
name='asset_groups',
),
migrations.AddField(
model_name='assetpermission',
name='date_start',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date start'),
),
migrations.AddField(
model_name='assetpermission',
name='nodes',
field=models.ManyToManyField(blank=True, related_name='granted_by_permissions', to='assets.Node', verbose_name='Nodes'),
),
]
# -*- 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
import django.utils.timezone
def migrate_node_permissions(apps, schema_editor):
node_perm_model = apps.get_model("perms", "NodePermission")
asset_perm_model = apps.get_model("perms", "AssetPermission")
db_alias = schema_editor.connection.alias
for old in node_perm_model.objects.using(db_alias).all():
perm = asset_perm_model.objects.using(db_alias).create(
name="{}-{}-{}".format(
old.node.value,
old.user_group.name,
old.system_user.name
),
is_active=old.is_active,
date_expired=old.date_expired,
created_by=old.date_expired,
date_created=old.date_created,
comment=old.comment,
)
perm.user_groups.add(old.user_group)
perm.nodes.add(old.node)
perm.system_users.add(old.system_user)
def migrate_system_assets_relation(apps, schema_editor):
system_user_model = apps.get_model("assets", "SystemUser")
db_alias = schema_editor.connection.alias
for s in system_user_model.objects.using(db_alias).all():
nodes = list(s.nodes.all())
s.nodes.set([])
s.nodes.set(nodes)
class Migration(migrations.Migration):
dependencies = [
('perms', '0004_auto_20180411_1135'),
]
operations = [
migrations.RunPython(migrate_node_permissions),
migrations.RunPython(migrate_system_assets_relation),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-06-06 07:05
from __future__ import unicode_literals
import common.utils
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('perms', '0005_migrate_data_20180411_1144'),
]
operations = [
migrations.AlterField(
model_name='assetpermission',
name='date_expired',
field=models.DateTimeField(db_index=True, default=common.utils.date_expired_default, verbose_name='Date expired'),
),
migrations.AlterField(
model_name='assetpermission',
name='date_start',
field=models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Date start'),
),
]
# Generated by Django 2.1.7 on 2019-06-28 11:47
from django.db import migrations, models
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,
}
for perm in perms:
actions = perm.actions.all()
new_actions = [actions_map.get(action.name, ActionFlag.ALL) for action in actions]
new_action = reduce(lambda x, y: x | y, new_actions)
perm.action = new_action
perm.save()
class Migration(migrations.Migration):
dependencies = [
('perms', '0005_auto_20190521_1619'),
]
operations = [
migrations.AddField(
model_name='assetpermission',
name='action',
field=models.IntegerField(
choices=[(255, 'All'), (1, 'Connect'), (2, 'Upload file'),
(6, 'Upload download'), (4, 'Download file')],
default=255, verbose_name='Action'),
),
migrations.RunPython(migrate_old_actions),
]
# Generated by Django 2.0.7 on 2018-08-07 03:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0006_auto_20180606_1505'),
]
operations = [
migrations.AddField(
model_name='assetpermission',
name='org_id',
field=models.CharField(blank=True, default=None, max_length=36, null=True),
),
migrations.AddField(
model_name='nodepermission',
name='org_id',
field=models.CharField(blank=True, default=None, max_length=36, null=True),
),
migrations.AlterField(
model_name='assetpermission',
name='name',
field=models.CharField(max_length=128, verbose_name='Name'),
),
migrations.AlterUniqueTogether(
name='assetpermission',
unique_together={('org_id', 'name')},
),
migrations.AlterUniqueTogether(
name='nodepermission',
unique_together=set(),
),
]
# Generated by Django 2.1 on 2018-09-03 03:32 # Generated by Django 2.1.7 on 2019-06-28 12:02
from django.db import migrations from django.db import migrations
...@@ -6,12 +6,12 @@ from django.db import migrations ...@@ -6,12 +6,12 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('perms', '0008_auto_20180816_1652'), ('perms', '0006_auto_20190628_1921'),
] ]
operations = [ operations = [
migrations.AlterModelOptions( migrations.RemoveField(
name='assetpermission', model_name='assetpermission',
options={'verbose_name': 'Asset permission'}, name='actions',
), ),
] ]
# Generated by Django 2.0.7 on 2018-08-16 08:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0007_auto_20180807_1116'),
]
operations = [
migrations.AlterField(
model_name='assetpermission',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
migrations.AlterField(
model_name='nodepermission',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
]
...@@ -11,7 +11,7 @@ from .base import BasePermission ...@@ -11,7 +11,7 @@ from .base import BasePermission
__all__ = [ __all__ = [
'Action', 'AssetPermission', 'NodePermission', 'Action', 'AssetPermission', 'NodePermission', 'ActionFlag'
] ]
...@@ -33,11 +33,28 @@ class Action(models.Model): ...@@ -33,11 +33,28 @@ class Action(models.Model):
return cls.objects.get(name=PERMS_ACTION_NAME_ALL) return cls.objects.get(name=PERMS_ACTION_NAME_ALL)
class ActionFlag:
CONNECT = 0b00000001
UPLOAD = 0b00000010
DOWNLOAD = 0b00000100
UPDOWNLOAD = CONNECT | DOWNLOAD
ALL = 0b11111111
CHOICES = (
(ALL, _('All')),
(CONNECT, _('Connect')),
(UPLOAD, _('Upload file')),
(UPDOWNLOAD, _("Upload download")),
(DOWNLOAD, _('Download file')),
)
class AssetPermission(BasePermission): class AssetPermission(BasePermission):
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset")) assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
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'))
action = models.IntegerField(choices=ActionFlag.CHOICES, default=ActionFlag.ALL, verbose_name=_("Action"))
class Meta: class Meta:
unique_together = [('org_id', 'name')] unique_together = [('org_id', 'name')]
......
...@@ -13,16 +13,10 @@ __all__ = [ ...@@ -13,16 +13,10 @@ __all__ = [
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer', 'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer', 'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer', 'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
'ActionSerializer', 'NodeGrantedSerializer', 'NodeGrantedSerializer',
] ]
class ActionSerializer(serializers.ModelSerializer):
class Meta:
model = Action
fields = '__all__'
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer): class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
class Meta: class Meta:
model = AssetPermission model = AssetPermission
...@@ -35,7 +29,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer): ...@@ -35,7 +29,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 = StringManyToManyField(many=True, read_only=True) action = serializers.IntegerField(read_only=True)
is_valid = serializers.BooleanField() is_valid = serializers.BooleanField()
is_expired = serializers.BooleanField() is_expired = serializers.BooleanField()
......
...@@ -25,13 +25,6 @@ def on_transaction_commit(func): ...@@ -25,13 +25,6 @@ def on_transaction_commit(func):
@on_transaction_commit @on_transaction_commit
def on_permission_created(sender, instance=None, created=False, **kwargs): def on_permission_created(sender, instance=None, created=False, **kwargs):
AssetPermissionUtil.expire_all_cache() AssetPermissionUtil.expire_all_cache()
actions = instance.actions.all()
if created and not actions:
default_action = Action.get_action_all()
instance.actions.add(default_action)
logger.debug(
"Set default action to perms: {}".format(default_action, instance)
)
@receiver(post_save, sender=AssetPermission) @receiver(post_save, sender=AssetPermission)
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
{% bootstrap_field form.system_users layout="horizontal" %} {% bootstrap_field form.system_users layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Action' %}</h3> <h3>{% trans 'Action' %}</h3>
{% bootstrap_field form.actions layout="horizontal" %} {% bootstrap_field form.action layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
<div class="form-group"> <div class="form-group">
...@@ -143,6 +143,34 @@ $(document).ready(function () { ...@@ -143,6 +143,34 @@ $(document).ready(function () {
$('#id_assets').val(assets).trigger('change'); $('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide'); $("#asset_list_modal").modal('hide');
}); })
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-perms:asset-permission-list' %}';
var redirect_to = '{% url "perms:asset-permission-list" %}';
var method = "POST";
var form = $("form");
var data = form.serializeObject();
console.log(data)
var actions = data.action;
var action = 0;
for (i=0;i<actions.length;i++) {
console.log(actions[i])
action |= actions[i];
}
data.action = action;
objectAttrsIsList(data, ['users', 'user_groups', 'system_users', 'nodes', 'assets']);
objectAttrsIsDatetime(data, ['date_start', 'date_expired']);
objectAttrsIsBool(data, ['is_active'])
console.log(data)
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -24,15 +24,7 @@ ...@@ -24,15 +24,7 @@
<div class="wrapper wrapper-content"> <div class="wrapper wrapper-content">
<div class="row"> <div class="row">
<div class="col-lg-3" id="split-left" style="padding-left: 3px"> <div class="col-lg-3" id="split-left" style="padding-left: 3px">
<div class="ibox float-e-margins"> {% include 'assets/_node_tree.html' %}
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
<div class="file-manager ">
<div id="assetTree" class="ztree">
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
</div> </div>
<div class="col-lg-9 animated fadeInRight" id="split-right"> <div class="col-lg-9 animated fadeInRight" id="split-right">
<div class="tree-toggle"> <div class="tree-toggle">
...@@ -86,7 +78,7 @@ ...@@ -86,7 +78,7 @@
<script> <script>
var zTree, table, show = 0; var zTree, table, show = 0;
function onSelected(event, treeNode) { function onNodeSelected(event, treeNode) {
setCookie('node_selected', treeNode.id); setCookie('node_selected', treeNode.id);
var url = table.ajax.url(); var url = table.ajax.url();
if (treeNode.meta.type === 'node') { if (treeNode.meta.type === 'node') {
...@@ -102,7 +94,7 @@ function onSelected(event, treeNode) { ...@@ -102,7 +94,7 @@ function onSelected(event, treeNode) {
} }
function beforeAsync(treeId, treeNode) { function beforeNodeAsync(treeId, treeNode) {
if (treeNode) { if (treeNode) {
return treeNode.meta.type === 'node' return treeNode.meta.type === 'node'
} }
...@@ -204,28 +196,12 @@ function initTable() { ...@@ -204,28 +196,12 @@ function initTable() {
function initTree() { function initTree() {
var setting = { initNodeTree({
view: { onSelected: onNodeSelected,
dblClickExpand: false, beforeAsync: beforeNodeAsync,
showLine: true showMenu: false,
}, showAssets: true,
data: { })
simpleData: {
enable: true
}
},
async: {
enable: true,
url: "{% url 'api-assets:node-children-tree' %}?assets=1",
autoParam:["id=key", "name=n", "level=lv"],
type: 'get'
},
callback: {
onSelected: onSelected,
beforeAsync: beforeAsync
}
};
zTree = $.fn.zTree.init($("#assetTree"), setting);
} }
function toggle() { function toggle() {
......
...@@ -7,7 +7,6 @@ from .. import api ...@@ -7,7 +7,6 @@ from .. import api
app_name = 'perms' app_name = 'perms'
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register('actions', api.ActionViewSet, 'action')
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission') router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission') router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission')
......
...@@ -5,6 +5,7 @@ from collections import defaultdict ...@@ -5,6 +5,7 @@ from collections import defaultdict
import json import json
from hashlib import md5 from hashlib import md5
import time import time
import itertools
from django.utils import timezone from django.utils import timezone
from django.db.models import Q from django.db.models import Q
...@@ -102,11 +103,11 @@ def get_user_permissions(user, include_group=True): ...@@ -102,11 +103,11 @@ def get_user_permissions(user, include_group=True):
arg = Q(users=user) | Q(user_groups__in=groups) arg = Q(users=user) | Q(user_groups__in=groups)
else: else:
arg = Q(users=user) arg = Q(users=user)
return AssetPermission.objects.all().valid().filter(arg) return AssetPermission.objects.valid().filter(arg)
def get_user_group_permissions(user_group): def get_user_group_permissions(user_group):
return AssetPermission.objects.all().valid().filter( return AssetPermission.objects.valid().filter(
user_groups=user_group user_groups=user_group
) )
...@@ -117,15 +118,15 @@ def get_asset_permissions(asset, include_node=True): ...@@ -117,15 +118,15 @@ def get_asset_permissions(asset, include_node=True):
arg = Q(assets=asset) | Q(nodes__in=nodes) arg = Q(assets=asset) | Q(nodes__in=nodes)
else: else:
arg = Q(assets=asset) arg = Q(assets=asset)
return AssetPermission.objects.all().valid().filter(arg) return AssetPermission.objects.valid().filter(arg)
def get_node_permissions(node): def get_node_permissions(node):
return AssetPermission.objects.all().valid().filter(nodes=node) return AssetPermission.objects.valid().filter(nodes=node)
def get_system_user_permissions(system_user): def get_system_user_permissions(system_user):
return AssetPermission.objects.valid().all().filter( return AssetPermission.objects.valid().filter(
system_users=system_user system_users=system_user
) )
...@@ -141,11 +142,6 @@ def timeit(func): ...@@ -141,11 +142,6 @@ def timeit(func):
return wrapper return wrapper
class AssetGranted:
def __init__(self):
self.system_users = {}
class AssetPermissionCacheMixin: class AssetPermissionCacheMixin:
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_' CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_' CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_'
...@@ -286,6 +282,38 @@ class AssetPermissionCacheMixin: ...@@ -286,6 +282,38 @@ class AssetPermissionCacheMixin:
cache.delete_pattern(key) cache.delete_pattern(key)
class FlatPermissionQueryset:
def __init__(self):
self.queryset = defaultdict(list)
def add(self, permission):
self.queryset[permission.id].append(permission)
def add_many(self, assets_or_nodes, system_users, actions):
if any([assets_or_nodes, system_users, actions]):
return
iterable = itertools.product(assets_or_nodes, system_users, actions)
for source, sysuser, action in iterable:
permission = FlatPermission(source, sysuser, action)
self.add(permission)
def clean(self):
pass
class FlatPermission:
def __init__(self, asset_or_node, system_user, action):
self.id = asset_or_node.id
self.source = asset_or_node
self.system_user = system_user
self.action = action
def __eq__(self, other):
pass
class AssetPermissionUtil(AssetPermissionCacheMixin): class AssetPermissionUtil(AssetPermissionCacheMixin):
get_permissions_map = { get_permissions_map = {
"User": get_user_permissions, "User": get_user_permissions,
...@@ -344,19 +372,15 @@ class AssetPermissionUtil(AssetPermissionCacheMixin): ...@@ -344,19 +372,15 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
def get_nodes_direct(self): def get_nodes_direct(self):
""" """
返回用户/组授权规则直接关联的节点 返回用户/组授权规则直接关联的节点
:return: {asset1: {system_user1: {'actions': set()},}} :return: {node1: {system_user1: {'actions': set()},}}
""" """
nodes = defaultdict(dict) nodes = FlatPermissionQueryset()
permissions = self.permissions.prefetch_related('nodes', 'system_users', 'actions') permissions = self.permissions
for perm in permissions: for perm in permissions:
actions = perm.actions.all() actions = perm.actions.all()
for node in perm.nodes.all(): system_users = perm.system_users.all()
system_users = perm.system_users.all() _nodes = perm.nodes.all()
system_users = self._structured_system_user(system_users, actions) nodes.add_many(_nodes, system_users, actions)
nodes[node].update(system_users)
self.tree.add_nodes(nodes.keys())
# 替换成优化过的node
nodes = {self.tree.node_util.get_node_by_key(k.key): v for k, v in nodes.items()}
return nodes return nodes
@timeit @timeit
...@@ -385,24 +409,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin): ...@@ -385,24 +409,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
assets = self.get_assets_direct() assets = self.get_assets_direct()
nodes = self.get_nodes_direct() nodes = self.get_nodes_direct()
# for node, system_users in nodes.items(): # for node, system_users in nodes.items():
# print(9999, node) # print(">>>>> Node<<<<<<<<<<<<: ", node.value)
# _assets = node.get_all_valid_assets() # _assets = list(node.get_all_valid_assets())
# print(".......... end .......")
# for asset in _assets: # for asset in _assets:
# print(">>asset")
# for system_user, attr_dict in system_users.items(): # for system_user, attr_dict in system_users.items():
# print(">>>system user")
# if not asset.has_protocol(system_user.protocol): # if not asset.has_protocol(system_user.protocol):
# continue # continue
# if system_user in assets[asset]: # if system_user in assets[asset]:
# actions = assets[asset][system_user]['actions'] # actions = assets[asset][system_user]['actions']
# attr_dict['actions'].update(actions) # attr_dict['actions'].update(actions)
# system_users.update({system_user: attr_dict}) # system_users.update({system_user: attr_dict})
# print("<<<system user")
# print("<<<asset")
# assets[asset].update(system_users) # assets[asset].update(system_users)
# print(">>>>>>")
#
__assets = defaultdict(set) __assets = defaultdict(set)
for asset, system_users in assets.items(): for asset, system_users in assets.items():
for system_user, attr_dict in system_users.items(): for system_user, attr_dict in system_users.items():
...@@ -507,8 +525,7 @@ def parse_asset_to_tree_node(node, asset, system_users): ...@@ -507,8 +525,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
'id': asset.id, 'id': asset.id,
'hostname': asset.hostname, 'hostname': asset.hostname,
'ip': asset.ip, 'ip': asset.ip,
'protocols': [{"name": p.name, "port": p.port} 'protocols': [str(p) for p in asset.protocols.all()],
for p in asset.protocols.all()],
'platform': asset.platform, 'platform': asset.platform,
'domain': None if not asset.domain else asset.domain.id, 'domain': None if not asset.domain else asset.domain.id,
'is_active': asset.is_active, 'is_active': asset.is_active,
......
...@@ -58,8 +58,6 @@ class AssetPermissionCreateView(PermissionsMixin, CreateView): ...@@ -58,8 +58,6 @@ class AssetPermissionCreateView(PermissionsMixin, CreateView):
assets_id = assets_id.split(",") assets_id = assets_id.split(",")
assets = Asset.objects.filter(id__in=assets_id) assets = Asset.objects.filter(id__in=assets_id)
form['assets'].initial = assets form['assets'].initial = assets
form['actions'].initial = Action.objects.get(name=PERMS_ACTION_NAME_ALL)
return form return form
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
......
...@@ -277,7 +277,7 @@ function APIUpdateAttr(props) { ...@@ -277,7 +277,7 @@ function APIUpdateAttr(props) {
}).done(function(data, textStatue, jqXHR) { }).done(function(data, textStatue, jqXHR) {
if (flash_message) { if (flash_message) {
var msg = ""; var msg = "";
if (user_fail_message) { if (user_success_message) {
msg = user_success_message; msg = user_success_message;
} else { } else {
msg = default_success_message; msg = default_success_message;
...@@ -635,7 +635,7 @@ jumpserver.initServerSideDataTable = function (options) { ...@@ -635,7 +635,7 @@ jumpserver.initServerSideDataTable = function (options) {
columns: options.columns || [], columns: options.columns || [],
select: options.select || select, select: options.select || select,
language: jumpserver.language, language: jumpserver.language,
lengthMenu: [[15, 25, 50, 9999], [15, 25, 50, 'All']] lengthMenu: options.lengthMenu || [[15, 25, 50, 9999], [15, 25, 50, 'All']]
}); });
table.selected = []; table.selected = [];
table.selected_rows = []; table.selected_rows = [];
...@@ -1072,3 +1072,27 @@ function htmlEscape ( d ) { ...@@ -1072,3 +1072,27 @@ function htmlEscape ( d ) {
d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') : d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
d; d;
} }
function objectAttrsIsList(obj, attrs) {
attrs.forEach(function (attr) {
if (obj[attr] && !(obj[attr] instanceof Array)){
obj[attr] = [obj[attr]]
}
})
}
function objectAttrsIsDatetime(obj, attrs) {
attrs.forEach(function (attr) {
obj[attr] = new Date(obj[attr]).toISOString();
})
}
function objectAttrsIsBool(obj, attrs) {
attrs.forEach(function (attr) {
if (!obj[attr]) {
obj[attr] = false
} else if (['on', '1'].includes(obj[attr])) {
obj[attr] = true
}
})
}
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