Completed
Pull Request — master (#2895)
by Anthony
10:42 queued 04:58
created

ActionAliasController.match()   B

Complexity

Conditions 5

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 5
c 3
b 0
f 0
dl 0
loc 24
rs 8.1671
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 /chatops/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 matched more than 1 pattern",
93
                                                    matches=matches)
94
            return [self._match_tuple_to_dict(match) for match in matches]
95
        except (ActionAliasAmbiguityException) as e:
96
            # TODO : error on unmatched alias
97
            LOG.exception('Command matched (%s) patterns.', len(e.matches))
98
            pecan.abort(http_client.BAD_REQUEST, str(e))
99
            return [self._match_tuple_to_dict(match) for match in e.matches]
100
101
    @jsexpose(body_cls=ActionAliasAPI, status_code=http_client.CREATED)
102
    @request_user_has_resource_api_permission(permission_type=PermissionType.ACTION_ALIAS_CREATE)
103
    def post(self, action_alias):
104
        """
105
            Create a new ActionAlias.
106
107
            Handles requests:
108
                POST /actionalias/
109
        """
110
        try:
111
            action_alias_db = ActionAliasAPI.to_model(action_alias)
112
            LOG.debug('/actionalias/ POST verified ActionAliasAPI and formulated ActionAliasDB=%s',
113
                      action_alias_db)
114
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
115
        except (ValidationError, ValueError, ValueValidationException) as e:
116
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
117
            pecan.abort(http_client.BAD_REQUEST, str(e))
118
            return
119
120
        extra = {'action_alias_db': action_alias_db}
121
        LOG.audit('Action alias created. ActionAlias.id=%s' % (action_alias_db.id), extra=extra)
122
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
123
124
        return action_alias_api
125
126
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_MODIFY)
127
    @jsexpose(arg_types=[str], body_cls=ActionAliasAPI)
128
    def put(self, action_alias_ref_or_id, action_alias):
129
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
130
        LOG.debug('PUT /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
131
                  action_alias_db)
132
133
        try:
134
            if action_alias.id is not None and action_alias.id is not '' and \
135
               action_alias.id != action_alias_ref_or_id:
136
                LOG.warning('Discarding mismatched id=%s found in payload and using uri_id=%s.',
137
                            action_alias.id, action_alias_ref_or_id)
138
            old_action_alias_db = action_alias_db
139
            action_alias_db = ActionAliasAPI.to_model(action_alias)
140
            action_alias_db.id = action_alias_ref_or_id
141
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
142
        except (ValidationError, ValueError) as e:
143
            LOG.exception('Validation failed for action alias data=%s', action_alias)
144
            pecan.abort(http_client.BAD_REQUEST, str(e))
145
            return
146
147
        extra = {'old_action_alias_db': old_action_alias_db, 'new_action_alias_db': action_alias_db}
148
        LOG.audit('Action alias updated. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
149
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
150
151
        return action_alias_api
152
153
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_ALIAS_DELETE)
154
    @jsexpose(arg_types=[str], status_code=http_client.NO_CONTENT)
155
    def delete(self, action_alias_ref_or_id):
156
        """
157
            Delete an action alias.
158
159
            Handles requests:
160
                DELETE /actionalias/1
161
        """
162
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
163
        LOG.debug('DELETE /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
164
                  action_alias_db)
165
        try:
166
            ActionAlias.delete(action_alias_db)
167
        except Exception as e:
168
            LOG.exception('Database delete encountered exception during delete of id="%s".',
169
                          action_alias_ref_or_id)
170
            pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
171
            return
172
173
        extra = {'action_alias_db': action_alias_db}
174
        LOG.audit('Action alias deleted. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
175