sparkbooth anbindung optimiert

This commit is contained in:
2025-12-05 22:00:20 +01:00
parent 821ad2a945
commit 08ee2205f5
7 changed files with 205 additions and 19 deletions

View File

@@ -1,16 +1 @@
{
"mcpServers": {
"laravel-boost": {
"command": "php",
"args": [
"artisan",
"boost:mcp"
],
"transport": "stdio",
"alwaysAllow": [
"application-info"
],
"disabled": false
}
}
}
{"mcpServers":{"laravel-boost":{"command":"php","args":["artisan","boost:mcp"],"transport":"stdio","alwaysAllow":["application-info","search-docs"],"disabled":false}}}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Filament\Pages;
use App\Models\Gallery;
use BackedEnum;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use UnitEnum;
class SparkboothConnections extends Page implements HasTable
{
use InteractsWithTable;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-link';
protected static string|UnitEnum|null $navigationGroup = 'Admin';
protected static ?int $navigationSort = 11;
protected static ?string $title = 'Sparkbooth Verbindungen';
protected ?string $heading = 'Sparkbooth Verbindungen';
protected string $view = 'filament.pages.sparkbooth-connections';
public function table(Table $table): Table
{
return $table
->heading('Vorhandene Sparkbooth-Verbindungen')
->query(
Gallery::query()
->whereNotNull('upload_token_hash')
->orderByDesc('created_at')
)
->columns([
TextColumn::make('name')
->label('Name')
->searchable(),
TextColumn::make('slug')
->label('Slug')
->copyable()
->toggleable(),
TextColumn::make('images_path')
->label('Upload-Pfad')
->copyable()
->toggleable(),
TextColumn::make('created_at')
->label('Angelegt')
->since()
->sortable(),
])
->actions([
Action::make('show')
->label('Zugangsdaten anzeigen')
->icon('heroicon-o-key')
->color('primary')
->modalHeading('Upload-Zugangsdaten')
->modalSubmitAction(false)
->modalCancelActionLabel('Schließen')
->modalContent(function (Gallery $record) {
$plainToken = $record->regenerateUploadToken();
$data = [
'gallery' => $record->only(['id', 'name', 'slug', 'images_path']),
'upload_token' => $plainToken,
'upload_url' => route('api.sparkbooth.upload'),
'gallery_url' => route('gallery.show', $record),
];
Notification::make()
->title('Upload-Token wurde erneuert.')
->body('Bitte verwende den neuen Token in Sparkbooth.')
->success()
->send();
return view('filament.pages.partials.sparkbooth-token', $data);
}),
])
->emptyStateHeading('Keine Sparkbooth-Verbindungen')
->emptyStateDescription('Lege eine neue Verbindung an oder aktiviere Uploads für eine Galerie.');
}
}

View File

@@ -49,7 +49,10 @@ class SparkboothSetup extends Page implements HasForms
->label('Upload-Pfad')
->helperText('Relativ zu public/storage, z.B. uploads/event-xyz')
->default(fn () => 'uploads/'.Str::slug('event-'.Str::random(4)))
->required(),
->required()
->rule('regex:/^[A-Za-z0-9._\\/-]+$/')
->unique(table: Gallery::class, column: 'images_path')
->dehydrateStateUsing(fn (string $state): string => trim($state, '/')),
Toggle::make('allow_print')
->label('Drucken erlauben')
->default(true),
@@ -100,8 +103,15 @@ class SparkboothSetup extends Page implements HasForms
{
return [
\Filament\Actions\Action::make('save')
->label('Setup erstellen')
->label('Speichern')
->icon('heroicon-m-check')
->color('primary')
->submit('save'),
\Filament\Actions\Action::make('cancel')
->label('Abbrechen')
->icon('heroicon-m-x-mark')
->color('gray')
->url(route('filament.admin.pages.dashboard')),
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('galleries', function (Blueprint $table) {
if (! Schema::hasColumn('galleries', 'images_path')) {
return;
}
$duplicates = DB::table('galleries')
->select('images_path', DB::raw('COUNT(*) as aggregate'))
->whereNotNull('images_path')
->groupBy('images_path')
->having('aggregate', '>', 1)
->pluck('images_path')
->all();
if (! empty($duplicates)) {
foreach ($duplicates as $path) {
$idsToKeep = DB::table('galleries')
->where('images_path', $path)
->orderBy('id')
->limit(1)
->pluck('id');
DB::table('galleries')
->where('images_path', $path)
->whereNotIn('id', $idsToKeep)
->delete();
}
}
$table->unique('images_path');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('galleries', function (Blueprint $table) {
if (! Schema::hasColumn('galleries', 'images_path')) {
return;
}
$table->dropUnique('galleries_images_path_unique');
});
}
};

View File

@@ -0,0 +1,34 @@
<div class="space-y-4">
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
<p class="text-xs uppercase tracking-[0.3em] text-gray-500 dark:text-gray-300">Upload Endpoint</p>
<p class="mt-1 break-all font-semibold text-gray-900 dark:text-white">{{ $upload_url }}</p>
</div>
<div class="grid gap-4 md:grid-cols-2">
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
<p class="text-xs uppercase tracking-[0.3em] text-gray-500 dark:text-gray-300">Upload Token</p>
<p class="mt-1 break-all font-mono text-sm text-gray-900 dark:text-white">{{ $upload_token }}</p>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-300">Trage diesen Token in Sparkbooth unter „Upload Secret“ ein.</p>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
<p class="text-xs uppercase tracking-[0.3em] text-gray-500 dark:text-gray-300">Galerie-Link</p>
<p class="mt-1 break-all font-semibold text-gray-900 dark:text-white">{{ $gallery_url }}</p>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-300">Slug: {{ $gallery['slug'] }}, Pfad: storage/{{ $gallery['images_path'] }}</p>
</div>
</div>
<div class="grid gap-4 md:grid-cols-2">
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
<p class="text-xs uppercase tracking-[0.3em] text-gray-500 dark:text-gray-300">QR Code (Galerie)</p>
<div class="mt-2 rounded-lg border border-gray-200 bg-white p-2 shadow-sm dark:border-white/20 dark:bg-white/5">
{!! \SimpleSoftwareIO\QrCode\Facades\QrCode::size(200)->margin(1)->generate($gallery_url) !!}
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
<p class="text-xs uppercase tracking-[0.3em] text-gray-500 dark:text-gray-300">QR Code (Upload)</p>
<div class="mt-2 rounded-lg border border-gray-200 bg-white p-2 shadow-sm dark:border-white/20 dark:bg-white/5">
{!! \SimpleSoftwareIO\QrCode\Facades\QrCode::size(200)->margin(1)->generate($upload_url.'?token='.$upload_token) !!}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<x-filament-panels::page>
{{ $this->table }}
</x-filament-panels::page>

View File

@@ -1,6 +1,12 @@
<x-filament-panels::page>
<div class="space-y-6">
{{ $this->form }}
<form wire:submit="save" class="space-y-4">
{{ $this->form }}
<div class="fi-form-actions">
<x-filament::actions :actions="$this->getFormActions()" />
</div>
</form>
@if ($result)
<div class="rounded-2xl border border-gray-200/80 bg-white/70 p-6 shadow-sm ring-1 ring-black/5 dark:border-white/10 dark:bg-white/5">