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 enum import Enum
7from azure.cli.core.util import CLIError
8from ._utils import (
9    get_resource_group_name_by_registry_name,
10    parse_scope_map_actions
11)
12
13
14class RepoScopeMapActions(Enum):
15    CONTENT_DELETE = 'content/delete'
16    CONTENT_READ = 'content/read'
17    CONTENT_WRITE = 'content/write'
18    METADATA_READ = 'metadata/read'
19    METADATA_WRITE = 'metadata/write'
20
21
22class GatewayScopeMapActions(Enum):
23    CONFIG_READ = 'config/read'
24    CONFIG_WRITE = 'config/write'
25    MESSAGES_READ = 'message/read'
26    MESSAGES_WRITE = 'message/write'
27
28
29def acr_scope_map_create(cmd,
30                         client,
31                         registry_name,
32                         scope_map_name,
33                         repository_actions_list=None,
34                         gateway_actions_list=None,
35                         resource_group_name=None,
36                         description=None):
37
38    resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name)
39
40    actions = parse_scope_map_actions(repository_actions_list, gateway_actions_list)
41
42    ScopeMap = cmd.get_models('ScopeMap')
43
44    scope_map = ScopeMap(
45        actions=actions,
46        description=description
47    )
48
49    return client.begin_create(
50        resource_group_name,
51        registry_name,
52        scope_map_name,
53        scope_map
54    )
55
56
57def acr_scope_map_delete(cmd,
58                         client,
59                         registry_name,
60                         scope_map_name,
61                         yes=None,
62                         resource_group_name=None):
63
64    if not yes:
65        from knack.prompting import prompt_y_n
66        confirmation = prompt_y_n("Deleting the scope map '{}' will remove its permissions with associated tokens. "
67                                  "Proceed?".format(scope_map_name))
68
69        if not confirmation:
70            return None
71
72    resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name)
73    return client.begin_delete(resource_group_name, registry_name, scope_map_name)
74
75
76def acr_scope_map_update(cmd,
77                         client,
78                         registry_name,
79                         scope_map_name,
80                         add_repository=None,
81                         remove_repository=None,
82                         add_gateway=None,
83                         remove_gateway=None,
84                         resource_group_name=None,
85                         description=None):
86
87    if not (add_repository or remove_repository or add_gateway or remove_gateway or description):
88        raise CLIError('No scope map properties to update.')
89
90    resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name)
91
92    current_scope_map = acr_scope_map_show(cmd, client, registry_name, scope_map_name, resource_group_name)
93    current_actions = current_scope_map.actions
94
95    if add_repository or remove_repository or add_gateway or remove_gateway:
96        add_actions_set = set(parse_scope_map_actions(add_repository, add_gateway))
97        remove_actions_set = set(parse_scope_map_actions(remove_repository, remove_gateway))
98        # Duplicate actions can lead to inconsistency based on order of operations (set subtraction isn't associative).
99        # Eg: ({A, B} - {B}) U {B, C} = {A, B, C},  ({A, B} U {B, C}) - {B}  = {A, C}
100        duplicate_actions = set.intersection(add_actions_set, remove_actions_set)
101        if duplicate_actions:
102            # Display these actions to users: remove 'repositories/' prefix from 'repositories/<repo>/<action>'
103            errors = sorted(map(lambda action: action[action.find('/') + 1:], duplicate_actions))
104            raise CLIError(
105                'Update ambiguity. Duplicate actions were provided with --add and --remove arguments.\n{}'
106                .format(errors))
107
108        final_actions_set = set(current_scope_map.actions).union(add_actions_set).difference(remove_actions_set)
109        current_actions = list(final_actions_set)
110
111    ScopeMapUpdateParameters = cmd.get_models('ScopeMapUpdateParameters')
112    scope_map_update_parameters = ScopeMapUpdateParameters(
113        description=description,
114        actions=current_actions
115    )
116    return client.begin_update(resource_group_name,
117                               registry_name,
118                               scope_map_name,
119                               scope_map_update_parameters)
120
121
122def acr_scope_map_show(cmd,
123                       client,
124                       registry_name,
125                       scope_map_name,
126                       resource_group_name=None):
127
128    resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name)
129
130    return client.get(
131        resource_group_name,
132        registry_name,
133        scope_map_name
134    )
135
136
137def acr_scope_map_list(cmd,
138                       client,
139                       registry_name,
140                       resource_group_name=None):
141
142    resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name)
143
144    return client.list(
145        resource_group_name,
146        registry_name
147    )
148