Members page: show a live total member count
Count every membership account (free and paid together) on each page load and show it under the headline; no per-tier numbers. Hidden when there are no members. Also correct the reference tiers.eom.json and service-groups.eom.json to the real LDAP DNs (ou=Memberships; ou=<Service>,ou=Services), which now match the ansible-role-www defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
.member-main { padding-bottom: 4rem; }
|
||||
.member-hero { padding-block: clamp(3rem, 8vw, 6rem); }
|
||||
.member-hero h1 { font-size: clamp(2.8rem, 6vw, 5rem); max-width: 900px; }
|
||||
.member-count { color: var(--muted); font-size: 1.1rem; }
|
||||
.member-count strong { color: var(--accent-strong); font-size: 1.6rem; font-variant-numeric: tabular-nums; }
|
||||
.member-intro { max-width: 700px; color: var(--muted); font-size: 1.2rem; }
|
||||
.member-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
|
||||
.member-actions form { margin: 0; }
|
||||
|
||||
@@ -51,6 +51,15 @@ class RegistrationTests(TestCase):
|
||||
self.assertEqual(response.headers["Cache-Control"], "no-store")
|
||||
self.assertContains(self.client.get("/members/register/"), "Send verification email")
|
||||
|
||||
def test_home_shows_live_total_member_count(self):
|
||||
self.assertNotContains(self.client.get("/members/"), "member-count")
|
||||
Account.objects.create(uid="alice", email="alice@example.org")
|
||||
self.assertContains(self.client.get("/members/"), "<strong>1</strong> member and counting", html=False)
|
||||
Account.objects.create(uid="bob", email="bob@example.org", membership_level=3)
|
||||
response = self.client.get("/members/")
|
||||
# One total across free and paid levels; no per-tier numbers.
|
||||
self.assertContains(response, "<strong>2</strong> members and counting", html=False)
|
||||
|
||||
def start_signup(self):
|
||||
self.client.post("/members/register/", {"uid": "alice", "email": "ALICE@example.org"})
|
||||
match = re.search(r"/verify/([^/]+)/", str(mail.outbox[-1].body))
|
||||
|
||||
@@ -79,7 +79,9 @@ def home(request):
|
||||
# Presentation copies only: never mutate authorization/payment settings.
|
||||
tiers = settings.MEMBERSHIP_TIERS
|
||||
services = service_access_catalog(tiers, settings.MEMBERSHIP_SERVICE_GROUPS)
|
||||
return page(request, account=account, tiers=tiers, services=services, subscriptions=subscriptions, crypto_invoices=invoices, shkeeper_enabled=settings.SHKEEPER_ENABLED, now=timezone.now())
|
||||
# Public total across every level (free and paid); never a per-tier breakdown.
|
||||
member_count = Account.objects.count()
|
||||
return page(request, account=account, tiers=tiers, services=services, subscriptions=subscriptions, crypto_invoices=invoices, shkeeper_enabled=settings.SHKEEPER_ENABLED, now=timezone.now(), member_count=member_count)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
{
|
||||
"0": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev"
|
||||
],
|
||||
"1": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev"
|
||||
],
|
||||
"2": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev"
|
||||
],
|
||||
"3": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Mastodon,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=PeerTube,ou=Services,dc=eom,dc=dev"
|
||||
],
|
||||
"4": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Mastodon,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=PeerTube,ou=Services,dc=eom,dc=dev"
|
||||
],
|
||||
"5": [
|
||||
"cn=Dex Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=Services,dc=eom,dc=dev"
|
||||
"cn=Dex Users,ou=Dex,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Discourse Users,ou=Discourse,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Gitea Users,ou=Gitea,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Matrix Users,ou=Matrix,ou=Services,dc=eom,dc=dev",
|
||||
"cn=Mastodon Users,ou=Mastodon,ou=Services,dc=eom,dc=dev",
|
||||
"cn=PeerTube Users,ou=PeerTube,ou=Services,dc=eom,dc=dev"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<section class="member-hero">
|
||||
<p class="eyebrow">Music, films, projects & shared worlds</p>
|
||||
<h1>Support the work.<br>Get closer to what’s next.</h1>
|
||||
{% if member_count %}<p class="member-count"><strong>{{ member_count }}</strong> member{{ member_count|pluralize }} and counting</p>{% endif %}
|
||||
<p class="member-intro">Membership supports my music, films, writing, open-source projects, and game servers. Join the community for free, or choose a paid tier to support the work and receive the benefits listed below.</p>
|
||||
{% if account %}
|
||||
<div class="member-panel account-panel">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"price_id": "price_1Rgv4xC5KPXqTvVLfMd6z7wn",
|
||||
"price_label": "$4 USD / month",
|
||||
"usd_amount": "4.00",
|
||||
"group_dn": "cn=Level 1,ou=Members,dc=eom,dc=dev",
|
||||
"group_dn": "cn=Level 1,ou=Memberships,dc=eom,dc=dev",
|
||||
"description": "Go beyond the public feed.",
|
||||
"benefits": [
|
||||
"Exclusive Discourse and Matrix content, including work-in-progress updates",
|
||||
@@ -19,7 +19,7 @@
|
||||
"price_id": "price_1Rgv5QC5KPXqTvVLv1PaHWb5",
|
||||
"price_label": "$8 USD / month",
|
||||
"usd_amount": "8.00",
|
||||
"group_dn": "cn=Level 2,ou=Members,dc=eom,dc=dev",
|
||||
"group_dn": "cn=Level 2,ou=Memberships,dc=eom,dc=dev",
|
||||
"description": "Try new work before release.",
|
||||
"benefits": [
|
||||
"Silver-tier giveaways",
|
||||
@@ -32,7 +32,7 @@
|
||||
"price_id": "price_1Rgv5rC5KPXqTvVL8Ol8sMUf",
|
||||
"price_label": "$16 USD / month",
|
||||
"usd_amount": "16.00",
|
||||
"group_dn": "cn=Level 3,ou=Members,dc=eom,dc=dev",
|
||||
"group_dn": "cn=Level 3,ou=Memberships,dc=eom,dc=dev",
|
||||
"description": "Help shape the next experiment.",
|
||||
"benefits": [
|
||||
"Gold-tier giveaways",
|
||||
@@ -46,7 +46,7 @@
|
||||
"price_id": "price_1Rgv6FC5KPXqTvVL39mAxYjm",
|
||||
"price_label": "$32 USD / month",
|
||||
"usd_amount": "32.00",
|
||||
"group_dn": "cn=Level 4,ou=Members,dc=eom,dc=dev",
|
||||
"group_dn": "cn=Level 4,ou=Memberships,dc=eom,dc=dev",
|
||||
"description": "Have a voice in the platform's direction.",
|
||||
"benefits": [
|
||||
"Platinum-tier giveaways",
|
||||
@@ -59,7 +59,7 @@
|
||||
"price_id": "price_1Rgv6mC5KPXqTvVLkcmznWZa",
|
||||
"price_label": "$64 USD / month",
|
||||
"usd_amount": "64.00",
|
||||
"group_dn": "cn=Level 5,ou=Members,dc=eom,dc=dev",
|
||||
"group_dn": "cn=Level 5,ou=Memberships,dc=eom,dc=dev",
|
||||
"description": "Give the independent work its biggest boost.",
|
||||
"benefits": [
|
||||
"Diamond-tier giveaways",
|
||||
|
||||
Reference in New Issue
Block a user