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