Completed
Pull Request — master (#2895)
by Anthony
07:18 queued 02:48
created

ActionAliasController.match()   B

Complexity

Conditions 3

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

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