Dandelion is a fair source project. View the code on Github

Commits on Jul 06, 2026
e89968c

Document Clearpay/Afterpay as an instalment payment option.

ca4022b

♻️ Rename event_creator to event_manager across the codebase

Rename the event_creator field on Organisationship, the admin_or_event_creator? method, the organisation_admins_or_event_creators_only! helper, the /event_creator/:id routes, the _event_creator partial, and the "Event creator" UI label to their event_manager equivalents.

The term "event manager" better describes the role of an account that can create and manage events on behalf of an organisation, rather than only creating them. Includes new tests covering the renamed permissions.

2e9edca

Remove high-price donation percent tier from purchase flow.

Suggested donation buttons now always use 1%, 5%, and 10% regardless of ticket price.

Commits on Jul 05, 2026
de5c766

🛂 (access_control.rb): add can_delete_event? helper to centralize event deletion authorization logic
🛂 (events_admin.rb): use new can_delete_event_only! guard for event deletion route
💄 (delete.erb): update view to use can_delete_event? for delete button visibility
✅ (event_creator_permissions_test.rb): add tests covering event deletion authorization scenarios

bdb356d

💚 (install.sh): add retry logic for bundle install to handle invalid git checkouts under Docker/OverlayFS

Clear bundler's cached git clones before each attempt and retry up to 3 times to recover from corrupted git-sourced gem caches that occur when copying from cache/bundler/git into bundler/gems.

8664a44

♻️ Extract event JSON serialization to model method

Move inline JSON hash construction from controller to @event.to_public_json to improve separation of concerns and reusability. Add with_key_includes to eager load associations and avoid N+1 queries. Update tests to match new JSON key names (start_time/end_time instead of start_date/end_date).

68c82ca

🔒️ Use signed token for organisation unsubscribe links

Replace the account_id query parameter on the organisation unsubscribe endpoint with a signed, organisation-scoped token so that recipients cannot be unsubscribed by anyone who knows their account id. The token is generated per (account, organisation) pair and verified server-side before resolving the account.

210d338

Increase sign_in_token entropy to 128 bits.

Replace the 5-character random suffix with SecureRandom.hex(16) so magic links are not trivially guessable when accepted globally via query params.

ab44d4d

⬆️ (Gemfile.lock): update activate-tools dependency to version 0.0.32

08e5a96

🐛 Wrap params with .to_s to prevent nil values from causing issues in database lookups

079cb51

✨ (donate.erb): embed a configurable (theme-aware) Circles iframe to enable in-page community/feedback flow when no event_feedback_id is present
♻️ (donate.erb): conditionally render the :badges partial only on event_feedback pages so the feedback context is the sole focus
💄 (donate.erb): wrap the :badges partial in a centered Bootstrap row/col to align with existing layout conventions
➕ (donate.erb): add iframe-resizer dependency (CDN) and init script to dynamically size the Circles iframe to its content

60f7db5

🎨 Refactor ticket type grip styling and position

Move the drag grip icon from a left-side bar with background and border to an inline right-aligned subtle icon. Simplify the CSS by removing the flexbox positioning and background styling, and use a centered absolutely positioned icon with reduced opacity that highlights on hover. This improves the visual hierarchy and reduces visual noise in the ticket type list.

b67a00a

The diff shows the refactoring of the magic tags system. The change moves the rendering of event_name and event_link tags from being passed as parameters to email views to being handled within the replace_magic_tags method itself. This makes the event_name rendering logic consistent across all email views (feedback, reminder, tickets) and centralizes it in one place. The event_name is now always rendered as a link (HTML) or plain text depending on the plain_text flag, and event_link is deprecated in favor of event_name.
♻️ (email_fields): centralize event_name and event_link rendering in replace_magic_tags method 📝 (email views): remove redundant event_name parameter passed to replace_magic_tags in email templates
💬 (email_fields): deprecate [event_link] tag in favor of [event_name] which now renders as a link
🚚 (email views): update default reminder email body to use [event_name] instead of [event_link] tag

ce12d31

✨ (events_admin.rb, email_fields.rb, event_notifications.rb): replace description_elements parameter with conditional logic and remove the orders parameter from recipient_variables


📝 (email_fields.rb): remove the description_elements parameter from recipient_tag_values method and from recipient_variables, also move the orders parameter as optional with a default value


✨ (email_fields.rb): add conditional logic to set the values for ticket_or_tickets, tickets_are, and description_elements tags based on the presence of orders


🔥 (events_admin.rb): remove order creation code in event_admin controllers as it's no longer needed


♻️ (event_notifications.rb): simplify the code by removing description_elements logic and changing how recipient_variables is called


🎨 (event_notifications.rb): improve code formatting and readability by breaking long lines and using a more consistent style for method calls

This refactor removes the need to pass orders and description_elements separately, simplifying the API of EmailFields. The conditional logic in recipient_tag_values handles the case where orders are not provided, making it easier to use these methods in different contexts.

d8a85dc

♻️ refactor(email_fields): centralize placeholder replacement across emails

Move scattered gsub chains into EmailFields.replace_magic_tags and recipient_variables so ticket, reminder, and feedback templates share one implementation. Batch reminder and feedback emails now support the full set of per-recipient tags (including description_elements) by loading each attendee's orders. Show available magic tags in event and organisation email settings; use Premailer for plain-text subject lines.

Commits on Jun 30, 2026
415f39b

♻️ Move answers blank check to before_validation callback

The answers blank check was duplicated in both the joined method and the event_feedback model. Centralize the logic in a before_validation callback in OrderFields concern so that the same behavior is applied consistently across all models including it.

Refactor the joined method to use method chaining and remove the now redundant blank check.

cda3183

🐛 (event_feedbacks): allow showing feedback report with exactly 5 feedbacks

The feedback report was only shown when there were more than 5 feedbacks, excluding cases with exactly 5. Changed the condition to use >= so the report is also generated/displayed when there are 5 feedbacks with answers.

03c8ba2

✨ Add per-event feedback report and reuse partial for facilitator Provide event admins with an AI-generated summary of feedback specific to an event, mirroring the existing facilitator report. Pass subject, intro and feedback via locals so the same partial can render both event and facilitator reports. Stash the result to avoid repeated generation and invalidate the cache on feedback create or destroy so changes are reflected promptly. Drop the unused since argument from EventFeedback.joined in favor of an explicit filter at the call site for clarity.

f7fc3c2

🎨 (app.scss): refactor sidebar nav styles for better structure and consistency
💄 (app.scss): improve sidebar nav padding, font sizes, and icon dimensions
📱 (app.scss): adjust sidebar nav padding for mobile devices
💄 (app.scss): add styles for minified sidebar nav layout
🎨 (app.scss): remove duplicate sidebar nav padding rule
✏️ (app.scss): add missing newline at end of file

Commits on Jun 26, 2026
b728d24

✨ (accounts): add separate ics_key for iCal feed authentication

Why: iCal feed URLs are typically shared with external calendar services (Google Calendar, Apple Calendar, etc.) which may store or transmit them in ways that aren't fully under the user's control. Using the api_key for these feeds over-exposed a credential that grants broader API access. A dedicated ics_key limits the blast radius if the URL leaks.

Changes: - add ics_key field on Account with uniqueness validation - add Account#ensure_ics_key! to lazily generate the key - add sign_in_via_ics_key helper alongside sign_in_via_api_key - scope ics_key auth to ICS endpoints only, so HTML views still require session sign-in - switch iCal feed links in views from api_key to ics_key - fix sign_in_via_api_key: return 403 via halt so it's actually applied