diff --git a/data/db.sqlite3 b/data/db.sqlite3 index e3662c8..c92850c 100644 Binary files a/data/db.sqlite3 and b/data/db.sqlite3 differ diff --git a/links/migrations/0040_site_settings.py b/links/migrations/0040_site_settings.py new file mode 100644 index 0000000..a88124a --- /dev/null +++ b/links/migrations/0040_site_settings.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.11 on 2026-03-21 10:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0039_file_upload'), + ] + + operations = [ + migrations.CreateModel( + name='SiteSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('public_sharing_domain', models.CharField(blank=True, default='', help_text='Domain (with protocol) used for public sharing links, e.g. https://go.example.com. Leave blank to use the same domain as the app.', max_length=255, verbose_name='Public Sharing Domain')), + ], + options={ + 'verbose_name': 'Site Settings', + }, + ), + ] diff --git a/links/models.py b/links/models.py index a5939f7..d46f6ec 100644 --- a/links/models.py +++ b/links/models.py @@ -387,9 +387,16 @@ class FileUpload(models.Model): @property def public_url(self): - import re - safe_name = re.sub(r'[^\w.\-]', '-', self.name) - return f'/public/files/{self.pk}-{safe_name}' + import re as _re + safe_name = _re.sub(r'[^\w.\-]', '-', self.name) + path = f'/public/files/{self.pk}-{safe_name}' + if not self.is_public: + return path + try: + domain = SiteSettings.get().public_sharing_domain.rstrip('/') + except Exception: + domain = '' + return f'{domain}{path}' if domain else path def formatted_size(self): if self.size < 1024: @@ -399,3 +406,35 @@ class FileUpload(models.Model): elif self.size < 1024 * 1024 * 1024: return f"{self.size / (1024 * 1024):.1f} MB" return f"{self.size / (1024 * 1024 * 1024):.2f} GB" + + +class SiteSettings(models.Model): + """ + Singleton model for app-wide configuration. + Always use SiteSettings.get() to retrieve the instance. + """ + public_sharing_domain = models.CharField( + _('Public Sharing Domain'), + max_length=255, + blank=True, + default='', + help_text=_( + 'Domain (with protocol) used for public sharing links, e.g. https://go.example.com. ' + 'Leave blank to use the same domain as the app.' + ), + ) + + class Meta: + verbose_name = _('Site Settings') + + def __str__(self): + return 'Site Settings' + + @classmethod + def get(cls): + obj, _ = cls.objects.get_or_create(pk=1) + return obj + + def save(self, *args, **kwargs): + self.pk = 1 + super().save(*args, **kwargs) diff --git a/links/templates/links/settings.html b/links/templates/links/settings.html new file mode 100644 index 0000000..7a67495 --- /dev/null +++ b/links/templates/links/settings.html @@ -0,0 +1,56 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +