| author | gibus |
| Tue, 25 Jun 2013 11:56:01 +0200 | |
| changeset 504 | b2e0186daa5b |
| parent 435 | 96c16cc6408b |
| child 605 | 830993bdf983 |
| permissions | -rw-r--r-- |
|
323
addba77f2f90
email_re has moved from django.form.fields to django.core.validators (Django 1.2 alpha 1)
gibus
parents:
144
diff
changeset
|
1 |
try: |
|
addba77f2f90
email_re has moved from django.form.fields to django.core.validators (Django 1.2 alpha 1)
gibus
parents:
144
diff
changeset
|
2 |
from django.core.validators import email_re |
|
addba77f2f90
email_re has moved from django.form.fields to django.core.validators (Django 1.2 alpha 1)
gibus
parents:
144
diff
changeset
|
3 |
except ImportError: |
|
addba77f2f90
email_re has moved from django.form.fields to django.core.validators (Django 1.2 alpha 1)
gibus
parents:
144
diff
changeset
|
4 |
# support for django pre 1.2 alpha 1 |
|
addba77f2f90
email_re has moved from django.form.fields to django.core.validators (Django 1.2 alpha 1)
gibus
parents:
144
diff
changeset
|
5 |
from django.forms.fields import email_re |
| 0 | 6 |
from django.http import HttpResponse, HttpResponseRedirect |
7 |
from django.core.exceptions import ObjectDoesNotExist |
|
8 |
from django.forms import ValidationError |
|
9 |
from django.utils import simplejson |
|
10 |
from django.utils.translation import ugettext as _ |
|
11 |
from tagging.models import Tag |
|
12 |
from tagging.utils import parse_tag_input, LOGARITHMIC, calculate_cloud |
|
13 |
from tagging.models import TaggedItem |
|
14 |
from cm.models import * |
|
15 |
from cm.utils.timezone import request_tz_convert |
|
16 |
from itertools import groupby |
|
17 |
from time import mktime, sleep |
|
18 |
from cm.converters.pandoc_converters import pandoc_convert |
|
19 |
from cm.security import get_viewable_comments, list_viewable_comments, has_perm, has_perm_on_text, has_perm_on_comment, has_own_perm |
|
20 |
from cm.activity import register_activity |
|
21 |
from cm.utils.date import datetime_to_user_str, datetime_to_epoch |
|
| 426 | 22 |
from cm.cm_settings import AUTO_CONTRIB_REGISTER, DECORATED_CREATORS |
| 0 | 23 |
from settings import CLIENT_DATE_FMT |
24 |
import re |
|
25 |
import time |
|
26 |
import operator |
|
27 |
||
28 |
||
29 |
selection_place_error_msg = _(u'A selection is required. Select in the text the part your comment applies to.') |
|
30 |
comment_states = ('approved', 'unapproved', 'pending') |
|
31 |
||
32 |
def is_valid_email(email): |
|
33 |
if email_re.match(email) : |
|
34 |
return True |
|
35 |
return False |
|
36 |
||
37 |
# |
|
38 |
def jsonize(obj, request): |
|
39 |
return simplejson.dumps(obj, cls=RequestComplexEncoder, request=request) |
|
40 |
||
41 |
class RequestComplexEncoder(simplejson.JSONEncoder): |
|
42 |
def __init__(self, request, **kw): |
|
43 |
self.request = request |
|
44 |
simplejson.JSONEncoder.__init__(self, **kw) |
|
45 |
||
46 |
||
47 |
def default(self, obj): |
|
48 |
if isinstance(obj, Comment) : |
|
49 |
comment = obj |
|
50 |
#replies = list(comment.comment_set.order_by('created')) |
|
51 |
text=comment.text_version.text |
|
52 |
replies = get_viewable_comments(self.request, comment.comment_set.all(), text) |
|
53 |
||
54 |
# can_view == true because of get_viewable_comments filter |
|
55 |
can_moderate = has_perm(self.request, 'can_edit_comment', text) |
|
56 |
can_edit = has_perm(self.request, 'can_edit_comment', text) or has_own_perm(self.request, 'can_edit_comment_own', text, comment) |
|
57 |
can_delete = has_perm(self.request, 'can_delete_comment', text) or has_own_perm(self.request, 'can_delete_comment_own', text, comment) |
|
58 |
||
59 |
return {'id' : comment.id, |
|
60 |
'key' : comment.key, |
|
| 144 | 61 |
'id_key' : comment.id_key, |
| 0 | 62 |
'created_user_str' : datetime_to_user_str(request_tz_convert(comment.created, self.request)), |
63 |
'modified_user_str' : datetime_to_user_str(request_tz_convert(comment.modified, self.request)), |
|
64 |
# 'created_str' : datetime_to_str(comment.created), # TODO change to a simple number as modified if possible |
|
65 |
'created' : datetime_to_epoch(comment.created), # TODO change to a simple number as modified if possible |
|
66 |
'modified' : datetime_to_epoch(comment.modified), |
|
67 |
# 'modified' : time.mktime(comment.modified.timetuple()), |
|
68 |
# 'created' : datetime_to_js_date_str(comment.created), |
|
69 |
'reply_to_id' : comment.reply_to_id, |
|
70 |
'replies' : replies, |
|
71 |
'name' : comment.get_name(), |
|
72 |
'email' : comment.get_email(), |
|
73 |
'logged_author' : (comment.user != None), |
|
74 |
'title':comment.title, |
|
75 |
'content':comment.content, |
|
76 |
'content_html':comment.content_html, |
|
77 |
'tags': ', '.join(parse_tag_input(comment.tags)), |
|
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
78 |
'category': comment.category, |
| 0 | 79 |
'format': comment.format, |
80 |
'start_wrapper' : comment.start_wrapper, |
|
81 |
'end_wrapper' : comment.end_wrapper, |
|
82 |
'start_offset' : comment.start_offset, |
|
83 |
'end_offset' : comment.end_offset, |
|
84 |
'state' : comment.state, |
|
| 144 | 85 |
'permalink' : reverse('text-view-show-comment', args=[text.key, comment.id_key]), |
| 0 | 86 |
# permission |
87 |
'can_edit' : can_edit, |
|
88 |
'can_delete' : can_delete, |
|
89 |
'can_moderate' : can_moderate, |
|
90 |
} |
|
91 |
if isinstance(obj, Tag) : |
|
92 |
tag = obj |
|
93 |
# RBE each time issuing a db request to find comments related to this tag !!! TODO |
|
94 |
return { 'ids' : [t.id for t in tag.items.all()], 'name' : tag.name, 'font_size' : tag.font_size} |
|
95 |
||
96 |
return simplejson.JSONEncoder.default(self, obj) |
|
97 |
||
98 |
def experiment() : |
|
99 |
sleep(5) ; |
|
100 |
return {"key":"value"} |
|
101 |
||
102 |
def read_comment_args(request): |
|
103 |
name = request.POST.get('name', None) |
|
104 |
email = request.POST.get('email', None) |
|
105 |
if name != None : |
|
|
400
b82f4f749b44
Do not transform commentator's displayed name in lower case when posting comment.
Production Moz <dev@sopinspace.com>
parents:
323
diff
changeset
|
106 |
# GIB: Is there any good reasons to transform the name into lower case? |
|
b82f4f749b44
Do not transform commentator's displayed name in lower case when posting comment.
Production Moz <dev@sopinspace.com>
parents:
323
diff
changeset
|
107 |
#name = name.lower().strip() |
|
b82f4f749b44
Do not transform commentator's displayed name in lower case when posting comment.
Production Moz <dev@sopinspace.com>
parents:
323
diff
changeset
|
108 |
name = name.strip() |
| 0 | 109 |
if email != None : |
110 |
email = email.lower().strip() |
|
111 |
||
112 |
title = request.POST['title'].strip() |
|
113 |
content = request.POST['content'].strip() |
|
114 |
||
115 |
tags = request.POST['tags'] |
|
116 |
||
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
117 |
category = request.POST.get('category', 0); |
|
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
118 |
|
| 0 | 119 |
reply_to_id = request.POST.get('reply_to_id', None) |
120 |
||
121 |
format = request.POST['format'] |
|
122 |
||
123 |
start_wrapper = request.POST.get('start_wrapper', None) |
|
124 |
end_wrapper = request.POST.get('end_wrapper', None) |
|
125 |
start_offset = request.POST.get('start_offset', None) |
|
126 |
end_offset = request.POST.get('end_offset', None) |
|
127 |
||
128 |
if start_wrapper : |
|
129 |
start_wrapper = int(start_wrapper.strip()) |
|
130 |
if end_wrapper : |
|
131 |
end_wrapper = int(end_wrapper.strip()) |
|
132 |
if start_offset : |
|
133 |
start_offset = int(start_offset.strip()) |
|
134 |
if end_offset : |
|
135 |
end_offset = int(end_offset.strip()) |
|
136 |
||
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
137 |
return name, email, title, content, tags, category, reply_to_id, format, start_wrapper, end_wrapper, start_offset, end_offset |
| 0 | 138 |
|
139 |
def validate_comment_args(name, email, title, content, tags): |
|
140 |
errors = {} |
|
141 |
if name != None : |
|
142 |
if name == "" : |
|
143 |
errors['name'] = _(u'name is required') |
|
144 |
if email != None : |
|
145 |
if email == "" : |
|
146 |
errors['email'] = _(u'email is required') |
|
147 |
if not is_valid_email(email) : |
|
148 |
errors['email'] = _('invalid email') |
|
149 |
if title == "" : |
|
150 |
errors['title'] = _(u'title is required') |
|
151 |
if content == "" : |
|
152 |
errors['content'] = _(u'content is required') |
|
153 |
||
154 |
tag_errors = validate_tags(tags) |
|
155 |
if tag_errors != "" : |
|
156 |
errors['tags'] = tag_errors |
|
157 |
||
158 |
return errors |
|
159 |
||
160 |
@has_perm_on_comment("can_delete_comment") |
|
161 |
def remove_comment(request, key, comment_key): |
|
162 |
ret={} |
|
163 |
try: |
|
164 |
text = Text.objects.get(key=key) |
|
165 |
comment = Comment.objects.get(key = comment_key) |
|
166 |
comment.delete() |
|
167 |
ret['msg'] = _(u'comment removed') |
|
168 |
register_activity(request, "comment_removed", text=text, comment=comment) |
|
169 |
except ObjectDoesNotExist: |
|
170 |
pass |
|
171 |
return ret ; |
|
172 |
||
173 |
@has_perm_on_comment("can_edit_comment") |
|
174 |
def edit_comment(request, key, comment_key): |
|
175 |
state = request.POST.get('state', None) |
|
176 |
change_state = state and state in comment_states |
|
177 |
||
178 |
errors = {} |
|
179 |
if not change_state : # moderation action |
|
180 |
change_scope = request.POST.get('change_scope', None) |
|
181 |
||
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
182 |
name, email, title, content, tags, category, reply_to_id, format, start_wrapper, end_wrapper, start_offset, end_offset = read_comment_args(request) |
| 0 | 183 |
|
184 |
errors = validate_comment_args(name, email, title, content, tags) |
|
185 |
||
186 |
if (change_scope) and start_wrapper=="" : |
|
187 |
errors['selection_place'] = selection_place_error_msg |
|
188 |
||
189 |
content_html = pandoc_convert(content, format, "html", full=False) |
|
190 |
||
191 |
ret = {} |
|
192 |
if errors != {} : |
|
193 |
ret['errors'] = errors |
|
194 |
else : |
|
195 |
# INSERT |
|
| 106 | 196 |
# TODO check version is latest (if boolean |
| 0 | 197 |
#comment = Comment.objects.get(id=edit_comment_id) |
198 |
comment = Comment.objects.get(key=comment_key) |
|
199 |
if change_state : # moderation action |
|
200 |
comment.state = state |
|
201 |
else : |
|
202 |
comment.name = name |
|
203 |
comment.email = email |
|
204 |
comment.title = title |
|
205 |
comment.content = content |
|
206 |
comment.content_html = content_html |
|
207 |
comment.tags = tags |
|
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
208 |
comment.category = category |
| 0 | 209 |
|
210 |
if change_scope : |
|
211 |
comment.start_wrapper = start_wrapper |
|
212 |
comment.start_offset = start_offset |
|
213 |
comment.end_wrapper = end_wrapper |
|
214 |
comment.end_offset = end_offset |
|
215 |
||
216 |
comment.save() |
|
217 |
||
218 |
ret['comment'] = comment |
|
219 |
ret['msg'] = _(u'comment saved') |
|
220 |
return ret |
|
221 |
||
| 12 | 222 |
# DIRTY : this function has no error check but anyway errors are not listened to client side |
223 |
@has_perm_on_text("can_create_comment") |
|
224 |
def own_notify(request, key): |
|
225 |
email_or_user = None if request.user.is_anonymous() else request.user |
|
226 |
if not email_or_user : |
|
227 |
email_or_user = request.POST.get('email', None) |
|
228 |
if email_or_user : |
|
229 |
email_or_user = email_or_user.lower().strip() |
|
230 |
||
|
17
a4be0b8a905d
bug fix : can view own comment on comment add on mod priori
reno
parents:
12
diff
changeset
|
231 |
active = (request.POST.get('active', False) == 'true') |
| 12 | 232 |
text = Text.objects.get(key=key) |
|
17
a4be0b8a905d
bug fix : can view own comment on comment add on mod priori
reno
parents:
12
diff
changeset
|
233 |
Notification.objects.set_notification(text=None, type='own', active=active, email_or_user=email_or_user) |
| 12 | 234 |
ret = HttpResponse() |
235 |
ret.status_code = 200 |
|
236 |
return ret |
|
237 |
||
| 0 | 238 |
@has_perm_on_text("can_create_comment") |
| 24 | 239 |
def add_comment(request, key, version_key): |
| 0 | 240 |
# if edit_comment_id : # |
241 |
# if self.request.user.is_anonymous() : # accessing via an admin url ? |
|
242 |
# and comment.user == self.request.user |
|
243 |
user = None if request.user.is_anonymous() else request.user |
|
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
244 |
name, email, title, content, tags, category, reply_to_id, format, start_wrapper, end_wrapper, start_offset, end_offset = read_comment_args(request) |
| 0 | 245 |
errors = {} |
246 |
errors = validate_comment_args(name, email, title, content, tags) |
|
247 |
||
248 |
if start_wrapper == "" : |
|
249 |
errors['selection_place'] = selection_place_error_msg |
|
250 |
||
251 |
#TODO validate pandoc conversion |
|
252 |
content_html = pandoc_convert(content, format, "html", full=False) |
|
253 |
||
254 |
ret = {} |
|
255 |
if errors != {} : |
|
256 |
ret['errors'] = errors |
|
257 |
else : |
|
258 |
# INSERT |
|
259 |
# TODO check version still exist ... |
|
260 |
reply_to = None |
|
261 |
if reply_to_id : |
|
262 |
reply_to = Comment.objects.get(id=reply_to_id) |
|
263 |
||
264 |
text = Text.objects.get(key=key) |
|
| 24 | 265 |
text_version = TextVersion.objects.get(key=version_key) |
| 0 | 266 |
|
267 |
comment_state = 'approved' if text_version.mod_posteriori else 'pending' |
|
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
268 |
comment = Comment.objects.create(state=comment_state, text_version=text_version, user=user, name=name, email=email, title=title, content=content, content_html=content_html, tags = tags, category = category, start_wrapper = start_wrapper, end_wrapper = end_wrapper, start_offset = start_offset, end_offset = end_offset, reply_to=reply_to) |
| 0 | 269 |
|
| 12 | 270 |
ask_for_notification = True |
271 |
if user : |
|
272 |
workspace_notify_count = Notification.objects.filter(text=None,type='workspace',user=user, active=True).count() |
|
273 |
text_notify_count = Notification.objects.filter(text=text,type='text',user=user, active=True).count() |
|
274 |
if workspace_notify_count > 0 or text_notify_count > 0 : |
|
275 |
ask_for_notification = False |
|
276 |
||
277 |
if ask_for_notification : |
|
278 |
ask_for_notification = ( None == Notification.objects.get_notifications(text=None, type='own', email_or_user=(user if user else email))) |
|
279 |
ret['ask_for_notification'] = ask_for_notification |
|
280 |
ret['email'] = '' if user else email |
|
|
17
a4be0b8a905d
bug fix : can view own comment on comment add on mod priori
reno
parents:
12
diff
changeset
|
281 |
|
|
a4be0b8a905d
bug fix : can view own comment on comment add on mod priori
reno
parents:
12
diff
changeset
|
282 |
if text_version.mod_posteriori or has_perm(request, 'can_view_unapproved_comment', text=text) or has_perm(request, 'can_view_comment_own', text=text) : |
| 0 | 283 |
ret['comment'] = comment |
284 |
ret['msg'] = _(u"comment saved") |
|
285 |
else : |
|
286 |
ret['msg'] = _(u"comment saved, it is being held for moderation") |
|
287 |
||
288 |
if AUTO_CONTRIB_REGISTER: |
|
| 12 | 289 |
Notification.objects.set_notification(text=text, type='own', active=True, email_or_user=user or email) |
| 0 | 290 |
register_activity(request, "comment_created", text, comment) |
291 |
return ret |
|
292 |
||
293 |
#we need to call comments_thread from here this function will be very expensive |
|
294 |
# TODO: stupid get rid of text argument |
|
295 |
def get_filter_datas(request, text_version, text): |
|
296 |
from django.db.models import Count |
|
297 |
from datetime import datetime, timedelta |
|
298 |
||
299 |
allowed_ids = [c.id for c in comments_thread(request, text_version, text)] |
|
300 |
allowed_comments = Comment.objects.filter(Q(text_version=text_version),Q(deleted=False),Q(id__in=allowed_ids)) |
|
301 |
#print allowed_ids |
|
302 |
||
303 |
# authors |
|
304 |
# names = list(Comment.objects.filter(text_version__text__key=key).filter(user__isnull=True).values('name').annotate(nb_comments=Count('id'))) #.order_by('name')) |
|
305 |
names = list(allowed_comments.filter(user__isnull=True).values('name').annotate(nb_comments=Count('id'))) #.order_by('name')) |
|
| 426 | 306 |
if DECORATED_CREATORS: |
307 |
names = list(allowed_comments.filter(user__isnull=False).values('name').annotate(nb_comments=Count('id'))) #.order_by('name')) |
|
308 |
author = text_version.name |
|
309 |
else: |
|
310 |
names += list(User.objects.filter(Q(comment__text_version=text_version),Q(comment__deleted=False), Q(comment__id__in=allowed_ids)).extra(select={'name': "username"}).values('name').annotate(nb_comments=Count('id'))) #.order_by('username')) |
|
| 429 | 311 |
has_author = User.objects.filter(id=text_version.user_id).values('username') |
312 |
if has_author: |
|
313 |
author = has_author[0]['username'] |
|
314 |
else: |
|
315 |
author = '' |
|
| 426 | 316 |
if request.GET.get('name', None): |
317 |
me = request.GET.get('name', None) |
|
318 |
else: |
|
319 |
me = request.user.username |
|
320 |
for name in names: |
|
|
435
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
321 |
if name['name']: |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
322 |
if name['name'] == me: |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
323 |
name['display'] = _(u'me') + ' (' + name['name'] + ')' |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
324 |
elif name['name'] == author: |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
325 |
name['display'] = _(u'author') + ' (' + name['name'] + ')' |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
326 |
else: |
|
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
327 |
name['display'] = name['name'] |
| 426 | 328 |
else: |
|
435
96c16cc6408b
Fixed comments filter by name when name is empty
Production Moz <dev@sopinspace.com>
parents:
431
diff
changeset
|
329 |
name['display'] = '' |
| 426 | 330 |
|
331 |
def sort_with_author_or_me_first(x, y): |
|
| 431 | 332 |
if x and (x.startswith(_(u'me')) or x.startswith(_(u'author'))): |
| 426 | 333 |
return -1 |
| 431 | 334 |
if y and (y.startswith(_(u'me')) or y.startswith(_(u'author'))): |
| 426 | 335 |
return 1 |
336 |
else: |
|
337 |
return cmp(x, y) |
|
338 |
||
339 |
names.sort(cmp = sort_with_author_or_me_first, key = lambda obj:obj["display"]) |
|
| 0 | 340 |
|
341 |
# dates |
|
342 |
# TODO maybe optimize by comparing dates in python and saving these 'by day db requests' |
|
343 |
nb_days = [1, 3, 7, 30] |
|
344 |
dates = [] |
|
345 |
today = datetime.today() |
|
346 |
for nb_day in nb_days : |
|
347 |
day_date = today - timedelta(nb_day) |
|
348 |
dates.append({'nb_day' : nb_day, 'nb_day_date':datetime_to_epoch(day_date), 'nb_comments':allowed_comments.filter(modified__gt = day_date).count()}) |
|
349 |
||
350 |
# tags |
|
351 |
comment_ids = [c.id for c in allowed_comments] |
|
352 |
tags = list(Tag.objects.filter(items__content_type = ContentType.objects.get_for_model(Comment),items__object_id__in=comment_ids).values("name").annotate(nb_comments=Count('id')).distinct().order_by('name')) |
|
353 |
||
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
354 |
# categories |
|
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
355 |
categories = [] |
|
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
356 |
for category in [0, 1, 2, 3, 4, 5] : |
|
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
357 |
categories.append({'cat' : category, 'nb_comments':allowed_comments.filter(category = category).count()}) |
|
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
358 |
|
| 0 | 359 |
# states |
360 |
states = [] |
|
361 |
for state in comment_states : |
|
362 |
states.append({'state' : state, 'nb_comments':allowed_comments.filter(state = state).count()}) |
|
363 |
||
|
504
b2e0186daa5b
Adds a category to comments, painted with colored vertical bar.
gibus
parents:
435
diff
changeset
|
364 |
return {'names':names, 'dates':dates, 'tags':tags, 'categories':categories, 'states':states} |
| 0 | 365 |
|
366 |
#def get_ordered_ids(text_version_id): |
|
367 |
# comments_and_replies = Comment.objects.filter(text_version__id=text_version_id) |
|
368 |
# comments = comments_and_replies.filter(reply_to__isnull=True) |
|
369 |
# |
|
370 |
# dic = {} |
|
371 |
# for c in comments_and_replies : |
|
372 |
# top_comment = c.top_comment() |
|
373 |
# max_modif = dic.get(top_comment.id, c.modified) |
|
374 |
# dic[top_comment.id] = c.modified if max_modif < c.modified else max_modif |
|
375 |
# |
|
376 |
# ordered_comment_ids = {'scope' : [c.id for c in comments.order_by('start_wrapper','start_offset','end_offset')], |
|
377 |
# 'thread_modified' : map(operator.itemgetter(0), sorted(dic.items(), key=operator.itemgetter(1)))} |
|
378 |
# return ordered_comment_ids |
|
379 |
||
380 |
def validate_tags(tags): |
|
381 |
if tags : |
|
382 |
try : |
|
383 |
if len(tags) > 250 : |
|
384 |
return _(u"Tags input must be no longer than 250 characters.") |
|
385 |
TagField().formfield().clean(tags) |
|
386 |
except ValidationError, e : |
|
387 |
return ",".join(e.messages) |
|
388 |
return '' |
|
389 |
||
390 |
MAX_NB_TAGS_IN_COMMENT_CLOUD = 30 |
|
391 |
def get_tagcloud(key) : |
|
392 |
tagCloud = Tag.objects.cloud_for_model(Comment, steps=8, distribution=LOGARITHMIC, filters=dict(text_version__text__key=key)) |
|
393 |
return tagCloud |
|
394 |
||
395 |
# returns a flat list of viewable comments and their replies ordered as they should be : |
|
396 |
# order is : |
|
397 |
# 'start_wrapper','start_offset','end_wrapper','end_offset' for 'real' comments |
|
398 |
# 'created' for replies |
|
399 |
# TODO: get rid of text here, keep text_version |
|
400 |
def comments_thread(request, text_version, text) : |
|
401 |
commentsnoreply = text_version.comment_set.filter(reply_to__isnull=True)#id=3) |
|
402 |
viewable_commentsnoreply = get_viewable_comments(request, commentsnoreply, text, order_by = ('start_wrapper','start_offset','end_wrapper','end_offset')) |
|
403 |
viewable_comments = [] |
|
404 |
for cc in viewable_commentsnoreply : |
|
405 |
viewable_comments += list_viewable_comments(request, [cc], text) |
|
406 |
return viewable_comments |
|
407 |