v1.70.0
Added
- Membership tiers now carry a persistable display order: a new
PATCH /organization-admin/{slug}/membership-tiers/reorderendpoint sets the order,display_orderis exposed on the tier schema, and newly created tiers append at the bottom — enabling drag-to-reorder in the org-admin UI. Existing tiers are backfilled in their current alphabetical order on deploy. - Organization subscription-policy fields
membership_grace_period_daysandmembership_refund_policyare now exposed on the org-admin detail and edit schemas, so the org-admin UI can display and edit them. Changing them requires themanage_subscriptionspermission (consistent with the rest of the subscription management surface); staff with onlyedit_organizationcannot alter subscription policy. - The public organization schema (
OrganizationRetrieveSchema) now includesmembership_refund_policy, so prospective and active subscribers can read the refund policy before requesting or paying for a membership (the grace period stays admin-internal). - Public organization-token preview (
GET /organizations/tokens/{token_id}) now includes the inviting organization'sorganization_name,organization_slug,organization_logo_url, and the grantedmembership_tier_name, so the pre-claim join page can show which organization (and tier) is inviting. - Public event-token preview (
GET /events/tokens/{token_id}) now includesevent_name,event_slug,organization_slug,event_start, andevent_cover_url, so the pre-claim join page can render the event instead of "Join undefined".
Changed
- Any organization staff member can now list members (
GET /organization-admin/{slug}/members); this previously required themanage_memberspermission, so staff who could already create RSVPs on behalf of a user had no way to look them up. - Public token previews (
GET /events/tokens/{token_id}andGET /organizations/tokens/{token_id}) now return 410 Gone with a machine-readablereason(expiredorused_up) plus minimal display fields for tokens that exist but are no longer servable, instead of a generic 404 — so the join pages can distinguish an expired invitation from a used-up one. A 404 is now returned only for genuinely unknown token ids.
Fixed
- Search results no longer contain duplicates when the search term matches on a multiplying relation (e.g. tags): an event with 3 matching tags used to appear 3× in events, event-series, organization, dashboard, and questionnaire listings.
- Membership request approval and rejection notifications are no longer silently dropped — approved and rejected applicants now receive their in-app/email notification (the notification context previously failed schema validation).
- Organization staff granted the relevant permissions can now use org-admin routes that previously denied every non-owner staff member regardless of their grants: deleting organization resources (requires
edit_organization) and managing discount codes (requiresmanage_tickets). Revenue & VAT report endpoints are now explicitly owner-only. - Attendees can now change or withdraw their RSVP on a full event: a
yes → no/maybe, amaybe → no, or a new decline are no longer rejected withevent_is_full— capacity is only enforced on seat-claiming (a newyes) writes. Freeing a seat this way triggers waitlist processing for the next person in line. PUT /organization-admin/{slug}now echoes the full admin representation (the same schema asGET), so a successful edit returns every updated field — including the subscription-policy and billing/VAT fields it previously omitted — instead of forcing a follow-upGET.
Security
- Upgraded Django 5.2.15 → 5.2.16 to patch three known vulnerabilities (
PYSEC-2026-2090,PYSEC-2026-2091,PYSEC-2026-2092). - Upgraded click 8.2.1 → 8.4.2 to patch
PYSEC-2026-2132.
What's Changed
- docs: document macOS GDAL/WeasyPrint native-lib fix by @biagiodistefano in #658
- fix: bootstrap seeding gaps blocking E2E journeys (#659–#662) by @biagiodistefano in #663
- fix: make bootstrap global-ban seeding idempotent (#665) by @biagiodistefano in #666
- fix: de-duplicate search results across M2M joins (#664) by @biagiodistefano in #667
- fix: bump django to 5.2.16 (PYSEC-2026-2090/2091/2092) by @biagiodistefano in #669
- test(#670) attempt-burn regression guard + docs(#671) silk E2E deadlock by @biagiodistefano in #672
- fix: stop swallowing membership request approval/rejection notifications (#673) by @biagiodistefano in #674
- feat: expose org name/slug/logo on public org-token preview (#675) by @biagiodistefano in #676
- feat: enrich public org/event token previews (#677, #679) by @biagiodistefano in #680
- fix: 410 + rejection reason for expired/used-up token previews (#681) by @biagiodistefano in #682
- fix: guard org-admin routes on real PermissionMap keys (#683) by @biagiodistefano in #685
- feat: prod-like E2E run target with PgBouncer by @biagiodistefano in #688
- feat: let any org staff list members (#686) by @biagiodistefano in #689
- feat: add display_order + reorder endpoint for membership tiers (#687) by @biagiodistefano in #690
- fix: allow RSVP no/maybe on full events (#691) by @biagiodistefano in #692
- fix(e2e): stop macOS fork crash; expose org subscription-policy fields by @biagiodistefano in #696
- fix: PUT /organization-admin/{slug} echoes the full admin schema (#697) by @biagiodistefano in #698
- feat(orgs): expose membership_refund_policy on public org schema (FE #633) by @biagiodistefano in #699
- chore(release): v1.70.0 by @biagiodistefano in #678
Full Changelog: v1.69.0...v1.70.0