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