Fixes #3866: Text counter with footnotes.
[redakcja.git] / src / wiki_img / views.py
1 import os
2 import functools
3 import logging
4 logger = logging.getLogger("fnp.wiki_img")
5
6 from django.core.urlresolvers import reverse
7 from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
8                 ajax_require_permission)
9
10 from django.http import Http404, HttpResponse, HttpResponseForbidden
11 from django.shortcuts import get_object_or_404, render
12 from django.views.decorators.http import require_GET, require_POST
13 from django.conf import settings
14 from django.utils.formats import localize
15 from django.utils.translation import ugettext as _
16
17 from catalogue.models import Image
18 from wiki import forms
19 from wiki import nice_diff
20 from wiki_img.forms import ImageSaveForm
21
22 #
23 # Quick hack around caching problems, TODO: use ETags
24 #
25 from django.views.decorators.cache import never_cache
26
27
28 @never_cache
29 def editor(request, slug, template_name='wiki_img/document_details.html'):
30     doc = get_object_or_404(Image, slug=slug)
31
32     return render(request, template_name, {
33         'document': doc,
34         'forms': {
35             "text_save": ImageSaveForm(user=request.user, prefix="textsave"),
36             "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
37             "pubmark": forms.DocumentPubmarkForm(prefix="pubmark"),
38         },
39         'can_pubmark': request.user.has_perm('catalogue.can_pubmark_image'),
40         'REDMINE_URL': settings.REDMINE_URL,
41     })
42
43
44 @require_GET
45 def editor_readonly(request, slug, template_name='wiki_img/document_details_readonly.html'):
46     doc = get_object_or_404(Image, slug=slug)
47     try:
48         revision = request.GET['revision']
49     except (KeyError):
50         raise Http404
51
52     return render(request, template_name, {
53         'document': doc,
54         'revision': revision,
55         'readonly': True,
56         'REDMINE_URL': settings.REDMINE_URL,
57     })
58
59
60 @never_cache
61 def text(request, image_id):
62     doc = get_object_or_404(Image, pk=image_id)
63     if request.method == 'POST':
64         form = ImageSaveForm(request.POST, user=request.user, prefix="textsave")
65         if form.is_valid():
66             if request.user.is_authenticated():
67                 author = request.user
68             else:
69                 author = None
70             text = form.cleaned_data['text']
71             parent_revision = form.cleaned_data['parent_revision']
72             if parent_revision is not None:
73                 parent = doc.at_revision(parent_revision)
74             else:
75                 parent = None
76             stage = form.cleaned_data['stage_completed']
77             tags = [stage] if stage else []
78             publishable = (form.cleaned_data['publishable'] and
79                     request.user.has_perm('catalogue.can_pubmark_image'))
80             doc.commit(author=author,
81                    text=text,
82                    parent=parent,
83                    description=form.cleaned_data['comment'],
84                    tags=tags,
85                    author_name=form.cleaned_data['author_name'],
86                    author_email=form.cleaned_data['author_email'],
87                    publishable=publishable,
88                 )
89             revision = doc.revision()
90             return JSONResponse({
91                 'text': doc.materialize() if parent_revision != revision else None,
92                 'meta': {},
93                 'revision': revision,
94             })
95         else:
96             return JSONFormInvalid(form)
97     else:
98         revision = request.GET.get("revision", None)
99         
100         try:
101             revision = int(revision)
102         except (ValueError, TypeError):
103             revision = doc.revision()
104
105         if revision is not None:
106             text = doc.at_revision(revision).materialize()
107         else:
108             text = ''
109
110         return JSONResponse({
111             'text': text,
112             'meta': {},
113             'revision': revision,
114         })
115
116
117 @never_cache
118 def history(request, object_id):
119     # TODO: pagination
120     doc = get_object_or_404(Image, pk=object_id)
121     if not doc.accessible(request):
122         return HttpResponseForbidden("Not authorized.")
123
124     changes = []
125     for change in doc.history().reverse():
126         changes.append({
127                 "version": change.revision,
128                 "description": change.description,
129                 "author": change.author_str(),
130                 "date": localize(change.created_at),
131                 "publishable": _("Publishable") + "\n" if change.publishable else "",
132                 "tag": ',\n'.join(unicode(tag) for tag in change.tags.all()),
133             })
134     return JSONResponse(changes)
135
136
137 @never_cache
138 @require_POST
139 def revert(request, object_id):
140     form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
141     if form.is_valid():
142         doc = get_object_or_404(Image, pk=object_id)
143         if not doc.accessible(request):
144             return HttpResponseForbidden("Not authorized.")
145
146         revision = form.cleaned_data['revision']
147
148         comment = form.cleaned_data['comment']
149         comment += "\n#revert to %s" % revision
150
151         if request.user.is_authenticated():
152             author = request.user
153         else:
154             author = None
155
156         before = doc.revision()
157         logger.info("Reverting %s to %s", object_id, revision)
158         doc.at_revision(revision).revert(author=author, description=comment)
159
160         return JSONResponse({
161             'text': doc.materialize() if before != doc.revision() else None,
162             'meta': {},
163             'revision': doc.revision(),
164         })
165     else:
166         return JSONFormInvalid(form)
167
168
169 @never_cache
170 def diff(request, object_id):
171     revA = int(request.GET.get('from', 0))
172     revB = int(request.GET.get('to', 0))
173
174     if revA > revB:
175         revA, revB = revB, revA
176
177     if revB == 0:
178         revB = None
179
180     doc = get_object_or_404(Image, pk=object_id)
181     if not doc.accessible(request):
182         return HttpResponseForbidden("Not authorized.")
183
184     # allow diff from the beginning
185     if revA:
186         docA = doc.at_revision(revA).materialize()
187     else:
188         docA = ""
189     docB = doc.at_revision(revB).materialize()
190
191     return HttpResponse(nice_diff.html_diff_table(docA.splitlines(),
192                                          docB.splitlines(), context=3))
193
194
195 @require_POST
196 @ajax_require_permission('catalogue.can_pubmark_image')
197 def pubmark(request, object_id):
198     form = forms.DocumentPubmarkForm(request.POST, prefix="pubmark")
199     if form.is_valid():
200         doc = get_object_or_404(Image, pk=object_id)
201         if not doc.accessible(request):
202             return HttpResponseForbidden("Not authorized.")
203
204         revision = form.cleaned_data['revision']
205         publishable = form.cleaned_data['publishable']
206         change = doc.at_revision(revision)
207         if publishable != change.publishable:
208             change.set_publishable(publishable)
209             return JSONResponse({"message": _("Revision marked")})
210         else:
211             return JSONResponse({"message": _("Nothing changed")})
212     else:
213         return JSONFormInvalid(form)