| author | raph |
| Mon, 17 May 2010 15:23:41 +0200 | |
| changeset 279 | 46b0773c20c1 |
| parent 274 | e49623f99d02 |
| child 301 | 6e8fb4869d50 |
| permissions | -rw-r--r-- |
| 24 | 1 |
from cm.utils.embed import embed_html |
| 0 | 2 |
from cm.activity import register_activity |
3 |
from cm.client import jsonize, get_filter_datas, edit_comment, remove_comment, \ |
|
| 12 | 4 |
add_comment, RequestComplexEncoder, comments_thread, own_notify |
| 0 | 5 |
from cm.cm_settings import NEW_TEXT_VERSION_ON_EDIT |
6 |
from cm.exception import UnauthorizedException |
|
7 |
from cm.message import * |
|
8 |
from cm.models import * |
|
| 70 | 9 |
from django.forms.util import ErrorList |
| 0 | 10 |
from cm.models_base import generate_key |
11 |
from cm.security import get_texts_with_perm, has_perm, get_viewable_comments, \ |
|
12 |
has_perm_on_text |
|
13 |
from cm.utils import get_among, get_among, get_int |
|
| 175 | 14 |
from cm.utils.html import on_content_receive |
| 0 | 15 |
from cm.utils.comment_positioning import compute_new_comment_positions, \ |
16 |
insert_comment_markers |
|
17 |
from cm.utils.spannifier import spannify |
|
| 24 | 18 |
from cm.views import get_keys_from_dict, get_textversion_by_keys_or_404, get_text_by_keys_or_404, redirect |
| 103 | 19 |
from cm.views.export import content_export2, content_export |
| 0 | 20 |
from cm.views.user import AnonUserRoleForm, cm_login |
21 |
from difflib import unified_diff |
|
22 |
from django import forms |
|
23 |
from django.conf import settings |
|
24 |
from django.contrib.auth import login as django_login |
|
25 |
from django.contrib.auth.forms import AuthenticationForm |
|
26 |
from django.contrib.auth.models import User |
|
27 |
from django.core.urlresolvers import reverse |
|
28 |
from django.db.models import Q |
|
29 |
from django.forms import ModelForm |
|
30 |
from django.forms.models import BaseModelFormSet, modelformset_factory |
|
31 |
from django.http import HttpResponse, HttpResponseRedirect, Http404 |
|
32 |
from django.shortcuts import render_to_response |
|
33 |
from django.template import RequestContext |
|
34 |
from django.template.loader import render_to_string |
|
35 |
from django.utils.translation import ugettext as _, ugettext_lazy |
|
36 |
from django.views.generic.list_detail import object_list |
|
| 38 | 37 |
from tagging.models import Tag |
| 0 | 38 |
import difflib |
39 |
import logging |
|
40 |
import mimetypes |
|
41 |
import simplejson |
|
42 |
import sys |
|
| 231 | 43 |
import re |
| 74 | 44 |
from django.db.models.sql.datastructures import EmptyResultSet |
| 0 | 45 |
|
46 |
def get_text_and_admin(key, adminkey, assert_admin = False): |
|
47 |
""" |
|
48 |
assert_admin => redirect to unauthorized if not admin |
|
49 |
""" |
|
50 |
admin = False |
|
51 |
if adminkey: |
|
52 |
text = Text.objects.get(key = key, adminkey = adminkey) |
|
53 |
if text: |
|
54 |
admin = True |
|
55 |
else: |
|
56 |
text = Text.objects.get(key=key) |
|
57 |
if assert_admin and not admin: |
|
58 |
raise UnauthorizedException('Is not admin') |
|
59 |
return text, admin |
|
60 |
||
61 |
||
62 |
||
63 |
ACTIVITY_PAGINATION = 10 |
|
64 |
RECENT_TEXT_NB = 5 |
|
65 |
RECENT_COMMENT_NB = RECENT_TEXT_NB |
|
66 |
||
67 |
MODERATE_NB = 5 |
|
68 |
||
69 |
def dashboard(request): |
|
70 |
request.session.set_test_cookie() |
|
71 |
if request.user.is_authenticated(): |
|
72 |
act_view = { |
|
| 279 | 73 |
'view_texts' : get_int(request.GET, 'view_texts',1), |
74 |
'view_comments' : get_int(request.GET, 'view_comments',1), |
|
75 |
'view_users' : get_int(request.GET, 'view_users',1), |
|
| 0 | 76 |
} |
77 |
||
| 279 | 78 |
paginate_by = get_int(request.GET, 'paginate', ACTIVITY_PAGINATION) |
| 0 | 79 |
|
80 |
# texts with can_view_unapproved_comment perms |
|
81 |
moderator_texts = get_texts_with_perm(request, 'can_view_unapproved_comment') |
|
82 |
viewer_texts = get_texts_with_perm(request, 'can_view_approved_comment') |
|
83 |
all_texts_ids = [t.id for t in moderator_texts] + [t.id for t in viewer_texts] |
|
84 |
||
| 279 | 85 |
span = get_among(request.GET, 'span', ('day','month','week',),'week') |
| 0 | 86 |
template_dict = { |
87 |
'span' : span, |
|
88 |
'last_texts' : get_texts_with_perm(request, 'can_view_text').order_by('-modified')[:RECENT_TEXT_NB], |
|
89 |
'last_comments' : Comment.objects.filter(text_version__text__in=all_texts_ids).order_by('-created')[:RECENT_COMMENT_NB],# TODO: useful? |
|
90 |
#'last_users' : User.objects.all().order_by('-date_joined')[:5], |
|
91 |
} |
|
92 |
template_dict.update(act_view) |
|
93 |
||
94 |
all_activities = { |
|
95 |
'view_comments' : ['comment_created','comment_removed'], |
|
96 |
'view_users' : ['user_created', 'user_activated', 'user_suspended','user_enabled',], |
|
97 |
'view_texts' : ['text_created','text_removed', 'text_edited', 'text_edited_new_version'], |
|
98 |
} |
|
99 |
||
100 |
selected_activities = [] |
|
101 |
[selected_activities.extend(all_activities[k]) for k in act_view.keys() if act_view[k]] |
|
102 |
||
103 |
activities = Activity.objects.filter(type__in = selected_activities) |
|
104 |
if not has_perm(request,'can_manage_workspace'): |
|
105 |
texts = get_texts_with_perm(request, 'can_view_text') |
|
106 |
activities = activities.filter(Q(text__in=texts)) |
|
107 |
||
108 |
comments = [] |
|
109 |
[comments.extend(get_viewable_comments(request, t.last_text_version.comment_set.all(), t)) for t in texts] |
|
110 |
||
111 |
activities = activities.filter(Q(comment__in=comments) | Q(comment=None) ) |
|
112 |
template_dict['to_mod_profiles'] = [] |
|
113 |
else: |
|
114 |
template_dict['to_mod_profiles'] = UserProfile.objects.filter(user__is_active=False).filter(is_suspended=True).order_by('-user__date_joined')[:MODERATE_NB] |
|
115 |
template_dict['to_mod_comments'] = Comment.objects.filter(state='pending').filter(text_version__text__in=moderator_texts).order_by('-modified')[:MODERATE_NB-len(template_dict['to_mod_profiles'])] |
|
116 |
||
117 |
activities = activities.order_by('-created') |
|
118 |
return object_list(request, activities, |
|
119 |
template_name = 'site/dashboard.html', |
|
120 |
paginate_by = paginate_by, |
|
121 |
extra_context = template_dict, |
|
122 |
) |
|
123 |
||
124 |
else: |
|
125 |
if request.method == 'POST': |
|
126 |
form = AuthenticationForm(request, request.POST) |
|
127 |
if form.is_valid(): |
|
128 |
user = form.get_user() |
|
129 |
user.backend = 'django.contrib.auth.backends.ModelBackend' |
|
130 |
cm_login(request, user) |
|
131 |
display_message(request, _(u"You're logged in!")) |
|
132 |
return HttpResponseRedirect(reverse('index')) |
|
133 |
else: |
|
134 |
form = AuthenticationForm() |
|
135 |
||
136 |
||
137 |
public_texts = get_texts_with_perm(request, 'can_view_text').order_by('-modified') |
|
138 |
||
139 |
template_dict = { |
|
140 |
'form' : form, |
|
141 |
'texts' : public_texts, |
|
142 |
} |
|
143 |
return render_to_response('site/non_authenticated_index.html', template_dict, context_instance=RequestContext(request)) |
|
144 |
||
145 |
TEXT_PAGINATION = 10 |
|
146 |
# security check inside view |
|
147 |
# TODO: set global access perm |
|
148 |
def text_list(request): |
|
149 |
paginate_by = get_int(request.GET,'paginate',TEXT_PAGINATION) |
|
| 38 | 150 |
tag_selected = request.GET.get('tag_selected', 0) |
151 |
||
| 0 | 152 |
order_by = get_among(request.GET,'order',('title','author','modified','-title','-author','-modified'),'-modified') |
153 |
||
154 |
if request.method == 'POST': |
|
155 |
action = request.POST.get('action',None) |
|
156 |
text_keys = get_keys_from_dict(request.POST, 'check-').keys() |
|
157 |
if action == 'delete': |
|
158 |
for text_key in text_keys: |
|
159 |
text = Text.objects.get(key=text_key) |
|
160 |
if has_perm(request, 'can_delete_text', text=text): |
|
161 |
text.delete() |
|
162 |
else: |
|
163 |
raise UnauthorizedException('No perm can_delete_text on comment') |
|
164 |
display_message(request, _(u'%(nb_texts)i text(s) deleted') %{'nb_texts':len(text_keys)}) |
|
165 |
return HttpResponseRedirect(reverse('text')) |
|
166 |
||
167 |
texts = get_texts_with_perm(request, 'can_view_text').order_by(order_by) |
|
| 38 | 168 |
|
| 74 | 169 |
try: |
170 |
tag_list = Tag.objects.usage_for_queryset(TextVersion.objects.filter(id__in = [t.last_text_version_id for t in get_texts_with_perm(request, 'can_view_text')])) |
|
171 |
except EmptyResultSet: |
|
172 |
tag_list = [] |
|
| 38 | 173 |
context = { |
| 74 | 174 |
'tag_list' : tag_list, |
| 38 | 175 |
'tag_selected': tag_selected, |
176 |
} |
|
177 |
||
178 |
if tag_selected: |
|
179 |
tag_ids = Tag.objects.filter(name=tag_selected) |
|
180 |
if tag_ids: |
|
181 |
content_type_id = ContentType.objects.get_for_model(TextVersion).pk |
|
182 |
# table cm_userprofile is not present if display_suspended_users: fix this |
|
183 |
texts = texts.extra(where=['tagging_taggeditem.object_id = cm_text.last_text_version_id', |
|
184 |
'tagging_taggeditem.content_type_id = %i' %content_type_id, |
|
185 |
'tagging_taggeditem.tag_id = %i' %tag_ids[0].id], |
|
186 |
tables=['tagging_taggeditem'], |
|
187 |
) |
|
188 |
||
| 0 | 189 |
return object_list(request, texts, |
190 |
template_name = 'site/text_list.html', |
|
191 |
paginate_by = paginate_by, |
|
| 38 | 192 |
extra_context=context, |
| 0 | 193 |
) |
194 |
||
195 |
@has_perm_on_text('can_view_text') |
|
196 |
def text_view(request, key, adminkey=None): |
|
197 |
text = get_text_by_keys_or_404(key) |
|
198 |
register_activity(request, "text_view", text=text) |
|
| 24 | 199 |
text_version = text.get_latest_version() |
| 103 | 200 |
embed_code = embed_html(key, 'id="text_view_frame" name="text_view_frame"', None, request.META.get('QUERY_STRING')) |
| 24 | 201 |
template_dict = { 'embed_code':embed_code, 'text' : text, 'text_version' : text_version, 'title' : text_version.title, 'content' : text_version.get_content()} |
| 0 | 202 |
return render_to_response('site/text_view.html', template_dict, context_instance=RequestContext(request)) |
203 |
||
204 |
@has_perm_on_text('can_delete_text') |
|
205 |
def text_delete(request, key): |
|
206 |
text = Text.objects.get(key=key) |
|
207 |
if request.method != 'POST': |
|
208 |
raise UnauthorizedException('Unauthorized') |
|
209 |
display_message(request, _(u'Text %(text_title)s deleted') %{'text_title':text.title}) |
|
210 |
register_activity(request, "text_removed", text=text) |
|
211 |
text.delete() |
|
212 |
return HttpResponse('') # no redirect because this is called by js |
|
213 |
||
| 145 | 214 |
@has_perm_on_text('can_delete_text') |
215 |
def text_version_delete(request, key, text_version_key): |
|
216 |
text_version = TextVersion.objects.get(key=text_version_key) |
|
217 |
text=text_version.text |
|
218 |
if request.method != 'POST': |
|
219 |
raise UnauthorizedException('Unauthorized') |
|
220 |
display_message(request, _(u'Text version %(text_version_title)s deleted') %{'text_version_title':text_version.title}) |
|
221 |
register_activity(request, "text_version_removed", text=text) |
|
222 |
text_version.delete() |
|
223 |
return HttpResponse('') # no redirect because this is called by js |
|
224 |
||
225 |
||
| 0 | 226 |
@has_perm_on_text('can_view_text') # only protected by text_view / comment filtering done in view |
| 24 | 227 |
def text_view_comments(request, key, version_key=None, adminkey=None): |
| 0 | 228 |
text = get_text_by_keys_or_404(key) |
|
114
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
229 |
|
|
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
230 |
read_only = False |
| 24 | 231 |
if version_key : |
232 |
text_version = get_textversion_by_keys_or_404(version_key, adminkey, key) |
|
|
114
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
233 |
if settings.ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY : |
|
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
234 |
read_only = (text.last_text_version_id != text_version.id) |
| 24 | 235 |
else : |
236 |
text_version = text.get_latest_version() |
|
|
114
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
237 |
|
| 0 | 238 |
comments = get_viewable_comments(request, text_version.comment_set.filter(reply_to__isnull=True),text) |
239 |
filter_datas = get_filter_datas(request, text_version, text) |
|
240 |
||
241 |
get_params = simplejson.dumps(request.GET) |
|
242 |
wrapped_text_version, _ , _ = spannify(text_version.get_content()) |
|
243 |
template_dict = {'text' : text, |
|
244 |
'text_version' : text_version, |
|
245 |
'title' : text_version.title, # TODO use it ... |
|
246 |
'get_params' : get_params, |
|
247 |
'json_comments':jsonize(comments, request), |
|
248 |
'json_filter_datas':jsonize(filter_datas, request), |
|
249 |
'content' : wrapped_text_version, |
|
250 |
'client_date_fmt' : settings.CLIENT_DATE_FMT, |
|
|
114
49647a504de8
ENH ticket 20 disable edit in versions tab added ALLOW_CLIENT_MODIF_ON_LAST_VERSION_ONLY to settings.py
rbernard
parents:
106
diff
changeset
|
251 |
'read_only' : read_only, |
| 0 | 252 |
} |
253 |
return render_to_response('site/text_view_comments.html', |
|
254 |
template_dict, |
|
255 |
context_instance=RequestContext(request)) |
|
256 |
def client_exchange(request): |
|
257 |
ret = None |
|
| 106 | 258 |
if request.method == 'POST' : |
259 |
function_name = request.POST['fun']# function called from client |
|
260 |
user = request.user |
|
261 |
if function_name == 'experiment' : |
|
262 |
ret = experiment() |
|
263 |
elif function_name == 'warn' : |
|
264 |
# TODO: (RBE to RBA) send mail withinfos |
|
265 |
ret = "warn test" |
|
266 |
#print request.POST |
|
267 |
else : |
|
268 |
key = request.POST['key'] |
|
269 |
version_key = request.POST['version_key'] |
|
270 |
||
| 279 | 271 |
text = Text.objects.get(key=key) |
| 106 | 272 |
#TODO: stupid why restrict to latest ? |
273 |
text_version = text.get_latest_version() |
|
274 |
||
275 |
if (text != None) : |
|
276 |
if function_name == 'ownNotify' : |
|
277 |
ret = own_notify(request=request, key=key) |
|
278 |
if function_name in ('editComment', 'addComment', 'removeComment',) : |
|
279 |
if function_name == 'editComment' : |
|
280 |
ret = edit_comment(request=request, key=key, comment_key=request.POST['comment_key']) |
|
281 |
elif function_name == 'addComment' : |
|
282 |
ret = add_comment(request=request, key=key, version_key=version_key) |
|
283 |
elif function_name == 'removeComment' : |
|
284 |
ret = remove_comment(request=request, key=key, comment_key=request.POST['comment_key']) |
|
285 |
||
286 |
ret['filterData'] = get_filter_datas(request, text_version, text) |
|
287 |
#ret['tagCloud'] = get_tagcloud(key) |
|
| 0 | 288 |
if ret : |
| 12 | 289 |
if type(ret) != HttpResponseRedirect and type(ret) != HttpResponse: |
| 0 | 290 |
ret = HttpResponse(simplejson.dumps(ret, cls=RequestComplexEncoder, request=request)) |
291 |
else : |
|
| 12 | 292 |
ret = HttpResponse() |
293 |
ret.status_code = 403 |
|
| 0 | 294 |
return ret |
295 |
||
296 |
||
| 231 | 297 |
def from_html_links_to_abs_links(content): |
298 |
""" |
|
299 |
Replaces (html) links to attachs with real file path on server |
|
300 |
""" |
|
301 |
attach_re = r'/text/(?P<key>\w*)/attach/(?P<attach_key>\w*)/' |
|
302 |
attach_str = r'/text/%s/attach/%s/' |
|
303 |
for match in re.findall(attach_re, content): |
|
304 |
link = attach_str %match |
|
305 |
attach = Attachment.objects.get(key=match[1], text_version__text__key=match[0]) |
|
306 |
content = content.replace(link, attach.data.path) |
|
307 |
return content |
|
308 |
||
| 0 | 309 |
#NOTE : some arguments like : withcolor = "yes" + format = "markdown" are incompatible |
310 |
#http://localhost:8000/text/text_key_1/export/pdf/1/all/1 |
|
311 |
def text_export(request, key, format, download, whichcomments, withcolor, adminkey=None): |
|
312 |
text, admin = get_text_and_admin(key, adminkey) |
|
313 |
text_version = text.get_latest_version() |
|
314 |
original_content = text_version.content |
|
315 |
original_format = text_version.format # BD : html or markdown for now ... |
|
316 |
||
317 |
download_response = download == "1" |
|
318 |
with_color = withcolor == "1" |
|
319 |
||
320 |
comments = [] # whichcomments=="none" |
|
321 |
||
322 |
if whichcomments == "filtered" or whichcomments == "all": |
|
323 |
#comments = text_version.comment_set.filter(reply_to__isnull=True)# whichcomments=="all" |
|
324 |
#comments = get_viewable_comments(request, text_version.comment_set.filter(reply_to__isnull=True), text, order_by=('start_wrapper','start_offset','end_wrapper','end_offset'))# whichcomments=="all" |
|
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
325 |
|
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
326 |
_comments = text_version.comment_set.all() |
| 0 | 327 |
if whichcomments == "filtered" : |
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
328 |
filteredIds = [] |
| 0 | 329 |
if request.method == 'POST' : |
330 |
ll = request.POST.get('filteredIds',[]).split(",") |
|
331 |
filteredIds = [ int(l) for l in ll if l] |
|
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
332 |
_comments = text_version.comment_set.filter(id__in=filteredIds) # security ! TODO CROSS PERMISSIONS WITH POST CONTENT |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
333 |
|
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
334 |
comments = get_viewable_comments(request, _comments, text, order_by=('start_wrapper','start_offset','end_wrapper','end_offset'))# whichcomments=="all" |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
335 |
|
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
336 |
# decide to use pandoc or not |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
337 |
if with_color : |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
338 |
use_pandoc = False # pandoc wouldn't preserve comments scope background colors |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
339 |
else : |
| 191 | 340 |
if format in ('markdown', 'latex') : |
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
341 |
use_pandoc = True |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
342 |
elif format in ('pdf', 'odt') : |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
343 |
use_pandoc = (original_format == "markdown") |
| 231 | 344 |
elif format in ('doc', 'html') : |
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
345 |
use_pandoc = False |
| 231 | 346 |
|
347 |
# correct attach path => real path |
|
348 |
if format in ('pdf','odt') : |
|
349 |
original_content = from_html_links_to_abs_links(original_content) |
|
350 |
||
| 0 | 351 |
if len(comments) == 0 : #want to bypass html conversion in this case |
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
352 |
return content_export2(request, original_content, text_version.title, original_format, format, use_pandoc, download_response) |
| 0 | 353 |
else : # case comments to be added |
354 |
#comments = comments.order_by('start_wrapper','start_offset','end_wrapper','end_offset') |
|
| 232 | 355 |
html = pandoc_convert(original_content, original_format, 'html') |
| 0 | 356 |
wrapped_text_version, _ , _ = spannify(html) |
357 |
with_markers = True |
|
358 |
marked_content = insert_comment_markers(wrapped_text_version, comments, with_markers, with_color) |
|
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
359 |
|
| 0 | 360 |
viewable_comments = comments_thread(request, text_version, text) |
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
361 |
# viewable_commentsnoreply = get_viewable_comments(request, commentsnoreply, text, order_by = ('start_wrapper','start_offset','end_wrapper','end_offset')) |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
362 |
# viewable_comments = [] |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
363 |
# for cc in viewable_commentsnoreply : |
|
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
364 |
# viewable_comments += list_viewable_comments(request, [cc], text) |
| 0 | 365 |
|
366 |
# numerotation{ id --> numbered as a child} |
|
367 |
extended_comments = {} |
|
368 |
nb_children = {} |
|
369 |
for cc in viewable_comments : |
|
370 |
id = 0 #<-- all top comments are children of comment with id 0 |
|
371 |
if cc.is_reply() : |
|
372 |
id = cc.reply_to_id |
|
373 |
||
374 |
nb_children[id] = nb_children.get(id, 0) + 1 |
|
375 |
||
376 |
cc.num = "%d"%nb_children[id] |
|
377 |
||
378 |
extended_comments[cc.id] = cc |
|
379 |
||
380 |
if cc.is_reply() : |
|
381 |
cc.num = "%s.%s"%(extended_comments[cc.reply_to_id].num, cc.num) |
|
382 |
||
|
56
bd8a4ffc7dad
BUG FIX : pdf export PhA tests, TODO fix special html caracters in comments
reno
parents:
42
diff
changeset
|
383 |
# viewable_comments += list_viewable_comments(request, viewable_commentsnoreply, text) |
| 0 | 384 |
html_comments=render_to_string('site/macros/text_comments.html',{'comments':viewable_comments }, context_instance=RequestContext(request)) |
385 |
||
386 |
content = "%s%s"%(marked_content, html_comments) |
|
387 |
content_format = "html" |
|
388 |
# impossible to satisfy because of color then no colors instead: |
|
389 |
if with_color and format in ('markdown', 'tex') : #TODO : add S5 |
|
390 |
with_color = False |
|
391 |
||
392 |
return content_export2(request, content, text_version.title, content_format, format, use_pandoc, download_response) |
|
393 |
||
394 |
def text_print(request, key, adminkey=None): |
|
395 |
text, admin = get_text_and_admin(key, adminkey) |
|
396 |
||
397 |
text_version = text.get_latest_version() |
|
398 |
||
399 |
# chosen default url behaviour is export all comments + bckcolor + pdf |
|
400 |
comments = Comment.objects.filter(text_version=text_version, reply_to__isnull=True) |
|
401 |
||
402 |
with_markers = True |
|
403 |
with_colors = True |
|
404 |
download_requested = True |
|
405 |
action = 'export' # client origine dialog |
|
406 |
requested_format = 'pdf' # requested output format |
|
407 |
||
408 |
if request.method == 'POST': |
|
409 |
# colors or not ? |
|
410 |
with_colors = (u'yes' == request.POST.get('p_color', u'no')) |
|
411 |
||
412 |
# restrict comments to ones that should be exported / printed |
|
413 |
p_comments = request.POST.get('p_comments') |
|
414 |
if p_comments == "filtered" or p_comments == "none" : |
|
415 |
filteredIds = [] # "none" case |
|
416 |
if p_comments == "filtered" : |
|
417 |
ll = request.POST.get('filteredIds').split(",") |
|
418 |
filteredIds = [ int(l) for l in ll if l] |
|
419 |
||
420 |
comments = comments.filter(id__in=filteredIds) |
|
421 |
||
422 |
# print or export ? |
|
423 |
action = request.POST.get('print_export_action') |
|
424 |
requested_format = request.POST.get('p_method') |
|
425 |
||
426 |
comments = comments.order_by('start_wrapper','start_offset','end_wrapper','end_offset') |
|
427 |
||
428 |
download_requested = (action == 'export') or (action == 'print' and requested_format != 'html') |
|
429 |
||
430 |
ori_format = text_version.format # BD : html or markdown for now ... |
|
431 |
src_format = ori_format # as expected by convert functions ... |
|
432 |
src = text_version.content |
|
433 |
||
434 |
if len(comments) > 0 and (with_markers or with_colors) : |
|
435 |
html = text_version.get_content() |
|
436 |
wrapped_text_version, _ , _ = spannify(html) |
|
437 |
marked_text_version = insert_comment_markers(wrapped_text_version, comments, with_markers, with_colors) |
|
438 |
||
439 |
src_format = 'html' |
|
440 |
src = marked_text_version |
|
441 |
html_comments=render_to_string('site/macros/text_comments.html',{'comments':comments}, context_instance=RequestContext(request)) |
|
442 |
src += html_comments |
|
443 |
||
444 |
if download_requested : |
|
445 |
use_pandoc = (requested_format == 'html' or requested_format == 'markdown') |
|
446 |
return content_export(request, src, text_version.title, src_format, requested_format, use_pandoc) |
|
447 |
else : # action == 'print' and requested_format == 'html' (no colors) |
|
448 |
template_dict = {'text' : text, |
|
449 |
'text_version' : text_version, |
|
450 |
'title' : text_version.title, # TODO use it ... |
|
451 |
'comments': comments, |
|
452 |
'content' : marked_text_version, |
|
453 |
'client_date_fmt' : settings.CLIENT_DATE_FMT |
|
454 |
} |
|
455 |
if admin: |
|
| 279 | 456 |
template_dict['adminkey'] = text.adminkey |
457 |
template_dict['admin'] = True |
|
| 0 | 458 |
return render_to_response('site/text_print.html', |
459 |
template_dict, |
|
460 |
context_instance=RequestContext(request)) |
|
461 |
||
462 |
@has_perm_on_text('can_view_text') |
|
| 24 | 463 |
def text_view_frame(request, key, version_key=None, adminkey=None): |
| 0 | 464 |
text = get_text_by_keys_or_404(key) |
465 |
||
| 24 | 466 |
if version_key : |
467 |
text_version = get_textversion_by_keys_or_404(version_key, adminkey, key) |
|
468 |
else : |
|
469 |
text_version = text.get_latest_version() |
|
470 |
template_dict = {'text' : text, 'text_version' : text_version} |
|
| 0 | 471 |
return render_to_response('site/text_view_frame.html', |
472 |
template_dict, |
|
473 |
context_instance=RequestContext(request)) |
|
474 |
||
475 |
||
476 |
@has_perm_on_text('can_view_text') |
|
| 145 | 477 |
def text_history_version(request, key, version_key): |
478 |
text = get_text_by_keys_or_404(key) |
|
479 |
text_version = get_textversion_by_keys_or_404(version_key, key=key) |
|
480 |
template_dict = {'text' : text, |
|
481 |
'text_version' : text_version, |
|
482 |
'embed_code' : embed_html(key, 'id="text_view_frame" name="text_view_frame"', version_key), |
|
483 |
} |
|
484 |
return render_to_response('site/text_history_version.html', |
|
485 |
template_dict, |
|
486 |
context_instance=RequestContext(request)) |
|
| 0 | 487 |
|
| 151 | 488 |
@has_perm_on_text('can_view_text') |
| 149 | 489 |
def text_history_compare(request, key, v1_version_key, v2_version_key, mode=''): |
| 145 | 490 |
text = get_text_by_keys_or_404(key) |
491 |
v1 = get_textversion_by_keys_or_404(v1_version_key, key=key) |
|
492 |
v2 = get_textversion_by_keys_or_404(v2_version_key, key=key) |
|
493 |
||
| 178 | 494 |
content = get_uniffied_inner_diff_table(v1.title, |
495 |
v2.title, |
|
496 |
_("by %(author)s") %{'author' : v1.get_name()}, |
|
497 |
_("by %(author)s") %{'author' : v2.get_name()}, |
|
498 |
v1.content, |
|
499 |
v2.content) |
|
| 149 | 500 |
if mode=='1': |
501 |
# alternate diff |
|
| 250 | 502 |
#from cm.utils.diff import text_diff |
| 274 | 503 |
from cm.utils.diff import diff_match_patch2 |
| 250 | 504 |
dif = diff_match_patch2() |
505 |
content = dif.diff_prettyHtml_one_way(dif.diff_main(v1.get_content(), v2.get_content()), mode='ins_del') |
|
| 0 | 506 |
|
| 145 | 507 |
template_dict = { |
508 |
'text' : text, |
|
509 |
'v1': v1, |
|
510 |
'v2': v2, |
|
511 |
'content' : content.strip(), |
|
512 |
'empty' : '<table class="diff"><tbody></tbody></table>'==content, |
|
513 |
} |
|
514 |
return render_to_response('site/text_history_compare.html', |
|
515 |
template_dict, |
|
516 |
context_instance=RequestContext(request)) |
|
517 |
||
518 |
@has_perm_on_text('can_view_text') |
|
519 |
def text_history(request, key): |
|
520 |
text = get_text_by_keys_or_404(key) |
|
521 |
||
522 |
if request.method == 'POST': |
|
523 |
v1_key = request.POST.get('newkey',None) |
|
524 |
v2_key = request.POST.get('oldkey',None) |
|
525 |
if v1_key and v2_key: |
|
526 |
return redirect(request, 'text-history-compare', args=[text.key, v2_key, v1_key ]) |
|
527 |
||
528 |
text_versions = text.get_versions() |
|
529 |
paginate_by = get_int(request.GET,'paginate',TEXT_PAGINATION) |
|
| 0 | 530 |
|
| 145 | 531 |
last_last_version = text_versions[1] if len(text_versions)>1 else None |
532 |
context = {'text':text, 'last_version':text.last_text_version, 'last_last_version':last_last_version} |
|
533 |
return object_list(request, text_versions, |
|
534 |
template_name = 'site/text_history.html', |
|
535 |
paginate_by = paginate_by, |
|
536 |
extra_context=context, |
|
537 |
) |
|
538 |
||
| 0 | 539 |
|
540 |
# taken from trac |
|
541 |
def _get_change_extent(str1, str2): |
|
542 |
""" |
|
543 |
Determines the extent of differences between two strings. Returns a tuple |
|
544 |
containing the offset at which the changes start, and the negative offset |
|
545 |
at which the changes end. If the two strings have neither a common prefix |
|
546 |
nor a common suffix, (0, 0) is returned. |
|
547 |
""" |
|
548 |
start = 0 |
|
549 |
limit = min(len(str1), len(str2)) |
|
550 |
while start < limit and str1[start] == str2[start]: |
|
551 |
start += 1 |
|
552 |
end = -1 |
|
553 |
limit = limit - start |
|
554 |
while - end <= limit and str1[end] == str2[end]: |
|
555 |
end -= 1 |
|
556 |
return (start, end + 1) |
|
557 |
||
558 |
def diff_decorate(minus, plus): |
|
559 |
return minus, plus |
|
560 |
||
| 178 | 561 |
def get_uniffied_inner_diff_table(title1, title2, author1, author2, text1, text2): |
| 0 | 562 |
""" |
563 |
Return the inner of the html table for text1 vs text2 diff |
|
564 |
""" |
|
565 |
gen = unified_diff(text1.split('\n'), text2.split('\n'), n=3) |
|
566 |
index = 0 |
|
567 |
res = ['<table class="diff"><tbody>'] |
|
| 178 | 568 |
res.append('<tr><td></td><td class="diff-title">%s</td><td></td><td></td><td class="diff-title">%s</td></tr>' %(title1, title2)) |
569 |
res.append('<tr><td></td><td class="diff-author">%s</td><td></td><td></td><td class="diff-author">%s</td></tr>' %(author1, author2)) |
|
570 |
res.append('<tr><td colspan="5"></td></tr>') |
|
| 0 | 571 |
#res.append('<tr><td width="50%" colspan="2"></td><td width="50%" colspan="2"></td></tr>') |
572 |
||
573 |
for g in gen: |
|
574 |
if index > 1: |
|
575 |
col_in = None |
|
576 |
if g.startswith('@@'): |
|
577 |
line_number = g.split(' ')[1][1:].split(',')[0] |
|
578 |
if index != 2: |
|
579 |
res.append('<tr><td></td> <td></td><td></td><td> </td></tr>') |
|
580 |
res.append('<tr><td class="diff-lineno" colspan="2">Line %s</td><td class="diff-separator"></td><td class="diff-lineno" colspan="2">Line %s</td></tr>' % (line_number, line_number)) |
|
581 |
if g.startswith(' '): |
|
582 |
res.append('<tr><td class="diff-marker"></td><td class="diff-context">%s</td><td class="diff-separator"></td><td class="diff-marker"></td><td class="diff-context">%s</td></tr>' % (g, g)) |
|
583 |
if g.startswith('-') or g.startswith('+'): |
|
584 |
plus = [] |
|
585 |
minus = [] |
|
586 |
while g.startswith('-') or g.startswith('+'): |
|
587 |
if g.startswith('-'): |
|
588 |
minus.append(g[1:]) |
|
589 |
else: |
|
590 |
plus.append(g[1:]) |
|
591 |
try: |
|
592 |
g = gen.next() |
|
593 |
except StopIteration: |
|
594 |
break |
|
595 |
minus, plus = diff_decorate(minus, plus) |
|
| 250 | 596 |
|
597 |
||
| 274 | 598 |
minus, plus = '<br />'.join(minus), '<br />'.join(plus) |
599 |
from cm.utils.diff import diff_match_patch2 |
|
| 250 | 600 |
dif = diff_match_patch2() |
| 254 | 601 |
res_diff1 = dif.diff_main(minus, plus) |
602 |
dif.diff_cleanupSemantic(res_diff1) |
|
603 |
p = dif.diff_prettyHtml_one_way(res_diff1, 1) |
|
604 |
minus = dif.diff_prettyHtml_one_way(res_diff1, 2) |
|
| 250 | 605 |
plus = p |
606 |
res.append('<tr><td class="diff-marker">-</td><td class="diff-deletedline">%s</td><td class="diff-separator"></td><td class="diff-marker">+</td><td class="diff-addedline">%s</td></tr>' % (minus, plus)) |
|
| 0 | 607 |
|
608 |
index += 1 |
|
609 |
res.append('</tbody></table>') |
|
610 |
return ''.join(res) |
|
611 |
||
612 |
#def text_history_version(request, key): |
|
613 |
# text = get_text_by_keys_or_404(key=key) |
|
614 |
# return _text_history_version(request, text) |
|
615 |
# |
|
616 |
#def text_history_version_admin(request, key, adminkey): |
|
617 |
# text = get_text_by_keys_or_404(key=key, adminkey=adminkey) |
|
618 |
# return _text_history_version(request, text, True) |
|
619 |
# if admin: |
|
620 |
# template_dict['adminkey'] = text.adminkey |
|
621 |
# template_dict['admin'] = True |
|
622 |
# return render_to_response('site/text_history.html', template_dict, context_instance=RequestContext(request)) |
|
623 |
# |
|
624 |
class TextVersionForm(ModelForm): |
|
625 |
class Meta: |
|
626 |
model = TextVersion |
|
627 |
fields = ('title', 'content', 'format') |
|
628 |
||
629 |
class EditTextForm(ModelForm): |
|
| 234 | 630 |
title = forms.CharField(label=ugettext_lazy("Title"), widget=forms.TextInput) |
| 0 | 631 |
#format = forms.CharField(label=_("Format")) |
632 |
#content = forms.TextField(label=_("Content")) |
|
633 |
||
| 234 | 634 |
note = forms.CharField(label=ugettext_lazy("Note (optional)"), |
| 0 | 635 |
widget=forms.TextInput, |
636 |
required=False, |
|
| 234 | 637 |
help_text=ugettext_lazy("Add a note to explain the modifications made to the text") |
| 0 | 638 |
) |
639 |
||
640 |
#tags = forms.CharField(label=_("Tags (optional)"), |
|
641 |
# widget=forms.TextInput, |
|
642 |
# required=False, |
|
643 |
# #help_text=_("Add a note to explain the modifications made to the text") |
|
644 |
# ) |
|
645 |
||
646 |
||
| 234 | 647 |
new_version = forms.BooleanField(label=ugettext_lazy("New version (optional)"), |
| 0 | 648 |
required=False, |
649 |
initial=True, |
|
| 234 | 650 |
help_text=ugettext_lazy("Create a new version of this text (recommended)") |
| 0 | 651 |
) |
652 |
||
| 235 | 653 |
keep_comments = forms.BooleanField(label=ugettext_lazy("Keep comments (optional)"), |
| 0 | 654 |
required=False, |
655 |
initial=True, |
|
| 234 | 656 |
help_text=ugettext_lazy("Keep comments (if not affected by the edit)") |
| 0 | 657 |
) |
658 |
||
659 |
class Meta: |
|
660 |
model = TextVersion |
|
661 |
fields = ('title', 'format', 'content', 'new_version', 'tags', 'note') |
|
662 |
||
663 |
def save_into_text(self, text, request): |
|
664 |
new_content = request.POST.get('content') |
|
665 |
new_title = request.POST.get('title') |
|
|
71
a865a5d0809a
format in text edit not required / add default to old value
raph
parents:
70
diff
changeset
|
666 |
new_format = request.POST.get('format', text.last_text_version.format) |
| 0 | 667 |
new_note = request.POST.get('note',None) |
668 |
new_tags = request.POST.get('tags',None) |
|
| 103 | 669 |
cancel_modified_scopes = (request.POST.get('cancel_modified_scopes',u'1') == u'1') |
| 0 | 670 |
version = text.get_latest_version() |
| 103 | 671 |
version.edit(new_title, new_format, new_content, new_tags, new_note, True, cancel_modified_scopes) |
672 |
||
| 0 | 673 |
return version |
674 |
||
675 |
def save_new_version(self, text, request): |
|
676 |
new_content = request.POST.get('content') |
|
677 |
new_title = request.POST.get('title') |
|
|
71
a865a5d0809a
format in text edit not required / add default to old value
raph
parents:
70
diff
changeset
|
678 |
new_format = request.POST.get('format', text.last_text_version.format) |
| 0 | 679 |
new_note = request.POST.get('note',None) |
680 |
new_tags = request.POST.get('tags',None) |
|
| 103 | 681 |
cancel_modified_scopes = (request.POST.get('cancel_modified_scopes',u'1') == u'1') |
| 178 | 682 |
|
683 |
new_text_version = text.edit(new_title, new_format, new_content, new_tags, new_note, keep_comments=True, cancel_modified_scopes=cancel_modified_scopes, new_version=True) |
|
684 |
||
| 103 | 685 |
new_text_version.edit(new_title, new_format, new_content, new_tags, new_note, True, cancel_modified_scopes) |
| 178 | 686 |
new_text_version.user = request.user if request.user.is_authenticated() else None |
687 |
new_text_version.note = request.POST.get('note','') |
|
688 |
new_text_version.email = request.POST.get('email','') |
|
689 |
new_text_version.name = request.POST.get('name','') |
|
690 |
new_text_version.save() |
|
| 0 | 691 |
|
692 |
return new_text_version |
|
693 |
||
| 70 | 694 |
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, |
695 |
initial=None, error_class=ErrorList, label_suffix=':', |
|
696 |
empty_permitted=False, instance=None): |
|
697 |
ModelForm.__init__(self, data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, instance) |
|
698 |
||
699 |
# override manually to disabled |
|
700 |
format_field = self.fields['format'] |
|
| 237 | 701 |
format_field.widget.attrs = {'disabled':'disabled'} |
|
71
a865a5d0809a
format in text edit not required / add default to old value
raph
parents:
70
diff
changeset
|
702 |
format_field.required = False |
| 70 | 703 |
|
704 |
self.fields['format'] = format_field |
|
705 |
||
| 0 | 706 |
@has_perm_on_text('can_edit_text') |
707 |
def text_pre_edit(request, key, adminkey=None): |
|
708 |
text = get_text_by_keys_or_404(key) |
|
709 |
||
710 |
text_version = text.get_latest_version() |
|
| 279 | 711 |
comments = text_version.get_comments() |
| 0 | 712 |
new_format = request.POST['new_format'] |
| 175 | 713 |
new_content = on_content_receive(request.POST['new_content'], new_format) |
| 0 | 714 |
|
715 |
# TODO: RBE : si commentaire mal forme : (position non existante : boom par key error) |
|
716 |
_tomodify_comments, toremove_comments = compute_new_comment_positions(text_version.content, text_version.format, new_content, new_format, comments) |
|
717 |
return HttpResponse(simplejson.dumps({'nb_removed' : len(toremove_comments) })) |
|
718 |
||
719 |
class EditTextFormAnon(EditTextForm): |
|
720 |
name = forms.CharField(label=ugettext_lazy("Name (optional)"), widget=forms.TextInput, required=False) |
|
721 |
email = forms.EmailField(label=ugettext_lazy("Email (optional)"), required=False) |
|
722 |
content = forms.CharField(label=ugettext_lazy("Content"), required=True, widget=forms.Textarea(attrs={'rows':'30', 'cols': '70'})) |
|
723 |
||
724 |
class Meta: |
|
725 |
model = TextVersion |
|
726 |
fields = ('title', 'format', 'content', 'tags', 'note', 'name', 'email') |
|
727 |
||
728 |
@has_perm_on_text('can_edit_text') |
|
729 |
def text_edit(request, key, adminkey=None): |
|
730 |
text = get_text_by_keys_or_404(key) |
|
731 |
text_version = text.get_latest_version() |
|
732 |
if request.method == 'POST': |
|
733 |
if request.user.is_authenticated(): |
|
734 |
form = EditTextForm(request.POST) |
|
735 |
else: |
|
736 |
form = EditTextFormAnon(request.POST) |
|
737 |
||
738 |
if form.is_valid(): |
|
739 |
if request.POST.get('new_version'): |
|
740 |
new_version = form.save_new_version(text, request) |
|
741 |
register_activity(request, "text_edited_new_version", text=text, text_version=new_version) |
|
742 |
else: |
|
743 |
form.save_into_text(text, request) |
|
744 |
register_activity(request, "text_edited", text=text) |
|
745 |
return redirect(request, 'text-view', args=[text.key]) |
|
746 |
else: |
|
747 |
default_data = { |
|
748 |
'content': text_version.content, |
|
749 |
'title': text_version.title, |
|
750 |
'format': text_version.format, |
|
751 |
'tags': text_version.tags, |
|
752 |
'new_version': NEW_TEXT_VERSION_ON_EDIT, |
|
|
240
a00efaf32ea7
note should not beeing passed to new version (fixes #12)
raph
parents:
237
diff
changeset
|
753 |
'note' : '', |
| 0 | 754 |
'keep_comments' : True, |
755 |
} |
|
756 |
if request.user.is_authenticated(): |
|
757 |
form = EditTextForm(default_data) |
|
758 |
else: |
|
759 |
form = EditTextFormAnon(default_data) |
|
760 |
||
761 |
template_dict = {'text' : text, 'form' : form} |
|
762 |
||
763 |
return render_to_response('site/text_edit.html', template_dict , context_instance=RequestContext(request)) |
|
764 |
||
765 |
@has_perm_on_text('can_edit_text') |
|
| 145 | 766 |
def text_revert(request, key, text_version_key): |
| 230 | 767 |
if request.method != 'POST': |
768 |
raise UnauthorizedException('Unauthorized') |
|
769 |
||
| 0 | 770 |
text = get_text_by_keys_or_404(key) |
771 |
||
| 145 | 772 |
text_version = text.revert_to_version(text_version_key) |
773 |
display_message(request, _(u'A new version (copied from version %(version_title)s) has been created') % {'version_title':text_version.title}) |
|
| 0 | 774 |
|
| 230 | 775 |
return HttpResponse('') # no redirect because this is called by js |
| 0 | 776 |
|
777 |
@has_perm_on_text('can_view_text') |
|
778 |
def text_attach(request, key, attach_key): |
|
779 |
attach = Attachment.objects.get(key=attach_key, text_version__text__key=key) |
|
780 |
content = file(attach.data.path).read() |
|
781 |
mimetype, _encoding = mimetypes.guess_type(attach.data.path) |
|
782 |
response = HttpResponse(content, mimetype) |
|
783 |
return response |
|
784 |
||
785 |
||
786 |
||
787 |
||
788 |
def fix_anon_in_formset(formset): |
|
789 |
# fix role choice in formset for anon (not all role are allowed) |
|
790 |
role_field = [f.fields['role'] for f in formset.forms if f.instance.user == None][0] |
|
791 |
role_field.choices = [(u'', u'---------')] + [(r.id, str(r)) for r in Role.objects.filter(anon = True)] # limit anon choices |
|
792 |
||
793 |
class BaseUserRoleFormSet(BaseModelFormSet): |
|
794 |
def clean(self): |
|
795 |
"""Checks that anon users are given roles with anon=True.""" |
|
796 |
for i in range(0, self.total_form_count()): |
|
797 |
form = self.forms[i] |
|
798 |
print form.cleaned_data |
|
799 |
user_role = form.cleaned_data['id'] |
|
800 |
if user_role.user == None: |
|
801 |
role = form.cleaned_data['role'] |
|
802 |
if not role.anon: |
|
803 |
# nasty stuff: cannot happen so not dealt with in tempate |
|
804 |
logging.warn('Cannot give such role to anon user.') |
|
805 |
raise forms.ValidationError, "Cannot give such role to anon user." |
|
806 |
||
807 |
#@has_perm_on_text('can_manage_text') |
|
808 |
#def xtext_share(request, key): |
|
809 |
# text = get_text_by_keys_or_404(key) |
|
810 |
# order_by = get_among(request.GET,'order',('user__username','-user__username','role__name','-role__name'),'user__username') |
|
811 |
# |
|
812 |
# UserRole.objects.create_userroles_text(text) |
|
813 |
# UserRoleFormSet = modelformset_factory(UserRole, fields=('role', ), extra=0, formset = BaseUserRoleFormSet) |
|
814 |
# |
|
815 |
# # put anon users on top no matter what the order says (TODO: ?) |
|
816 |
# userrole_queryset = UserRole.objects.filter(text=text).extra(select={'anon':'"cm_userrole"."user_id">-1'}).order_by('-anon',order_by) |
|
817 |
# if request.method == 'POST': |
|
818 |
# formset = UserRoleFormSet(request.POST, queryset = userrole_queryset) |
|
819 |
# |
|
820 |
# if formset.is_valid(): |
|
821 |
# formset.save() |
|
822 |
# display_message(request, "Sharing updated.") |
|
823 |
# return HttpResponseRedirect(reverse('text-share',args=[text.key])) |
|
824 |
# |
|
825 |
# else: |
|
826 |
# formset = UserRoleFormSet(queryset = userrole_queryset) |
|
827 |
# fix_anon_in_formset(formset) |
|
828 |
# |
|
829 |
# global_anon_userrole = UserRole.objects.get(text=None, user=None) |
|
830 |
# return render_to_response('site/text_share.html', {'text' : text, |
|
831 |
# 'formset' : formset, |
|
832 |
# 'global_anon_userrole' : global_anon_userrole, |
|
833 |
# } , context_instance=RequestContext(request)) |
|
834 |
||
835 |
# TODO: permission protection ? format value check ? |
|
836 |
def text_wysiwyg_preview(request, format): |
|
837 |
html_content = "" |
|
838 |
if request.POST : # if satisfied in the no html case, in html case : no POST (cf. markitup) previewTemplatePath and previewParserPath |
|
839 |
html_content = pandoc_convert(request.POST['data'], format, "html", full=False) |
|
840 |
||
841 |
return render_to_response('site/wysiwyg_preview.html', {'content':html_content} , context_instance=RequestContext(request)) |
|
842 |
#return HttpResponse(pandoc_convert(content, format, "html", full=False)) |
|
843 |
||
| 97 | 844 |
USER_PAGINATION = 10 |
845 |
||
| 0 | 846 |
@has_perm_on_text('can_manage_text') |
847 |
def text_share(request, key): |
|
| 42 | 848 |
display_suspended_users = get_int(request.GET, 'display', 0) |
849 |
tag_selected = request.GET.get('tag_selected', 0) |
|
| 97 | 850 |
paginate_by = get_int(request.GET, 'paginate', USER_PAGINATION) |
| 42 | 851 |
|
| 0 | 852 |
text = get_text_by_keys_or_404(key) |
853 |
order_by = get_among(request.GET,'order',('user__username', |
|
854 |
'user__email', |
|
855 |
'-user__username', |
|
856 |
'-user__email', |
|
857 |
'role__name', |
|
858 |
'-role__name', |
|
859 |
), |
|
860 |
'user__username') |
|
861 |
||
862 |
UserRole.objects.create_userroles_text(text) |
|
863 |
||
864 |
if request.method == 'POST': |
|
865 |
if 'save' in request.POST: |
|
866 |
user_profile_keys_roles = get_keys_from_dict(request.POST, 'user-role-') |
|
867 |
count = 0 |
|
868 |
for user_profile_key in user_profile_keys_roles: |
|
869 |
role_id = user_profile_keys_roles[user_profile_key] |
|
870 |
if not user_profile_key: |
|
871 |
user_role = UserRole.objects.get(user = None, text = text) |
|
872 |
else: |
|
873 |
user_role = UserRole.objects.get(user__userprofile__key = user_profile_key, text = text) |
|
874 |
if (role_id != u'' or user_role.role_id!=None) and role_id!=unicode(user_role.role_id): |
|
875 |
if role_id: |
|
876 |
user_role.role_id = int(role_id) |
|
877 |
else: |
|
878 |
user_role.role_id = None |
|
879 |
user_role.save() |
|
880 |
count += 1 |
|
881 |
display_message(request, _(u'%(count)i user(s) role modified') %{'count':count}) |
|
882 |
return HttpResponseRedirect(reverse('text-share', args=[text.key])) |
|
883 |
||
884 |
anon_role = UserRole.objects.get(user = None, text = text).role |
|
885 |
global_anon_role = UserRole.objects.get(user = None, text = None).role |
|
886 |
||
887 |
context = { |
|
888 |
'anon_role' : anon_role, |
|
889 |
'global_anon_role' : global_anon_role, |
|
890 |
'all_roles' : Role.objects.all(), |
|
891 |
'anon_roles' : Role.objects.filter(anon = True), |
|
892 |
'text' : text, |
|
| 42 | 893 |
'display_suspended_users' : display_suspended_users, |
894 |
'tag_list' : Tag.objects.usage_for_model(UserProfile), |
|
895 |
'tag_selected': tag_selected, |
|
| 0 | 896 |
} |
897 |
||
| 42 | 898 |
query = UserRole.objects.filter(text=text).filter(~Q(user=None)).order_by(order_by) |
899 |
if not display_suspended_users: |
|
900 |
query = query.exclude(Q(user__userprofile__is_suspended=True) & Q(user__is_active=True)) |
|
901 |
else: |
|
902 |
# trick to include userprofile table anyway (to filter by tags) |
|
903 |
query = query.filter(Q(user__userprofile__is_suspended=True) | Q(user__userprofile__is_suspended=False)) |
|
904 |
||
905 |
if tag_selected: |
|
906 |
tag_ids = Tag.objects.filter(name=tag_selected) |
|
907 |
if tag_ids: |
|
908 |
content_type_id = ContentType.objects.get_for_model(UserProfile).pk |
|
909 |
query = query.extra(where=['tagging_taggeditem.object_id = cm_userprofile.id', |
|
910 |
'tagging_taggeditem.content_type_id = %i' %content_type_id, |
|
911 |
'tagging_taggeditem.tag_id = %i' %tag_ids[0].id], |
|
912 |
tables=['tagging_taggeditem'], |
|
913 |
) |
|
914 |
||
915 |
return object_list(request, query, |
|
| 0 | 916 |
template_name = 'site/text_share.html', |
917 |
paginate_by = paginate_by, |
|
918 |
extra_context = context, |
|
919 |
) |
|
920 |
||
921 |
||
922 |
class SettingsTextForm(ModelForm): |
|
923 |
# example name = forms.CharField(label=_("Name (optional)"), widget=forms.TextInput, required=False) |
|
924 |
||
925 |
class Meta: |
|
926 |
model = TextVersion |
|
927 |
fields = ('mod_posteriori',) |
|
928 |
||
929 |
@has_perm_on_text('can_manage_text') |
|
930 |
def text_settings(request, key): |
|
931 |
text = get_text_by_keys_or_404(key) |
|
932 |
||
933 |
text_version = text.get_latest_version() |
|
934 |
if request.method == 'POST': |
|
935 |
form = SettingsTextForm(request.POST, instance = text_version) |
|
936 |
||
937 |
if form.is_valid(): |
|
938 |
form.save() |
|
939 |
display_message(request, _(u'Text settings updated')) |
|
940 |
return redirect(request, 'text-view', args=[text.key]) |
|
941 |
else: |
|
942 |
form = SettingsTextForm(instance = text_version) |
|
943 |
||
944 |
template_dict = {'text' : text, 'form' : form} |
|
945 |
||
946 |
return render_to_response('site/text_settings.html', template_dict , context_instance=RequestContext(request)) |
|
947 |