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': doc.assigned_to.username if doc.assigned_to else None,
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 return JSONResponse({
125 'text': None, # doc.materialize() if parent_revision != revision else None,
126 'version': len(get_history(doc)),
128 'stage_name': doc.stage_name(),
129 'assignment': doc.assigned_to.username if doc.assigned_to else None
132 return JSONFormInvalid(form)
134 revision = request.GET.get("revision", None)
137 revision = int(revision)
138 except (ValueError, TypeError):
139 revision = doc.revision()
141 if revision is not None:
142 text = doc.at_revision(revision).materialize()
146 return JSONResponse({
149 'revision': revision,
155 def revert(request, doc_id):
156 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
158 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
159 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
161 comment = form.cleaned_data['comment']
162 comment += "\n#revert to %s" % rev.pk
164 if request.user.is_authenticated():
165 author = request.user
169 # before = doc.revision
170 logger.info("Reverting %s to %s", doc_id, rev.pk)
174 text=rev.materialize(),
176 # author_name=form.cleaned_data['author_name'], #?
177 # author_email=form.cleaned_data['author_email'], #?
180 return JSONResponse({
181 'document': doc.materialize(),
182 'version': len(get_history(doc)),
184 'stage_name': doc.stage_name(),
185 'assignment': doc.assigned_to.username if doc.assigned_to else None,
188 return JSONFormInvalid(form)
192 def gallery(request, directory):
193 if not request.user.is_authenticated():
194 return HttpResponseForbidden("Not authorized.")
198 smart_unicode(settings.MEDIA_URL),
199 smart_unicode(settings.IMAGE_DIR),
200 smart_unicode(directory)))
202 base_dir = os.path.join(
203 smart_unicode(settings.MEDIA_ROOT),
204 smart_unicode(settings.IMAGE_DIR),
205 smart_unicode(directory))
207 def map_to_url(filename):
208 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
210 def is_image(filename):
211 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
213 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
216 return JSONResponse(images)
217 except (IndexError, OSError):
218 logger.exception("Unable to fetch gallery")
223 def diff(request, doc_id):
224 revA = int(request.GET.get('from', 0))
225 revB = int(request.GET.get('to', 0))
228 revA, revB = revB, revA
233 # TODO: check if revisions in line.
235 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
237 # allow diff from the beginning
239 docA = Revision.objects.get(pk=revA).materialize()
242 docB = Revision.objects.get(pk=revB).materialize()
244 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
248 def history(request, doc_id):
250 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
252 return JSONResponse(get_history(doc))