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)
59 save_form = forms.DocumentTextSaveForm(user=request.user, prefix="textsave")
60 text = doc.materialize()
61 revision = doc.revision
62 history = get_history(doc)
63 return render(request, template_name, {
64 'serialized_document_data': json.dumps({
66 'document_id': doc.pk,
67 'title': doc.meta().get('title', ''),
69 'version': len(history),
70 'revision': revision.pk,
72 'stage_name': doc.stage_name(),
73 'assignment': str(doc.assigned_to),
75 'serialized_templates': json.dumps([
76 {'id': t.id, 'name': t.name, 'content': t.content} for t in Template.objects.filter(is_partial=True)
79 "text_save": save_form,
80 "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
81 "text_publish": forms.DocumentTextPublishForm(prefix="textpublish"),
88 @decorator_from_middleware(GZipMiddleware)
89 def text(request, doc_id):
90 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
91 # if not doc.book.accessible(request):
92 # return HttpResponseForbidden("Not authorized.")
94 if request.method == 'POST':
95 form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
97 if request.user.is_authenticated():
101 text = form.cleaned_data['text']
102 # parent_revision = form.cleaned_data['parent_revision']
103 # if parent_revision is not None:
104 # parent = doc.at_revision(parent_revision)
107 stage = form.cleaned_data['stage']
108 # tags = [stage] if stage else []
109 # publishable = (form.cleaned_data['publishable'] and
110 # request.user.has_perm('catalogue.can_pubmark'))
115 description=form.cleaned_data['comment'],
116 author_name=form.cleaned_data['author_name'],
117 author_email=form.cleaned_data['author_email'],
121 from traceback import print_exc
124 # revision = doc.revision()
125 return JSONResponse({
126 'text': None, # doc.materialize() if parent_revision != revision else None,
127 # 'version': revision,
129 'stage_name': doc.stage_name(),
130 'assignment': doc.assigned_to.username if doc.assigned_to else None
133 return JSONFormInvalid(form)
135 revision = request.GET.get("revision", None)
138 revision = int(revision)
139 except (ValueError, TypeError):
140 revision = doc.revision()
142 if revision is not None:
143 text = doc.at_revision(revision).materialize()
147 return JSONResponse({
150 'revision': revision,
156 def revert(request, doc_id):
157 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
159 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
160 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
162 comment = form.cleaned_data['comment']
163 comment += "\n#revert to %s" % rev.pk
165 if request.user.is_authenticated():
166 author = request.user
170 # before = doc.revision
171 logger.info("Reverting %s to %s", doc_id, rev.pk)
175 text=rev.materialize(),
177 # author_name=form.cleaned_data['author_name'], #?
178 # author_email=form.cleaned_data['author_email'], #?
181 return JSONResponse({
182 # 'document': None, #doc.materialize() if before != doc.revision else None,
183 # 'version': doc.revision(),
186 return JSONFormInvalid(form)
190 def gallery(request, directory):
191 if not request.user.is_authenticated():
192 return HttpResponseForbidden("Not authorized.")
196 smart_unicode(settings.MEDIA_URL),
197 smart_unicode(settings.IMAGE_DIR),
198 smart_unicode(directory)))
200 base_dir = os.path.join(
201 smart_unicode(settings.MEDIA_ROOT),
202 smart_unicode(settings.IMAGE_DIR),
203 smart_unicode(directory))
205 def map_to_url(filename):
206 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
208 def is_image(filename):
209 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
211 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
214 return JSONResponse(images)
215 except (IndexError, OSError):
216 logger.exception("Unable to fetch gallery")
221 def diff(request, doc_id):
222 revA = int(request.GET.get('from', 0))
223 revB = int(request.GET.get('to', 0))
226 revA, revB = revB, revA
231 # TODO: check if revisions in line.
233 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
235 # allow diff from the beginning
237 docA = Revision.objects.get(pk=revA).materialize()
240 docB = Revision.objects.get(pk=revB).materialize()
242 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
246 def history(request, doc_id):
248 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
250 return JSONResponse(get_history(doc))