1 # -*- coding: utf-8 -*-
3 # This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
11 from django.conf import settings
12 from django import http
13 from django.http import HttpResponseForbidden
14 from django.middleware.gzip import GZipMiddleware
15 from django.utils.decorators import decorator_from_middleware
16 from django.utils.encoding import smart_unicode
17 from django.utils.formats import localize
18 from django.utils.html import escape
19 from django.utils.translation import ugettext as _
20 from django.views.decorators.http import require_POST
21 from django.shortcuts import get_object_or_404, render
23 from catalogue.models import Document, Template
24 from dvcs.models import Revision
26 from wiki import forms
27 from wiki.helpers import JSONResponse, JSONFormInvalid
30 # Quick hack around caching problems, TODO: use ETags
32 from django.views.decorators.cache import never_cache
34 logger = logging.getLogger("fnp.wiki")
39 def get_history(document):
41 for i, revision in enumerate(document.history()):
44 "description": revision.description,
45 "author": escape(revision.author_str()),
46 "date": localize(revision.created_at),
47 "revision": revision.pk,
48 "published": _("Published") + ": " +
49 localize(revision.publish_log.order_by('-timestamp')[0].timestamp)
50 if revision.publish_log.exists() else "",
56 def editor(request, pk, template_name='wiki/bootstrap.html'):
57 doc = get_object_or_404(Document, pk=pk, deleted=False)
58 if not doc.can_edit(request.user):
59 return HttpResponseForbidden("Not authorized.")
61 save_form = forms.DocumentTextSaveForm(user=request.user, prefix="textsave")
62 text = doc.materialize()
63 revision = doc.revision
64 history = get_history(doc)
65 return render(request, template_name, {
66 'serialized_document_data': json.dumps({
68 'document_id': doc.pk,
69 'title': doc.meta().get('title', ''),
71 'version': len(history),
72 'revision': revision.pk,
74 'stage_name': doc.stage_name(),
75 'assignment': doc.assigned_to.username if doc.assigned_to else None,
77 'serialized_templates': json.dumps([
78 {'id': t.id, 'name': t.name, 'content': t.content} for t in Template.objects.filter(is_partial=True)
81 "text_save": save_form,
82 "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
83 "text_publish": forms.DocumentTextPublishForm(prefix="textpublish"),
90 @decorator_from_middleware(GZipMiddleware)
91 def text(request, doc_id):
92 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
94 if request.method == 'POST':
95 if not doc.can_edit(request.user):
96 return HttpResponseForbidden("Not authorized.")
97 form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
99 if request.user.is_authenticated():
100 author = request.user
103 text = form.cleaned_data['text']
104 # parent_revision = form.cleaned_data['parent_revision']
105 # if parent_revision is not None:
106 # parent = doc.at_revision(parent_revision)
109 stage = form.cleaned_data['stage']
110 # tags = [stage] if stage else []
111 # publishable = (form.cleaned_data['publishable'] and
112 # request.user.has_perm('catalogue.can_pubmark'))
117 description=form.cleaned_data['comment'],
118 author_name=form.cleaned_data['author_name'],
119 author_email=form.cleaned_data['author_email'],
123 from traceback import print_exc
126 return JSONResponse({
127 'text': None, # doc.materialize() if parent_revision != revision else None,
128 'version': len(get_history(doc)),
130 'stage_name': doc.stage_name(),
131 'assignment': doc.assigned_to.username if doc.assigned_to else None
134 return JSONFormInvalid(form)
136 revision = request.GET.get("revision", None)
139 revision = int(revision)
140 except (ValueError, TypeError):
141 revision = doc.revision()
143 if revision is not None:
144 text = doc.at_revision(revision).materialize()
148 return JSONResponse({
151 'revision': revision,
157 def revert(request, doc_id):
158 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
160 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
161 if not doc.can_edit(request.user):
162 return HttpResponseForbidden("Not authorized.")
163 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
165 comment = form.cleaned_data['comment']
166 comment += "\n#revert to %s" % rev.pk
168 if request.user.is_authenticated():
169 author = request.user
173 # before = doc.revision
174 logger.info("Reverting %s to %s", doc_id, rev.pk)
178 text=rev.materialize(),
180 # author_name=form.cleaned_data['author_name'], #?
181 # author_email=form.cleaned_data['author_email'], #?
184 return JSONResponse({
185 'document': doc.materialize(),
186 'version': len(get_history(doc)),
188 'stage_name': doc.stage_name(),
189 'assignment': doc.assigned_to.username if doc.assigned_to else None,
192 return JSONFormInvalid(form)
196 def gallery(request, directory):
197 if not request.user.is_authenticated():
198 return HttpResponseForbidden("Not authorized.")
202 smart_unicode(settings.MEDIA_URL),
203 smart_unicode(settings.IMAGE_DIR),
204 smart_unicode(directory)))
206 base_dir = os.path.join(
207 smart_unicode(settings.MEDIA_ROOT),
208 smart_unicode(settings.IMAGE_DIR),
209 smart_unicode(directory))
211 def map_to_url(filename):
212 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
214 def is_image(filename):
215 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
217 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
220 return JSONResponse(images)
221 except (IndexError, OSError):
222 logger.exception("Unable to fetch gallery")
227 def diff(request, doc_id):
228 revA = int(request.GET.get('from', 0))
229 revB = int(request.GET.get('to', 0))
232 revA, revB = revB, revA
237 # TODO: check if revisions in line.
239 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
241 # allow diff from the beginning
243 docA = Revision.objects.get(pk=revA).materialize()
246 docB = Revision.objects.get(pk=revB).materialize()
248 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
252 def history(request, doc_id):
254 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
256 return JSONResponse(get_history(doc))