Free · Level 0 and above
+Discourse · Forums
+Ask questions, share projects and join longer conversations. Bronze and above also get exclusive member content.
+ Visit Discourse +diff --git a/htdocs/index.html b/htdocs/index.html index e86ba43..9289206 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -13,6 +13,7 @@ Explore the projects Join the conversation Create an eom.dev account + Browse community services
Independent software, open-source projects, music, and games—made in Raleigh, North Carolina.
@@ -94,6 +95,65 @@ +One account, a community of services
+A free account includes forums, chat, Git hosting and hosted games. Gold (Level 3) and above add Mastodon and PeerTube account access. Public posts and videos can still be browsed without a paid membership.
+Free · Level 0 and above
+Ask questions, share projects and join longer conversations. Bronze and above also get exclusive member content.
+ Visit Discourse +Free · Level 0 and above
+Keep in touch in community rooms through Element. Bronze and above also get exclusive member content.
+ Open Matrix chat +Free · Level 0 and above
+Host code, collaborate on repositories and explore the projects behind the lab.
+ Explore Gitea +Free · Level 0 and above
+Join community games, including Luanti, and try The Button. No paid membership is needed; exclusive higher-tier servers are not currently offered.
+ +Gold · Levels 3–5
+Participate with an eom.dev Mastodon account and connect with the wider fediverse.
+ Visit Mastodon +Gold · Levels 3–5
+Use an eom.dev PeerTube account to take part in the video community. Public recordings remain available to watch.
+ Visit PeerTube +Included with your free account
+Use the same eom.dev identity across compatible services. Dex handles sign-in; start from the service you want to use.
+ Create your account +Public live channel
+Watch live performances, experiments and work in progress when the channel is on air.
+ Watch Owncast +Built in public
diff --git a/membership/members/tests/test_service_groups.py b/membership/members/tests/test_service_groups.py index e2eaa4a..5a28bfb 100755 --- a/membership/members/tests/test_service_groups.py +++ b/membership/members/tests/test_service_groups.py @@ -81,6 +81,59 @@ class ServiceGroupLDAPIntegrationTests(TestCase): @override_settings(MEMBERSHIP_TIERS=TIERS) class ServiceDisplayTests(TestCase): + def test_published_tier_copy_matches_role_defaults(self): + root = Path(__file__).absolute().parents[3] + tiers = json.loads((root / "membership/tiers.eom.json").read_text(encoding="utf-8")) + role = root.parent / "ansible-role-www/defaults/main.yml" + if not role.exists(): + self.skipTest("Role checkout is not present in the application test image") + import yaml + + deployed = yaml.safe_load(role.read_text(encoding="utf-8"))["www_membership_tiers"] + for key, tier in tiers.items(): + self.assertEqual(tier["description"], deployed[key]["description"]) + self.assertEqual(tier["benefits"], deployed[key]["benefits"]) + + def test_homepage_lists_services_with_clear_access_labels(self): + root = Path(__file__).absolute().parents[3] + homepage = root / "htdocs/index.html" + if not homepage.exists(): + self.skipTest("Static website checkout is not present in the application test image") + from html.parser import HTMLParser + + class DirectoryParser(HTMLParser): + def __init__(self): + super().__init__() + self.active = False + self.text = [] + self.links = [] + + def handle_starttag(self, tag, attrs): + attributes = dict(attrs) + if tag == "section" and attributes.get("id") == "services": + self.active = True + if self.active and tag == "a": + self.links.append(attributes.get("href")) + + def handle_endtag(self, tag): + if tag == "section": + self.active = False + + def handle_data(self, data): + if self.active: + self.text.append(data) + + parser = DirectoryParser() + parser.feed(homepage.read_text(encoding="utf-8")) + text = " ".join(parser.text) + for name in ("Dex", "Discourse", "Matrix", "Gitea", "Mastodon", "PeerTube", "Hosted games", "Owncast"): + self.assertIn(name, text) + self.assertIn("Free · Level 0 and above", text) + self.assertIn("Gold · Levels 3–5", text) + self.assertIn("not currently offered", text) + self.assertIn("/members/", parser.links) + self.assertIn("https://element.eom.dev/", parser.links) + @override_settings(MEMBERSHIP_SERVICE_GROUPS={ "0": ["cn=Dex Users," + BASE, "cn=Matrix Users," + BASE], "1": ["cn=Gitea Users," + BASE], diff --git a/membership/templates/members.html b/membership/templates/members.html index 3ce7478..fcb113a 100755 --- a/membership/templates/members.html +++ b/membership/templates/members.html @@ -43,7 +43,7 @@Keep your own corner of the internet alive
A private place to connect, a closer look at what is being made, and opportunities to help shape it. Start with a free eom.dev account, then choose an optional membership to support the independent work.
+Join free for community services and games. Choose a paid tier for exclusive content, previews and a closer say in what comes next.
{% if account %}Your eom.dev account · Membership level {{ account.membership_level }}
{{ account.email }}
Level 0 · The starting point
Free / always
-One account for eom.dev, its community, and its services.
-Your free community account.
+Your free account is ready.
{% endif %}Level {{ tier.level }} · Independent work, supported together
{{ tier.price_label }}
+Level {{ tier.level }}
{{ tier.price_label }}
{{ tier.description|default:"Help keep the projects and community running." }}
Each membership tier, including free Open Lab, has its own exclusive giveaways when announced. Eligibility is based on the tier specified in each giveaway's rules; higher tiers do not automatically qualify for another tier's giveaway. Availability, dates, prizes and eligibility restrictions will be published for each giveaway. Membership does not guarantee a prize.
Platinum (Level 4) and Diamond (Level 5) members can take part in exclusive polls about the direction of the platform. These are separate from Gold's project-topic polls. Results help inform decisions; they are not binding commitments or guarantees of particular features.
Your free eom.dev account stays. Member-only access ends when your paid membership expires. An immediate cancellation removes that access once your membership status updates.
The shared members' Matrix space is the home for informal conversations and work in progress. Private forum discussions can complement it as they become available, without splitting everyone into separate rooms for each tier.
Depending on what is being made, Silver members and above may preview music, game builds, videos or new experiments and join playtests or listening sessions. Gold members and above can also take part in project-topic polls and occasional small-group feedback sessions. Polls help inform the work; they are not promises to build requested features.
On Discourse and Matrix. Ordinary community access is free; Bronze and above also receive exclusive content in those services.
Use Manage billing after signing in. The billing portal offers the changes enabled for your plan. Cancellation at period end keeps access through the paid expiry date.
SHKeeper payments prepay one calendar month, without automatic charges. Create a new invoice for each renewal. Confirmed payment on the same tier extends its prepaid term. Partial or unconfirmed payments do not grant access. Do not send renewal funds to an old invoice address.