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, Category
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"),
85 'tag_categories': Category.objects.all(),
91 @decorator_from_middleware(GZipMiddleware)
92 def text(request, doc_id):
93 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
95 if request.method == 'POST':
96 if not doc.can_edit(request.user):
97 return HttpResponseForbidden("Not authorized.")
98 form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
100 if request.user.is_authenticated():
101 author = request.user
104 text = form.cleaned_data['text']
105 # parent_revision = form.cleaned_data['parent_revision']
106 # if parent_revision is not None:
107 # parent = doc.at_revision(parent_revision)
110 stage = form.cleaned_data['stage']
111 # tags = [stage] if stage else []
112 # publishable = (form.cleaned_data['publishable'] and
113 # request.user.has_perm('catalogue.can_pubmark'))
118 description=form.cleaned_data['comment'],
119 author_name=form.cleaned_data['author_name'],
120 author_email=form.cleaned_data['author_email'],
124 from traceback import print_exc
127 return JSONResponse({
128 'text': None, # doc.materialize() if parent_revision != revision else None,
129 'version': len(get_history(doc)),
131 'stage_name': doc.stage_name(),
132 'assignment': doc.assigned_to.username if doc.assigned_to else None
135 return JSONFormInvalid(form)
137 revision = request.GET.get("revision", None)
140 revision = int(revision)
141 except (ValueError, TypeError):
142 revision = doc.revision()
144 if revision is not None:
145 text = doc.at_revision(revision).materialize()
149 return JSONResponse({
152 'revision': revision,
158 def revert(request, doc_id):
159 form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
161 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
162 if not doc.can_edit(request.user):
163 return HttpResponseForbidden("Not authorized.")
164 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
166 comment = form.cleaned_data['comment']
167 comment += "\n#revert to %s" % rev.pk
169 if request.user.is_authenticated():
170 author = request.user
174 # before = doc.revision
175 logger.info("Reverting %s to %s", doc_id, rev.pk)
179 text=rev.materialize(),
181 # author_name=form.cleaned_data['author_name'], #?
182 # author_email=form.cleaned_data['author_email'], #?
185 return JSONResponse({
186 'document': doc.materialize(),
187 'version': len(get_history(doc)),
189 'stage_name': doc.stage_name(),
190 'assignment': doc.assigned_to.username if doc.assigned_to else None,
193 return JSONFormInvalid(form)
197 def gallery(request, directory):
198 if not request.user.is_authenticated():
199 return HttpResponseForbidden("Not authorized.")
203 smart_unicode(settings.MEDIA_URL),
204 smart_unicode(settings.IMAGE_DIR),
205 smart_unicode(directory)))
207 base_dir = os.path.join(
208 smart_unicode(settings.MEDIA_ROOT),
209 smart_unicode(settings.IMAGE_DIR),
210 smart_unicode(directory))
212 def map_to_url(filename):
213 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
215 def is_image(filename):
216 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
218 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
221 return JSONResponse(images)
222 except (IndexError, OSError):
223 logger.exception("Unable to fetch gallery")
228 def diff(request, doc_id):
229 revA = int(request.GET.get('from', 0))
230 revB = int(request.GET.get('to', 0))
233 revA, revB = revB, revA
238 # TODO: check if revisions in line.
240 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
242 # allow diff from the beginning
244 docA = Revision.objects.get(pk=revA).materialize()
247 docB = Revision.objects.get(pk=revB).materialize()
249 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
253 def history(request, doc_id):
255 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
257 return JSONResponse(get_history(doc))