Passed
Push — master ( 34f323...e86776 )
by Plexxi
02:43
created

ActionAliasController.help()   A

Complexity

Conditions 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 21
rs 9.3142
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 pecan
17
import six
18
19
from mongoengine import ValidationError
20
from st2api.controllers import resource
21
from st2common import log as logging
22
from st2common.exceptions.actionalias import ActionAliasAmbiguityException
23
from st2common.exceptions.apivalidation import ValueValidationException
24
from st2common.models.api.action import ActionAliasAPI
25
from st2common.models.api.action import ActionAliasMatchAPI
26
from st2common.models.api.action import ActionAliasHelpAPI
27
from st2common.persistence.actionalias import ActionAlias
28
from st2common.models.api.base import jsexpose
29
from st2common.rbac.types import PermissionType
30
from st2common.rbac.decorators import request_user_has_permission
31
from st2common.rbac.decorators import request_user_has_resource_api_permission
32
from st2common.rbac.decorators import request_user_has_resource_db_permission
33
34
from st2common.util.actionalias_matching import match_command_to_alias
35
from st2common.util.actionalias_helpstring import generate_helpstring_result
36
37
38
http_client = six.moves.http_client
39
40
LOG = logging.getLogger(__name__)
41
42
43
class ActionAliasController(resource.ContentPackResourceController):
44
    """
45
        Implements the RESTful interface for ActionAliases.
46
    """
47
    model = ActionAliasAPI
48
    access = ActionAlias
49
    supported_filters = {
50
        'name': 'name',
51
        'pack': 'pack'
52
    }
53
54
    query_options = {
55
        'sort': ['pack', 'name']
56
    }
57
58
    _custom_actions = {
59
        'match': ['POST'],
60
        'help': ['POST']
61
    }
62
63
    def _match_tuple_to_dict(self, match):
64
        return {
65
            'actionalias': match[0],
66
            'display': match[1],
67
            'representation': match[2]
68
        }
69
70
    @request_user_has_permission(permission_type=PermissionType.ACTION_ALIAS_LIST)
71
    @jsexpose()
72
    def get_all(self, **kwargs):
73
        return super(ActionAliasController, self)._get_all(**kwargs)
74
75
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_ALIAS_VIEW)
76
    @jsexpose(arg_types=[str])
77
    def get_one(self, ref_or_id):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'get_one' method
Loading history...
78
        return super(ActionAliasController, self)._get_one(ref_or_id)
79
80
    @request_user_has_permission(permission_type=PermissionType.ACTION_ALIAS_MATCH)
81
    @jsexpose(arg_types=[str], body_cls=ActionAliasMatchAPI, status_code=http_client.ACCEPTED)
82
    def match(self, action_alias_match_api, **kwargs):
83
        """
84
            Run a chatops command
85
86
            Handles requests:
87
                POST /actionalias/match
88
        """
89
        command = action_alias_match_api.command
90
91
        try:
92
            # 1. Get aliases
93
            aliases = super(ActionAliasController, self)._get_all(**kwargs)
94
            # 2. Match alias(es) to command
95
            matches = match_command_to_alias(command, aliases)
96
            if len(matches) > 1:
97
                raise ActionAliasAmbiguityException("Command '%s' matched more than 1 pattern" %
98
                                                    command,
99
                                                    matches=matches,
100
                                                    command=command)
101
            elif len(matches) == 0:
102
                raise ActionAliasAmbiguityException("Command '%s' matched no patterns" %
103
                                                    command,
104
                                                    matches=[],
105
                                                    command=command)
106
            return [self._match_tuple_to_dict(match) for match in matches]
107
        except (ActionAliasAmbiguityException) as e:
108
            LOG.exception('Command "%s" matched (%s) patterns.', e.command, len(e.matches))
109
            pecan.abort(http_client.BAD_REQUEST, str(e))
110
            return [self._match_tuple_to_dict(match) for match in e.matches]
