From e191147a1430475d022ab4a37b5aa84cdcd85c7b Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sat, 21 Mar 2026 21:22:04 +1100 Subject: [PATCH] Update sharing domain --- data/db.sqlite3 | Bin 479232 -> 479232 bytes links/migrations/0040_site_settings.py | 23 ++++++++++ links/models.py | 45 ++++++++++++++++++-- links/templates/links/settings.html | 56 +++++++++++++++++++++++++ links/urls.py | 1 + links/views.py | 17 +++++++- templates/base.html | 9 ++++ 7 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 links/migrations/0040_site_settings.py create mode 100644 links/templates/links/settings.html diff --git a/data/db.sqlite3 b/data/db.sqlite3 index e3662c8586a9093916079ab212e91a15e1292113..c92850cb262f4e621922235d42f3160005435ab9 100644 GIT binary patch delta 868 zcmZozAltA&c7n9vLk0$hQXsYlVh$j_JyFM)@!`gVCGyOod@7UK6*QUnR5m*reBzZ6 zwPZHr%*o8lE{-qGEJ-a+Eh)*&OD`6;U^Zr)F37QEWVtkI1*$tE!9XD$ji1Ueyv52cOf{j5oMQn3~-5N&b7)G<$|_7*8|KU`z#a z91Y6qbz@i=81*g1$}&^SQLJ`O%u@gfDg*=FqYw;rkYO}Xxv{NSN@`AONh*d0h%lO# zD2SHijKsWjbS=(#3J`HrJ=&2#J-X&%i76=t9G$iv4R!x1x?JzygT#|n-< zjuMU-V7SgT#O_OqcI~kUqnM>usAkKjD=B`5yMH5oA*b!mNUoj-kr>T zVIv3cd)}A4k9qF`t(WDMU}a`x6pI0q(O@zPOh#`0dYAtZvlySlboK*`+Dv>7K;=Aq z;-X?K4C1O7@z)-Hj&XbVIi?L4S=oWfC~-T_0_Gq7T+IA_4E%fe+xY!93l=!=TbMbp zGKd>Gg0&kMm>7UVE*_SYj0}v-bPbGkjSLkG4Xlg|tPBkGEDelIEX~{7{xeT+`_ED* z#m!>Oz@NZ%htr&69tR`OJk}QW{p__YuUL$M?h|D(Z8UC_Viz|wWNZ>FNleN~#Z0i6 zBJtB56B$K0;fZ?sh9o8nk delta 353 zcmZozAltA&c7n9vT?Ph*QXsYlVoo5wHBrZy@$SZiCGyN7eAbiM6*M;sCb02w$(S(P zGKyO;8#7K9soe3vF$T> zSaUA(urQuvU>0K9#pK3#5-7iuk+Yhcok2a((NTW-aYeQg&LS=dmv_3m5?eNB7$-Y} nxul~b@AQ32Z2sIcvpF~z6gPzf1-45ovpwc%`@p*F16u+B1s!Ig 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 %} +
+

{% trans "Settings" %}

+ +
+ {% csrf_token %} + + +
+

{% trans "Public Sharing Domain" %}

+

+ {% trans "Domain (with protocol) used for public file sharing links. Leave blank to use the same domain as the app." %} +
+ {% trans "Example:" %} https://go.example.com +

+ + {% if site_settings.public_sharing_domain %} +

+ {% trans "Active. Public links will use:" %} + {{ site_settings.public_sharing_domain }}/public/files/… +

+ {% else %} +

+ {% trans "Not set. Public links will use the app's own domain." %} +

+ {% endif %} +
+ +
+ +
+
+
+{% endblock %} diff --git a/links/urls.py b/links/urls.py index 2549273..ffbade2 100644 --- a/links/urls.py +++ b/links/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ path('ui/tools/', views.ToolsView.as_view(), name='tools'), path('tools/export-database/', views.export_database, name='export_database'), path('ui/help/', views.HelpView.as_view(), name='help'), + path('ui/settings/', views.SiteSettingsView.as_view(), name='site-settings'), # Pages path('ui/pages/', page_views.PageListView.as_view(), name='page-list'), diff --git a/links/views.py b/links/views.py index d9c43d2..93dff08 100644 --- a/links/views.py +++ b/links/views.py @@ -4,7 +4,7 @@ from django.views import View # Add this import from django.urls import reverse_lazy, reverse # Add 'reverse' here from django.db.models import F, Count, Q, Case, When, Value, IntegerField from django.db.models.functions import TruncDate -from .models import Link, ClickLog, LinkChangeLog, Page, Post +from .models import Link, ClickLog, LinkChangeLog, Page, Post, SiteSettings from .forms import LinkForm, PageForm import json from django.core.serializers.json import DjangoJSONEncoder @@ -533,6 +533,21 @@ def export_database(request): class HelpView(TemplateView): template_name = 'links/help.html' + +class SiteSettingsView(View): + template_name = 'links/settings.html' + + def get(self, request): + site_settings = SiteSettings.get() + return render(request, self.template_name, {'site_settings': site_settings}) + + def post(self, request): + site_settings = SiteSettings.get() + site_settings.public_sharing_domain = request.POST.get('public_sharing_domain', '').strip() + site_settings.save() + messages.success(request, _('Settings saved.')) + return redirect('site-settings') + @require_http_methods(["POST"]) def generate_tts(request, post_id): """Generate TTS audio for a post""" diff --git a/templates/base.html b/templates/base.html index f8bd0a4..05aaba5 100644 --- a/templates/base.html +++ b/templates/base.html @@ -177,6 +177,15 @@ {% trans "Help" %} + + +
+ + + + {% trans "Settings" %} +
+