BTHLABS-66: Prepping for public release: Take one

This commit is contained in:
2025-11-18 20:47:07 +01:00
parent 16a9c73624
commit 20fa33abeb
84 changed files with 839 additions and 631 deletions

View File

@@ -79,3 +79,17 @@ class AuthKeysService:
raise self.NotFound(
f'Auth Key not found: key=`{key}`',
) from exception
def clean_expired_auth_keys(self) -> int:
current_timestamp = now()
cutoff_timestamp = current_timestamp - datetime.timedelta(
seconds=(settings.AUTH_KEY_TTL + 5),
)
deleted, _ = AuthKey.active_objects.\
filter(
created_at__lte=cutoff_timestamp,
).\
delete()
return deleted

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
import logging
from celery import shared_task
from django import db
from hotpocket_backend.apps.accounts.services import AuthKeysService
LOGGER = logging.getLogger(__name__)
@shared_task
def clean_expired_auth_keys():
with db.transaction.atomic():
deleted_count = AuthKeysService().clean_expired_auth_keys()
LOGGER.debug(
'Deleted expired AuthKey objects: deleted_count=`%d`', deleted_count,
)

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.8 on 2025-11-18 14:13
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('saves', '0008_alter_save_url'),
]
operations = [
migrations.AlterField(
model_name='save',
name='description',
field=models.CharField(blank=True, db_index=True, default=None, null=True),
),
migrations.AlterField(
model_name='save',
name='title',
field=models.CharField(blank=True, db_index=True, default=None, null=True),
),
migrations.AlterField(
model_name='save',
name='url',
field=models.CharField(db_index=True, default=None, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])]),
),
]

View File

@@ -20,7 +20,7 @@ class Save(Model):
blank=False, null=False, default=None, db_index=True,
)
url = models.CharField(
blank=False, null=False, default=None,
blank=False, null=False, default=None, db_index=True,
validators=[
validators.URLValidator(schemes=['http', 'https']),
],
@@ -29,10 +29,10 @@ class Save(Model):
blank=True, null=True, default=None, editable=False,
)
title = models.CharField(
blank=True, null=True, default=None,
blank=True, null=True, default=None, db_index=True,
)
description = models.CharField(
blank=True, null=True, default=None,
blank=True, null=True, default=None, db_index=True,
)
last_processed_at = models.DateTimeField(
auto_now=False,

View File

@@ -122,3 +122,7 @@ body.ui-mode-standalone #offcanvas-controls .offcanvas-body {
position: relative;
}
}
.ui-login-logo {
width: 128px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -1,6 +1,6 @@
{% extends "ui/base.html" %}
{% load crispy_forms_tags i18n ui %}
{% load crispy_forms_tags i18n static ui %}
{% block title %}{% translate 'Log in' %}{% endblock %}
@@ -10,6 +10,11 @@
<div class="container">
<div class="row">
<div class="col col-12 col-md-6 offset-md-3">
<img
alt="HotPocket Icon"
class="d-block ms-auto me-auto ui-login-logo"
src="{% static 'ui/img/icon-mac-384.png' %}"
>
<div class="card">
<div class="card-header text-center">
<p class="fs-3 mb-0">{{ SITE_TITLE }}</p>

View File

@@ -16,7 +16,7 @@
{% endif %}
</div>
<div class="card-footer d-flex align-items-center">
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferer"><small>{{ association.target.url|render_url_domain }}</small></a>
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferrer"><small>{{ association.target.url|render_url_domain }}</small></a>
<div class="ms-auto flex-shrink-0 d-flex align-items-center">
{% if not association.archived_at %}
<div class="spinner-border spinner-border-sm ui-htmx-indicator" role="status">

View File

@@ -20,7 +20,7 @@
{% blocktranslate with created_at=association.created_at %}Saved on {{ created_at }}{% endblocktranslate %}
</span>
<br>
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferer">
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferrer">
{% translate 'View original' %} <i class="bi bi-box-arrow-up-right"></i>
</a>
</p>
@@ -51,7 +51,7 @@
<a
class="btn btn-secondary btn-sm ui-noscript-show"
href="{{ share_url }}"
rel="noopener noreferer"
rel="noopener noreferrer"
target="_blank"
>
<i class="bi bi-link-45deg"></i> {% translate 'Share link' %}

View File

@@ -1,6 +1,6 @@
<p class="mb-0 mt-2 text-center text-muted ui-uname">
<span>
<a href="https://hotpocket.app/" target="_blank" rel="noopener noreferer">{{ SITE_TITLE }}</a> v{{ VERSION }}
<a href="https://hotpocket.app/" target="_blank" rel="noopener noreferrer">{{ SITE_TITLE }}</a> v{{ VERSION }}
(<code>{{ IMAGE_ID }}</code>)
</span>
<br>

View File

@@ -4,6 +4,7 @@ from __future__ import annotations
import os
from celery.schedules import crontab
from corsheaders.defaults import default_headers
from .base import * # noqa: F401,F403
@@ -46,6 +47,13 @@ SESSION_COOKIE_SECURE = True
CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap5'
CRISPY_TEMPLATE_PACK = 'bootstrap5'
CELERY_BEAT_SCHEDULE = {
'clean-expired-auth-keys': {
'task': 'hotpocket_backend.apps.accounts.tasks.clean_expired_auth_keys',
'schedule': crontab(minute='30', hour='3'),
},
}
HOTPOCKET_BOT_STRATEGY = 'hotpocket_backend.apps.bot.strategy.basic:BasicStrategy'
HOTPOCKET_BOT_BANNED_HOSTNAMES = [
# YT returns dummy data when I try to fetch the page and extract