GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — develop-v1.3.1 ( 8fa207...a1cf9b )
by
unknown
06:11
created

MongoDBAccess.query()   A

Complexity

Conditions 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 22
rs 9.2
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 copy
17
import importlib
18
19
import six
20
import mongoengine
21
22
from st2common import log as logging
23
from st2common.util import isotime
24
from st2common.models.db import stormbase
25
from st2common.models.utils.profiling import log_query_and_profile_data_for_queryset
26
27
28
LOG = logging.getLogger(__name__)
29
30
MODEL_MODULE_NAMES = [
31
    'st2common.models.db.auth',
32
    'st2common.models.db.action',
33
    'st2common.models.db.actionalias',
34
    'st2common.models.db.keyvalue',
35
    'st2common.models.db.execution',
36
    'st2common.models.db.executionstate',
37
    'st2common.models.db.liveaction',
38
    'st2common.models.db.policy',
39
    'st2common.models.db.rule',
40
    'st2common.models.db.runner',
41
    'st2common.models.db.sensor',
42
    'st2common.models.db.trigger',
43
]
44
45
46
def get_model_classes():
47
    """
48
    Retrieve a list of all the defined model classes.
49
50
    :rtype: ``list``
51
    """
52
    result = []
53
    for module_name in MODEL_MODULE_NAMES:
54
        module = importlib.import_module(module_name)
55
        model_classes = getattr(module, 'MODELS', [])
56
        result.extend(model_classes)
57
58
    return result
59
60
61
def db_setup(db_name, db_host, db_port, username=None, password=None,
62
             ensure_indexes=True):
63
    LOG.info('Connecting to database "%s" @ "%s:%s" as user "%s".',
64
             db_name, db_host, db_port, str(username))
65
    connection = mongoengine.connection.connect(db_name, host=db_host,
66
                                                port=db_port, tz_aware=True,
67
                                                username=username, password=password)
68
69
    # Create all the indexes upfront to prevent race-conditions caused by
70
    # lazy index creation
71
    if ensure_indexes:
72
        db_ensure_indexes()
73
74
    return connection
75
76
77
def db_ensure_indexes():
78
    """
79
    This function ensures that indexes for all the models have been created.
80
81
    Note #1: When calling this method database connection already needs to be
82
    established.
83
84
    Note #2: This method blocks until all the index have been created (indexes
85
    are created in real-time and not in background).
86
    """
87
    LOG.debug('Ensuring database indexes...')
88
    model_classes = get_model_classes()
89
90
    for cls in model_classes:
91
        LOG.debug('Ensuring indexes for model "%s"...' % (cls.__name__))
92
        cls.ensure_indexes()
93
94
95
def db_teardown():
96
    mongoengine.connection.disconnect()
97
98
99
class MongoDBAccess(object):
100
    """Database object access class that provides general functions for a model type."""
101
102
    def __init__(self, model):
103
        self.model = model
104
105
    def get_by_name(self, value):
106
        return self.get(name=value, raise_exception=True)
107
108
    def get_by_id(self, value):
109
        return self.get(id=value, raise_exception=True)
110
111
    def get_by_ref(self, value):
112
        return self.get(ref=value, raise_exception=True)
113
114
    def get(self, exclude_fields=None, *args, **kwargs):
115
        raise_exception = kwargs.pop('raise_exception', False)
116
117
        instances = self.model.objects(**kwargs)
118
119
        if exclude_fields:
120
            instances = instances.exclude(*exclude_fields)
121
122
        instance = instances[0] if instances else None
123
        log_query_and_profile_data_for_queryset(queryset=instances)
124
125
        if not instance and raise_exception:
126
            raise ValueError('Unable to find the %s instance. %s' % (self.model.__name__, kwargs))
127
        return instance
128
129
    def get_all(self, *args, **kwargs):
130
        return self.query(*args, **kwargs)
131
132
    def count(self, *args, **kwargs):
133
        result = self.model.objects(**kwargs).count()
