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

ActionAliasController.match()   B

Complexity

Conditions 3

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 24
rs 8.9713
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.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
    @request_user_has_resource_api_permission(permission_type=PermissionType.ACTION_ALIAS_CREATE)
72
    def match(self, command):
73
        """
74
            Run a chatops command
75
76
            Handles requests:
77
                POST /chatops/match
78
79
                command=hello%20world
80
        """
81
        try:
82
            # 1. Get aliases
83
            aliases = self.get_all()
84
            # 2. Match alias(es) to command
85
            match = match_command_to_alias(command, aliases)
86
            if len(match) > 1:
87
                raise ActionAliasAmbiguityException("Too much choice, not enough action (alias).")
88
            return match
89
        except (ActionAliasAmbiguityException) as e:
90
            # TODO : error on unmatched alias
91
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'action_alias'
Loading history...
92
            pecan.abort(http_client.BAD_REQUEST, str(e))
93
            return
94
95
    @jsexpose(body_cls=ActionAliasAPI, status_code=http_client.CREATED)
96
    @request_user_has_resource_api_permission(permission_type=PermissionType.ACTION_ALIAS_CREATE)
97
    def post(self, action_alias):
98
        """
99
            Create a new ActionAlias.
100
101
            Handles requests:
102
                POST /actionalias/
103
        """
104
        try:
105
            action_alias_db = ActionAliasAPI.to_model(action_alias)
106
            LOG.debug('/actionalias/ POST verified ActionAliasAPI and formulated ActionAliasDB=%s',
107
                      action_alias_db)
108
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
109
        except (ValidationError, ValueError, ValueValidationException) as e:
110
            LOG.exception('Validation failed for action alias data=%s.', action_alias)
111
            pecan.abort(http_client.BAD_REQUEST, str(e))
112
            return
113
114
        extra = {'action_alias_db': action_alias_db}
115
        LOG.audit('Action alias created. ActionAlias.id=%s' % (action_alias_db.id), extra=extra)
116
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
117
118
        return action_alias_api
119
120
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_MODIFY)
121
    @jsexpose(arg_types=[str], body_cls=ActionAliasAPI)
122
    def put(self, action_alias_ref_or_id, action_alias):
123
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
124
        LOG.debug('PUT /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
125
                  action_alias_db)
126
127
        try:
128
            if action_alias.id is not None and action_alias.id is not '' and \
129
               action_alias.id != action_alias_ref_or_id:
130
                LOG.warning('Discarding mismatched id=%s found in payload and using uri_id=%s.',
131
                            action_alias.id, action_alias_ref_or_id)
132
            old_action_alias_db = action_alias_db
133
            action_alias_db = ActionAliasAPI.to_model(action_alias)
134
            action_alias_db.id = action_alias_ref_or_id
135
            action_alias_db = ActionAlias.add_or_update(action_alias_db)
136
        except (ValidationError, ValueError) as e:
137
            LOG.exception('Validation failed for action alias data=%s', action_alias)
138
            pecan.abort(http_client.BAD_REQUEST, str(e))
139
            return
140
141
        extra = {'old_action_alias_db': old_action_alias_db, 'new_action_alias_db': action_alias_db}
142
        LOG.audit('Action alias updated. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
143
        action_alias_api = ActionAliasAPI.from_model(action_alias_db)
144
145
        return action_alias_api
146
147
    @request_user_has_resource_db_permission(permission_type=PermissionType.ACTION_ALIAS_DELETE)
148
    @jsexpose(arg_types=[str], status_code=http_client.NO_CONTENT)
149
    def delete(self, action_alias_ref_or_id):
150
        """
151
            Delete an action alias.
152
153
            Handles requests:
154
                DELETE /actionalias/1
155
        """
156
        action_alias_db = self._get_by_ref_or_id(ref_or_id=action_alias_ref_or_id)
157
        LOG.debug('DELETE /actionalias/ lookup with id=%s found object: %s', action_alias_ref_or_id,
158
                  action_alias_db)
159
        try:
160
            ActionAlias.delete(action_alias_db)
161
        except Exception as e:
162
            LOG.exception('Database delete encountered exception during delete of id="%s".',
163
                          action_alias_ref_or_id)
164
            pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
165
            return
166
167
        extra = {'action_alias_db': action_alias_db}
168
        LOG.audit('Action alias deleted. ActionAlias.id=%s.' % (action_alias_db.id), extra=extra)
169