Commit Graph

287 Commits

Author SHA1 Message Date
The Ben 9884fd25de ⬆️ Upgrade spatie/laravel-permission to v8, league/glide to v4, laravel/mcp to v0.8 (#3)
- spatie/laravel-permission ^7.0 → ^8.0 (8.1.0)
- league/glide ^3.0 → ^4.0 (4.0.0), pulls intervention/image v4
- laravel/mcp ^0.7.0 → ^0.8.0 (0.8.2)

No application code changes required: MCP uses server features only,
Role/Permission are standard (no contract overrides), and the Glide
ImageController already uses v4-compatible ImageManager instantiation.
2026-06-30 13:49:49 +00:00
HolgerHatGarKeineNode 306997a3cf ⬆️ Upgrade JS dependencies 2026-06-30 14:25:48 +02:00
HolgerHatGarKeineNode 2822b9fe27 ⬆️ Upgrade composer dependencies 2026-06-30 14:25:48 +02:00
HolgerHatGarKeineNode a2a640809a Refactor components and models:
- 🔥 Removed deprecated `placeholder-pattern` component.
- 🧹 Simplified and cleaned up Blade views by removing unused comments and sections.
- 🗂️ Extracted `SetsCreatedBy` concern for DRY and reused it across models.
- 🔧 Consolidated configuration for Horizon `authorized_nostr_keys`.
- 🧪 Migrated media conversion to use new Spatie enums for clarity.
- ♻️ Replaced repetitive link rendering with dynamic rendering in meetups and services views.
2026-06-29 22:20:01 +02:00
HolgerHatGarKeineNode beaf028c1d 🎨 Add AVIF logo support to Meetups and tests 2026-06-29 21:16:56 +02:00
HolgerHatGarKeineNode 473b7880a7 ⬆️ Upgrade JS dependencies 2026-06-29 19:26:34 +02:00
HolgerHatGarKeineNode 99c5cb2b9e ⬆️ Upgrade composer dependencies 2026-06-29 19:26:34 +02:00
HolgerHatGarKeineNode 02b1c161d3 ⬆️ Upgrade JS dependencies 2026-06-28 17:11:58 +02:00
HolgerHatGarKeineNode 75fdaffdb4 ⬆️ Upgrade composer dependencies 2026-06-28 17:11:58 +02:00
HolgerHatGarKeineNode 31c1b9355a 🐛 Target mobile sidebar toggle via data-test (Flux overrides aria-label) 2026-06-26 21:10:02 +02:00
HolgerHatGarKeineNode 219f5f083b 🔧 Expect 201 Created from Passport dynamic client registration (RFC 7591) 2026-06-26 18:34:35 +02:00
HolgerHatGarKeineNode 02b4518170 ⬆️ Upgrade JS dependencies 2026-06-26 18:34:35 +02:00
HolgerHatGarKeineNode fb78fb46a3 ⬆️ Upgrade composer dependencies 2026-06-26 18:34:35 +02:00
HolgerHatGarKeineNode 4c9dec42f2 Add service disclaimer component and Nostr validation links
-  Introduced reusable `<x-service-disclaimer>` component for better clarity and consistency on service pages.
- 🔗 Added `njump` links for Nostr profile validation in service listings and landing pages.
- 🧪 Included feature tests to verify disclaimer visibility and correct `njump` link rendering or omission for anonymous services.
2026-06-25 14:12:21 +02:00
HolgerHatGarKeineNode dc1d679e4b Add leader-based permissions to Meetup event tests and editable scope
- 🔒 Ensure leader users are required for Meetup event tests to simulate accurate permissions.
-  Add `editableBy` scope to `MeetupEvent` model for consistent editable event handling.
- 🛠️ Refactor `mine` API endpoint and MCP tool to leverage `editableBy` scope.
- 🧪 Update tests to verify leader-based accessibility for Meetup events.
2026-06-17 20:05:39 +02:00
HolgerHatGarKeineNode 7c142fb37a 🔤 Fix quotes in German translations for Meetup operation descriptions
- ✏️ Replace incorrect German straight quotes with proper German curly quotes in `MeetupController` comments for improved localization consistency.
2026-06-17 18:37:08 +02:00
HolgerHatGarKeineNode 276016eed7 Handle non-numeric values in selected filter for Country API and add corresponding tests
- 🔧 Refactor `CountryController` to safely process non-numeric values in `selected` query parameter using `array_filter`.
- 🧪 Add feature test to ensure API does not crash when `selected` includes non-numeric codes.
2026-06-17 09:56:25 +02:00
HolgerHatGarKeineNode a051188907 Add next_event to Lecturer API responses and tests
-  Extend `withDetails` flag in Lecturer API to include `next_event` (date of the next course event or null).
- 🧪 Update feature tests to assert presence and validity of `next_event` in responses.
2026-06-16 23:37:15 +02:00
HolgerHatGarKeineNode ffcee850ca Add leader management functionality for Meetups
-  Introduced `leaders`, `promoteLeader`, and `demoteLeader` methods in `Meetup` model for consistent handling of meetup leadership.
- ⚙️ Refactored `MeetupLeaderController` to use new leadership methods, improving reusability and maintainability.
- 👮‍♂️ Added `ValidNpub` validation rule for npub input standardization.
- 🧪 Added feature tests for leadership delegation and permissions.
- 🖼️ Implemented leader management UI in meetup edit page with flash messaging for actions.
2026-06-16 23:11:24 +02:00
HolgerHatGarKeineNode 9f8fda294a Implement leadership-based permissions for Meetup management
- 🔒 Restrict event creation, editing, and deletion to Meetup leaders (`is_leader`) and creators for consistency across APIs, frontend, and MCP.
-  Add new APIs for leader delegation: assign/remove Meetup leaders via `meetup_user.is_leader`.
- 🛠️ Replace loose member checks with specific leadership checks in policies, controllers, and views.
- 🧪 Add exhaustive tests to ensure only eligible leaders execute critical actions (e.g., event creation/edit, Meetup updates).
- 🔄 Refactor pivot relationships and models (`leadByMe`, `isLeader`) for explicit leadership handling.
-  Introduce artisan command `meetups:promote-existing-leaders` to transition legacy data.
2026-06-16 22:04:34 +02:00
HolgerHatGarKeineNode 39af153f52 🖼️ Replace Manipulations::FIT_CROP with `Fit 2026-06-16 16:37:08 +02:00
HolgerHatGarKeineNode ae5eae576c Introduce places:cleanup command to remove unused venues and cities
- 🧹 Add `places:cleanup` console command for dry-run and forced deletion of venues (without course/bitcoin events) and cities (without venues/meetups).
- 🧪 Add feature tests for `places:cleanup`, covering dry-run, forced deletion, and scenarios ensuring retention of dependent records.
-  Add `bitcoinEvents` relationship to `Venue` model to support cleanup logic.
2026-06-16 16:32:57 +02:00
HolgerHatGarKeineNode 29628b41e9 Add lecturer cleanup job and update profile update functionality
- 🧹 Introduce `lecturers:cleanup` command to delete lecturers without associated courses or events, merging their items into "Einundzwanzig."
- ⚙️ Add `update` method to `UserController` for handling profile updates, allowing name changes while restricting role modifications.
- 🌐 Register `PATCH /api/user` route for profile updates and update related API tests.
- 🧪 Add feature and console tests for `lecturers:cleanup`, covering dry-run, forced deletion, and edge cases.
2026-06-16 14:40:40 +02:00
HolgerHatGarKeineNode c3028b8260 Add attendee count helpers and enhance Meetup API responses
-  Introduce `attendeesCount` and `mightAttendeesCount` methods in `MeetupEvent` model for cleaner attendee calculations.
- 🛠️ Refactor API responses to use attendee count helpers in `Meetup` and `MeetupEventController`.
- 🧪 Update tests to validate JSON structure with attendee-related fields (`id`, `attendees`, `might_attendees`).
2026-06-15 22:45:28 +02:00
HolgerHatGarKeineNode 0a1d177fc4 Add RSVP functionality for Meetup Events
- 🏷️ Introduce `RsvpStatus` enum for managing attendance states (`attending`, `maybe`, `none`).
- ✏️ Add `MeetupEventController` methods for RSVP actions (`rsvpStatus`, `rsvp`) and payload handling.
-  Implement RSVP helpers in `MeetupEvent` model for user-specific attendance management.
- 🌐 Register RSVP routes for showing and updating attendance in the API.
- 🧪 Add feature tests for RSVP actions, covering validation, idempotency, and correct list handling.
2026-06-15 22:10:10 +02:00
HolgerHatGarKeineNode e55967e9ac Add removeFromMine functionality to Meetups API for removing meetups from a user's "My Meetups" list
- 🔒 Introduce `removeFromMine` policy for authenticated users to remove meetups.
- ✏️ Add `removeFromMine` method in `MeetupController` with idempotent handling.
-  Add `removeMember` utility in `Meetup` model for managing pivot relationships.
- 🧪 Add feature tests for `removeFromMine`, covering idempotency, permissions, and unknown slugs.
- 🌐 Register `removeFromMine` route in API and link it to `MeetupController`.
2026-06-15 21:28:01 +02:00
HolgerHatGarKeineNode 4b6cf95932 🖼️ Implement Logo/Avatar Uploads & Recurrence UI in Mobile App
- **A1**: Added image uploads (Meetup logo, Lecturer avatar, Course logo) via `HandlesImageUpload` with reusable `<x-image-picker>` component and Saloon multipart requests.
- **A2**: Introduced Recurrence UI in Event Editor with support for `weekly`, `monthly`, and `custom` recurrence types, aligning with portal capabilities.
- Fixed `myCourseEvents` API response handling (`data` wrapper) for consistency.
2026-06-15 19:32:56 +02:00
HolgerHatGarKeineNode 1518611bdb - 🏗️ Introduced CoursePolicy and CourseEventPolicy for authorization.
-  Added `StoreCourseRequest` and `UpdateCourseRequest` for structured validation.
-  Introduced `StoreCourseEventRequest` and `UpdateCourseEventRequest` for consistent request validation.
- 🖼️ Created `CourseResource` and `CourseEventResource` for API responses.
- 🔄 Refactored `CourseController` and `CourseEventController` to use Policies and FormRequests.
-  Added dedicated `uploadLogo` and `uploadAvatar` API endpoints with shared media validation.
- 🚀 Improved API by aligning Course and CourseEvent behavior with other entities.
2026-06-15 15:06:07 +02:00
HolgerHatGarKeineNode 119deb4f5c Add addToMine functionality to Meetups API for adding meetups to a user's "My Meetups" list
- 🔒 Introduce `addToMine` policy for authenticated users to add existing meetups.
- ✏️ Add `addToMine` method in `MeetupController` with idempotent handling.
-  Include `addMember` utility in `Meetup` model for managing pivot relationships.
- 🛠️ Refactor `AddMeetupToMineTool` to use `addMember` for consistency.
- 🧪 Add feature tests for `addToMine`, covering idempotency, permissions, and unknown slugs.
- 🌐 Register `addToMine` route in API and link it to `MeetupController`.
2026-06-15 00:10:21 +02:00
HolgerHatGarKeineNode ac1abc4435 🔄 Replace ilike/like with whereLike and orWhereLike across views and remove macros for cleaner, driver-agnostic querying 2026-06-14 01:43:34 +02:00
HolgerHatGarKeineNode f93190f029 Add whereLike and orWhereLike macros for driver-agnostic case-insensitive searches
- 🔄 Replace `ilike`/`like` conditions with `whereLike` in API controllers and search tools for consistency.
- 🚀 Enhance query usability by ensuring cross-database compatibility (PostgreSQL and SQLite).
2026-06-14 01:32:03 +02:00
HolgerHatGarKeineNode 6239842b15 🖼️ Add "Close" translation across languages and introduce lightbox functionality for **KI-Assistent** images 2026-06-14 00:50:59 +02:00
HolgerHatGarKeineNode 19dee6356a 🖼️ Replace outdated screenshots with new **KI-Assistent** images and update asset paths 2026-06-14 00:38:07 +02:00
HolgerHatGarKeineNode a353d7e089 🔗 Add **KI-Assistent** guide for integrating EINUNDZWANZIG with Claude.ai
- 🌐 Added translations (de, en, es, lv, nl, pt) and localized content for setup guide.
- 🧭 Introduced `/ki-assistent` route with detailed instructions and screenshots.
- 🎉 Updated sidebar navigation to include KI-Assistent link.
- ✏️ Configured SEO metadata for KI-Assistent page.
- 🧪 Added feature tests for guide accessibility and key content.
2026-06-14 00:32:53 +02:00
HolgerHatGarKeineNode 8fd4900138 🔠 Standardize brand name casing to **EINUNDZWANZIG** across translations, controllers, views, and configurations 2026-06-13 23:53:11 +02:00
HolgerHatGarKeineNode d07b141b40 🎨 Add logo field to meetups API responses and fetch media relations for meetups
- ✏️ Updated `MeetupController` to include `with('media')` for meetups query.
- 🖼️ Added `logo` to `MeetupResource` via `getFirstMediaUrl`.
- 🧪 Extended feature tests to validate `logo` presence and type in API responses.
2026-06-13 22:56:10 +02:00
HolgerHatGarKeineNode 8d7b1515d8 Update MeetupController to use pivot memberships for "My Meetups" in both listing and detail views
- ✏️ Adjust `mine` method to fetch meetups based on dashboard selections (`meetup_user` pivot).
- ✏️ Add `viewMine` policy to control access to individual meetups for pivot members.
- 🧪 Update feature tests to reflect pivot-based logic for "My Meetups."
2026-06-13 22:42:33 +02:00
HolgerHatGarKeineNode b6f5d57530 🔄 Update flag asset paths for cities, venues, and countries across API and tools 2026-06-12 18:09:54 +02:00
HolgerHatGarKeineNode 0b454dfc80 🧪 Add API tests and update controllers for city and venue details
- ✏️ Added feature tests for cities and venues, including pagination limits and `withDetails` parameter handling.
- ✏️ Updated `CityController` to support `withDetails`, returning country code and flag URL while lifting pagination limits.
- ✏️ Updated `VenueController` to support `withDetails`, lifting pagination limits and enriching venue responses with city details.
2026-06-12 18:00:14 +02:00
HolgerHatGarKeineNode 6a2958c90a 🧪 Add API tests and update controllers for detailed course and lecturer data
- 🚀 Introduced feature tests for courses and lecturers, covering pagination limits, detailed data retrieval, and 404 responses.
- ✏️ Updated `CourseController` to support `withDetails` for courses, including lecturer and next event data.
- ✏️ Updated `LecturerController` to support `withDetails` for lecturers, including future events count.
- ⚙️ Expanded routes to include `show` endpoints for courses and lecturers.
2026-06-12 17:16:53 +02:00
HolgerHatGarKeineNode f9b3428865 Add DELETE /api/mobile/token so the app can revoke its token on logout 2026-06-12 15:12:38 +02:00
HolgerHatGarKeineNode 54c959d18e Return the signed event to the app via custom scheme, not a browser page
A signer-owned Custom Tab never reliably displayed the browser handoff
page, so the token never returned. The Nostr launcher now uses the app's
custom scheme as the callback (einundzwanzig://signed/{k1}/): Amber opens
it directly after signing and the app exchanges the event for a token via
/api/mobile/token — no browser handoff in the loop.
2026-06-12 01:14:01 +02:00
HolgerHatGarKeineNode 76787a1bee Render the handoff page directly instead of 302-redirecting to /app/auth
Chrome follows a server 302 internally and never dispatches the /app/auth
App Link, so the handoff page stayed in the browser and the token never
reached the app. The signed callback (and complete/confirm) now render
the handoff page directly with the einundzwanzig:// deep-link button — the
signer opens the callback in the browser, the user lands on the handoff
page and taps once to return to the app, which stores the token.
2026-06-12 00:29:44 +02:00
HolgerHatGarKeineNode 4fa4a84b7d Launch the Nostr signer via an intent:// URL with extras
Amber v6.2.0 rejects a plain nostrsigner: navigation as malformed: it
reads the signer parameters from intent extras, which a window.location
navigation cannot set. An intent:// URL lets the launcher pass the event
as the data URI plus type/returnType/appName/callbackUrl as S.* extras,
so Amber accepts the request and shows its sign dialog. The query is also
kept on the data URI for the EXTRA_APPLICATION_ID web flow.

Note: on the emulator with Amber v6.2.0 the post-approval callback did
not always fire (Amber returns via setResult when callingPackage != null);
needs verification on a real device.
2026-06-11 23:28:32 +02:00
HolgerHatGarKeineNode 76894a6634 Require a user tap to launch the Nostr signer (fixes Amber malformed)
Amber v6.2.0 routes nostrsigner: intents by EXTRA_APPLICATION_ID: present
(web flow, reads the event from the URI) vs absent (app-to-app flow,
reads type/event from intent extras → rejects our URI as malformed).
Browsers only attach that extra when the external-app launch comes from a
user gesture, so the auto-redirect on page load always failed. The
launcher now waits for the user to tap "Mit Amber signieren".
2026-06-11 22:54:40 +02:00
HolgerHatGarKeineNode 7e491326a9 Build the Nostr signer URI in the browser, not server-side
Server-side percent-encoding (rawurlencode/http_build_query) produced a
nostrsigner: URI that Amber rejected as malformed. The launcher view now
assembles it in JS with encodeURIComponent(JSON.stringify(event)) — the
exact encoding Amber accepts (verified working earlier in the session).
The controller only passes k1 and the callback URL.
2026-06-11 22:40:57 +02:00
HolgerHatGarKeineNode 58c7e410b0 Add headless Nostr launcher page for the mobile app
A direct ACTION_VIEW intent to nostrsigner: (Browser::open from the app)
lacks category.BROWSABLE, so Amber routes it into its app-to-app path
and rejects it as malformed. The app instead opens /auth/mobile/nostr in
an in-app browser; that page fires the signer via window.location, so
the intent carries BROWSABLE and Amber uses its web-signing flow. No
visible login UI, local signing, token returned via the App Link.
2026-06-11 22:08:17 +02:00
HolgerHatGarKeineNode 64a5fcd9f1 Make the mobile login page Lightning-only
The Nostr login is now driven entirely by the app (it launches the
NIP-55 signer via an ACTION_VIEW intent and posts the signed event to
/auth/mobile/signed), so the portal page no longer needs window.nostr or
an Amber button — it only renders the Lightning QR. The path-based
signer callback and token exchange endpoints remain server-side.
2026-06-11 21:51:01 +02:00
HolgerHatGarKeineNode c30f1932e4 Use window.nostr (NIP-46/Amber bunker) on the mobile login page
Replaces the fragile NIP-55 intent/callback round-trip with the same
mechanism the desktop login uses: openNostrLogin signs the session
challenge via window.nostr — provided by an extension or by
window.nostr.js over a persistent NIP-46 connection (Amber pairing with
permissions). The listener stores a LoginKey for the page's k1 and
navigates to the completion route, which issues the token and redirects
into the app via the verified App Link handoff.
2026-06-11 20:47:02 +02:00
HolgerHatGarKeineNode 7531f28f22 Add verified App Link handoff and mobile token exchange endpoint
Replaces the custom-scheme auto-redirect (which triggers Chrome's
confirmation prompt) with a verified Android App Link handoff:

- public/.well-known/assetlinks.json for space.einundzwanzig.mobile
  (debug cert fingerprint; add the release cert before store builds)
- GET /app/auth handoff: opens the app directly when the App Link is
  verified; renders a button-based fallback page otherwise
- POST /api/mobile/token: trades a NIP-55-signed login event for a
  Sanctum token — used when Amber's callback opens the app directly
- complete/confirm/signedCallback now redirect to the handoff URL
2026-06-11 19:51:14 +02:00