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

ActionAliasController.match()   A

Complexity

Conditions 3

Size

Total Lines 23

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