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']
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 if not doc.can_edit(request.user):
160 return HttpResponseForbidden("Not authorized.")
161 rev = get_object_or_404(Revision, pk=form.cleaned_data['revision'])
163 comment = form.cleaned_data['comment']
164 comment += "\n#revert to %s" % rev.pk
166 if request.user.is_authenticated():
167 author = request.user
171 # before = doc.revision
172 logger.info("Reverting %s to %s", doc_id, rev.pk)
176 text=rev.materialize(),
178 # author_name=form.cleaned_data['author_name'], #?
179 # author_email=form.cleaned_data['author_email'], #?
182 return JSONResponse({
183 'document': doc.materialize(),
184 'version': len(get_history(doc)),
186 'stage_name': doc.stage_name(),
187 'assignment': doc.assigned_to.username if doc.assigned_to else None,
190 return JSONFormInvalid(form)
194 def gallery(request, directory):
195 if not request.user.is_authenticated():
196 return HttpResponseForbidden("Not authorized.")
200 smart_unicode(settings.MEDIA_URL),
201 smart_unicode(settings.IMAGE_DIR),
202 smart_unicode(directory)))
204 base_dir = os.path.join(
205 smart_unicode(settings.MEDIA_ROOT),
206 smart_unicode(settings.IMAGE_DIR),
207 smart_unicode(directory))
209 def map_to_url(filename):
210 return urllib.quote("%s/%s" % (base_url, smart_unicode(filename)))
212 def is_image(filename):
213 return os.path.splitext(f)[1].lower() in (u'.jpg', u'.jpeg', u'.png')
215 images = [map_to_url(f) for f in map(smart_unicode, os.listdir(base_dir)) if is_image(f)]
218 return JSONResponse(images)
219 except (IndexError, OSError):
220 logger.exception("Unable to fetch gallery")
225 def diff(request, doc_id):
226 revA = int(request.GET.get('from', 0))
227 revB = int(request.GET.get('to', 0))
230 revA, revB = revB, revA
235 # TODO: check if revisions in line.
237 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
239 # allow diff from the beginning
241 docA = Revision.objects.get(pk=revA).materialize()
244 docB = Revision.objects.get(pk=revB).materialize()
246 return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
250 def history(request, doc_id):
252 doc = get_object_or_404(Document, pk=doc_id, deleted=False)
254 return JSONResponse(get_history(doc))