Passed
Push — develop ( f534b1...a82689 )
by Plexxi
06:09 queued 03:13
created

ActionAliasController.delete()   B

Complexity

Conditions 2

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
import six
17
18
from mongoengine import ValidationError
19
from st2api.controllers import resource
20
from st2common import log as logging
21
from st2common.exceptions.actionalias import ActionAliasAmbiguityException
22
from st2common.exceptions.apivalidation import ValueValidationException
23
from st2common.models.api.action import ActionAliasAPI
24
from st2common.persistence.actionalias import ActionAlias
25
from st2common.rbac.types import PermissionType
26
from st2common.rbac import utils as rbac_utils
27
28
from st2common.router import abort
29
from st2common.router import Response
30
from st2common.util.actionalias_matching import match_command_to_alias
31
from st2common.util.actionalias_helpstring import generate_helpstring_result
32
33
34
http_client = six.moves.http_client
35
36
LOG = logging.getLogger(__name__)
37
38
39
class ActionAliasController(resource.ContentPackResourceController):
40
    """
41
        Implements the RESTful interface for ActionAliases.
42
    """
43
    model = ActionAliasAPI
44
    access = ActionAlias
45
    supported_filters = {
46
        'name': 'name',
47
        'pack': 'pack'
48
    }
49
50
    query_options = {
51
        'sort': ['pack', 'name']
52
    }
53
54
    _custom_actions = {
55
        'match': ['POST'],
56
        'help': ['POST']
57
    }
58
59
    def _match_tuple_to_dict(self, match):
60
        return {
61
            'actionalias': match[0],
62
            'display': match[1],
63
            'representation': match[2]
64
        }
65
66
    def get_all(self, **kwargs):
67
        return super(ActionAliasController, self)._get_all(**kwargs)
68
69
    def get_one(self, ref_or_id, requester_user):
0 ignored issues
show
Bug Best Practice introduced by
Signature differs from overridden 'get_one' method

It is generally a good practice to use signatures that are compatible with the Liskov substitution principle.

This allows to pass instances of the child class anywhere where the instances of the super-class/interface would be acceptable.

Loading history...
70
        permission_type = PermissionType.ACTION_ALIAS_VIEW
71
        return super(ActionAliasController, self)._get_one(ref_or_id,
72
                                                           requester_user=requester_user,
73
                                                           permission_type=permission_type)
74
75
    def match(self, action_alias_match_api, **kwargs):
76
        """
77
            Run a chatops command
78
79
            Handles requests:
80
                POST /actionalias/match
81
        """
82
        command = action_alias_match_api.command
83
        try:
84
            # 1. Get aliases
85
            aliases_resp = super(ActionAliasController, self)._get_all(**kwargs)
86
            aliases = [ActionAliasAPI(**alias) for alias in aliases_resp.json]
87
            # 2. Match alias(es) to command
88
            matches = match_command_to_alias(command, aliases)
89
            if len(matches) > 1:
90
                raise ActionAliasAmbiguityException("Command '%s' matched more than 1 pattern" %
91
                                                    command,
92
                                                    matches=matches,
93
                                                    command=command)
94
            elif len(matches) == 0:
95
                raise ActionAliasAmbiguityException("Command '%s' matched no patterns" %
96
                                                    command,
97
                                                    matches=[],
98
                                                    command=command)
99
            return [self._match_tuple_to_dict(match) for match in matches]
100
        except ActionAliasAmbiguityException as e:
101
            LOG.exception('Command "%s" matched (%s) patterns.', e.command, len(e.matches))
102
            return abort(http_client.BAD_REQUEST, str(e))
103
104
    def help(self, filter, pack, limit, offset, **kwargs):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in filter.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
105
        """
106
            Get available help strings for action aliases.
107
108
            Handles requests:
109
                GET /actionalias/help
110
        """
111
        try:
112
            aliases_resp = super(ActionAliasController, self)._get_all(**kwargs)
113
            aliases = [ActionAliasAPI(**alias) for alias in aliases_resp.json]
