Memberships
This commit is contained in:
@@ -11,7 +11,7 @@ class RegistrationForm(forms.Form):
|
||||
|
||||
|
||||
class PasswordForm(forms.Form):
|
||||
password = forms.CharField(max_length=1024, widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), label="Password", help_text="At least 12 characters. Stored only in OpenLDAP, never on this website.")
|
||||
password = forms.CharField(max_length=1024, widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), label="Password", help_text="Use at least 12 characters. Choose a strong, unique password for your eom.dev account.")
|
||||
confirm_password = forms.CharField(max_length=1024, widget=forms.PasswordInput(attrs={"autocomplete": "new-password"}), label="Confirm password")
|
||||
|
||||
def clean_password(self):
|
||||
|
||||
@@ -91,7 +91,7 @@ def register(request):
|
||||
Registration.objects.filter(pk=digest).delete()
|
||||
logger.error("Registration email failed kind=%s", type(exc).__name__)
|
||||
return page(request, title="Email unavailable", message="Account email could not be sent. Please try again later.")
|
||||
return page(request, title="Check your inbox", message="Use the verification link to choose a password and create your free account. If you already have an account, sign in through Dex instead.")
|
||||
return page(request, title="Check your inbox", message="Follow the confirmation link in your email to choose a password and finish creating your free eom.dev account. If you already have an account, sign in instead.")
|
||||
return page(request, title="Create your free account", form=form, submit="Send verification email", registration=True)
|
||||
|
||||
|
||||
@@ -129,12 +129,12 @@ def finish_registration(request):
|
||||
remember_groups(account)
|
||||
Registration.objects.filter(uid=registration.uid).delete()
|
||||
request.session.pop("registration_hash", None)
|
||||
return page(request, title="Account created", message="Your free account is now in OpenLDAP. Sign in through Dex to manage membership.")
|
||||
return page(request, title="Account created", message="Your free eom.dev account is ready. Sign in to explore the community and its services, or choose an optional paid membership for additional benefits.")
|
||||
except ValueError:
|
||||
form.add_error(None, "An account with those details may already exist. Sign in through Dex or contact the administrator.")
|
||||
form.add_error(None, "An account with those details may already exist. Try signing in or contact us for help.")
|
||||
except Exception as exc:
|
||||
logger.error("Account provisioning failed kind=%s", type(exc).__name__)
|
||||
form.add_error(None, "Account creation could not finish. Try Dex sign-in first, or contact the administrator before retrying.")
|
||||
form.add_error(None, "Account creation could not finish. Try signing in first, or contact us for help before retrying.")
|
||||
return page(request, title="Choose your password", form=form, submit="Create free account")
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,15 @@
|
||||
<p class="eyebrow">One account. An independent community.</p>
|
||||
<h1>{{ title }}</h1>
|
||||
{% if message %}<p>{{ message }}</p>{% endif %}
|
||||
{% if registration %}<p>Everyone can join. Verify your email, set a password in OpenLDAP, then sign in with Dex. A paid membership is optional.</p>{% endif %}
|
||||
{% if registration %}
|
||||
<p>One account for all of eom.dev. Use the same sign-in to explore the community and its services, without creating a separate account for each one.</p>
|
||||
<ol>
|
||||
<li>Choose a username and enter your email address below.</li>
|
||||
<li>Check your inbox and follow the confirmation link.</li>
|
||||
<li>Choose a password, then sign in and start exploring.</li>
|
||||
</ol>
|
||||
<p>Creating an account is free. Paid memberships are optional and unlock additional benefits.</p>
|
||||
{% endif %}
|
||||
{% if form %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
@@ -29,16 +37,16 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
<p><a href="{% url 'members:home' %}">Back to membership</a></p>
|
||||
<form action="{% url 'members:login' %}" method="post">{% csrf_token %}<button class="button button-secondary" type="submit">Sign in with Dex</button></form>
|
||||
<form action="{% url 'members:login' %}" method="post">{% csrf_token %}<button class="button button-secondary" type="submit">Sign in to eom.dev</button></form>
|
||||
</section>
|
||||
{% else %}
|
||||
<section class="member-hero">
|
||||
<p class="eyebrow">Keep your own corner of the internet alive</p>
|
||||
<h1>A place to belong.<br>A way to give back.</h1>
|
||||
<p class="member-intro">Start with a free eom.dev account. Choose an optional membership to support the servers, experiments, and independent work behind the community.</p>
|
||||
<p class="member-intro">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.</p>
|
||||
{% if account %}
|
||||
<div class="member-panel account-panel">
|
||||
<div><p class="eyebrow">Signed in through Dex</p><h2>{{ account.uid }}</h2><p>{{ account.email }}</p></div>
|
||||
<div><p class="eyebrow">Your eom.dev account</p><h2>{{ account.uid }}</h2><p>{{ account.email }}</p></div>
|
||||
<div class="member-actions">
|
||||
{% if account.stripe_customer %}<form action="{% url 'members:portal' %}" method="post">{% csrf_token %}<button class="button button-primary" type="submit">Manage billing</button></form>{% endif %}
|
||||
<form action="{% url 'members:logout' %}" method="post">{% csrf_token %}<button class="button button-secondary" type="submit">Sign out</button></form>
|
||||
@@ -51,20 +59,20 @@
|
||||
{% for invoice in crypto_invoices %}
|
||||
<p class="member-notice">SHKeeper · {{ invoice.tier|title }} · {{ invoice.status }}{% if invoice.access_end > now %} · Prepaid term {{ invoice.access_start|date:"M j, Y" }}–{{ invoice.access_end|date:"M j, Y" }}{% endif %} · <a href="{% url 'members:crypto_invoice' invoice.id %}">View crypto invoice</a></p>
|
||||
{% endfor %}
|
||||
<p class="member-small">Billing and directory status update automatically, usually within a few minutes. Signing out here does not sign you out of other Dex applications.</p>
|
||||
<p class="member-small">Membership access updates automatically, usually within a few minutes. Signing out here does not sign you out of other eom.dev services.</p>
|
||||
{% else %}
|
||||
<div class="member-actions">
|
||||
<a class="button button-primary" href="{% url 'members:register' %}">Create a free account</a>
|
||||
<form action="{% url 'members:login' %}" method="post">{% csrf_token %}<button class="button button-secondary" type="submit">Sign in with Dex</button></form>
|
||||
<form action="{% url 'members:login' %}" method="post">{% csrf_token %}<button class="button button-secondary" type="submit">Sign in to eom.dev</button></form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
<section aria-labelledby="tiers-heading">
|
||||
<div class="section-heading"><p class="eyebrow">Your support, your choice</p><h2 id="tiers-heading">Find your membership</h2><p>Your account stays free. Paid group access lasts only for the service period covered by your subscription.</p></div>
|
||||
<div class="section-heading"><p class="eyebrow">Your support, your choice</p><h2 id="tiers-heading">Find your membership</h2><p>Public projects and ordinary community participation stay free. Membership adds a closer connection to the work, not a barrier to joining in.</p></div>
|
||||
<div class="member-grid">
|
||||
<article class="member-panel tier-card free-tier">
|
||||
<p class="card-kicker">The starting point</p><h3>Community</h3><p class="tier-price">Free <span>/ always</span></p>
|
||||
<p>An account for the eom.dev community, stored in OpenLDAP and signed into through Dex.</p>
|
||||
<p>One account for eom.dev, its community, and its services.</p>
|
||||
<ul><li>No payment required</li><li>One account for compatible community services</li><li>Upgrade whenever you choose</li></ul>
|
||||
{% if not account %}<a class="button button-secondary" href="{% url 'members:register' %}">Join the community</a>{% else %}<p class="tier-footnote">Your free account is ready.</p>{% endif %}
|
||||
</article>
|
||||
@@ -72,17 +80,20 @@
|
||||
<article class="member-panel tier-card">
|
||||
<p class="card-kicker">Independent work, supported together</p><h3>{{ tier.label }}</h3><p class="tier-price">{{ tier.price_label }}</p>
|
||||
<p>{{ tier.description|default:"Help keep the projects and community running." }}</p>
|
||||
<ul><li>Tier-specific community access</li><li>Recurring payments through Stripe{% if shkeeper_enabled and tier.usd_amount %}, or prepaid crypto through SHKeeper{% endif %}</li><li>Your free account stays when paid access ends</li></ul>
|
||||
<ul>{% for benefit in tier.benefits %}<li>{{ benefit }}</li>{% empty %}<li>Support independent projects and the community</li>{% endfor %}</ul>
|
||||
{% if account %}<div class="tier-payment-actions"><form action="{% url 'members:checkout' key %}" method="post">{% csrf_token %}<button class="button button-primary" type="submit">Subscribe with Stripe</button></form>
|
||||
{% if shkeeper_enabled and tier.usd_amount %}<a class="button button-secondary" href="{% url 'members:crypto_checkout' key %}">Pay with crypto</a>{% endif %}</div>{% else %}<a class="button button-primary" href="{% url 'members:register' %}">Create an account to join</a>{% endif %}
|
||||
</article>
|
||||
{% empty %}<div class="member-panel"><h3>Paid memberships are coming soon.</h3><p>You can create your free account now. Paid tiers will appear when their prices and groups are configured.</p></div>{% endfor %}
|
||||
</div>
|
||||
<p class="member-small">One shared members' space, not a separate community at every price. Sustainer and Patron include the same access as Collaborator; choose them if you would like to contribute more.</p>
|
||||
<p class="member-small">Previews are shared when available, and playtests, listening sessions and feedback gatherings are occasional. Membership does not include storage quotas, personal consulting, guaranteed support or promised feature development. Recognition is always optional.</p>
|
||||
</section>
|
||||
<section class="member-faq" aria-labelledby="membership-faq">
|
||||
<h2 id="membership-faq">Simple, by design.</h2>
|
||||
<details><summary>What happens when a membership ends?</summary><p>Your LDAP account stays. Paid group access is removed automatically when the paid service period expires. An immediate cancellation removes access on the next successful sync.</p></details>
|
||||
<details><summary>Where is my password stored?</summary><p>Only OpenLDAP stores your password hash. This website sends your initial password over verified TLS to OpenLDAP's password-modify operation. Future sign-ins happen through Dex.</p></details>
|
||||
<details><summary>What happens when a membership ends?</summary><p>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.</p></details>
|
||||
<details><summary>Where do members connect?</summary><p>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.</p></details>
|
||||
<details><summary>What can I preview or take part in?</summary><p>Depending on what is being made, Insider members and above may preview music, game builds, videos or new experiments and join playtests or listening sessions. Collaborator 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.</p></details>
|
||||
<details><summary>Can I change or cancel a plan?</summary><p>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.</p></details>
|
||||
{% if shkeeper_enabled %}<details><summary>How do crypto memberships renew?</summary><p>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.</p></details>{% endif %}
|
||||
</section>
|
||||
|
||||
+35
-10
@@ -1,42 +1,67 @@
|
||||
{
|
||||
"level-0": {
|
||||
"label": "Level 0",
|
||||
"label": "Supporter",
|
||||
"price_id": "price_1Rgv4xC5KPXqTvVLfMd6z7wn",
|
||||
"price_label": "$4 USD / month",
|
||||
"usd_amount": "4.00",
|
||||
"group_dn": "cn=www-level-0,ou=groups,dc=eom,dc=dev",
|
||||
"description": "Support the independent work with a Level 0 membership."
|
||||
"description": "A private place to connect and a closer look at what is being made.",
|
||||
"benefits": [
|
||||
"Access to the shared members' Matrix space",
|
||||
"Behind-the-scenes notes and work-in-progress updates",
|
||||
"Optional recognition on the supporters page"
|
||||
]
|
||||
},
|
||||
"level-1": {
|
||||
"label": "Level 1",
|
||||
"label": "Insider",
|
||||
"price_id": "price_1Rgv5QC5KPXqTvVLv1PaHWb5",
|
||||
"price_label": "$8 USD / month",
|
||||
"usd_amount": "8.00",
|
||||
"group_dn": "cn=www-level-1,ou=groups,dc=eom,dc=dev",
|
||||
"description": "Support the independent work with a Level 1 membership."
|
||||
"description": "See new experiments take shape, and try things before their public release.",
|
||||
"benefits": [
|
||||
"Everything in Supporter",
|
||||
"Early previews of music, games, videos and experiments when available",
|
||||
"Invitations to member playtests and listening sessions"
|
||||
]
|
||||
},
|
||||
"level-2": {
|
||||
"label": "Level 2",
|
||||
"label": "Collaborator",
|
||||
"price_id": "price_1Rgv5rC5KPXqTvVL8Ol8sMUf",
|
||||
"price_label": "$16 USD / month",
|
||||
"usd_amount": "16.00",
|
||||
"group_dn": "cn=www-level-2,ou=groups,dc=eom,dc=dev",
|
||||
"description": "Support the independent work with a Level 2 membership."
|
||||
"description": "Share your perspective and help shape the next community experiment.",
|
||||
"benefits": [
|
||||
"Everything in Insider",
|
||||
"Member polls on future project topics and experiments",
|
||||
"Invitations to occasional small-group feedback sessions"
|
||||
]
|
||||
},
|
||||
"level-3": {
|
||||
"label": "Level 3",
|
||||
"label": "Sustainer",
|
||||
"price_id": "price_1Rgv6FC5KPXqTvVL39mAxYjm",
|
||||
"price_label": "$32 USD / month",
|
||||
"usd_amount": "32.00",
|
||||
"group_dn": "cn=www-level-3,ou=groups,dc=eom,dc=dev",
|
||||
"description": "Support the independent work with a Level 3 membership."
|
||||
"description": "The same community access, with a larger contribution to keeping it independent.",
|
||||
"benefits": [
|
||||
"Everything in Collaborator, with the same access",
|
||||
"A larger contribution toward servers and public projects",
|
||||
"Choose this level if you would like to give more"
|
||||
]
|
||||
},
|
||||
"level-4": {
|
||||
"label": "Level 4",
|
||||
"label": "Patron",
|
||||
"price_id": "price_1Rgv6mC5KPXqTvVLkcmznWZa",
|
||||
"price_label": "$64 USD / month",
|
||||
"usd_amount": "64.00",
|
||||
"group_dn": "cn=www-level-4,ou=groups,dc=eom,dc=dev",
|
||||
"description": "Support the independent work with a Level 4 membership."
|
||||
"description": "Help underwrite the public work and the community around it.",
|
||||
"benefits": [
|
||||
"Everything in Collaborator, with the same access",
|
||||
"Optional patron credit on the supporters page",
|
||||
"Your highest level of support for independent public projects"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user