111
112
    @request_user_has_permission(permission_type=PermissionType.ACTION_ALIAS_HELP)
113
    @jsexpose(arg_types=[str, str, int], body_cls=ActionAliasHelpAPI,
114
    status_code=http_client.ACCEPTED)
115
    def help(self, action_alias_help_api, **kwargs):
116
        """
117
            Get available help strings for action aliases.
118
119
            Handles requests:
120
                POST /actionalias/help
121
        """
122
        filter_ = action_alias_help_api.filter
123
        pack = action_alias_help_api.pack
124
        limit = action_alias_help_api.limit
125
        offset = action_alias_help_api.offset
126
127
        try:
128
            aliases = super(ActionAliasController, self)._get_all(**kwargs)
129
            return generate_helpstring_result(aliases, filter_, pack, limit, offset)
130
        except (TypeError) as e:
131
            LOG.exception('Helpstring request contains an invalid data type: %s.', str(e))
132
            pecan.abort(http_client.BAD_REQUEST, str(e))
133
134
    @jsexpose(body_cls=ActionAliasAPI, status_code=http_client.CREATED)
135
    @request_user_has_resource_api_permission(permission_type=PermissionType.ACTION_ALIAS_CREATE)
136
    def post(self, action_alias):
137
        """
138
            Create a new ActionAlias.
139
140
            Handles requests:
141
                POST /actionalias/
142
        """
143
        try:
144
            action_alias_db = ActionAliasAPI.to_model(action_alias)
145
            LOG.debug('/actionalias/ POST verified ActionAliasAPI and formulated ActionAliasDB=%s',
146
                      action_alias_db)
147
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
148
        except (ValidationError, ValueError, ValueValidationException) as e:
149
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
150
            pecan.abort(http_client.BAD_REQUEST, str(e))
151
            return
152
153
        extra = {'action_alias_db': action_alias_db}
154
        LOG.audit('Action alias created. ActionAlias.id=%s' % (action_alias_db.id), extra=extra)
155
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
156
157
        return action_alias_api
158
159
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_MODIFY)
160
    @jsexpose(arg_types=[str], body_cls=ActionAliasAPI)
161
    def put(self, action_alias_ref_or_id, action_alias):
162
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
163
        LOG.debug('PUT /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
164
                  action_alias_db)
165
166
        try:
167
            if action_alias.id is not None and action_alias.id is not '' and \
168
               action_alias.id != action_alias_ref_or_id:
169
                LOG.warning('Discarding mismatched id=%s found in payload and using uri_id=%s.',
170
                            action_alias.id, action_alias_ref_or_id)
171
            old_action_alias_db = action_alias_db
172
            action_alias_db = ActionAliasAPI.to_model(action_alias)
173
            action_alias_db.id = action_alias_ref_or_id
174
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
175
        except (ValidationError, ValueError) as e:
176
            LOG.exception('Validation failed for action alias data=%s', action_alias)
177
            pecan.abort(http_client.BAD_REQUEST, str(e))
178
            return
179
180
        extra = {'old_action_alias_db': old_action_alias_db, 'new_action_alias_db': action_alias_db}
181
        LOG.audit('Action alias updated. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
182
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
183
184
        return action_alias_api
185
186
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_ALIAS_DELETE)
187
    @jsexpose(arg_types=[str], status_code=http_client.NO_CONTENT)
188
    def delete(self, action_alias_ref_or_id):
189
        """
190
            Delete an action alias.
191
192
            Handles requests:
193
                DELETE /actionalias/1
194
        """
195
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
196
        LOG.debug('DELETE /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
197
                  action_alias_db)
198
        try:
199
            ActionAlias.delete(action_alias_db)
200
        except Exception as e:
201
            LOG.exception('Database delete encountered exception during delete of id="%s".',
202
                          action_alias_ref_or_id)
203
            pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
204
            return
205
206
        extra = {'action_alias_db': action_alias_db}
207
        LOG.audit('Action alias deleted. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
208