pasteque/paste/models.py

91 lines
2.9 KiB
Python

from datetime import datetime, timedelta
from hashlib import sha256
import shortuuid
from django.core.validators import MaxLengthValidator
from django.db import models
from django.urls import reverse
from django.utils import timezone
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(
validators=[MaxLengthValidator(settings.PASTE["max_characters"])]
)
size = models.IntegerField(default=0, editable=False)
paste_time = models.DateTimeField(auto_now_add=True)
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 check_secret(self, secret=None):
if not secret:
return False
return self.auth == sha256(secret.encode("UTF-8")).hexdigest()
def compute_size(self):
"""Computes size."""
self.size = len(self.content)
def get_absolute_url(self, request=None):
uri = reverse("paste", kwargs={"path": self.slug})
if request:
uri = request.build_absolute_uri(uri)
return uri
def incr_viewcount(self):
"""Increment view counter."""
self.viewcount = self.viewcount + 1
self.save()
def __str__(self):
excerpt = repr(self.content.split("\n")[0][:100]) + (
"..." if len(self.content) > 100 else ""
)
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):
while True:
uuid = shortuuid.uuid()
for i in range(4, len(uuid)):
potential_uuid = uuid[:i]
if not type(self).objects.filter(slug=potential_uuid):
self.slug = potential_uuid
return