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.translation import ugettext as _
19 from django.views.decorators.http import require_POST
20 from django.shortcuts import get_object_or_404, render
22 from catalogue.models import Document, Template
23 from dvcs.models import Revision
25 from wiki import forms
26 from wiki.helpers import JSONResponse, JSONFormInvalid
29 # Quick hack around caching problems, TODO: use ETags
31 from django.views.decorators.cache import never_cache
33 logger = logging.getLogger("fnp.wiki")
38 def get_history(document):
40 for i, revision in enumerate(document.history()):
43 "description": revision.description,
44 "author": revision.author_str(),
45 "date": localize(revision.created_at),
46 "revision": revision.pk,
47 "published": _("Published") + ": " +
48 localize(revision.publish_log.order_by('-timestamp')[0].timestamp)
49 if revision.publish_log.exists() else "",
55 def editor(request, pk, template_name='wiki/bootstrap.html'):
56 doc = get_object_or_404(Document, pk=pk, deleted=False)
58 save_form = forms.DocumentTextSaveForm(user=request.user, prefix="textsave")
59 text = doc.materialize()
60 revision = doc.revision
61 history = get_history(doc)
62 return render(request, template_name, {
63 'serialized_document_data': json.dumps({
65 'document_id': doc.pk,
66 'title': doc.meta().get('title', ''),
68 'version': len(history),
69 'revision': revision.pk,
71 'assignment': str(doc.assigned_to),
73 'serialized_templates': json.dumps([
74 {'id': t.id, 'name': t.name, 'content': t.content} for t in Template.objects.filter(is_partial=True)
77 "text_save": save_form,
78 "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
79 "text_publish": forms.DocumentTextPublishForm(prefix="textpublish"),
86 @decorator_from_middleware(GZipMiddleware)
87 def text(request, doc_id):
88 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
89 # if not doc.book.accessible(request):
90 # return HttpResponseForbidden("Not authorized.")
92 if request.method == 'POST':
93 form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
95 if request.user.is_authenticated():
99 text = form.cleaned_data['text']
100 # parent_revision = form.cleaned_data['parent_revision']
101 # if parent_revision is not None:
102 # parent = doc.at_revision(parent_revision)
105 stage = form.cleaned_data['stage']
106 # tags = [stage] if stage else []
107 # publishable = (form.cleaned_data['publishable'] and
108 # request.user.has_perm('catalogue.can_pubmark'))
113 description=form.cleaned_data['comment'],
114 author_name=form.cleaned_data['author_name'],
115 author_email=form.cleaned_data['author_email'],
119 from traceback import print_exc
122 # revision = doc.revision()
123 return JSONResponse({
124 'text': None, # doc.materialize() if parent_revision != revision else None,
125 # 'version': revision,
126 # 'stage': doc.stage.name if doc.stage else None,
127 'assignment': doc.assigned_to.username if doc.assigned_to else None
130 return JSONFormInvalid(form)
132 revision = request.GET.get("revision", None)
135 revision = int(revision)
136 except (ValueError, TypeError):
137 revision = doc.revision()
139 if revision is not None:
140 text = doc.at_revision(revision).materialize()
144 return JSONResponse({
147 'revision': revision,
153 def revert(request, doc_id):
154 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
156 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
157 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
159 comment = form.cleaned_data['comment']
160 comment += "\n#revert to %s" % rev.pk
162 if request.user.is_authenticated():
163 author = request.user
167 # before = doc.revision
168 logger.info("Reverting %s to %s", doc_id, rev.pk)
172 text=rev.materialize(),
174 # author_name=form.cleaned_data['author_name'], #?
175 # author_email=form.cleaned_data['author_email'], #?
178 return JSONResponse({
179 # 'document': None, #doc.materialize() if before != doc.revision else None,
180 # 'version': doc.revision(),
183 return JSONFormInvalid(form)
187 def gallery(request, directory):
188 if not request.user.is_authenticated():
189 return HttpResponseForbidden("Not authorized.")
193 smart_unicode(settings.MEDIA_URL),
194 smart_unicode(settings.IMAGE_DIR),
195 smart_unicode(directory)))
197 base_dir = os.path.join(
198 smart_unicode(settings.MEDIA_ROOT),
199 smart_unicode(settings.IMAGE_DIR),
200 smart_unicode(directory))
202 def map_to_url(filename):
203 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
205 def is_image(filename):
206 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
208 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
211 return JSONResponse(images)
212 except (IndexError, OSError):
213 logger.exception("Unable to fetch gallery")
218 def diff(request, doc_id):
219 revA = int(request.GET.get('from', 0))
220 revB = int(request.GET.get('to', 0))
223 revA, revB = revB, revA
228 # TODO: check if revisions in line.
230 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
232 # allow diff from the beginning
234 docA = Revision.objects.get(pk=revA).materialize()
237 docB = Revision.objects.get(pk=revB).materialize()
239 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
243 def history(request, doc_id):
245 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
247 return JSONResponse(get_history(doc))