Group pastes from a same upload with the same slug.
This commit is contained in:
parent
14c6436b23
commit
1b1c3a1a47
|
@ -3,6 +3,7 @@ from datetime import datetime, timedelta
|
||||||
import shortuuid
|
import shortuuid
|
||||||
from django.core.validators import MaxLengthValidator
|
from django.core.validators import MaxLengthValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
@ -25,15 +26,35 @@ class Paste(models.Model):
|
||||||
"""Computes size."""
|
"""Computes size."""
|
||||||
self.size = len(self.content)
|
self.size = len(self.content)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("short_paste", kwargs={"slug": self.slug})
|
||||||
|
|
||||||
def incr_viewcount(self):
|
def incr_viewcount(self):
|
||||||
"""Increment view counter."""
|
"""Increment view counter."""
|
||||||
self.viewcount = self.viewcount + 1
|
self.viewcount = self.viewcount + 1
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
excerpt = repr(self.content[:100]) + ("..." if len(self.content) > 100 else "")
|
excerpt = repr(self.content.split("\n")[0][:100]) + (
|
||||||
|
"..." if len(self.content) > 100 else ""
|
||||||
|
)
|
||||||
return f"{self.slug} - {excerpt}"
|
return f"{self.slug} - {excerpt}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def choose_prefix(cls, filenames):
|
||||||
|
"""Find a prefix free for all the given filenames.
|
||||||
|
|
||||||
|
Such as <prefix>/filename is unused.
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
uuid = shortuuid.uuid()
|
||||||
|
for i in range(4, len(uuid) + 1):
|
||||||
|
potential_uuid = uuid[:i]
|
||||||
|
for filename in filenames:
|
||||||
|
slug = f"{potential_uuid}/{filename}"
|
||||||
|
if not any(cls.objects.filter(slug=slug) for filename in filenames):
|
||||||
|
return potential_uuid
|
||||||
|
|
||||||
def choose_slug(self):
|
def choose_slug(self):
|
||||||
while True:
|
while True:
|
||||||
uuid = shortuuid.uuid()
|
uuid = shortuuid.uuid()
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
{% load i18n %}{% load compress %}<!doctype html>
|
{% load i18n compress static %}
|
||||||
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
{% compress css %}
|
{% compress css %}
|
||||||
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
|
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet">
|
||||||
<link href="/static/css/pygments-highlight.css" rel="stylesheet">
|
<link href="{% static 'css/pygments-highlight.css' %}" rel="stylesheet">
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{% block extrastyle %}{% endblock %}
|
{% block extrastyle %}{% endblock %}
|
||||||
<title>{% block title %}{{ DISPLAY_NAME }}{% endblock %}</title>
|
<title>{% block title %}{{ DISPLAY_NAME }}{% endblock %}</title>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block extrastyle %}
|
{% block extrastyle %}
|
||||||
<link href="/static/css/github-markdown.css" rel="stylesheet">
|
<link href="{% static 'css/github-markdown.css' %}" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block title %}{{ filename }}{% endblock %}
|
{% block title %}{{ filename }}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block extrastyle %}
|
{% block extrastyle %}
|
||||||
<link href="/static/css/pasteque.css" rel="stylesheet">
|
<link href="{% static 'css/pasteque.css' %}" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block title %}{{ filename }}{% endblock %}
|
{% block title %}{{ filename }}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -6,6 +6,6 @@ from webtools import settings
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", views.index, name="index"),
|
path("", views.index, name="index"),
|
||||||
path("static/<path>", serve, {"document_root": settings.STATIC_ROOT}),
|
path("::/static/<path>", serve, {"document_root": settings.STATIC_ROOT}),
|
||||||
path("<slug>", views.show, name="short_paste"),
|
path("<path:slug>", views.show, name="short_paste"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,7 +10,6 @@ from markdown.extensions.codehilite import CodeHiliteExtension
|
||||||
from pygments.formatters import HtmlFormatter
|
from pygments.formatters import HtmlFormatter
|
||||||
from pygments.lexers import get_lexer_by_name, get_lexer_for_filename
|
from pygments.lexers import get_lexer_by_name, get_lexer_for_filename
|
||||||
|
|
||||||
|
|
||||||
ALLOWED_TAGS = [
|
ALLOWED_TAGS = [
|
||||||
# Bleach Defaults
|
# Bleach Defaults
|
||||||
"a",
|
"a",
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from mimetypes import common_types, types_map
|
from mimetypes import common_types, types_map
|
||||||
|
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.template import RequestContext, loader
|
from django.template import RequestContext, loader
|
||||||
from django.urls import reverse
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
@ -14,7 +13,8 @@ from webtools import settings
|
||||||
|
|
||||||
NON_STANDARD_TYPES_INV = {value: key for key, value in common_types.items()}
|
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()}
|
STANDARD_TYPES_INV = {value: key for key, value in types_map.items()}
|
||||||
TYPES_INV = NON_STANDARD_TYPES_INV | STANDARD_TYPES_INV
|
HARDCODED_TYPES_INV = {"text/plain": ".txt"}
|
||||||
|
TYPES_INV = NON_STANDARD_TYPES_INV | STANDARD_TYPES_INV | HARDCODED_TYPES_INV
|
||||||
|
|
||||||
|
|
||||||
def get_files(request):
|
def get_files(request):
|
||||||
|
@ -24,7 +24,9 @@ def get_files(request):
|
||||||
return request.FILES
|
return request.FILES
|
||||||
content_type = request.headers.get("content-type", "")
|
content_type = request.headers.get("content-type", "")
|
||||||
ext = TYPES_INV.get(content_type, "")
|
ext = TYPES_INV.get(content_type, "")
|
||||||
return {"request" + ext: request}
|
if ext:
|
||||||
|
return {"request" + ext: request}
|
||||||
|
return {"": request}
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
@ -35,36 +37,37 @@ def index(request):
|
||||||
if request.headers.get("Expect") == "100-continue":
|
if request.headers.get("Expect") == "100-continue":
|
||||||
return HttpResponse("")
|
return HttpResponse("")
|
||||||
pastes = []
|
pastes = []
|
||||||
for filename, the_file in get_files(request).items():
|
files = get_files(request)
|
||||||
|
prefix = Paste.choose_prefix(list(files.keys()))
|
||||||
|
for filename, the_file in files.items():
|
||||||
|
filename = filename.replace("\\", "/")
|
||||||
paste = Paste(
|
paste = Paste(
|
||||||
filename=filename.split("/")[-1].split("\\")[-1],
|
slug=f"{prefix}/{filename}".rstrip("/"),
|
||||||
|
filename=filename.split("/")[-1],
|
||||||
content=the_file.read().decode("UTF-8"),
|
content=the_file.read().decode("UTF-8"),
|
||||||
)
|
)
|
||||||
paste.choose_slug()
|
|
||||||
paste.compute_size()
|
paste.compute_size()
|
||||||
paste.save()
|
paste.save()
|
||||||
pastes.append(
|
pastes.append(paste)
|
||||||
(
|
|
||||||
request.build_absolute_uri(
|
table = [
|
||||||
reverse("short_paste", kwargs={"slug": paste.slug})
|
(
|
||||||
),
|
request.build_absolute_uri(paste.get_absolute_url()),
|
||||||
paste.size,
|
paste.size,
|
||||||
paste.filename,
|
paste.filename,
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
for paste in pastes
|
||||||
if not pastes:
|
]
|
||||||
return HttpResponse("error: Please provide a file.")
|
|
||||||
|
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
tabulate(pastes, headers=("URL", "size", "filename"), tablefmt="github") + "\n",
|
tabulate(table, headers=("URL", "size", "filename"), tablefmt="github") + "\n",
|
||||||
content_type="text/plain",
|
content_type="text/plain",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def show(request, slug):
|
def show(request, slug):
|
||||||
"""Display paste."""
|
"""Display paste."""
|
||||||
|
if slug.startswith("::"):
|
||||||
|
raise Http404()
|
||||||
paste = get_object_or_404(Paste, slug=slug)
|
paste = get_object_or_404(Paste, slug=slug)
|
||||||
paste.incr_viewcount()
|
paste.incr_viewcount()
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ MEDIA_URL = ""
|
||||||
COMPRESS_ROOT = os.path.join(SITE_ROOT, "static")
|
COMPRESS_ROOT = os.path.join(SITE_ROOT, "static")
|
||||||
MEDIA_ROOT = os.path.join(SITE_ROOT, "assets")
|
MEDIA_ROOT = os.path.join(SITE_ROOT, "assets")
|
||||||
STATIC_ROOT = os.path.join(SITE_ROOT, "static")
|
STATIC_ROOT = os.path.join(SITE_ROOT, "static")
|
||||||
STATIC_URL = "/static/"
|
STATIC_URL = "/::/static/"
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||||
|
|
|
@ -2,6 +2,6 @@ from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path("::/admin/", admin.site.urls),
|
||||||
path('', include('paste.urls')),
|
path("", include("paste.urls")),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue