X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/3ca475c8e10c811633dec531772e18da6e5fa33d..491078616e2129745f300c1f0357f5bac52e801d:/src/wiki/views.py diff --git a/src/wiki/views.py b/src/wiki/views.py index aea44390..3e6fedbf 100644 --- a/src/wiki/views.py +++ b/src/wiki/views.py @@ -2,6 +2,7 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from datetime import datetime +import json import os import logging from time import mktime @@ -11,18 +12,20 @@ from django.apps import apps from django.conf import settings from django.urls import reverse from django import http -from django.http import Http404, HttpResponseForbidden +from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseBadRequest from django.middleware.gzip import GZipMiddleware from django.utils.decorators import decorator_from_middleware from django.utils.formats import localize from django.utils.translation import gettext as _ from django.views.decorators.http import require_POST, require_GET from django.shortcuts import get_object_or_404, render +from django_gravatar.helpers import get_gravatar_url from sorl.thumbnail import get_thumbnail from documents.models import Book, Chunk import sources.models from . import nice_diff +from team.models import Presence from wiki import forms from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError, ajax_require_permission) @@ -38,6 +41,10 @@ logger = logging.getLogger("fnp.wiki") MAX_LAST_DOCS = 10 +class HttpResponseLengthRequired(HttpResponse): + status_code = 411 + + @never_cache def editor(request, slug, chunk=None, template_name='wiki/document_details.html'): try: @@ -129,6 +136,20 @@ def text(request, chunk_id): return HttpResponseForbidden("Not authorized.") if request.method == 'POST': + # Check length to reject broken request. + try: + expected_cl = int(request.META['CONTENT_LENGTH']) + except: + return HttpResponseLengthRequired(json.dumps( + {"__message": _("Content length required.")} + )) + # 411 if missing + cl = len(request.body) + if cl != expected_cl: + return HttpResponseBadRequest(json.dumps( + {"__message": _("Wrong content length, request probably interrupted.")} + )) + form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave") if form.is_valid(): if request.user.is_authenticated: @@ -252,15 +273,21 @@ def gallery(request, directory): @never_cache -def scans_list(request, pk): - bs = get_object_or_404(sources.models.BookSource, pk=pk) +def scans_list(request, pks): + pks = pks.split(',') + bss = [ + get_object_or_404(sources.models.BookSource, pk=pk) + for pk in pks + ] def map_to_url(filename): return quote(("%s/%s" % (settings.MEDIA_URL, filename))) - images = [ - { - "url": map_to_url(f), - } for f in bs.get_view_files() - ] + images = [] + for bs in bss: + images.extend([ + { + "url": map_to_url(f), + } for f in bs.get_view_files() + ]) return JSONResponse(images) @@ -292,12 +319,34 @@ def diff(request, chunk_id): @never_cache def revision(request, chunk_id): + if not request.session.session_key: + return HttpResponseForbidden("Not authorized.") doc = get_object_or_404(Chunk, pk=chunk_id) if not doc.book.accessible(request): return HttpResponseForbidden("Not authorized.") - Presence = apps.get_model('team', 'Presence') - Presence.report(request.user, doc, request.GET.get('a') == 'true') - return http.HttpResponse(str(doc.revision())) + + Presence.report( + request.user, request.session.session_key, + doc, + request.GET.get('a') == 'true' + ) + + # Temporary compat for unreloaded clients. + if not request.GET.get('new'): + return http.HttpResponse(str(doc.revision())) + + return JSONResponse({ + 'rev': doc.revision(), + 'people': list([ + { + 'name': (p.user.first_name + ' ' + p.user.last_name) if p.user is not None else '?', + 'gravatar': get_gravatar_url(p.user.email if p.user is not None else '-', size=26), + 'since': p.since.strftime('%H:%M'), + 'active': p.active, + } + for p in Presence.get_current(request.session.session_key, doc) + ]), + }) @never_cache