11# (C) 2025 GoodData Corporation
2- from abc import abstractmethod
2+
33from enum import Enum
4- from typing import Any , Iterator , TypeAlias , TypeVar
4+ from typing import Iterator , TypeAlias
55
66import attrs
77from gooddata_sdk .catalog .identifier import CatalogAssigneeIdentifier
1414from gooddata_pipelines .provisioning .utils .exceptions import BaseUserException
1515
1616TargetsPermissionDict : TypeAlias = dict [str , dict [str , bool ]]
17- ConstructorType = TypeVar ("ConstructorType" , bound = "ConstructorMixin" )
1817
1918
20- class PermissionType (str , Enum ):
19+ class EntityType (str , Enum ):
2120 # NOTE: Start using StrEnum with Python 3.11
2221 user = "user"
2322 user_group = "userGroup"
2423
2524
26- class ConstructorMixin :
27- @staticmethod
28- def _get_id_and_type (
29- permission : dict [str , Any ],
30- ) -> tuple [str , PermissionType ]:
31- user_id : str | None = permission .get ("user_id" )
32- user_group_id : str | None = permission .get ("ug_id" )
33- if user_id and user_group_id :
34- raise ValueError ("Only one of user_id or ug_id must be present" )
35- elif user_id :
36- return user_id , PermissionType .user
37- elif user_group_id :
38- return user_group_id , PermissionType .user_group
39- else :
40- raise ValueError ("Either user_id or ug_id must be present" )
41-
42- @classmethod
43- def from_list_of_dicts (
44- cls : type [ConstructorType ], data : list [dict [str , Any ]]
45- ) -> list [ConstructorType ]:
46- """Creates a list of instances from list of dicts."""
47- # NOTE: We can use typing.Self for the return type in Python 3.11
48- permissions = []
49- for permission in data :
50- permissions .append (cls .from_dict (permission ))
51- return permissions
52-
53- @classmethod
54- @abstractmethod
55- def from_dict (cls , data : dict [str , Any ]) -> Any :
56- """Construction form a dictionary to be implemented by subclasses."""
57- pass
58-
59-
60- class PermissionIncrementalLoad (BaseModel , ConstructorMixin ):
25+ class BasePermission (BaseModel ):
6126 permission : str
6227 workspace_id : str
63- id_ : str
64- type_ : PermissionType
65- is_active : bool
28+ entity_id : str
29+ entity_type : EntityType
6630
67- @classmethod
68- def from_dict (cls , data : dict [str , Any ]) -> "PermissionIncrementalLoad" :
69- """Returns an instance of PermissionIncrementalLoad from a dictionary."""
70- id_ , target_type = cls ._get_id_and_type (data )
71- return cls (
72- permission = data ["ws_permissions" ],
73- workspace_id = data ["ws_id" ],
74- id_ = id_ ,
75- type_ = target_type ,
76- is_active = data ["is_active" ],
77- )
7831
32+ class PermissionFullLoad (BasePermission ):
33+ """Input validator for full load of workspace permissions provisioning."""
7934
80- class PermissionFullLoad (BaseModel , ConstructorMixin ):
81- permission : str
82- workspace_id : str
83- id_ : str
84- type_ : PermissionType
8535
86- @classmethod
87- def from_dict (cls , data : dict [str , Any ]) -> "PermissionFullLoad" :
88- """Returns an instance of PermissionFullLoad from a dictionary."""
89- id_ , target_type = cls ._get_id_and_type (data )
90- return cls (
91- permission = data ["ws_permissions" ],
92- workspace_id = data ["ws_id" ],
93- id_ = id_ ,
94- type_ = target_type ,
95- )
36+ class PermissionIncrementalLoad (BasePermission ):
37+ """Input validator for incremental load of workspace permissions provisioning."""
38+
39+ is_active : bool
9640
9741
9842@attrs .define
@@ -117,7 +61,7 @@ def from_sdk_api(
11761 permission .assignee .id ,
11862 )
11963
120- if permission_type == PermissionType .user .value :
64+ if permission_type == EntityType .user .value :
12165 target_dict = users
12266 else :
12367 target_dict = user_groups
@@ -170,7 +114,7 @@ def to_sdk_api(self) -> CatalogDeclarativeWorkspacePermissions:
170114
171115 for user_id , permissions in self .users .items ():
172116 assignee = CatalogAssigneeIdentifier (
173- id = user_id , type = PermissionType .user .value
117+ id = user_id , type = EntityType .user .value
174118 )
175119 for declaration in self ._permissions_for_target (
176120 permissions , assignee
@@ -179,7 +123,7 @@ def to_sdk_api(self) -> CatalogDeclarativeWorkspacePermissions:
179123
180124 for ug_id , permissions in self .user_groups .items ():
181125 assignee = CatalogAssigneeIdentifier (
182- id = ug_id , type = PermissionType .user_group .value
126+ id = ug_id , type = EntityType .user_group .value
183127 )
184128 for declaration in self ._permissions_for_target (
185129 permissions , assignee
@@ -200,15 +144,15 @@ def add_incremental_permission(
200144 """
201145 target_dict = (
202146 self .users
203- if permission .type_ == PermissionType .user
147+ if permission .entity_type == EntityType .user
204148 else self .user_groups
205149 )
206150
207- if permission .id_ not in target_dict :
208- target_dict [permission .id_ ] = {}
151+ if permission .entity_id not in target_dict :
152+ target_dict [permission .entity_id ] = {}
209153
210154 is_active = permission .is_active
211- target_permissions = target_dict [permission .id_ ]
155+ target_permissions = target_dict [permission .entity_id ]
212156 permission_value = permission .permission
213157
214158 if permission_value not in target_permissions :
@@ -233,14 +177,14 @@ def add_full_load_permission(self, permission: PermissionFullLoad) -> None:
233177 """
234178 target_dict = (
235179 self .users
236- if permission .type_ == PermissionType .user
180+ if permission .entity_type == EntityType .user
237181 else self .user_groups
238182 )
239183
240- if permission .id_ not in target_dict :
241- target_dict [permission .id_ ] = {}
184+ if permission .entity_id not in target_dict :
185+ target_dict [permission .entity_id ] = {}
242186
243- target_permissions = target_dict [permission .id_ ]
187+ target_permissions = target_dict [permission .entity_id ]
244188 permission_value = permission .permission
245189
246190 if permission_value not in target_permissions :
0 commit comments