summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Reporting/utils.py
blob: 4165477ab4dc20a83110dcf52a5cd5d300b17cf7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""Helper functions for reports"""
import re

"""List of filters provided by filteredUrls"""
filter_list = ('server', 'state', 'group')


class BatchFetch(object):
    """Fetch Django objects in smaller batches to save memory"""

    def __init__(self, obj, step=10000):
        self.count = 0
        self.block_count = 0
        self.obj = obj
        self.data = None
        self.step = step
        self.max = obj.count()

    def __iter__(self):
        return self

    def __next__(self):
        """Provide compatibility with python < 3.0"""
        return self.__next__()

    def __next__(self):
        """Return the next object from our array and fetch from the
           database when needed"""
        if self.block_count + self.count - self.step == self.max:
            raise StopIteration
        if self.block_count == 0 or self.count == self.step:
            # Without list() this turns into LIMIT 1 OFFSET x queries
            self.data = list(self.obj.all()[self.block_count: \
                                   (self.block_count + self.step)])
            self.block_count += self.step
            self.count = 0
        self.count += 1
        return self.data[self.count - 1]


def generateUrls(fn):
    """
    Parse url tuples and send to functions.

    Decorator for url generators.  Handles url tuple parsing
    before the actual function is called.
    """
    def url_gen(*urls):
        results = []
        for url_tuple in urls:
            if isinstance(url_tuple, (list, tuple)):
                results += fn(*url_tuple)
            else:
                raise ValueError("Unable to handle compiled urls")
        return results
    return url_gen


@generateUrls
def paginatedUrls(pattern, view, kwargs=None, name=None):
    """
    Takes a group of url tuples and adds paginated urls.

    Extends a url tuple to include paginated urls.
    Currently doesn't handle url() compiled patterns.

    """
    results = [(pattern, view, kwargs, name)]
    tail = ''
    mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
    if mtail:
        tail = mtail.group(1)
    pattern = pattern[:len(pattern) - len(tail)]
    results += [(pattern + "/(?P<page_number>\d+)" + tail, view, kwargs)]
    results += [(pattern + "/(?P<page_number>\d+)\|(?P<page_limit>\d+)" +
                 tail, view, kwargs)]
    if not kwargs:
        kwargs = dict()
    kwargs['page_limit'] = 0
    results += [(pattern + "/?\|(?P<page_limit>all)" + tail, view, kwargs)]
    return results


@generateUrls
def filteredUrls(pattern, view, kwargs=None, name=None):
    """
    Takes a url and adds filtered urls.

    Extends a url tuple to include filtered view urls.  Currently doesn't
    handle url() compiled patterns.
    """
    results = [(pattern, view, kwargs, name)]
    tail = ''
    mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
    if mtail:
        tail = mtail.group(1)
    pattern = pattern[:len(pattern) - len(tail)]
    for filter in ('/state/(?P<state>\w+)',
                   '/group/(?P<group>[^/]+)',
                   '/group/(?P<group>[^/]+)/(?P<state>[A-Za-z]+)',
                   '/server/(?P<server>[^/]+)',
                   '/server/(?P<server>[^/]+)/(?P<state>[A-Za-z]+)',
                   '/server/(?P<server>[^/]+)/group/(?P<group>[^/]+)',
                   '/server/(?P<server>[^/]+)/group/(?P<group>[^/]+)/(?P<state>[A-Za-z]+)'):
        results += [(pattern + filter + tail, view, kwargs)]
    return results


@generateUrls
def timeviewUrls(pattern, view, kwargs=None, name=None):
    """
    Takes a url and adds timeview urls

    Extends a url tuple to include filtered view urls.  Currently doesn't
    handle url() compiled patterns.
    """
    results = [(pattern, view, kwargs, name)]
    tail = ''
    mtail = re.search('(/+\+?\\*?\??\$?)$', pattern)
    if mtail:
        tail = mtail.group(1)
    pattern = pattern[:len(pattern) - len(tail)]
    for filter in ('/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/' + \
                       '(?P<hour>\d\d)-(?P<minute>\d\d)',
                   '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'):
        results += [(pattern + filter + tail, view, kwargs)]
    return results