134
        log_query_and_profile_data_for_queryset(queryset=result)
135
        return result
136
137
    def query(self, offset=0, limit=None, order_by=None, exclude_fields=None,
138
              **filters):
139
        order_by = order_by or []
140
        exclude_fields = exclude_fields or []
141
        eop = offset + int(limit) if limit else None
142
143
        # Process the filters
144
        # Note: Both of those functions manipulate "filters" variable so the order in which they
145
        # are called matters
146
        filters, order_by = self._process_datetime_range_filters(filters=filters, order_by=order_by)
147
        filters = self._process_null_filters(filters=filters)
148
149
        result = self.model.objects(**filters)
150
151
        if exclude_fields:
152
            result = result.exclude(*exclude_fields)
153
154
        result = result.order_by(*order_by)
155
        result = result[offset:eop]
156
        log_query_and_profile_data_for_queryset(queryset=result)
157
158
        return result
159
160
    def distinct(self, *args, **kwargs):
161
        field = kwargs.pop('field')
162
        result = self.model.objects(**kwargs).distinct(field)
163
        log_query_and_profile_data_for_queryset(queryset=result)
164
        return result
165
166
    def aggregate(self, *args, **kwargs):
167
        return self.model.objects(**kwargs)._collection.aggregate(*args, **kwargs)
168
169
    def insert(self, instance):
170
        instance = self.model.objects.insert(instance)
171
        return self._undo_dict_field_escape(instance)
172
173
    def add_or_update(self, instance):
174
        instance.save()
175
        return self._undo_dict_field_escape(instance)
176
177
    def update(self, instance, **kwargs):
178
        return instance.update(**kwargs)
179
180
    def delete(self, instance):
181
        return instance.delete()
182
183
    def delete_by_query(self, **query):
184
        qs = self.model.objects.filter(**query)
185
        qs.delete()
186
        log_query_and_profile_data_for_queryset(queryset=qs)
187
        # mongoengine does not return anything useful so cannot return anything meaningful.
188
        return None
189
190
    def _undo_dict_field_escape(self, instance):
191
        for attr, field in instance._fields.iteritems():
192
            if isinstance(field, stormbase.EscapedDictField):
193
                value = getattr(instance, attr)
194
                setattr(instance, attr, field.to_python(value))
195
        return instance
196
197
    def _process_null_filters(self, filters):
198
        result = copy.deepcopy(filters)
199
200
        null_filters = {k: v for k, v in six.iteritems(filters)
201
                        if v is None or (type(v) in [str, unicode] and str(v.lower()) == 'null')}
202
203
        for key in null_filters.keys():
204
            result['%s__exists' % (key)] = False
205
            del result[key]
206
207
        return result
208
209
    def _process_datetime_range_filters(self, filters, order_by=None):
210
        ranges = {k: v for k, v in filters.iteritems()
211
                  if type(v) in [str, unicode] and '..' in v}
212
213
        order_by_list = copy.deepcopy(order_by) if order_by else []
214
        for k, v in ranges.iteritems():
215
            values = v.split('..')
216
            dt1 = isotime.parse(values[0])
217
            dt2 = isotime.parse(values[1])
218
219
            k__gte = '%s__gte' % k
220
            k__lte = '%s__lte' % k
221
            if dt1 < dt2:
222
                query = {k__gte: dt1, k__lte: dt2}
223
                sort_key, reverse_sort_key = k, '-' + k
224
            else:
225
                query = {k__gte: dt2, k__lte: dt1}
226
                sort_key, reverse_sort_key = '-' + k, k
227
            del filters[k]
228
            filters.update(query)
229
230
            if reverse_sort_key in order_by_list:
231
                idx = order_by_list.index(reverse_sort_key)
232
                order_by_list.pop(idx)
233
                order_by_list.insert(idx, sort_key)
234
            elif sort_key not in order_by_list:
235
                order_by_list = [sort_key] + order_by_list
236
237
        return filters, order_by_list
238