Add ::/list/ endpoint, with a secret to find them.
This commit is contained in:
parent
e376fab285
commit
2b13d6cbb0
|
@ -12,12 +12,14 @@ class PasteAdmin(admin.ModelAdmin):
|
|||
"paste_time",
|
||||
"access_time",
|
||||
"viewcount",
|
||||
"auth",
|
||||
)
|
||||
fields = (
|
||||
(
|
||||
"slug",
|
||||
"size",
|
||||
),
|
||||
"auth",
|
||||
(
|
||||
"paste_time",
|
||||
"access_time",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 4.2 on 2023-04-25 09:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("paste", "0008_paste_access_time"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="paste",
|
||||
name="auth",
|
||||
field=models.CharField(default="", max_length=64),
|
||||
),
|
||||
]
|
|
@ -1,4 +1,5 @@
|
|||
from datetime import datetime, timedelta
|
||||
from hashlib import sha256
|
||||
|
||||
import shortuuid
|
||||
from django.core.validators import MaxLengthValidator
|
||||
|
@ -10,9 +11,16 @@ from django.utils.translation import gettext_lazy as _
|
|||
from webtools import settings
|
||||
|
||||
|
||||
class PasteQuerySet(models.QuerySet):
|
||||
def by_secret(self, secret):
|
||||
auth = sha256(secret.encode("UTF-8")).hexdigest()
|
||||
return self.filter(auth=auth)
|
||||
|
||||
|
||||
class Paste(models.Model):
|
||||
"""Paste object."""
|
||||
|
||||
objects = PasteQuerySet.as_manager()
|
||||
filename = models.CharField(max_length=255, default="")
|
||||
slug = models.SlugField(unique=True, editable=False)
|
||||
content = models.TextField(
|
||||
|
@ -23,6 +31,14 @@ class Paste(models.Model):
|
|||
access_time = models.DateTimeField(auto_now=True)
|
||||
viewcount = models.IntegerField(default=0, editable=False)
|
||||
|
||||
# auth stores a sha256 (hexdigest) of the Authentication header.
|
||||
auth = models.CharField(max_length=64, default="")
|
||||
|
||||
def set_secret(self, secret=None):
|
||||
if not secret:
|
||||
return
|
||||
self.auth = sha256(secret.encode("UTF-8")).hexdigest()
|
||||
|
||||
def compute_size(self):
|
||||
"""Computes size."""
|
||||
self.size = len(self.content)
|
||||
|
|
|
@ -7,5 +7,6 @@ from webtools import settings
|
|||
urlpatterns = [
|
||||
path("", views.index, name="index"),
|
||||
path("::/static/<path>", serve, {"document_root": settings.STATIC_ROOT}),
|
||||
path("::/list/", views.list_view),
|
||||
path("<path:slug>", views.show, name="short_paste"),
|
||||
]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from datetime import datetime
|
||||
from functools import lru_cache
|
||||
from mimetypes import common_types, types_map
|
||||
|
||||
|
@ -29,6 +30,21 @@ def get_files(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."""
|
||||
|
@ -46,22 +62,32 @@ def index(request):
|
|||
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)
|
||||
|
||||
table = [
|
||||
(
|
||||
request.build_absolute_uri(paste.get_absolute_url()),
|
||||
paste.size,
|
||||
paste.filename,
|
||||
)
|
||||
for paste in pastes
|
||||
]
|
||||
return HttpResponse(
|
||||
tabulate(table, headers=("URL", "size", "filename"), tablefmt="github") + "\n",
|
||||
content_type="text/plain",
|
||||
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):
|
||||
|
|
Loading…
Reference in New Issue