pref: 修改授权 api,去掉不用的

pull/9075/head
ibuler 2022-11-15 10:43:21 +08:00
parent 8e1312e8ce
commit 63b32ae903
8 changed files with 87 additions and 187 deletions

View File

@ -3,42 +3,18 @@ from rest_framework.generics import ListAPIView, get_object_or_404
from common.permissions import IsValidUser
from common.utils import get_logger, lazyproperty
from assets.serializers import AccountSerializer
from perms.hands import User, Asset, Account
from perms import serializers
from perms.hands import User, Asset
from perms.utils import PermAccountUtil
from .mixin import RoleAdminMixin, RoleUserMixin
logger = get_logger(__name__)
__all__ = [
'UserAllGrantedAccountsApi',
'MyAllGrantedAccountsApi',
'UserGrantedAssetAccountsApi',
'MyGrantedAssetAccountsApi',
'UserGrantedAssetSpecialAccountsApi',
'MyGrantedAssetSpecialAccountsApi',
]
class UserAllGrantedAccountsApi(RoleAdminMixin, ListAPIView):
""" 授权给用户的所有账号列表 """
serializer_class = AccountSerializer
filterset_fields = ("name", "username", "privileged", "version")
search_fields = filterset_fields
def get_queryset(self):
util = PermAccountUtil()
accounts = util.get_perm_accounts_for_user(self.user)
return accounts
class MyAllGrantedAccountsApi(RoleUserMixin, UserAllGrantedAccountsApi):
""" 授权给我的所有账号列表 """
pass
class UserGrantedAssetAccountsApi(ListAPIView):
serializer_class = serializers.AccountsGrantedSerializer
@ -55,9 +31,8 @@ class UserGrantedAssetAccountsApi(ListAPIView):
return asset
def get_queryset(self):
accounts = PermAccountUtil().get_perm_accounts_for_user_asset(
self.user, self.asset, with_actions=True
)
util = PermAccountUtil()
accounts = util.get_permed_accounts_for_user(self.user, self.asset)
return accounts
@ -67,29 +42,3 @@ class MyGrantedAssetAccountsApi(UserGrantedAssetAccountsApi):
@lazyproperty
def user(self):
return self.request.user
class UserGrantedAssetSpecialAccountsApi(ListAPIView):
serializer_class = serializers.AccountsGrantedSerializer
@lazyproperty
def user(self):
return self.request.user
def get_queryset(self):
# 构造默认包含的账号,如: @INPUT @USER
accounts = [
Account.get_manual_account(),
Account.get_user_account(self.user.username)
]
for account in accounts:
account.actions = Action.ALL
return accounts
class MyGrantedAssetSpecialAccountsApi(UserGrantedAssetSpecialAccountsApi):
permission_classes = (IsValidUser,)
@lazyproperty
def user(self):
return self.request.user

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
#
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
from assets.models import Node, Asset, Platform, Account
from assets.const import Category, AllTypes
from assets.models import Node, Asset, Platform, Account
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
from perms.serializers.permission import ActionChoicesField
__all__ = [
@ -49,13 +49,9 @@ class ActionsSerializer(serializers.Serializer):
class AccountsGrantedSerializer(serializers.ModelSerializer):
""" 授权的账号序列类 """
# Todo: 添加前端登录逻辑中需要的一些字段,比如:是否需要手动输入密码
# need_manual = serializers.BooleanField(label=_('Need manual input'))
actions = ActionChoicesField(read_only=True)
class Meta:
model = Account
fields = ['id', 'name', 'username', 'actions']
fields = ['id', 'name', 'username', 'secret_type', 'has_secret', 'actions']
read_only_fields = fields

View File

@ -7,10 +7,14 @@ from .. import api
router = BulkRouter()
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
router.register('asset-permissions-users-relations', api.AssetPermissionUserRelationViewSet, 'asset-permissions-users-relation')
router.register('asset-permissions-user-groups-relations', api.AssetPermissionUserGroupRelationViewSet, 'asset-permissions-user-groups-relation')
router.register('asset-permissions-assets-relations', api.AssetPermissionAssetRelationViewSet, 'asset-permissions-assets-relation')
router.register('asset-permissions-nodes-relations', api.AssetPermissionNodeRelationViewSet, 'asset-permissions-nodes-relation')
router.register('asset-permissions-users-relations', api.AssetPermissionUserRelationViewSet,
'asset-permissions-users-relation')
router.register('asset-permissions-user-groups-relations', api.AssetPermissionUserGroupRelationViewSet,
'asset-permissions-user-groups-relation')
router.register('asset-permissions-assets-relations', api.AssetPermissionAssetRelationViewSet,
'asset-permissions-assets-relation')
router.register('asset-permissions-nodes-relations', api.AssetPermissionNodeRelationViewSet,
'asset-permissions-nodes-relation')
user_permission_urlpatterns = [
# 以 serializer 格式返回
@ -34,18 +38,22 @@ user_permission_urlpatterns = [
path('<uuid:pk>/nodes/children/', api.UserGrantedNodeChildrenForAdminApi.as_view(), name='user-nodes-children'),
path('nodes/children/', api.MyGrantedNodeChildrenApi.as_view(), name='my-nodes-children'),
# 以 Tree Node 的数据格式返回
path('<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeForAdminApi.as_view(), name='user-nodes-children-as-tree'),
path('<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeForAdminApi.as_view(),
name='user-nodes-children-as-tree'),
# 部分调用位置
# - 普通用户 -> 我的资产 -> 展开节点 时调用
path('nodes/children/tree/', api.MyGrantedNodeChildrenAsTreeApi.as_view(), name='my-nodes-children-as-tree'),
# 此接口会返回整棵树
# 普通用户 -> 命令执行 -> 左侧树
path('nodes-with-assets/tree/', api.MyGrantedNodesWithAssetsAsTreeApi.as_view(), name='my-nodes-with-assets-as-tree'),
path('nodes-with-assets/tree/', api.MyGrantedNodesWithAssetsAsTreeApi.as_view(),
name='my-nodes-with-assets-as-tree'),
# 主要用于 luna 页面,带资产的节点树
path('<uuid:pk>/nodes/children-with-assets/tree/', api.UserGrantedNodeChildrenWithAssetsAsTreeApi.as_view(), name='user-nodes-children-with-assets-as-tree'),
path('nodes/children-with-assets/tree/', api.MyGrantedNodeChildrenWithAssetsAsTreeApi.as_view(), name='my-nodes-children-with-assets-as-tree'),
path('<uuid:pk>/nodes/children-with-assets/tree/', api.UserGrantedNodeChildrenWithAssetsAsTreeApi.as_view(),
name='user-nodes-children-with-assets-as-tree'),
path('nodes/children-with-assets/tree/', api.MyGrantedNodeChildrenWithAssetsAsTreeApi.as_view(),
name='my-nodes-children-with-assets-as-tree'),
# 查询授权树上某个节点的所有资产
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'),
@ -59,16 +67,10 @@ user_permission_urlpatterns = [
path('<uuid:pk>/nodes/favorite/assets/', api.UserFavoriteGrantedAssetsApi.as_view(), name='user-ungrouped-assets'),
path('nodes/favorite/assets/', api.MyFavoriteGrantedAssetsApi.as_view(), name='my-ungrouped-assets'),
# 获取授权给用户的所有账号
path('<uuid:pk>/accounts/', api.UserAllGrantedAccountsApi.as_view(), name='user-accounts'),
path('accounts/', api.MyAllGrantedAccountsApi.as_view(), name='my-accounts'),
# 获取授权给用户某个资产的所有账号
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccountsApi.as_view(), name='user-asset-accounts'),
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccountsApi.as_view(),
name='user-asset-accounts'),
path('assets/<uuid:asset_id>/accounts/', api.MyGrantedAssetAccountsApi.as_view(), name='my-asset-accounts'),
# 用户登录资产的特殊账号, @INPUT, @USER 等
path('<uuid:pk>/assets/special-accounts/', api.UserGrantedAssetSpecialAccountsApi.as_view(), name='user-special-accounts'),
path('assets/special-accounts/', api.MyGrantedAssetSpecialAccountsApi.as_view(), name='my-special-accounts'),
]
user_group_permission_urlpatterns = [
@ -76,11 +78,14 @@ user_group_permission_urlpatterns = [
path('<uuid:pk>/assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'),
path('<uuid:pk>/nodes/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
path('<uuid:pk>/nodes/children/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes-children'),
path('<uuid:pk>/nodes/children/tree/', api.UserGroupGrantedNodeChildrenAsTreeApi.as_view(), name='user-group-nodes-children-as-tree'),
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(), name='user-group-node-assets'),
path('<uuid:pk>/nodes/children/tree/', api.UserGroupGrantedNodeChildrenAsTreeApi.as_view(),
name='user-group-nodes-children-as-tree'),
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(),
name='user-group-node-assets'),
# 获取所有和资产-用户组关联的账号列表
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGroupGrantedAssetAccountsApi.as_view(), name='user-group-asset-accounts'),
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGroupGrantedAssetAccountsApi.as_view(),
name='user-group-asset-accounts'),
]
permission_urlpatterns = [

View File

@ -2,22 +2,20 @@
#
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import MethodNotAllowed
from rest_framework.response import Response
from common.const.http import POST, PUT, PATCH
from common.mixins.api import CommonApiMixin
from orgs.utils import tmp_to_root_org
from rbac.permissions import RBACPermission
from tickets import serializers
from tickets import filters
from tickets.permissions.ticket import IsAssignee, IsApplicant
from tickets import serializers
from tickets.models import (
Ticket, ApplyAssetTicket, ApplyLoginTicket,
ApplyLoginAssetTicket, ApplyCommandTicket
)
from tickets.permissions.ticket import IsAssignee, IsApplicant
__all__ = [
'TicketViewSet', 'ApplyAssetTicketViewSet',
@ -27,10 +25,8 @@ __all__ = [
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
serializer_class = serializers.TicketDisplaySerializer
serializer_class = serializers.TicketSerializer
serializer_classes = {
'list': serializers.TicketListSerializer,
'open': serializers.TicketApplySerializer,
'approve': serializers.TicketApproveSerializer
}
model = Ticket
@ -40,8 +36,8 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
'title', 'type', 'status'
]
ordering_fields = (
'title', 'status', 'state',
'action_display', 'date_created', 'serial_num',
'title', 'status', 'state', 'action_display',
'date_created', 'serial_num',
)
ordering = ('-date_created',)
rbac_perms = {
@ -98,11 +94,7 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
class ApplyAssetTicketViewSet(TicketViewSet):
serializer_class = serializers.ApplyAssetDisplaySerializer
serializer_classes = {
'open': serializers.ApplyAssetSerializer,
'approve': serializers.ApproveAssetSerializer
}
serializer_class = serializers.ApplyAssetSerializer
model = ApplyAssetTicket
filterset_class = filters.ApplyAssetTicketFilter

View File

@ -1,6 +1,7 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from perms.const import ActionChoices
from .general import Ticket
__all__ = ['ApplyAssetTicket']
@ -14,13 +15,6 @@ class ApplyAssetTicket(Ticket):
# 申请信息
apply_assets = models.ManyToManyField('assets.Asset', verbose_name=_('Apply assets'))
apply_accounts = models.JSONField(default=list, verbose_name=_('Apply accounts'))
apply_actions = models.IntegerField(default=1, verbose_name=_('Actions'))
apply_actions = models.IntegerField(verbose_name=_('Actions'), default=ActionChoices.all())
apply_date_start = models.DateTimeField(verbose_name=_('Date start'), null=True)
apply_date_expired = models.DateTimeField(verbose_name=_('Date expired'), null=True)
@property
def apply_actions_display(self):
return 'Todo'
def get_apply_actions_display(self):
return ', '.join(self.apply_actions_display)

View File

@ -1,40 +1,40 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from perms.serializers.permission import ActionChoicesField
from perms.models import AssetPermission
from orgs.utils import tmp_to_org
from assets.models import Asset, Node
from common.drf.fields import ObjectRelatedField
from perms.models import AssetPermission
from perms.serializers.permission import ActionChoicesField
from tickets.models import ApplyAssetTicket
from .common import BaseApplyAssetSerializer
from .ticket import TicketApplySerializer
from .common import BaseApplyAssetApplicationSerializer
__all__ = ['ApplyAssetSerializer', 'ApplyAssetDisplaySerializer', 'ApproveAssetSerializer']
__all__ = ['ApplyAssetSerializer']
asset_or_node_help_text = _("Select at least one asset or node")
class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySerializer):
apply_actions = ActionChoicesField(required=True, allow_empty=False)
class ApplyAssetSerializer(BaseApplyAssetSerializer, TicketApplySerializer):
apply_assets = ObjectRelatedField(queryset=Asset.objects, many=True, required=False, label=_('Apply assets'))
apply_nodes = ObjectRelatedField(queryset=Node.objects, many=True, required=False, label=_('Apply nodes'))
apply_actions = ActionChoicesField(required=False, allow_null=True, label=_("Apply actions"))
permission_model = AssetPermission
class Meta:
class Meta(TicketApplySerializer.Meta):
model = ApplyAssetTicket
fields_mini = ['id', 'title']
writeable_fields = [
'id', 'title', 'type', 'apply_nodes', 'apply_assets',
'id', 'title', 'apply_nodes', 'apply_assets',
'apply_accounts', 'apply_actions', 'org_id', 'comment',
'apply_date_start', 'apply_date_expired'
]
fields = TicketApplySerializer.Meta.fields + writeable_fields + [
'apply_permission_name', 'apply_actions_display'
]
fields = TicketApplySerializer.Meta.fields + writeable_fields + ['apply_permission_name', ]
read_only_fields = list(set(fields) - set(writeable_fields))
ticket_extra_kwargs = TicketApplySerializer.Meta.extra_kwargs
extra_kwargs = {
'apply_nodes': {'required': False, 'allow_empty': True},
'apply_assets': {'required': False, 'allow_empty': True},
'apply_accounts': {'required': False, 'allow_empty': True},
'apply_nodes': {'required': False},
'apply_assets': {'required': False},
'apply_accounts': {'required': False},
}
extra_kwargs.update(ticket_extra_kwargs)
@ -45,9 +45,11 @@ class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySeria
return self.filter_many_to_many_field(Asset, assets)
def validate(self, attrs):
attrs['type'] = 'apply_asset'
attrs = super().validate(attrs)
if self.is_final_approval and (
not attrs.get('apply_nodes') and not attrs.get('apply_assets')
not attrs.get('apply_nodes')
and not attrs.get('apply_assets')
):
raise serializers.ValidationError({
'apply_nodes': asset_or_node_help_text,
@ -56,29 +58,7 @@ class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySeria
return attrs
class ApproveAssetSerializer(ApplyAssetSerializer):
class Meta(ApplyAssetSerializer.Meta):
read_only_fields = ApplyAssetSerializer.Meta.read_only_fields + [
'title', 'type'
]
class ApplyAssetDisplaySerializer(ApplyAssetSerializer):
apply_nodes = serializers.SerializerMethodField()
apply_assets = serializers.SerializerMethodField()
class Meta:
model = ApplyAssetSerializer.Meta.model
fields = ApplyAssetSerializer.Meta.fields
read_only_fields = fields
@staticmethod
def get_apply_nodes(instance):
with tmp_to_org(instance.org_id):
return instance.apply_nodes.values_list('id', flat=True)
@staticmethod
def get_apply_assets(instance):
with tmp_to_org(instance.org_id):
return instance.apply_assets.values_list('id', flat=True)
@classmethod
def setup_eager_loading(cls, queryset):
queryset = queryset.prefetch_related('apply_nodes', 'apply_assets')
return queryset

View File

@ -1,12 +1,12 @@
from django.db.transaction import atomic
from django.db.models import Model
from django.db.transaction import atomic
from django.utils.translation import ugettext as _
from rest_framework import serializers
from orgs.utils import tmp_to_org
from tickets.models import Ticket
__all__ = ['DefaultPermissionName', 'get_default_permission_name', 'BaseApplyAssetApplicationSerializer']
__all__ = ['DefaultPermissionName', 'get_default_permission_name', 'BaseApplyAssetSerializer']
def get_default_permission_name(ticket):
@ -34,7 +34,7 @@ class DefaultPermissionName(object):
return self.default
class BaseApplyAssetApplicationSerializer(serializers.Serializer):
class BaseApplyAssetSerializer(serializers.Serializer):
permission_model: Model
@property

View File

@ -3,31 +3,35 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from orgs.models import Organization
from common.drf.fields import LabeledChoiceField
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from orgs.models import Organization
from tickets.const import TicketType, TicketStatus, TicketState
from tickets.models import Ticket, TicketFlow
from tickets.const import TicketType
__all__ = [
'TicketDisplaySerializer', 'TicketApplySerializer', 'TicketListSerializer', 'TicketApproveSerializer'
'TicketApplySerializer', 'TicketApproveSerializer', 'TicketSerializer',
]
class TicketSerializer(OrgResourceModelSerializerMixin):
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
status_display = serializers.ReadOnlyField(source='get_status_display', label=_('Status display'))
type = LabeledChoiceField(choices=TicketType.choices, read_only=True, label=_('Type'))
status = LabeledChoiceField(choices=TicketStatus.choices, read_only=True, label=_('Status'))
state = LabeledChoiceField(choices=TicketState.choices, read_only=True, label=_("State"))
class Meta:
model = Ticket
fields_mini = ['id', 'title']
fields_small = fields_mini + [
'type', 'type_display', 'status', 'status_display',
'state', 'approval_step', 'rel_snapshot', 'comment',
'type', 'status', 'state', 'approval_step', 'comment',
'date_created', 'date_updated', 'org_id', 'rel_snapshot',
'process_map', 'org_name', 'serial_num'
]
fields_fk = ['applicant', ]
fields = fields_small + fields_fk
extra_kwargs = {
'type': {'required': True}
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -41,43 +45,20 @@ class TicketSerializer(OrgResourceModelSerializerMixin):
choices.pop(TicketType.general, None)
tp._choices = choices
class TicketListSerializer(TicketSerializer):
class Meta:
model = Ticket
fields = [
'id', 'title', 'serial_num', 'type', 'type_display', 'status',
'state', 'rel_snapshot', 'date_created', 'rel_snapshot'
]
read_only_fields = fields
class TicketDisplaySerializer(TicketSerializer):
class Meta:
model = Ticket
fields = TicketSerializer.Meta.fields
read_only_fields = fields
@classmethod
def setup_eager_loading(cls, queryset):
queryset = queryset.prefetch_related('ticket_steps')
return queryset
class TicketApproveSerializer(TicketSerializer):
class Meta:
model = Ticket
class Meta(TicketSerializer.Meta):
fields = TicketSerializer.Meta.fields
read_only_fields = fields
class TicketApplySerializer(TicketSerializer):
org_id = serializers.CharField(
required=True, max_length=36,
allow_blank=True, label=_("Organization")
)
class Meta:
model = Ticket
fields = TicketSerializer.Meta.fields
extra_kwargs = {
'type': {'required': True}
}
org_id = serializers.CharField(required=True, max_length=36, allow_blank=True, label=_("Organization"))
@staticmethod
def validate_org_id(org_id):
@ -91,10 +72,13 @@ class TicketApplySerializer(TicketSerializer):
if self.instance:
return attrs
print("Attrs: ", attrs)
ticket_type = attrs.get('type')
org_id = attrs.get('org_id')
flow = TicketFlow.get_org_related_flows(org_id=org_id)\
flow = TicketFlow.get_org_related_flows(org_id=org_id) \
.filter(type=ticket_type).first()
if flow:
attrs['flow'] = flow
else: