Completed
Pull Request — master (#2895)
by Anthony
04:32
created

ActionAliasController.match()   B

Complexity

Conditions 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
dl 0
loc 30
rs 7.5384
c 3
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.persistence.actionalias import ActionAlias
26
from st2common.models.api.base import jsexpose
27
from st2common.rbac.types import PermissionType
28
from st2common.rbac.decorators import request_user_has_permission
29
from st2common.rbac.decorators import request_user_has_resource_api_permission
30
from st2common.rbac.decorators import request_user_has_resource_db_permission
31
32
from st2common.util.actionalias_matching import match_command_to_alias
33
34
35
http_client = six.moves.http_client
36
37
LOG = logging.getLogger(__name__)
38
39
40
class ActionAliasController(resource.ContentPackResourceController):
41
    """
42
        Implements the RESTful interface for ActionAliases.
43
    """
44
    model = ActionAliasAPI
45
    access = ActionAlias
46
    supported_filters = {
47
        'name': 'name',
48
        'pack': 'pack'
49
    }
50
51
    query_options = {
52
        'sort': ['pack', 'name']
53
    }
54
55
    _custom_actions = {
56
        'match': ['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
    @request_user_has_permission(permission_type=PermissionType.ACTION_ALIAS_LIST)
67
    @jsexpose()
68
    def get_all(self, **kwargs):
69
        return super(ActionAliasController, self)._get_all(**kwargs)
70
71
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_ALIAS_VIEW)
72
    @jsexpose(arg_types=[str])
73
    def get_one(self, ref_or_id):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'get_one' method
Loading history...
74
        return super(ActionAliasController, self)._get_one(ref_or_id)
75
76
    @jsexpose(arg_types=[str], status_code=http_client.ACCEPTED)
77
    def match(self, command, **kwargs):
78
        """
79
            Run a chatops command
80
81
            Handles requests:
82
                POST /actionalias/match
83
84
                command=hello%20world
85
        """
86
        try:
87
            # 1. Get aliases
88
            aliases = super(ActionAliasController, self)._get_all(**kwargs)
89
            # 2. Match alias(es) to command
90
            matches = match_command_to_alias(command, aliases)
91
            if len(matches) > 1:
92
                raise ActionAliasAmbiguityException("Command '%s' matched more than 1 pattern" %
93
                                                    command,
94
                                                    matches=matches,
95
                                                    command=command)
96
            elif len(matches) == 0:
97
                raise ActionAliasAmbiguityException("Command '%s' matched no patterns" %
98
                                                    command,
99
                                                    matches=[],
100
                                                    command=command)
101
            return [self._match_tuple_to_dict(match) for match in matches]
102
        except (ActionAliasAmbiguityException) as e:
103
            LOG.exception('Command "%s" matched (%s) patterns.', e.command, len(e.matches))
104
            pecan.abort(http_client.BAD_REQUEST, str(e))
105
            return [self._match_tuple_to_dict(match) for match in e.matches]
106
107
    @jsexpose(body_cls=ActionAliasAPI, status_code=http_client.CREATED)
108
    @request_user_has_resource_api_permission(permission_type=PermissionType.ACTION_ALIAS_CREATE)
109
    def post(self, action_alias):
110
        """
111
            Create a new ActionAlias.
112
113
            Handles requests:
114
                POST /actionalias/
115
        """
116
        try:
117
            action_alias_db = ActionAliasAPI.to_model(action_alias)
118
            LOG.debug('/actionalias/ POST verified ActionAliasAPI and formulated ActionAliasDB=%s',
119
                      action_alias_db)
120
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
121
        except (ValidationError, ValueError, ValueValidationException) as e:
122
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
123
            pecan.abort(http_client.BAD_REQUEST, str(e))
124
            return
125
126
        extra = {'action_alias_db': action_alias_db}
127
        LOG.audit('Action alias created. ActionAlias.id=%s' % (action_alias_db.id), extra=extra)
128
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
129
130
        return action_alias_api
131
132
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_MODIFY)
133
    @jsexpose(arg_types=[str], body_cls=ActionAliasAPI)
134
    def put(self, action_alias_ref_or_id, action_alias):
135
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
136
        LOG.debug('PUT /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
137
                  action_alias_db)
138
139
        try:
140
            if action_alias.id is not None and action_alias.id is not '' and \
141
               action_alias.id != action_alias_ref_or_id:
142
                LOG.warning('Discarding mismatched id=%s found in payload and using uri_id=%s.',
143
                            action_alias.id, action_alias_ref_or_id)
144
            old_action_alias_db = action_alias_db
145
            action_alias_db = ActionAliasAPI.to_model(action_alias)
146
            action_alias_db.id = action_alias_ref_or_id
147
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
148
        except (ValidationError, ValueError) 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 = {'old_action_alias_db': old_action_alias_db, 'new_action_alias_db': action_alias_db}
154
        LOG.audit('Action alias updated. 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_ALIAS_DELETE)
160
    @jsexpose(arg_types=[str], status_code=http_client.NO_CONTENT)
161
    def delete(self, action_alias_ref_or_id):
162
        """
163
            Delete an action alias.
164
165
            Handles requests:
166
                DELETE /actionalias/1
167
        """
168
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
169
        LOG.debug('DELETE /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
170
                  action_alias_db)
171
        try:
172
            ActionAlias.delete(action_alias_db)
173
        except Exception as e:
174
            LOG.exception('Database delete encountered exception during delete of id="%s".',
175
                          action_alias_ref_or_id)
176
            pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
177
            return
178
179
        extra = {'action_alias_db': action_alias_db}
180
        LOG.audit('Action alias deleted. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
181