piha.lc / beta.piha.li + company_site marketing landing (#4)
Deploy Beta / unit-tests (push) Successful in 4s
Deploy Beta / docker (push) Successful in 10s
Deploy Beta / deploy-beta (push) Successful in 1m3s

## Summary

- Public short domain is **`piha.lc`** (prod) and **`beta.piha.li`** (beta)
- `/` is a marketing page in [aimloperations.com](https://aimloperations.com) / `company_site` styling (Inter, dark, cyan)
- CTA: want access → [contact](https://aimloperations.com/contact)
- Nav/logo/footer match the company site; debug mint form uses the same chrome

Closes #3.

## Secrets (control node)

Update hostnames only — no new token/pepper unless you are rotating:

**`url_shortening_service_prod.env`**
```text
DJANGO_ALLOWED_HOSTS=piha.lc,shortener.aimloperations.com,url-shortener,web
SHORT_DOMAIN=piha.lc
PUBLIC_SHORT_URL=https://piha.lc
SHORT_PUBLIC_HOSTS=piha.lc
CONTACT_URL=https://aimloperations.com/contact
```

**`url_shortening_service_beta.env`**
```text
DJANGO_ALLOWED_HOSTS=beta.piha.li,shortener-beta.aimloperations.com,url-shortener,web
SHORT_DOMAIN=beta.piha.li
PUBLIC_SHORT_URL=https://beta.piha.li
SHORT_PUBLIC_HOSTS=beta.piha.li
CONTACT_URL=https://aimloperations.com/contact
```

NPM: `piha.lc` / `beta.piha.li` → this container. Still do not proxy `/api/` on the short host.

## Test plan
- [ ] `cd site && uv run python manage.py test`
- [ ] `GET /` looks like aimloperations.com; Request access / Contact go to aimloperations.com/contact
- [ ] `GET /<code>` still 302
- [ ] `/api/` on Host `piha.lc` is 404

Reviewed-on: #4
This commit was merged in pull request #4.
This commit is contained in:
2026-08-30 06:55:43 -07:00
parent 630b770c12
commit ccb4d0097d
18 changed files with 1373 additions and 214 deletions
+1
View File
@@ -10,5 +10,6 @@ def branding(request):
"PUBLIC_SHORT_URL": settings.PUBLIC_SHORT_URL,
"CREDIT_NAME": settings.CREDIT_NAME,
"CREDIT_URL": settings.CREDIT_URL,
"CONTACT_URL": settings.CONTACT_URL,
"show_debug_create": settings.DEBUG and not is_public_host(request.get_host()),
}
+69
View File
@@ -0,0 +1,69 @@
/* Shortener-only bits on top of company_site style.css */
.hero-cta {
margin-top: 1.75rem;
}
.hero-subtitle--wide {
max-width: 40rem;
}
.debug-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1100;
background: var(--secondary-color);
color: #fff;
text-align: center;
font-size: 0.75rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 0.4rem 1rem;
}
.debug-banner a {
color: #fff;
text-decoration: underline;
}
body.has-debug-banner nav {
top: 1.7rem;
}
.page-main {
min-height: 60vh;
}
.debug-section {
padding-top: 8rem;
}
.debug-section .form-control {
margin-top: 0.35rem;
}
.debug-section label {
display: block;
margin-bottom: 1rem;
color: var(--text-muted);
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.debug-result {
margin-bottom: 1.5rem;
}
.debug-result code {
color: var(--primary-color);
word-break: break-all;
}
.brand-logo-img {
height: 28px;
width: auto;
display: block;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

+57 -118
View File
@@ -1,128 +1,67 @@
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{{ SITE_NAME }}{% endblock %}</title>
<style>
:root {
--ink: #1c1914;
--paper: #f3ead8;
--rule: #c9b896;
--pine: #2a4a3c;
--rust: #9a3f24;
--muted: #6b6254;
}
* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }
body {
background: var(--paper);
color: var(--ink);
font-family: "Iowan Old Style", Palatino, "Palatino Linotype", "Times New Roman", serif;
line-height: 1.5;
}
.shell {
max-width: 40rem;
margin: 0 auto;
padding: 3.5rem 1.5rem 2rem;
}
.eyebrow {
font-family: ui-monospace, "Cascadia Code", "SF Mono", Menlo, monospace;
font-size: 0.72rem;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--pine);
margin: 0 0 0.75rem;
}
h1 {
font-size: clamp(2.4rem, 8vw, 4.2rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 0.95;
margin: 0 0 1.25rem;
}
p { margin: 0 0 1rem; font-size: 1.15rem; }
.lede { color: var(--muted); max-width: 32rem; }
a { color: var(--rust); }
a:hover { color: var(--ink); }
footer {
margin-top: 3.5rem;
padding-top: 1rem;
border-top: 1px solid var(--rule);
font-family: ui-monospace, "Cascadia Code", "SF Mono", Menlo, monospace;
font-size: 0.78rem;
color: var(--muted);
}
footer a { color: inherit; }
.banner {
font-family: ui-monospace, Menlo, monospace;
font-size: 0.75rem;
letter-spacing: 0.08em;
text-transform: uppercase;
background: var(--ink);
color: var(--paper);
padding: 0.4rem 1.5rem;
}
form { margin-top: 1.75rem; display: grid; gap: 0.9rem; }
label {
display: grid;
gap: 0.3rem;
font-family: ui-monospace, Menlo, monospace;
font-size: 0.78rem;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--pine);
}
input[type="url"], input[type="text"] {
font: 1rem/1.4 "Iowan Old Style", Palatino, serif;
padding: 0.55rem 0.65rem;
border: 1px solid var(--rule);
background: #fffdf6;
color: var(--ink);
}
button, .btn {
appearance: none;
border: 0;
background: var(--pine);
color: var(--paper);
font-family: ui-monospace, Menlo, monospace;
font-size: 0.8rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 0.7rem 1rem;
cursor: pointer;
text-decoration: none;
display: inline-block;
width: fit-content;
}
button:hover, .btn:hover { background: var(--ink); }
.error { color: var(--rust); font-size: 0.95rem; }
.result {
margin-top: 1.5rem;
padding: 1rem;
border: 1px dashed var(--pine);
background: #fffdf6;
}
.result code {
font-size: 1.05rem;
word-break: break-all;
}
.messages { list-style: none; padding: 0; margin: 0 0 1rem; color: var(--pine); }
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ SITE_NAME }} · {{ CREDIT_NAME }}{% endblock %}</title>
<meta name="description" content="{% block meta_description %}{{ SITE_NAME }} by {{ CREDIT_NAME }}. Short links for campaigns and trusted callers. Request access at aimloperations.com.{% endblock %}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&display=swap" rel="stylesheet">
<link href="{% static 'core/css/style.css' %}" rel="stylesheet">
<link href="{% static 'core/css/overrides.css' %}" rel="stylesheet">
<link rel="icon" type="image/png" href="{% static 'core/img/logo.png' %}">
</head>
<body>
<body{% if debug %} class="has-debug-banner"{% endif %}>
{% if debug %}
<div class="banner">Debug — create page is local only</div>
<div class="debug-banner">Debug — mint form is local only{% if show_debug_create %} · <a href="{% url 'debug-create' %}">Create a short link</a>{% endif %}</div>
{% endif %}
<main class="shell">
<nav aria-label="Main navigation">
<a href="{{ CREDIT_URL }}" class="brand-logo">
<img src="{% static 'core/img/logo.png' %}" alt="{{ CREDIT_NAME }}" class="brand-logo-img" width="243" height="28">
</a>
<button type="button" class="mobile-menu-btn" aria-label="Open menu" aria-expanded="false" aria-controls="main-nav-links"></button>
<ul class="nav-links" id="main-nav-links">
<li><a href="{{ CREDIT_URL }}">Home</a></li>
<li><a href="{{ CREDIT_URL }}/web_design">Web Design</a></li>
<li><a href="{{ CONTACT_URL }}" class="btn" style="border: 1px solid var(--primary-color); padding: 0.4rem 1rem; border-radius: 4px; margin-left: 1rem; color: #000;">Contact</a></li>
</ul>
</nav>
<main class="page-main">
{% block content %}{% endblock %}
<footer>
Created by
<a href="{{ CREDIT_URL }}">{{ CREDIT_NAME }}</a>
{% if show_debug_create %}
· <a href="{% url 'debug-create' %}">Create a short link</a>
{% endif %}
</footer>
</main>
<footer class="footer">
<div class="container">
<p class="footer-text">{{ CREDIT_NAME }}, LLC — Forward-deployed AI engineering.</p>
<p class="footer-links">
<a href="{{ CREDIT_URL }}/terms">Terms &amp; Privacy</a>
{% if show_debug_create %}
<span class="footer-separator">|</span>
<a href="{% url 'debug-create' %}">Create a short link</a>
{% endif %}
</p>
<p class="footer-text footer-text--muted">&copy; 2023 -
<script>document.write(new Date().getFullYear());</script> All rights reserved.
</p>
</div>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function () {
const mobileBtn = document.querySelector('.mobile-menu-btn');
const navLinks = document.querySelector('.nav-links');
if (mobileBtn && navLinks) {
mobileBtn.addEventListener('click', function () {
const isOpen = navLinks.classList.toggle('active');
mobileBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
mobileBtn.setAttribute('aria-label', isOpen ? 'Close menu' : 'Open menu');
});
}
});
</script>
</body>
</html>
+54 -11
View File
@@ -1,14 +1,57 @@
{% extends "core/base.html" %}
{% block title %}{{ SITE_NAME }}{% endblock %}
{% block title %}{{ SHORT_DOMAIN }} · URL shortener · {{ CREDIT_NAME }}{% endblock %}
{% block content %}
<p class="eyebrow">{{ SITE_NAME }}</p>
<h1>{{ SHORT_DOMAIN }}</h1>
<p class="lede">
This is a URL shortening service. A path like
<strong>/a3k9xm</strong> sends you to the long HTTPS URL.
</p>
<p class="lede">
Created by <a href="{{ CREDIT_URL }}">{{ CREDIT_NAME }}</a>
· <a href="{{ CREDIT_URL }}">aimloperations.com</a>
</p>
<div class="hero-section">
<div class="hero-content">
<h1 class="hero-title">{{ SHORT_DOMAIN }}</h1>
<p class="hero-subtitle hero-subtitle--wide">
Short links for campaigns and trusted callers. Built by
{{ CREDIT_NAME }} — not an open public shortener.
</p>
<div class="hero-cta">
<a href="{{ CONTACT_URL }}" class="btn">Request access</a>
</div>
</div>
</div>
<div class="section" style="background: var(--surface-color);">
<div class="container">
<h2 class="section-title">A shortener you can hand to SMS</h2>
<p style="text-align: center; max-width: 820px; margin: 0 auto; color: var(--text-muted); font-size: 1.1rem;">
{{ SHORT_DOMAIN }} turns a long HTTPS URL into a short path like
<strong>/a3k9xm</strong>. Recipients tap it and get a 302 to your site.
Creating links is Bearer-authenticated — only onboarded services can mint.
</p>
</div>
</div>
<div class="section">
<div class="container">
<h2 class="section-title">Want access?</h2>
<div class="card-grid">
<div class="card">
<h3 class="card-title">For your product</h3>
<p class="card-text">
We issue a named token and allowlist your destination hosts.
Your app POSTs to the API and drops <code>short_url</code> into SMS or email.
</p>
</div>
<div class="card">
<h3 class="card-title">Not self-serve</h3>
<p class="card-text">
There is no public signup. If you want this for a campaign or another
{{ CREDIT_NAME }} property, talk to us.
</p>
</div>
<div class="card">
<h3 class="card-title">Talk to us</h3>
<p class="card-text">
Contact <a href="{{ CREDIT_URL }}">aimloperations.com</a> and tell us
which hosts you need to shorten to.
</p>
<a href="{{ CONTACT_URL }}" class="btn" style="margin-top: 1rem; padding: 0.7rem 1.4rem;">Contact</a>
</div>
</div>
</div>
</div>
{% endblock %}
+36 -28
View File
@@ -1,35 +1,43 @@
{% extends "core/base.html" %}
{% block title %}Create short link · debug{% endblock %}
{% block content %}
<p class="eyebrow">Debug only</p>
<h1>Create a short link</h1>
<p class="lede">Uses the same allowlist as the API. Not served when <code>DEBUG</code> is false.</p>
<div class="section debug-section">
<div class="container" style="max-width: 40rem;">
<h1 class="hero-title" style="font-size: 2.2rem;">Create a short link</h1>
<p class="hero-subtitle" style="margin: 1rem 0 2rem; text-align: left;">
DEBUG only. Same allowlist as the API. Not served when <code>DEBUG</code> is false.
</p>
{% if messages %}
<ul class="messages">
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
</ul>
{% endif %}
{% if messages %}
<ul class="messages" style="list-style: none; padding: 0; margin: 0 0 1rem; color: var(--primary-color);">
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
</ul>
{% endif %}
{% if created_link %}
<div class="result">
<p>Short URL</p>
<p><code>{{ created_link.public_short_url }}</code></p>
<p>Target: {{ created_link.target_url }}</p>
<a class="btn" href="{{ created_link.public_short_url }}">Open</a>
{% if created_link %}
<div class="card debug-result">
<p class="card-title">Short URL</p>
<p><code>{{ created_link.public_short_url }}</code></p>
<p class="card-text">Target: {{ created_link.target_url }}</p>
<a class="btn" href="{{ created_link.public_short_url }}" style="margin-top: 1rem; padding: 0.7rem 1.4rem;">Open</a>
</div>
{% endif %}
<form method="post" action="{% url 'debug-create' %}">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<label>
{{ field.label }}
<input class="form-control" type="{{ field.field.widget.input_type|default:'text' }}"
name="{{ field.name }}" value="{{ field.value|default_if_none:'' }}"
{% if field.field.widget.attrs.placeholder %}placeholder="{{ field.field.widget.attrs.placeholder }}"{% endif %}
{% if field.field.widget.attrs.autofocus %}autofocus{% endif %}>
{% if field.errors %}<span class="alert-text" style="color: #ff6b6b;">{{ field.errors|striptags }}</span>{% endif %}
</label>
{% endfor %}
<button type="submit" class="btn">Mint</button>
</form>
</div>
{% endif %}
<form method="post" action="{% url 'debug-create' %}">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<label>
{{ field.label }}
{{ field }}
{% if field.errors %}<span class="error">{{ field.errors|striptags }}</span>{% endif %}
</label>
{% endfor %}
<button type="submit">Mint</button>
</form>
</div>
{% endblock %}
+27 -24
View File
@@ -18,8 +18,9 @@ TOKENS = [("monica", "dev-only-token")]
SETTINGS = dict(
SHORTENER_API_TOKENS=TOKENS,
PUBLIC_SHORT_URL="https://go.mkdrealtor.com",
SHORT_PUBLIC_HOSTS=["go.mkdrealtor.com"],
SHORT_DOMAIN="piha.lc",
PUBLIC_SHORT_URL="https://piha.lc",
SHORT_PUBLIC_HOSTS=["piha.lc"],
SHORT_API_HOSTS=["testserver", "localhost", "127.0.0.1", "shortener.example.com"],
SHORT_ADMIN_HOSTS=["localhost", "127.0.0.1"],
SHORT_ALLOWED_HOSTS=["mkdrealtor.com"],
@@ -28,7 +29,7 @@ SETTINGS = dict(
"testserver",
"localhost",
"127.0.0.1",
"go.mkdrealtor.com",
"piha.lc",
"shortener.example.com",
],
SHORT_CODE_LENGTH=6,
@@ -93,7 +94,7 @@ class HostSplitTests(TestCase):
data=json.dumps({"target_url": "https://mkdrealtor.com/x"}),
content_type="application/json",
HTTP_AUTHORIZATION=AUTH,
HTTP_HOST="go.mkdrealtor.com",
HTTP_HOST="piha.lc",
)
self.assertEqual(response.status_code, 404)
@@ -103,7 +104,7 @@ class HostSplitTests(TestCase):
"localhost",
"127.0.0.1",
"shortener.example.com",
"go.mkdrealtor.com",
"piha.lc",
]
)
def test_short_host_never_serves_api_even_if_also_listed_as_api(self):
@@ -112,12 +113,12 @@ class HostSplitTests(TestCase):
data=json.dumps({"target_url": "https://mkdrealtor.com/x"}),
content_type="application/json",
HTTP_AUTHORIZATION=AUTH,
HTTP_HOST="go.mkdrealtor.com",
HTTP_HOST="piha.lc",
)
self.assertEqual(response.status_code, 404)
def test_public_host_admin_404(self):
response = self.client.get("/admin/", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/admin/", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
def test_public_api_host_without_bearer_401(self):
@@ -155,7 +156,7 @@ class HostSplitTests(TestCase):
self.assertEqual(response.status_code, 404)
def test_healthz_on_public_and_api(self):
for host in ("go.mkdrealtor.com", "testserver", "shortener.example.com"):
for host in ("piha.lc", "testserver", "shortener.example.com"):
response = self.client.get("/healthz/", HTTP_HOST=host)
self.assertEqual(response.status_code, 200)
self.assertEqual(_json(response), {"status": "ok"})
@@ -216,7 +217,7 @@ class RedirectTests(TestCase):
def test_active_code_302_to_target(self):
response = self.client.get(
"/a3k9xm", HTTP_HOST="go.mkdrealtor.com", follow=False
"/a3k9xm", HTTP_HOST="piha.lc", follow=False
)
self.assertEqual(response.status_code, 302)
self.assertNotEqual(response.status_code, 301)
@@ -226,7 +227,7 @@ class RedirectTests(TestCase):
def test_head_also_302_without_click(self):
response = self.client.head(
"/a3k9xm", HTTP_HOST="go.mkdrealtor.com", follow=False
"/a3k9xm", HTTP_HOST="piha.lc", follow=False
)
self.assertEqual(response.status_code, 302)
self.assertEqual(
@@ -239,34 +240,36 @@ class RedirectTests(TestCase):
def test_inactive_404(self):
self.link.is_active = False
self.link.save()
response = self.client.get("/a3k9xm", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/a3k9xm", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
def test_expired_404(self):
self.link.expires_at = timezone.now() - timedelta(minutes=1)
self.link.save()
response = self.client.get("/a3k9xm", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/a3k9xm", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
def test_unknown_404(self):
response = self.client.get("/zzzzzz", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/zzzzzz", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
def test_invalid_code_shape_404(self):
response = self.client.get("/AB", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/AB", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
def test_public_root_is_landing(self):
response = self.client.get("/", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "URL Shortening Service")
self.assertContains(response, "piha.lc")
self.assertContains(response, "Request access")
self.assertContains(response, "aimloperations.com")
self.assertContains(response, "Contact")
self.assertNotContains(response, "Create a short link")
def test_click_row_and_count(self):
self.client.get(
"/a3k9xm",
HTTP_HOST="go.mkdrealtor.com",
HTTP_HOST="piha.lc",
HTTP_USER_AGENT="sms-client",
)
self.link.refresh_from_db()
@@ -296,7 +299,7 @@ class CreateTests(TestCase):
)
self.assertEqual(response.status_code, 201)
body = _json(response)
self.assertTrue(body["short_url"].startswith("https://go.mkdrealtor.com/"))
self.assertTrue(body["short_url"].startswith("https://piha.lc/"))
self.assertNotIn("testserver", body["short_url"])
def test_idempotent_same_target_and_external_ref(self):
@@ -349,9 +352,9 @@ class CreateTests(TestCase):
self.assertEqual(first.status_code, 200)
self.assertEqual(second.status_code, 200)
self.assertFalse(_json(second)["is_active"])
self.client.get(f"/{code}", HTTP_HOST="go.mkdrealtor.com")
self.client.get(f"/{code}", HTTP_HOST="piha.lc")
# disabled → no redirect
response = self.client.get(f"/{code}", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get(f"/{code}", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
@@ -379,12 +382,12 @@ class UseCaseTests(TestCase):
self.assertEqual(create.status_code, 201)
body = _json(create)
self.assertEqual(
body["short_url"], f"https://go.mkdrealtor.com/{body['code']}"
body["short_url"], f"https://piha.lc/{body['code']}"
)
follow = self.client.get(
f"/{body['code']}",
HTTP_HOST="go.mkdrealtor.com",
HTTP_HOST="piha.lc",
follow=False,
)
self.assertEqual(follow.status_code, 302)
@@ -408,7 +411,7 @@ class DebugCreateTests(TestCase):
@override_settings(DEBUG=True)
def test_hidden_on_public_short_host_even_in_debug(self):
response = self.client.get("/debug/", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/debug/", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
@override_settings(DEBUG=True)
@@ -494,7 +497,7 @@ class AdminTests(TestCase):
def test_admin_404_on_public_hosts(self):
self.client.logout()
response = self.client.get("/admin/", HTTP_HOST="go.mkdrealtor.com")
response = self.client.get("/admin/", HTTP_HOST="piha.lc")
self.assertEqual(response.status_code, 404)
response = self.client.get("/admin/", HTTP_HOST="shortener.example.com")
self.assertEqual(response.status_code, 404)
+5 -2
View File
@@ -89,7 +89,7 @@ DEBUG = env_bool("DJANGO_DEBUG", False)
allowed_hosts = env_list(
"DJANGO_ALLOWED_HOSTS",
"localhost,127.0.0.1,0.0.0.0,testserver,web,url-shortener,go.mkdrealtor.com",
"localhost,127.0.0.1,0.0.0.0,testserver,web,url-shortener,piha.lc,beta.piha.li",
)
ALLOWED_HOSTS = allowed_hosts if allowed_hosts else ["*"]
@@ -176,7 +176,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# --- Shortener ---
SHORT_DOMAIN = env("SHORT_DOMAIN", "localhost:8000") or "localhost:8000"
PUBLIC_SHORT_URL = (env("PUBLIC_SHORT_URL", "https://go.mkdrealtor.com") or "").rstrip(
PUBLIC_SHORT_URL = (env("PUBLIC_SHORT_URL", "https://piha.lc") or "").rstrip(
"/"
)
SHORT_PUBLIC_HOSTS = env_list("SHORT_PUBLIC_HOSTS", SHORT_DOMAIN.split(":")[0])
@@ -196,3 +196,6 @@ CODE_ALPHABET = "23456789abcdefghjkmnpqrstuvwxyz"
SITE_NAME = env("SITE_NAME", "URL Shortening Service") or "URL Shortening Service"
CREDIT_NAME = env("CREDIT_NAME", "AI ML Operations") or "AI ML Operations"
CREDIT_URL = env("CREDIT_URL", "https://aimloperations.com") or "https://aimloperations.com"
CONTACT_URL = env("CONTACT_URL", "https://aimloperations.com/contact") or (
"https://aimloperations.com/contact"
)