Fixes #756: problem with save form
[redakcja.git] / apps / wiki / helpers.py
1 from django import http
2 from django.utils import simplejson as json
3 from django.utils.functional import Promise
4 from datetime import datetime
5 from functools import wraps
6
7
8 class ExtendedEncoder(json.JSONEncoder):
9
10     def default(self, obj):
11         if isinstance(obj, Promise):
12             return unicode(obj)
13
14         if isinstance(obj, datetime):
15             return datetime.ctime(obj) + " " + (datetime.tzname(obj) or 'GMT')
16
17         return json.JSONEncoder.default(self, obj)
18
19
20 # shortcut for JSON reponses
21 class JSONResponse(http.HttpResponse):
22
23     def __init__(self, data={}, **kwargs):
24         # get rid of mimetype
25         kwargs.pop('mimetype', None)
26
27         data = json.dumps(data, cls=ExtendedEncoder)
28         super(JSONResponse, self).__init__(data, mimetype="application/json", **kwargs)
29
30
31 # return errors
32 class JSONFormInvalid(JSONResponse):
33     def __init__(self, form):
34         super(JSONFormInvalid, self).__init__(form.errors, status=400)
35
36
37 class JSONServerError(JSONResponse):
38     def __init__(self, *args, **kwargs):
39         kwargs['status'] = 500
40         super(JSONServerError, self).__init__(*args, **kwargs)
41
42
43 def ajax_login_required(view):
44     @wraps(view)
45     def authenticated_view(request, *args, **kwargs):
46         if not request.user.is_authenticated():
47             return http.HttpResponse("Login required.", status=401, mimetype="text/plain")
48         return view(request, *args, **kwargs)
49     return authenticated_view
50
51
52 def ajax_require_permission(permission):
53     def decorator(view):
54         @wraps(view)
55         def authorized_view(request, *args, **kwargs):
56             if not request.user.has_perm(permission):
57                 return http.HttpResponse("Access Forbidden.", status=403, mimetype="text/plain")
58             return view(request, *args, **kwargs)
59         return authorized_view
60     return decorator
61
62 import collections
63
64 def recursive_groupby(iterable):
65     """
66 #    >>> recursive_groupby([1,2,3,4,5])
67 #    [1, 2, 3, 4, 5]
68
69     >>> recursive_groupby([[1]])
70     [1]
71
72     >>> recursive_groupby([('a', 1),('a', 2), 3, ('b', 4), 5])
73     ['a', [1, 2], 3, 'b', [4], 5]
74
75     >>> recursive_groupby([('a', 'x', 1),('a', 'x', 2), ('a', 'x', 3)])
76     ['a', ['x', [1, 2, 3]]]
77
78     """
79
80     def _generator(iterator):
81         group = None
82         grouper = None
83
84         for item in iterator:
85             if not isinstance(item, collections.Sequence):
86                 if grouper is not None:
87                     yield grouper
88                     if len(group):
89                         yield recursive_groupby(group)
90                     group = None
91                     grouper = None
92                 yield item
93                 continue
94             elif len(item) == 1:
95                 if grouper is not None:
96                     yield grouper
97                     if len(group):
98                         yield recursive_groupby(group)
99                     group = None
100                     grouper = None
101                 yield item[0]
102                 continue
103             elif not len(item):
104                 continue
105
106             if grouper is None:
107                 group = [item[1:]]
108                 grouper = item[0]
109                 continue
110
111             if grouper != item[0]:
112                 if grouper is not None:
113                     yield grouper
114                     if len(group):
115                         yield recursive_groupby(group)
116                     group = None
117                     grouper = None
118                 group = [item[1:]]
119                 grouper = item[0]
120                 continue
121
122             group.append(item[1:])
123
124         if grouper is not None:
125             yield grouper
126             if len(group):
127                 yield recursive_groupby(group)
128             group = None
129             grouper = None
130
131     return list(_generator(iterable))