from datetime import datetime from functools import lru_cache from mimetypes import common_types, types_map from django.http import Http404, HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.template import RequestContext, loader from django.views.decorators.csrf import csrf_exempt from tabulate import tabulate from paste.models import Paste from paste.utils import markdown_to_html, pygmentize from webtools import settings NON_STANDARD_TYPES_INV = {value: key for key, value in common_types.items()} STANDARD_TYPES_INV = {value: key for key, value in types_map.items()} HARDCODED_TYPES_INV = {"text/plain": ".txt"} TYPES_INV = NON_STANDARD_TYPES_INV | STANDARD_TYPES_INV | HARDCODED_TYPES_INV def get_files(request): """Get one or multiple files from either a multipart/form-data or raw request body with a Content-Type header.""" if request.FILES: return request.FILES content_type = request.headers.get("content-type", "") ext = TYPES_INV.get(content_type, "") if ext: return {"request" + ext: request} return {"": request} def pastes_as_table(request, pastes, headers=("URL", "size", "filename")): def paste_attr(paste, attr): if attr == "URL": return request.build_absolute_uri(paste.get_absolute_url()) value = getattr(paste, attr) if isinstance(value, datetime): return value.isoformat(timespec="seconds") return value values = [] for paste in pastes: values.append([paste_attr(paste, attr) for attr in headers]) return tabulate(values, headers=headers, tablefmt="github") + "\n" @csrf_exempt def index(request): """Displays form.""" if request.method == "GET": return render(request, "paste/index.html") if request.headers.get("Expect") == "100-continue": return HttpResponse("") pastes = [] files = get_files(request) prefix = Paste.choose_prefix(list(files.keys())) for filename, the_file in files.items(): filename = filename.replace("\\", "/") paste = Paste( slug=f"{prefix}/{filename}".rstrip("/"), filename=filename.split("/")[-1], content=the_file.read().decode("UTF-8"), ) paste.set_secret(request.headers.get("Authorization")) paste.compute_size() paste.save() pastes.append(paste) return HttpResponse(pastes_as_table(request, pastes), content_type="text/plain") def list_view(request): secret = request.headers.get("Authorization") pastes = [] if secret: pastes = Paste.objects.by_secret(secret).order_by("paste_time") table = pastes_as_table( request, pastes, headers=("filename", "size", "URL", "paste_time", "access_time"), ) if "html" in request.headers["accept"]: return HttpResponse( loader.render_to_string( "paste/show-markdown.html", {"highlighted": markdown_to_html(table)} ) ) else: return HttpResponse(table, content_type="text/plain") def show(request, slug): """Display paste.""" if slug.startswith("::"): raise Http404() paste = get_object_or_404(Paste, slug=slug) paste.incr_viewcount() if "html" in request.headers["accept"]: return HttpResponse(paste_to_html(paste.filename, paste.content)) else: return HttpResponse(paste.content, content_type="text/plain") @lru_cache(1024) def paste_to_html(filename, filecontents): data = {} data["filename"] = filename if filename.endswith(".md") or filename.endswith(".txt") or "." not in filename: data["highlighted"] = markdown_to_html(filecontents) return loader.render_to_string("paste/show-markdown.html", data) else: data["highlighted"] = pygmentize(filename, filecontents) return loader.render_to_string("paste/show-pygments.html", data)