]> git.openstreetmap.org Git - osqa.git/blob - forum/modules/ui_objects.py
Merge pull request #26 from udacity/remove_dj_version
[osqa.git] / forum / modules / ui_objects.py
1 from django.core.urlresolvers import reverse
2 from django.template.defaultfilters import slugify
3 from django import template
4 from forum.utils import html
5 from forum.models.user import AnonymousUser
6 from ui import Registry
7 from copy import copy
8
9 class Visibility(object):
10     def __init__(self, level='public', negated=False):
11         if level not in ['public', 'authenticated', 'staff', 'superuser', 'owner']:
12             try:
13                 int(level)
14                 self.by_reputation = True
15             except:
16                 raise "Invalid visibility level for ui object: %s" % level
17         else:
18             self.by_reputation = False
19
20         self.level = level
21         self.negated = negated
22
23     def show_to(self, user):
24         if self.by_reputation:
25             res = user.is_authenticated() and (user.reputation >= int(self.level) or user.is_staff or user.is_superuser)
26         else:
27             res = self.level == 'public' or (user.is_authenticated() and (
28                 self.level == 'authenticated' or (
29                 self.level == 'superuser' and user.is_superuser) or (
30                 self.level == 'staff' and (user.is_staff or user.is_superuser)) or (
31                 self.level == 'owner' and user.is_siteowner)))
32
33         if self.negated:
34             return not res
35         else:
36             return res
37
38     def __invert__(self):
39         return Visibility(self.level, not self.negated)
40         
41
42 Visibility.PUBLIC = Visibility('public')
43 Visibility.AUTHENTICATED = Visibility('authenticated')
44 Visibility.STAFF = Visibility('staff')
45 Visibility.SUPERUSER = Visibility('superuser')
46 Visibility.OWNER = Visibility('owner')
47 Visibility.REPUTED = lambda r: Visibility(r)
48
49
50 class Url(object):
51     def __init__(self, url_pattern):
52         self.url_pattern = url_pattern
53
54     def __call__(self, u, c):
55         return reverse(self.url_pattern)
56
57
58 class ObjectBase(object):
59     class Argument(object):
60         def __init__(self, argument):
61             self.argument = argument
62
63         def __call__(self, context):
64             if callable(self.argument):
65                 user = context.get('request', None) and context['request'].user or AnonymousUser()
66                 return self.argument(user, context)
67             else:
68                 return self.argument
69
70     def __init__(self, visibility=None, weight=500, name=''):
71         self.visibility = visibility
72         self.weight = weight
73         self.name = name
74
75     def _visible_to(self, user):
76         return (not self.visibility) or (self.visibility and self.visibility.show_to(user))
77
78     def can_render(self, context):
79         try:
80             return self._visible_to(context['request'].user)
81         except KeyError:
82             try:
83                 return self._visible_to(context['viewer'])
84             except KeyError:
85                 return self._visible_to(AnonymousUser())
86
87     def render(self, context):
88         return ''
89
90 class LoopBase(ObjectBase):
91     def update_context(self, context):
92         pass
93
94
95
96 class Link(ObjectBase):
97     def __init__(self, text, url, attrs=None, pre_code='', post_code='', visibility=None, weight=500, name=''):
98         super(Link, self).__init__(visibility, weight, name)
99         self.text = self.Argument(text)
100         self.url = self.Argument(url)
101         self.attrs = self.Argument(attrs or {})
102         self.pre_code = self.Argument(pre_code)
103         self.post_code = self.Argument(post_code)
104
105     def render(self, context):
106         return "%s %s %s" % (self.pre_code(context),
107             html.hyperlink(self.url(context), self.text(context), **self.attrs(context)),
108             self.post_code(context))
109
110 class Include(ObjectBase):
111     def __init__(self, tpl, visibility=None, weight=500, name=''):
112         super(Include, self).__init__(visibility, weight, name)
113         self.template = template.loader.get_template(tpl)
114
115     def render(self, context):
116         if not isinstance(context, template.Context):
117             context = template.Context(context)
118         return self.template.render(context)
119         
120
121 class LoopContext(LoopBase):
122     def __init__(self, loop_context, visibility=None, weight=500, name=''):
123         super(LoopContext, self).__init__(visibility, weight, name)
124         self.loop_context = self.Argument(loop_context)
125
126     def update_context(self, context):
127         context.update(self.loop_context(context))
128
129
130 class PageTab(LoopBase):
131     def __init__(self, tab_name, tab_title, url_getter, weight, name=''):
132         super(PageTab, self).__init__(weight=weight, name=name)
133         self.tab_name = tab_name
134         self.tab_title = tab_title
135         self.url_getter = url_getter
136
137     def update_context(self, context):
138         context.update(dict(
139             tab_name=self.tab_name,
140             tab_title=self.tab_title,
141             tab_url=self.url_getter()
142         ))
143
144
145 class ProfileTab(LoopBase):
146     def __init__(self, name, title, description, url_getter, private=False, render_to=None, weight=500):
147         super(ProfileTab, self).__init__(weight=weight, name=name)
148         self.name = name
149         self.title = title
150         self.description = description
151         self.url_getter = url_getter
152         self.private = private
153         self.render_to = render_to
154
155     def can_render(self, context):
156         return (not self.render_to or (self.render_to(context['view_user']))) and (
157             not self.private or (
158             context['view_user'] == context['request'].user or context['request'].user.is_superuser))
159
160     def update_context(self, context):        
161         context.update(dict(
162             tab_name=self.name,
163             tab_title=self.title,
164             tab_description = self.description,
165             tab_url=self.url_getter(context['view_user'])
166         ))
167
168
169 class AjaxMenuItem(ObjectBase):
170     def __init__(self, label, url, a_attrs=None, span_label='', span_attrs=None, visibility=None, weight=500, name=''):
171         super(AjaxMenuItem, self).__init__(visibility, weight, name)
172         self.label = self.Argument(label)
173         self.url = self.Argument(url)
174         self.a_attrs = self.Argument(a_attrs or {})
175         self.span_label = self.Argument(span_label)
176         self.span_attrs = self.Argument(span_attrs or {})
177
178     def render(self, context):
179         return html.buildtag('li',
180             html.buildtag('span', self.span_label(context), **self.span_attrs(context)) + \
181             html.hyperlink(self.url(context), self.label(context), **self.a_attrs(context)),
182             **{'class': 'item'})
183
184 class AjaxMenuGroup(ObjectBase, Registry):
185     def __init__(self, label, items, visibility=None, weight=500, name=''):
186         super(AjaxMenuGroup, self).__init__(visibility, weight, name)
187         self.label = label
188
189         for item in items:
190             self.add(item)
191
192     def can_render(self, context):
193         if super(AjaxMenuGroup, self).can_render(context):
194             for item in self:
195                 if item.can_render(context): return True
196
197         return False
198
199     def render(self, context):
200         return html.buildtag('li', self.label, **{'class': 'separator'}) + "".join([
201             item.render(context) for item in self if item.can_render(context)
202         ])
203
204 class UserMenuItem(AjaxMenuItem):
205     def __init__(self, render_to=None, *args, **kwargs):
206         super(UserMenuItem, self).__init__(*args, **kwargs)
207         self.render_to = render_to
208
209     def can_render(self, context):
210         return (not self.render_to or (self.render_to(context['user']))) and super(UserMenuItem, self)._visible_to(context['viewer'])