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

ActionAliasController.match()   B

Complexity

Conditions 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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