1# --------------------------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for license information.
4# --------------------------------------------------------------------------------------------
5
6from azure.cli.core.profiles import ResourceType, get_sdk, supported_api_version
7
8
9class MultiAPIAdaptor:
10    # We will bridge all the code difference here caused by SDK breaking changes
11    def __init__(self, cli_ctx):
12        self.old_api = supported_api_version(cli_ctx, resource_type=ResourceType.MGMT_AUTHORIZATION,
13                                             max_api='2015-07-01')
14        self.cli_ctx = cli_ctx
15
16    def _init_individual_permission(self, cfg):
17        Permission = get_sdk(self.cli_ctx, ResourceType.MGMT_AUTHORIZATION, 'Permission', mod='models',
18                             operation_group='role_definitions')
19        permission = Permission(actions=cfg.get('actions', None),
20                                not_actions=cfg.get('notActions', None))
21        if not self.old_api:
22            permission.data_actions = cfg.get('dataActions', None)
23            permission.not_data_actions = cfg.get('notDataActions', None)
24        return permission
25
26    def _init_permissions(self, role_definition_input):
27        # we will handle with or w/o 'permissions'
28        if 'permissions' in role_definition_input:
29            return [self._init_individual_permission(p) for p in role_definition_input['permissions']]
30        return [self._init_individual_permission(role_definition_input)]
31
32    def create_role_definition(self, client, role_name, role_id, role_definition_input):
33        RoleDefinitionBase = get_sdk(self.cli_ctx, ResourceType.MGMT_AUTHORIZATION, 'RoleDefinition',
34                                     mod='models', operation_group='role_definitions')
35        role_configuration = RoleDefinitionBase(role_name=role_name,
36                                                description=role_definition_input.get('description', None),
37                                                type='CustomRole',
38                                                assignable_scopes=role_definition_input['assignableScopes'],
39                                                permissions=self._init_permissions(role_definition_input))
40        scope = role_definition_input['assignableScopes'][0]
41        return client.create_or_update(role_definition_id=role_id, scope=scope, role_definition=role_configuration)
42
43    def create_role_assignment(self, client, assignment_name, role_id, object_id, scope, assignee_principal_type=None,
44                               description=None, condition=None, condition_version=None):
45        RoleAssignmentCreateParameters = get_sdk(
46            self.cli_ctx, ResourceType.MGMT_AUTHORIZATION,
47            'RoleAssignmentProperties' if self.old_api else 'RoleAssignmentCreateParameters',
48            mod='models', operation_group='role_assignments')
49        parameters = RoleAssignmentCreateParameters(role_definition_id=role_id, principal_id=object_id)
50        if assignee_principal_type:
51            parameters.principal_type = assignee_principal_type
52        if description:
53            parameters.description = description
54        if condition:
55            parameters.condition = condition
56        if condition_version:
57            parameters.condition_version = condition_version
58        return client.create(scope, assignment_name, parameters)
59
60    def get_role_property(self, obj, property_name):  # pylint: disable=no-self-use
61        """Get property for RoleDefinition and RoleAssignment object."""
62        # 2015-07-01          RoleDefinition: flattened, RoleAssignment: unflattened
63        # 2018-01-01-preview  RoleDefinition: flattened
64        # 2020-04-01-preview                             RoleAssignment: flattened
65        # Get property_name from properties if the model is unflattened.
66        if isinstance(obj, dict):
67            if 'properties' in obj:
68                obj = obj['properties']
69            return obj[property_name]
70
71        if hasattr(obj, 'properties'):
72            obj = obj.properties
73        return getattr(obj, property_name)
74
75    def set_role_property(self, obj, property_name, property_value):  # pylint: disable=no-self-use
76        """Set property for RoleDefinition and RoleAssignment object.
77        Luckily this function is only called for an RoleAssignment `obj` returned by the service, and `properties`
78         has been processed, either by being flattened or set. We can definitively know whether `obj` is flattened
79         or not.
80        There is NO use case where `obj` is provided by the user and `properties` has not been processed.
81         In such case, we won't be able to decide if `obj` is flattened or not."""
82        if isinstance(obj, dict):
83            if 'properties' in obj:
84                obj = obj['properties']
85            obj[property_name] = property_value
86        else:
87            if hasattr(obj, 'properties'):
88                obj = obj.properties
89            obj.property_name = property_value
90