114
            return generate_helpstring_result(aliases, filter, pack, int(limit), int(offset))
115
        except (TypeError) as e:
116
            LOG.exception('Helpstring request contains an invalid data type: %s.', str(e))
117
            return abort(http_client.BAD_REQUEST, str(e))
118
119
    def post(self, action_alias, requester_user):
120
        """
121
            Create a new ActionAlias.
122
123
            Handles requests:
124
                POST /actionalias/
125
        """
126
127
        permission_type = PermissionType.ACTION_ALIAS_CREATE
128
        rbac_utils.assert_user_has_resource_api_permission(user_db=requester_user,
129
                                                           resource_api=action_alias,
130
                                                           permission_type=permission_type)
131
132
        try:
133
            action_alias_db = ActionAliasAPI.to_model(action_alias)
134
            LOG.debug('/actionalias/ POST verified ActionAliasAPI and formulated ActionAliasDB=%s',
135
                      action_alias_db)
136
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
137
        except (ValidationError, ValueError, ValueValidationException) as e:
138
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
139
            abort(http_client.BAD_REQUEST, str(e))
140
            return
141
142
        extra = {'action_alias_db': action_alias_db}
143
        LOG.audit('Action alias created. ActionAlias.id=%s' % (action_alias_db.id), extra=extra)
144
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
145
146
        return Response(json=action_alias_api, status=http_client.CREATED)
147
148
    def put(self, action_alias, ref_or_id, requester_user):
149
        """
150
            Update an action alias.
151
152
            Handles requests:
153
                PUT /actionalias/1
154
        """
155
        action_alias_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)
156
        LOG.debug('PUT /actionalias/ lookup with id=%s found object: %s', ref_or_id,
157
                  action_alias_db)
158
159
        permission_type = PermissionType.ACTION_ALIAS_MODIFY
160
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
161
                                                          resource_db=action_alias_db,
162
                                                          permission_type=permission_type)
163
164
        if not hasattr(action_alias, 'id'):
165
            action_alias.id = None
166
167
        try:
168
            if action_alias.id is not None and action_alias.id is not '' and \
169
               action_alias.id != ref_or_id:
170
                LOG.warning('Discarding mismatched id=%s found in payload and using uri_id=%s.',
171
                            action_alias.id, ref_or_id)
172
            old_action_alias_db = action_alias_db
173
            action_alias_db = ActionAliasAPI.to_model(action_alias)
174
            action_alias_db.id = ref_or_id
175
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
176
        except (ValidationError, ValueError) as e:
177
            LOG.exception('Validation failed for action alias data=%s', action_alias)
178
            abort(http_client.BAD_REQUEST, str(e))
179
            return
180
181
        extra = {'old_action_alias_db': old_action_alias_db, 'new_action_alias_db': action_alias_db}
182
        LOG.audit('Action alias updated. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
183
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
184
185
        return action_alias_api
186
187
    def delete(self, ref_or_id, requester_user):
188
        """
189
            Delete an action alias.
190
191
            Handles requests:
192
                DELETE /actionalias/1
193
        """
194
        action_alias_db = self._get_by_ref_or_id(ref_or_id=ref_or_id)
195
        LOG.debug('DELETE /actionalias/ lookup with id=%s found object: %s', ref_or_id,
196
                  action_alias_db)
197
198
        permission_type = PermissionType.ACTION_ALIAS_DELETE
199
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
200
                                                          resource_db=action_alias_db,
201
                                                          permission_type=permission_type)
202
203
        try:
204
            ActionAlias.delete(action_alias_db)
205
        except Exception as e:
206
            LOG.exception('Database delete encountered exception during delete of id="%s".',
207
                          ref_or_id)
208
            abort(http_client.INTERNAL_SERVER_ERROR, str(e))
209
            return
210
211
        extra = {'action_alias_db': action_alias_db}
212
        LOG.audit('Action alias deleted. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
213
214
        return Response(status=http_client.NO_CONTENT)
215
216
217
action_alias_controller = ActionAliasController()
218