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