]> git.openstreetmap.org Git - osqa.git/blob - forum/templatetags/node_tags.py
104f866323f3ca72d15b8ded5a6c78b3f6562301
[osqa.git] / forum / templatetags / node_tags.py
1 from datetime import datetime, timedelta\r
2 import re\r
3 \r
4 from forum.models import Question, Action\r
5 from django.template import Template, Context\r
6 from django.utils.translation import ungettext, ugettext as _\r
7 from django.utils.html import strip_tags\r
8 from django.utils.encoding import smart_unicode\r
9 from django.utils.safestring import mark_safe\r
10 from django.conf import settings as django_settings\r
11 from django.core.urlresolvers import reverse\r
12 from django import template\r
13 from forum.actions import *\r
14 from forum import settings\r
15 \r
16 register = template.Library()\r
17 \r
18 @register.inclusion_tag('node/vote_buttons.html')\r
19 def vote_buttons(post, user):\r
20     context = dict(post=post, user_vote='none')\r
21 \r
22     if user.is_authenticated():\r
23         context['user_vote'] = {1: 'up', -1: 'down', None: 'none'}[VoteAction.get_for(user, post)]\r
24 \r
25     return context\r
26 \r
27 @register.inclusion_tag('node/accept_button.html')\r
28 def accept_button(answer, user):\r
29     if not settings.DISABLE_ACCEPTING_FEATURE:\r
30         return {\r
31             'can_accept': user.is_authenticated() and user.can_accept_answer(answer),\r
32             'answer': answer,\r
33             'user': user\r
34         }\r
35     else:\r
36         return ''\r
37 \r
38 @register.inclusion_tag('node/wiki_symbol.html')\r
39 def wiki_symbol(user, post):\r
40     context = {\r
41         'is_wiki': post.nis.wiki,\r
42         'post_type': post.friendly_name\r
43     }\r
44 \r
45     if post.nis.wiki:\r
46         if user.can_edit_post(post):\r
47             context['can_edit'] = True\r
48             context['edit_url'] = reverse('edit_' + post.node_type, kwargs={'id': post.id})\r
49         context['by'] = post.nstate.wiki.by.username\r
50         context['at'] = post.nstate.wiki.at\r
51 \r
52     return context\r
53 \r
54 @register.inclusion_tag('node/favorite_mark.html')\r
55 def favorite_mark(question, user):\r
56     try:\r
57         FavoriteAction.objects.get(canceled=False, node=question, user=user)\r
58         favorited = True\r
59     except:\r
60         favorited = False\r
61 \r
62     return {'favorited': favorited, 'favorite_count': question.favorite_count, 'question': question}\r
63 \r
64 @register.simple_tag\r
65 def post_classes(post):\r
66     classes = []\r
67 \r
68     if post.nis.deleted:\r
69         classes.append('deleted')\r
70 \r
71     if post.node_type == "answer":\r
72         if (not settings.DISABLE_ACCEPTING_FEATURE) and post.nis.accepted:\r
73             classes.append('accepted-answer')\r
74 \r
75         if post.author == post.question.author:\r
76             classes.append('answered-by-owner')\r
77 \r
78     return " ".join(classes)\r
79 \r
80 def post_control(text, url, command=False, withprompt=False, confirm=False, title="", copy=False):\r
81     classes = (command and "ajax-command" or " ") + (withprompt and " withprompt" or " ") + (confirm and " confirm" or " ") + \\r
82         (copy and " copy" or " ")\r
83     return {'text': text, 'url': url, 'classes': classes, 'title': title}\r
84 \r
85 \r
86 moderation_enabled = False\r
87 for m in django_settings.MODULE_LIST:\r
88     if m.__name__.endswith('moderation'):\r
89         moderation_enabled = True\r
90 \r
91 @register.inclusion_tag('node/post_controls.html' if not moderation_enabled else "modules/moderation/node/post_controls.html")\r
92 def post_controls(post, user):\r
93     controls = []\r
94     menu = []\r
95     post_type = post.node_type\r
96 \r
97     # We show the link tool if the post is an Answer. It is visible to Guests too.\r
98     if post_type == "answer":\r
99         # Answer permanent link tool\r
100         controls.append(post_control(_('permanent link'), reverse('answer_permanent_link', kwargs={'id' : post.id,}),\r
101                                      title=_("answer permanent link"), command=True, withprompt=True, copy=True))\r
102 \r
103         # Users should be able to award points for an answer. Users cannot award their own answers\r
104         if user != post.author and user.is_authenticated():\r
105             controls.append(post_control(_("award points"), reverse('award_points', kwargs={'user_id' : post.author.id,\r
106                                          'answer_id' : post.id}), title=_("award points to %s") % smart_unicode(post.author.username),\r
107                                          command=True, withprompt=True))\r
108 \r
109     # The other controls are visible only to authenticated users.\r
110     if user.is_authenticated():\r
111         try:\r
112             edit_url = reverse('edit_' + post_type, kwargs={'id': post.id})\r
113             if user.can_edit_post(post):\r
114                 controls.append(post_control(_('edit'), edit_url))\r
115             elif post_type == 'question' and user.can_retag_questions():\r
116                 controls.append(post_control(_('retag'), edit_url))\r
117         except:\r
118             pass\r
119 \r
120         if post_type == 'question':\r
121             if post.nis.closed and user.can_reopen_question(post):\r
122                 controls.append(post_control(_('reopen'), reverse('reopen', kwargs={'id': post.id}), command=True))\r
123             elif not post.nis.closed and user.can_close_question(post):\r
124                 controls.append(post_control(_('close'), reverse('close', kwargs={'id': post.id}), command=True, withprompt=True))\r
125 \r
126         if user.can_flag_offensive(post):\r
127             label = _('report')\r
128             \r
129             if user.can_view_offensive_flags(post):\r
130                 label =  "%s (%d)" % (label, post.flag_count)\r
131 \r
132 \r
133             report_control = post_control(label, reverse('flag_post', kwargs={'id': post.id}),\r
134                     command=True, withprompt=True,\r
135                     title=_("report as offensive (i.e containing spam, advertising, malicious text, etc.)"))\r
136 \r
137             # Depending on the setting choose where to attach the control\r
138             if settings.REPORT_OFFENSIVE_CONTROL_POSITION.value == "more":\r
139                 menu.append(report_control)\r
140             else:\r
141                 controls.append(report_control)\r
142 \r
143         if user.can_delete_post(post):\r
144             if post.nis.deleted:\r
145                 controls.append(post_control(_('undelete'), reverse('delete_post', kwargs={'id': post.id}),\r
146                         command=True, confirm=True))\r
147             else:\r
148                 controls.append(post_control(_('delete'), reverse('delete_post', kwargs={'id': post.id}),\r
149                         command=True, confirm=True))\r
150 \r
151         if user.can_delete_post(post):\r
152             menu.append(post_control(_('see revisions'),\r
153                         reverse('revisions',\r
154                         kwargs={'id': post.id}),\r
155                         command=False, confirm=False))\r
156 \r
157         if settings.WIKI_ON:\r
158             if (not post.nis.wiki) and user.can_wikify(post):\r
159                 menu.append(post_control(_('mark as community wiki'), reverse('wikify', kwargs={'id': post.id}),\r
160                             command=True, confirm=True))\r
161 \r
162             elif post.nis.wiki and user.can_cancel_wiki(post):\r
163                 menu.append(post_control(_('cancel community wiki'), reverse('wikify', kwargs={'id': post.id}),\r
164                             command=True, confirm=True))\r
165 \r
166         if post.node_type == "answer" and user.can_convert_to_comment(post):\r
167             menu.append(post_control(_('convert to comment'), reverse('convert_to_comment', kwargs={'id': post.id}),\r
168                         command=True, withprompt=True))\r
169         \r
170         if post.node_type == "answer" and user.can_convert_to_question(post):\r
171             menu.append(post_control(_('convert to question'), reverse('convert_to_question', kwargs={'id': post.id}),\r
172                         command=False, confirm=True))\r
173 \r
174         if user.is_superuser or user.is_staff:\r
175             plain_text = strip_tags(post.html)\r
176 \r
177             char_count = len(plain_text)\r
178             fullStr = plain_text + " "\r
179             left_trimmedStr = re.sub(re.compile(r"^[^\w]+", re.IGNORECASE), "", fullStr)\r
180             cleanedStr = re.sub(re.compile(r"[^\w]+", re.IGNORECASE), " ", left_trimmedStr)\r
181             splitString = cleanedStr.split(" ")\r
182             word_count = len(splitString) - 1\r
183 \r
184             metrics = mark_safe("<b>%s %s / %s %s</b>" % (char_count, ungettext('character', 'characters', char_count),\r
185                                         word_count, ungettext('word', 'words', word_count)))\r
186 \r
187             menu.append(post_control(metrics, "#", command=False, withprompt=False))\r
188 \r
189     return {'controls': controls, 'menu': menu, 'post': post, 'user': user}\r
190 \r
191 @register.inclusion_tag('node/comments.html')\r
192 def comments(post, user):\r
193     all_comments = post.comments.filter_state(deleted=False)\\r
194                                 .order_by('-added_at' if settings.SHOW_LATEST_COMMENTS_FIRST else 'added_at')\r
195 \r
196     if len(all_comments) <= 5:\r
197         top_scorers = all_comments\r
198     else:\r
199         top_scorers = sorted(all_comments, lambda c1, c2: cmp(c2.score, c1.score))[0:5]\r
200 \r
201     comments = []\r
202     showing = 0\r
203     for c in all_comments:\r
204         context = {\r
205             'can_delete': user.can_delete_comment(c),\r
206             'can_like': user.can_like_comment(c),\r
207             'can_edit': user.can_edit_comment(c),\r
208             'can_convert': user.can_convert_comment_to_answer(c)\r
209         }\r
210 \r
211         if c in top_scorers or c.is_reply_to(user):\r
212             context['top_scorer'] = True\r
213             showing += 1\r
214         \r
215         if context['can_like']:\r
216             context['likes'] = VoteAction.get_for(user, c) == 1\r
217 \r
218         context['user'] = c.user\r
219         context['comment'] = c.comment\r
220         context.update(dict(c.__dict__))\r
221         comments.append(context)\r
222 \r
223     # Generate canned comments\r
224     canned_comments = []\r
225     for comment in settings.CANNED_COMMENTS:\r
226         t = Template(smart_unicode(comment))\r
227         c = Context({\r
228             'post' : post,\r
229             'settings' : settings,\r
230         })\r
231         canned_comments.append(t.render(c))\r
232 \r
233     total = len(all_comments)\r
234     return {\r
235         'comments': comments,\r
236         'canned_comments': canned_comments,\r
237         'post': post,\r
238         'can_comment': user.can_comment(post),\r
239         'max_length': settings.FORM_MAX_COMMENT_BODY,\r
240         'min_length': settings.FORM_MIN_COMMENT_BODY,\r
241         'show_gravatar': settings.FORM_GRAVATAR_IN_COMMENTS,\r
242         'showing': showing,\r
243         'total': total,\r
244         'more_comments_count' : int(total - showing),\r
245         'show_latest_comments_first' : settings.SHOW_LATEST_COMMENTS_FIRST,\r
246         'user': user,\r
247     }\r
248 \r
249 \r
250 @register.inclusion_tag("node/contributors_info.html")\r
251 def contributors_info(node, verb=None):\r
252     return {\r
253         'node_verb': verb and verb or ((node.node_type == "question") and _("asked") or (\r
254                     (node.node_type == "answer") and _("answered") or _("posted"))),\r
255         'node': node,\r
256     }\r
257 \r
258 @register.inclusion_tag("node/reviser_info.html")\r
259 def reviser_info(revision):\r
260     return {'revision': revision}\r