diff --git a/apps/assets/models/account.py b/apps/assets/models/account.py index 65e6c74f0..be568d9dd 100644 --- a/apps/assets/models/account.py +++ b/apps/assets/models/account.py @@ -9,6 +9,10 @@ __all__ = ['Account', 'AccountTemplate'] class Account(BaseAccount): + class InnerAccount(models.TextChoices): + INPUT = '@INPUT', '@INPUT' + USER = '@USER', '@USER' + asset = models.ForeignKey( 'assets.Asset', related_name='accounts', on_delete=models.CASCADE, verbose_name=_('Asset') @@ -40,6 +44,16 @@ class Account(BaseAccount): def __str__(self): return '{}@{}'.format(self.username, self.asset.name) + @classmethod + def get_input_account(cls): + """ @INPUT 手动登录的账号(any) """ + return cls(name=cls.InnerAccount.INPUT.value, username='') + + @classmethod + def get_user_account(cls, username): + """ @USER 动态用户的账号(self) """ + return cls(name=cls.InnerAccount.USER.value, username=username) + class AccountTemplate(BaseAccount): class Meta: diff --git a/apps/assets/models/asset/common.py b/apps/assets/models/asset/common.py index f94143c6e..163d1a873 100644 --- a/apps/assets/models/asset/common.py +++ b/apps/assets/models/asset/common.py @@ -4,8 +4,6 @@ import logging import uuid -from functools import reduce -from collections import Iterable from django.db import models from django.db.models import Q @@ -180,9 +178,11 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel): return tree_node def filter_accounts(self, account_names=None): + from perms.models import AssetPermission if account_names is None: return self.accounts.all() - assert isinstance(account_names, Iterable), '`account_names` must be an iterable object' + if AssetPermission.SpecialAccount.ALL in account_names: + return self.accounts.all() queries = Q(name__in=account_names) | Q(username__in=account_names) accounts = self.accounts.filter(queries) return accounts diff --git a/apps/perms/api/user_permission/common.py b/apps/perms/api/user_permission/common.py index 87b78fe8c..962d079bb 100644 --- a/apps/perms/api/user_permission/common.py +++ b/apps/perms/api/user_permission/common.py @@ -19,7 +19,7 @@ from perms.utils.permission import ( from common.permissions import IsValidUser from common.utils import get_logger, lazyproperty -from perms.hands import User, Asset +from perms.hands import User, Asset, Account from perms import serializers from perms.models import AssetPermission @@ -150,7 +150,7 @@ class UserGrantedAssetAccounts(ListAPIView): } @lazyproperty - def user(self): + def user(self) -> User: user_id = self.kwargs.get('pk') return User.objects.get(id=user_id) @@ -163,11 +163,14 @@ class UserGrantedAssetAccounts(ListAPIView): def get_queryset(self): # 获取用户-资产的授权规则 - assetperms = AssetPermission.filter_permissions(self.user, self.asset) + assetperms = AssetPermission.filter(self.user, self.asset) account_names = AssetPermission.get_account_names(assetperms) - accounts = self.asset.filter_accounts(account_names) + accounts = list(self.asset.filter_accounts(account_names)) + # @INPUT @USER + inner_accounts = [Account.get_input_account(), Account.get_user_account(self.user.username)] + all_accounts = accounts + inner_accounts # 构造默认包含的账号,如: @INPUT @USER - return accounts + return all_accounts class MyGrantedAssetAccounts(UserGrantedAssetAccounts): diff --git a/apps/perms/hands.py b/apps/perms/hands.py index 1537b7260..dabb9f7c0 100644 --- a/apps/perms/hands.py +++ b/apps/perms/hands.py @@ -2,12 +2,12 @@ # from users.models import User, UserGroup -from assets.models import Asset, Node, Label, FavoriteAsset +from assets.models import Asset, Node, Label, FavoriteAsset, Account from assets.serializers import NodeSerializer __all__ = [ 'User', 'UserGroup', 'Asset', 'Node', 'Label', 'FavoriteAsset', - 'NodeSerializer', + 'NodeSerializer', 'Account' ] diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py index 61f5a4fd2..fe9d1b1b7 100644 --- a/apps/perms/models/asset_permission.py +++ b/apps/perms/models/asset_permission.py @@ -83,6 +83,9 @@ class AssetPermissionManager(OrgManager): class AssetPermission(OrgModelMixin): + class SpecialAccount(models.TextChoices): + ALL = '@ALL', 'All' + id = models.UUIDField(default=uuid.uuid4, primary_key=True) name = models.CharField(max_length=128, verbose_name=_('Name')) users = models.ManyToManyField('users.User', blank=True, verbose_name=_("User"), @@ -113,11 +116,6 @@ class AssetPermission(OrgModelMixin): objects = AssetPermissionManager.from_queryset(AssetPermissionQuerySet)() - class SpecialAccount(models.TextChoices): - ALL = '@ALL', 'All' - INPUT = '@INPUT', 'Input' - USER = '@USER', 'User' - class Meta: unique_together = [('org_id', 'name')] verbose_name = _("Asset permission") @@ -232,17 +230,17 @@ class AssetPermission(OrgModelMixin): return account_names @classmethod - def filter_permissions(cls, user=None, asset=None, account=None): + def filter(cls, user=None, asset=None, account=None): """ 获取同时包含 用户-资产-账号 的授权规则 """ assetperm_ids = [] if user: - user_assetperm_ids = cls.filter_permissions_by_user(user, flat=True) + user_assetperm_ids = cls.filter_by_user(user, flat=True) assetperm_ids.append(user_assetperm_ids) if asset: - asset_assetperm_ids = cls.filter_permissions_by_asset(asset, flat=True) + asset_assetperm_ids = cls.filter_by_asset(asset, flat=True) assetperm_ids.append(asset_assetperm_ids) if account: - account_assetperm_ids = cls.filter_permissions_by_account(account, flat=True) + account_assetperm_ids = cls.filter_by_account(account, flat=True) assetperm_ids.append(account_assetperm_ids) # & 是同时满足,比如有用户,但是用户的规则是空,那么返回也应该是空 assetperm_ids = list(reduce(lambda x, y: set(x) & set(y), assetperm_ids)) @@ -250,7 +248,7 @@ class AssetPermission(OrgModelMixin): return assetperms @classmethod - def filter_permissions_by_user(cls, user, with_group=True, flat=False): + def filter_by_user(cls, user, with_group=True, flat=False): assetperm_ids = set() user_assetperm_ids = AssetPermission.users.through.objects \ .filter(user_id=user.id) \ @@ -273,7 +271,7 @@ class AssetPermission(OrgModelMixin): return assetperms @classmethod - def filter_permissions_by_asset(cls, asset, with_node=True, flat=False): + def filter_by_asset(cls, asset, with_node=True, flat=False): assetperm_ids = set() asset_assetperm_ids = AssetPermission.assets.through.objects \ .filter(asset_id=asset.id) \ @@ -294,8 +292,9 @@ class AssetPermission(OrgModelMixin): return assetperms @classmethod - def filter_permissions_by_account(cls, account, flat=False): - assetperms = cls.objects.filter(accounts__contains=account).valid() + def filter_by_account(cls, account, flat=False): + queries = Q(accounts__contains=account) | Q(accounts__contains=cls.SpecialAccount.ALL.value) + assetperms = cls.objects.filter(queries).valid() if flat: assetperm_ids = assetperms.values_list('id', flat=True) return assetperm_ids