diff --git a/htdocs/static/membership.css b/htdocs/static/membership.css index fd7f43a..9f50a8d 100755 --- a/htdocs/static/membership.css +++ b/htdocs/static/membership.css @@ -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; } diff --git a/membership/members/tests/test_membership.py b/membership/members/tests/test_membership.py index 9e0d80f..73d4ae6 100755 --- a/membership/members/tests/test_membership.py +++ b/membership/members/tests/test_membership.py @@ -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/"), "1 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, "2 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)) diff --git a/membership/members/views.py b/membership/members/views.py index dee05f6..af54992 100755 --- a/membership/members/views.py +++ b/membership/members/views.py @@ -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"]) diff --git a/membership/service-groups.eom.json b/membership/service-groups.eom.json index b2342d4..3f0593c 100755 --- a/membership/service-groups.eom.json +++ b/membership/service-groups.eom.json @@ -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" ] } diff --git a/membership/templates/members.html b/membership/templates/members.html index 71a7ebe..38e3200 100755 --- a/membership/templates/members.html +++ b/membership/templates/members.html @@ -43,6 +43,7 @@

Music, films, projects & shared worlds

Support the work.
Get closer to what’s next.

+ {% if member_count %}

{{ member_count }} member{{ member_count|pluralize }} and counting

{% endif %}

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.

{% if account %}
diff --git a/membership/tiers.eom.json b/membership/tiers.eom.json index 915a5ac..8ae9418 100755 --- a/membership/tiers.eom.json +++ b/membership/tiers.eom.json @@ -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",