pp-planer/app/Http/Controllers/MacroAssignmentController.php
Thorsten Bus 6ce5b6e018 feat(controllers): add macro/label import + global assignment + service override controllers and routes
- MacroImportController + LabelImportController: POST endpoints accepting uploaded .bin files,
  delegating to MacrosImportService / LabelsImportService and returning import stats / warnings as JSON.
  Generic German 422 error if parser rejects the file.
- MacroAssignmentController: index renders Settings Inertia page with assignments / macros / labels /
  collections / last-import metadata. store/update/destroy/reorder for global MacroAssignment rows.
- ServiceMacroOverrideController: store snapshots all matching global MacroAssignments into
  service-specific rows when a service opts to override; destroy removes both override and
  service-specific assignments. storeAssignment / updateAssignment / destroyAssignment manage the
  per-service rows directly.
- routes/web.php: 12 new named routes inside the auth middleware group; reorder route placed before
  {macroAssignment} parameter route to avoid capture conflict.
- Tests: 19 new Pest tests across 4 feature files (54 assertions). Full suite 376 passed.
2026-05-03 23:17:04 +02:00

87 lines
3.1 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Label;
use App\Models\Macro;
use App\Models\MacroAssignment;
use App\Models\MacroCollection;
use App\Models\Setting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class MacroAssignmentController extends Controller
{
public function index(): Response
{
return Inertia::render('Settings', [
'assignments' => MacroAssignment::with(['macro', 'label'])->orderBy('part_type')->orderBy('order')->get(),
'macros' => Macro::with('collections')->orderBy('name')->get(),
'labels' => Label::orderBy('name')->get(),
'collections' => MacroCollection::orderBy('name')->get(),
'last_macros_import' => [
'at' => Setting::get('macros_last_imported_at'),
'filename' => Setting::get('macros_last_imported_filename'),
],
'last_labels_import' => [
'at' => Setting::get('labels_last_imported_at'),
'filename' => Setting::get('labels_last_imported_filename'),
],
]);
}
public function store(Request $request): JsonResponse
{
$validated = $request->validate([
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item'],
'macro_id' => ['required', 'integer', 'exists:macros,id'],
'position' => ['required', 'in:all_slides,first_slide,last_slide,by_label'],
'label_id' => ['nullable', 'integer', 'exists:labels,id'],
'order' => ['integer', 'min:0'],
]);
$assignment = MacroAssignment::create($validated);
return response()->json(['id' => $assignment->id, 'success' => true]);
}
public function update(Request $request, MacroAssignment $macroAssignment): JsonResponse
{
$validated = $request->validate([
'part_type' => ['sometimes', 'in:information,moderation,sermon,song,agenda_item'],
'macro_id' => ['sometimes', 'integer', 'exists:macros,id'],
'position' => ['sometimes', 'in:all_slides,first_slide,last_slide,by_label'],
'label_id' => ['nullable', 'integer', 'exists:labels,id'],
'order' => ['sometimes', 'integer', 'min:0'],
]);
$macroAssignment->update($validated);
return response()->json(['success' => true]);
}
public function destroy(MacroAssignment $macroAssignment): JsonResponse
{
$macroAssignment->delete();
return response()->json(['success' => true]);
}
public function reorder(Request $request): JsonResponse
{
$validated = $request->validate([
'assignments' => ['required', 'array'],
'assignments.*.id' => ['required', 'integer', 'exists:macro_assignments,id'],
'assignments.*.order' => ['required', 'integer', 'min:0'],
]);
foreach ($validated['assignments'] as $item) {
MacroAssignment::where('id', $item['id'])->update(['order' => $item['order']]);
}
return response()->json(['success' => true]);
}
}