pasteque/paste/views.py

116 lines
3.9 KiB
Python

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)