149 lines
5.1 KiB
Python
149 lines
5.1 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.utils.decorators import method_decorator
|
|
from django.views import View
|
|
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 paste.get_absolute_url(request)
|
|
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"
|
|
|
|
|
|
@method_decorator(csrf_exempt, name="dispatch")
|
|
class PasteView(View):
|
|
def get(self, request, path=""):
|
|
paste = get_object_or_404(Paste, slug=path)
|
|
paste.incr_viewcount()
|
|
|
|
if "html" in request.headers.get(
|
|
"accept", "html"
|
|
) and not paste.filename.endswith(".txt"):
|
|
return HttpResponse(paste_to_html(paste.filename, paste.content))
|
|
else:
|
|
return HttpResponse(paste.content, content_type="text/plain")
|
|
|
|
def put(self, request, path=""):
|
|
if request.headers.get("Expect") == "100-continue":
|
|
return HttpResponse("")
|
|
try:
|
|
paste = Paste.objects.get(slug=path)
|
|
except Paste.DoesNotExist:
|
|
paste = Paste(
|
|
slug=path,
|
|
filename=path.rstrip("/").split("/")[-1],
|
|
)
|
|
paste.set_secret(request.headers.get("Authorization"))
|
|
else:
|
|
if not paste.check_secret(request.headers.get("Authorization")):
|
|
return HttpResponse("Paste already exists.\n", status=401)
|
|
paste.content = request.read().decode("UTF-8")
|
|
paste.compute_size()
|
|
paste.save()
|
|
return HttpResponse("- " + paste.get_absolute_url(request) + "\n")
|
|
|
|
|
|
@method_decorator(csrf_exempt, name="dispatch")
|
|
class IndexView(PasteView):
|
|
def post(self, request):
|
|
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(
|
|
"- "
|
|
+ " \n- ".join(paste.get_absolute_url(request) for paste in pastes)
|
|
+ "\n",
|
|
content_type="text/plain",
|
|
)
|
|
|
|
|
|
class ListView(View):
|
|
def get(self, 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",
|
|
"viewcount",
|
|
),
|
|
)
|
|
if "html" in request.headers.get("accept", "html"):
|
|
return HttpResponse(
|
|
loader.render_to_string(
|
|
"paste/show-markdown.html", {"highlighted": markdown_to_html(table)}
|
|
)
|
|
)
|
|
else:
|
|
return HttpResponse(table, content_type="text/plain")
|
|
|
|
|
|
@lru_cache(1024)
|
|
def paste_to_html(filename, filecontents):
|
|
data = {}
|
|
data["filename"] = filename
|
|
if filename.endswith(".md") 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)
|