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 'assignment': str(doc.assigned_to),
74 'serialized_templates': json.dumps([
75 {'id': t.id, 'name': t.name, 'content': t.content} for t in Template.objects.filter(is_partial=True)
78 "text_save": save_form,
79 "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
80 "text_publish": forms.DocumentTextPublishForm(prefix="textpublish"),
87 @decorator_from_middleware(GZipMiddleware)
88 def text(request, doc_id):
89 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
90 # if not doc.book.accessible(request):
91 # return HttpResponseForbidden("Not authorized.")
93 if request.method == 'POST':
94 form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
96 if request.user.is_authenticated():
100 text = form.cleaned_data['text']
101 # parent_revision = form.cleaned_data['parent_revision']
102 # if parent_revision is not None:
103 # parent = doc.at_revision(parent_revision)
106 stage = form.cleaned_data['stage']
107 # tags = [stage] if stage else []
108 # publishable = (form.cleaned_data['publishable'] and
109 # request.user.has_perm('catalogue.can_pubmark'))
114 description=form.cleaned_data['comment'],
115 author_name=form.cleaned_data['author_name'],
116 author_email=form.cleaned_data['author_email'],
120 from traceback import print_exc
123 # revision = doc.revision()
124 return JSONResponse({
125 'text': None, # doc.materialize() if parent_revision != revision else None,
126 # 'version': revision,
127 # 'stage': doc.stage.name if doc.stage else None,
128 'assignment': doc.assigned_to.username if doc.assigned_to else None
131 return JSONFormInvalid(form)
133 revision = request.GET.get("revision", None)
136 revision = int(revision)
137 except (ValueError, TypeError):
138 revision = doc.revision()
140 if revision is not None:
141 text = doc.at_revision(revision).materialize()
145 return JSONResponse({
148 'revision': revision,
154 def revert(request, doc_id):
155 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
157 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
158 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
160 comment = form.cleaned_data['comment']
161 comment += "\n#revert to %s" % rev.pk
163 if request.user.is_authenticated():
164 author = request.user
168 # before = doc.revision
169 logger.info("Reverting %s to %s", doc_id, rev.pk)
173 text=rev.materialize(),
175 # author_name=form.cleaned_data['author_name'], #?
176 # author_email=form.cleaned_data['author_email'], #?
179 return JSONResponse({
180 # 'document': None, #doc.materialize() if before != doc.revision else None,
181 # 'version': doc.revision(),
184 return JSONFormInvalid(form)
188 def gallery(request, directory):
189 if not request.user.is_authenticated():
190 return HttpResponseForbidden("Not authorized.")
194 smart_unicode(settings.MEDIA_URL),
195 smart_unicode(settings.IMAGE_DIR),
196 smart_unicode(directory)))
198 base_dir = os.path.join(
199 smart_unicode(settings.MEDIA_ROOT),
200 smart_unicode(settings.IMAGE_DIR),
201 smart_unicode(directory))
203 def map_to_url(filename):
204 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
206 def is_image(filename):
207 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
209 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
212 return JSONResponse(images)
213 except (IndexError, OSError):
214 logger.exception("Unable to fetch gallery")
219 def diff(request, doc_id):
220 revA = int(request.GET.get('from', 0))
221 revB = int(request.GET.get('to', 0))
224 revA, revB = revB, revA
229 # TODO: check if revisions in line.
231 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
233 # allow diff from the beginning
235 docA = Revision.objects.get(pk=revA).materialize()
238 docB = Revision.objects.get(pk=revB).materialize()
240 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
244 def history(request, doc_id):
246 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
248 return JSONResponse(get_history(doc))