mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
Update sharing domain
This commit is contained in:
Binary file not shown.
@@ -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',
|
||||
},
|
||||
),
|
||||
]
|
||||
+42
-3
@@ -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)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link href="{% static 'css/dist/styles.css' %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<h1 class="text-2xl font-bold text-gray-800 mb-6">{% trans "Settings" %}</h1>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Public Sharing Domain -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<h2 class="text-lg font-semibold text-gray-700 mb-1">{% trans "Public Sharing Domain" %}</h2>
|
||||
<p class="text-sm text-gray-500 mb-4">
|
||||
{% trans "Domain (with protocol) used for public file sharing links. Leave blank to use the same domain as the app." %}
|
||||
<br>
|
||||
<span class="font-mono text-xs text-gray-400">{% trans "Example:" %} https://go.example.com</span>
|
||||
</p>
|
||||
<input
|
||||
type="url"
|
||||
name="public_sharing_domain"
|
||||
id="public_sharing_domain"
|
||||
value="{{ site_settings.public_sharing_domain }}"
|
||||
placeholder="https://go.example.com"
|
||||
class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
>
|
||||
{% if site_settings.public_sharing_domain %}
|
||||
<p class="mt-2 text-xs text-green-600">
|
||||
{% trans "Active. Public links will use:" %}
|
||||
<span class="font-mono">{{ site_settings.public_sharing_domain }}/public/files/…</span>
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="mt-2 text-xs text-gray-400">
|
||||
{% trans "Not set. Public links will use the app's own domain." %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
style="background:#1d4ed8;color:#fff;padding:.5rem 1.5rem;border-radius:.375rem;font-size:.875rem;font-weight:500;cursor:pointer;"
|
||||
onmouseover="this.style.background='#1e40af'"
|
||||
onmouseout="this.style.background='#1d4ed8'"
|
||||
>
|
||||
{% trans "Save Settings" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -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'),
|
||||
|
||||
+16
-1
@@ -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"""
|
||||
|
||||
@@ -177,6 +177,15 @@
|
||||
{% trans "Help" %}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'site-settings' %}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"/>
|
||||
</svg>
|
||||
{% trans "Settings" %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 语言选择器 -->
|
||||
|
||||
Reference in New Issue
Block a user