LAN admin on 10.0.0.128 plus quick campaign mint form (#12)
Deploy Beta / unit-tests (push) Successful in 4s
Deploy Beta / docker (push) Successful in 10s
Deploy Beta / deploy-beta (push) Successful in 53s

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
This commit was merged in pull request #12.
This commit is contained in:
2026-09-16 03:39:04 -07:00
parent dd627b75c9
commit 69d8b3e7a3
10 changed files with 351 additions and 16 deletions
+79 -1
View File
@@ -426,7 +426,11 @@ class DebugCreateTests(TestCase):
self.assertContains(response, link.public_short_url)
ADMIN_SETTINGS = {**SETTINGS, "SHORT_ADMIN_HOSTS": ["testserver", "localhost"]}
ADMIN_SETTINGS = {
**SETTINGS,
"SHORT_ADMIN_HOSTS": ["testserver", "localhost", "10.0.0.128"],
"ALLOWED_HOSTS": [*SETTINGS["ALLOWED_HOSTS"], "10.0.0.128"],
}
@override_settings(**ADMIN_SETTINGS)
@@ -497,3 +501,77 @@ class AdminTests(TestCase):
self.assertEqual(response.status_code, 404)
response = self.client.get("/admin/", HTTP_HOST="shortener.example.com")
self.assertEqual(response.status_code, 404)
def test_admin_200_on_lan_ip(self):
response = self.client.get("/admin/", HTTP_HOST="10.0.0.128")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Create a short link")
self.assertContains(response, "Domain")
self.assertContains(response, "Campaign")
self.assertContains(response, "Source")
self.assertContains(response, "Metric")
def test_quick_mint_creates_tracked_url(self):
response = self.client.post(
"/admin/",
{
"domain": "mkdrealtor.com",
"campaign": "open-house",
"source": "sms",
"metric": "listing-click",
},
HTTP_HOST="10.0.0.128",
)
self.assertEqual(response.status_code, 200)
created = ShortLink.objects.exclude(code="a3k9xm").get()
self.assertEqual(
created.target_url,
"https://mkdrealtor.com/?utm_campaign=open-house&utm_source=sms&utm_medium=listing-click",
)
self.assertEqual(created.title, "open-house")
self.assertEqual(created.created_by_token, "admin")
self.assertContains(response, created.public_short_url)
self.assertContains(response, "Copy")
def test_quick_mint_rejects_unknown_host(self):
response = self.client.post(
"/admin/",
{
"domain": "evil.example",
"campaign": "spam",
"source": "sms",
"metric": "click",
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(ShortLink.objects.exclude(code="a3k9xm").count(), 0)
self.assertContains(response, "host not allowlisted")
class TrackedUrlTests(TestCase):
@override_settings(**SETTINGS)
def test_build_tracked_url(self):
from links.services import build_tracked_url
url = build_tracked_url(
domain="https://mkdrealtor.com/ignored",
campaign="open house",
source="sms",
metric="listing-click",
)
self.assertEqual(
url,
"https://mkdrealtor.com/?utm_campaign=open+house&utm_source=sms&utm_medium=listing-click",
)
@override_settings(**SETTINGS)
def test_build_tracked_url_rejects_unknown_host(self):
from links.services import ValidationError, build_tracked_url
with self.assertRaises(ValidationError):
build_tracked_url(
domain="evil.example",
campaign="c",
source="s",
metric="m",
)