mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-app.git
synced 2026-06-17 16:40:31 +00:00
1518611bdb
- ✨ 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.
162 lines
6.2 KiB
PHP
162 lines
6.2 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Api;
|
||
|
||
use App\Actions\MeetupEvents\CreateMeetupEventSeries;
|
||
use App\Http\Controllers\Controller;
|
||
use App\Http\Requests\Api\StoreMeetupEventRequest;
|
||
use App\Http\Requests\Api\UpdateMeetupEventRequest;
|
||
use App\Http\Resources\MeetupEventResource;
|
||
use App\Models\MeetupEvent;
|
||
use Carbon\Carbon;
|
||
use Carbon\Exceptions\InvalidFormatException;
|
||
use Dedoc\Scramble\Attributes\Group;
|
||
use Dedoc\Scramble\Attributes\PathParameter;
|
||
use Dedoc\Scramble\Attributes\Response as ResponseAttribute;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||
use Illuminate\Support\Collection;
|
||
use Illuminate\Support\Facades\Gate;
|
||
use Symfony\Component\HttpFoundation\Response;
|
||
|
||
#[Group(name: 'Meetups', weight: 3)]
|
||
class MeetupEventController extends Controller
|
||
{
|
||
/**
|
||
* Meetup-Termine auflisten
|
||
*
|
||
* Liefert kommende/vergangene Meetup-Termine. Mit optionalem Datum wird auf den
|
||
* jeweiligen Monat dieses Datums gefiltert.
|
||
*
|
||
* @return Collection<int, array<string, mixed>>
|
||
*/
|
||
#[PathParameter(name: 'date', description: 'Optionales Datum (Y-m-d); filtert auf den Monat dieses Datums.', required: false, type: 'string')]
|
||
#[ResponseAttribute(status: 400, description: 'Das übergebene Datum ist nicht parsebar (erwartet wird Y-m-d).')]
|
||
public function __invoke(?string $date = null): Collection
|
||
{
|
||
if ($date) {
|
||
try {
|
||
$date = Carbon::parse($date);
|
||
} catch (InvalidFormatException) {
|
||
abort(Response::HTTP_BAD_REQUEST, 'Ungültiges Datum. Erwartet wird das Format Y-m-d.');
|
||
}
|
||
}
|
||
$events = MeetupEvent::query()
|
||
->with([
|
||
'meetup.city.country',
|
||
'meetup.media',
|
||
])
|
||
->when(
|
||
$date,
|
||
fn ($query) => $query
|
||
->where('start', '>=', $date)
|
||
->where('start', '<=', $date->copy()->endOfMonth()),
|
||
)
|
||
->get();
|
||
|
||
return $events->map(fn ($event) => [
|
||
'start' => $event->start->format('Y-m-d H:i'),
|
||
'location' => $event->location,
|
||
'description' => $event->description,
|
||
'link' => $event->link,
|
||
'meetup.name' => $event->meetup->name,
|
||
'meetup.portalLink' => url()->route(
|
||
'meetups.landingpage',
|
||
[
|
||
'country' => $event->meetup->city->country,
|
||
'meetup' => $event->meetup,
|
||
],
|
||
),
|
||
'meetup.url' => $event->meetup->telegram_link ?? $event->meetup->webpage,
|
||
'meetup.country' => str($event->meetup->city->country->code)->upper(),
|
||
'meetup.city' => $event->meetup->city->name,
|
||
'meetup.longitude' => (float) $event->meetup->city->longitude,
|
||
'meetup.latitude' => (float) $event->meetup->city->latitude,
|
||
'meetup.twitter_username' => $event->meetup->twitter_username,
|
||
'meetup.website' => $event->meetup->webpage,
|
||
'meetup.simplex' => $event->meetup->simplex,
|
||
'meetup.signal' => $event->meetup->signal,
|
||
'meetup.nostr' => $event->meetup->nostr,
|
||
'meetup.logo' => $event->meetup->getFirstMediaUrl('logo'),
|
||
],
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Meetup-Event anlegen
|
||
*
|
||
* Erlaubt einem authentifizierten Nutzer, ein Meetup-Event programmatisch anzulegen.
|
||
* Der Ersteller (created_by) wird automatisch gesetzt.
|
||
*
|
||
* Werden sowohl `recurrence_type` als auch `recurrence_end_date` übergeben, wird – wie im
|
||
* Web-Editor – eine Serie einzelner Termine erzeugt (gemeinsame Expansions-Action, harte
|
||
* Obergrenze von 100 Terminen) und die Antwort enthält die Liste aller erstellten Events.
|
||
* Ohne diese Felder entsteht ein einzelner Termin.
|
||
*/
|
||
#[ResponseAttribute(status: 401, description: 'Nicht authentifiziert.')]
|
||
#[ResponseAttribute(status: 422, description: 'Validierungsfehler.')]
|
||
public function store(StoreMeetupEventRequest $request, CreateMeetupEventSeries $createSeries): JsonResponse
|
||
{
|
||
$validated = $request->validated();
|
||
|
||
if (! empty($validated['recurrence_type']) && ! empty($validated['recurrence_end_date'])) {
|
||
$events = $createSeries->handle($validated);
|
||
|
||
return MeetupEventResource::collection($events)
|
||
->response()
|
||
->setStatusCode(Response::HTTP_CREATED);
|
||
}
|
||
|
||
$meetupEvent = MeetupEvent::create($validated);
|
||
|
||
return MeetupEventResource::make($meetupEvent->fresh())
|
||
->response()
|
||
->setStatusCode(Response::HTTP_CREATED);
|
||
}
|
||
|
||
/**
|
||
* Meetup-Event aktualisieren
|
||
*
|
||
* Aktualisiert ein Meetup-Event; nur fuer den Ersteller oder einen Super-Admin.
|
||
*/
|
||
#[ResponseAttribute(status: 403, description: 'Nur der Ersteller oder ein Super-Admin darf das Meetup-Event aendern.')]
|
||
#[ResponseAttribute(status: 422, description: 'Validierungsfehler.')]
|
||
public function update(UpdateMeetupEventRequest $request, MeetupEvent $meetupEvent): MeetupEventResource
|
||
{
|
||
$meetupEvent->update($request->validated());
|
||
|
||
return MeetupEventResource::make($meetupEvent->fresh());
|
||
}
|
||
|
||
/**
|
||
* Eigene Meetup-Events auflisten
|
||
*
|
||
* Liefert alle vom authentifizierten Nutzer erstellten Meetup-Events, nach Startzeit absteigend sortiert.
|
||
*/
|
||
public function mine(Request $request): AnonymousResourceCollection
|
||
{
|
||
Gate::authorize('viewAny', MeetupEvent::class);
|
||
|
||
$meetupEvents = MeetupEvent::query()
|
||
->where('created_by', $request->user()->id)
|
||
->orderByDesc('start')
|
||
->get();
|
||
|
||
return MeetupEventResource::collection($meetupEvents);
|
||
}
|
||
|
||
/**
|
||
* Eigenes Meetup-Event anzeigen
|
||
*
|
||
* Zeigt ein einzelnes, vom authentifizierten Nutzer erstelltes Meetup-Event.
|
||
*/
|
||
#[ResponseAttribute(status: 403, description: 'Nur der Ersteller oder ein Super-Admin darf das Meetup-Event sehen.')]
|
||
public function mineShow(MeetupEvent $meetupEvent): MeetupEventResource
|
||
{
|
||
Gate::authorize('view', $meetupEvent);
|
||
|
||
return MeetupEventResource::make($meetupEvent);
|
||
}
|
||
}
|