Closes #11. ## Summary - Serve Django admin on LAN IP `10.0.0.128` (not `piha.li`). Compose now publishes `0.0.0.0:8005` and passes `SHORT_ADMIN_HOSTS` into the container. - Admin index has a campaign mint form: domain, campaign, source, metric. Save builds `https://{domain}/?utm_campaign=&utm_source=&utm_medium=` (metric) and shows a copyable short URL. - Public `/admin/` on `piha.lc` / `piha.li` stays 404. ## Test plan - [ ] `cd site && uv run python manage.py test` - [ ] Recreate compose (`docker compose up --build`) so `WEB_BIND` / `SHORT_ADMIN_HOSTS` take effect - [ ] From another LAN machine: `http://10.0.0.128:8005/admin/` (staff login) shows the mint form - [ ] Save a link for an allowlisted domain, copy the short URL, confirm it 302s - [ ] `https://piha.li/admin` still 404 Reviewed-on: #12
77 lines
2.4 KiB
Python
77 lines
2.4 KiB
Python
from django import forms
|
|
from django.conf import settings
|
|
|
|
from links.services import ValidationError, build_tracked_url, validate_target_url
|
|
|
|
|
|
class DebugCreateForm(forms.Form):
|
|
target_url = forms.URLField(
|
|
label="Target URL",
|
|
widget=forms.URLInput(
|
|
attrs={"placeholder": "https://mkdrealtor.com/listings/oak-st", "autofocus": True}
|
|
),
|
|
)
|
|
title = forms.CharField(label="Title", required=False, max_length=200)
|
|
external_ref = forms.CharField(label="External ref", required=False, max_length=64)
|
|
|
|
def clean_target_url(self) -> str:
|
|
raw = self.cleaned_data["target_url"]
|
|
try:
|
|
return validate_target_url(raw)
|
|
except ValidationError as exc:
|
|
raise forms.ValidationError(str(exc)) from exc
|
|
|
|
|
|
def allowlisted_domain_choices() -> list[str]:
|
|
hosts = list(getattr(settings, "SHORT_ALLOWED_HOSTS", []) or [])
|
|
return [host for host in hosts if host and not host.startswith("*")]
|
|
|
|
|
|
class QuickMintForm(forms.Form):
|
|
domain = forms.CharField(
|
|
label="Domain",
|
|
max_length=253,
|
|
widget=forms.TextInput(
|
|
attrs={
|
|
"placeholder": "mkdrealtor.com",
|
|
"list": "allowed-domains",
|
|
"autocomplete": "off",
|
|
}
|
|
),
|
|
)
|
|
campaign = forms.CharField(
|
|
label="Campaign",
|
|
max_length=200,
|
|
widget=forms.TextInput(attrs={"placeholder": "open-house"}),
|
|
)
|
|
source = forms.CharField(
|
|
label="Source",
|
|
max_length=200,
|
|
widget=forms.TextInput(attrs={"placeholder": "sms"}),
|
|
)
|
|
metric = forms.CharField(
|
|
label="Metric",
|
|
max_length=200,
|
|
widget=forms.TextInput(attrs={"placeholder": "listing-click"}),
|
|
help_text="Stored as utm_medium.",
|
|
)
|
|
|
|
def clean(self):
|
|
cleaned = super().clean()
|
|
domain = cleaned.get("domain")
|
|
campaign = cleaned.get("campaign")
|
|
source = cleaned.get("source")
|
|
metric = cleaned.get("metric")
|
|
if not all((domain, campaign, source, metric)):
|
|
return cleaned
|
|
try:
|
|
cleaned["target_url"] = build_tracked_url(
|
|
domain=domain,
|
|
campaign=campaign,
|
|
source=source,
|
|
metric=metric,
|
|
)
|
|
except ValidationError as exc:
|
|
self.add_error("domain", str(exc))
|
|
return cleaned
|