feat(macros): add 'abspann' macro assignment part type
Add new part type 'abspann' (credits/Abspann presentation) to the macro assignment enum, validation and UI. - Relax part_type from enum to plain string on macro_assignments, service_macro_overrides and service_macro_assignments so 'abspann' (and any controller-validated value) is accepted across MySQL and SQLite. - Add 'abspann' to Rule::in validation in MacroAssignmentController and ServiceMacroOverrideController. - Include 'abspann' in the per-service macros_per_part list in ServiceController so the override UI exposes it. - Add 'abspann' to the parts array in Settings/MacroAssignments.vue (by_label stays song-only; abspann offers all/first/last slide).
This commit is contained in:
parent
7a29a21822
commit
e849d43b74
|
|
@ -35,7 +35,7 @@ public function index(): Response
|
|||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item'],
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item,abspann'],
|
||||
'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'],
|
||||
|
|
@ -50,7 +50,7 @@ public function store(Request $request): JsonResponse
|
|||
public function update(Request $request, MacroAssignment $macroAssignment): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'part_type' => ['sometimes', 'in:information,moderation,sermon,song,agenda_item'],
|
||||
'part_type' => ['sometimes', 'in:information,moderation,sermon,song,agenda_item,abspann'],
|
||||
'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'],
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public function edit(Service $service, \App\Services\ServiceImageResolver $image
|
|||
// Macro resolution per part type (for icons + Anpassen/Standard panel)
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
$macros_per_part = [];
|
||||
foreach (['information', 'moderation', 'sermon', 'song', 'agenda_item'] as $partType) {
|
||||
foreach (['information', 'moderation', 'sermon', 'song', 'agenda_item', 'abspann'] as $partType) {
|
||||
$assignments = $resolver->resolveAssignmentsForPart($service, $partType);
|
||||
$isOverridden = ServiceMacroOverride::where('service_id', $service->id)
|
||||
->where('part_type', $partType)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class ServiceMacroOverrideController extends Controller
|
|||
public function store(Request $request, Service $service): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item'],
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item,abspann'],
|
||||
]);
|
||||
|
||||
ServiceMacroOverride::firstOrCreate([
|
||||
|
|
@ -40,7 +40,7 @@ public function store(Request $request, Service $service): JsonResponse
|
|||
public function destroy(Service $service, Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item'],
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item,abspann'],
|
||||
]);
|
||||
|
||||
ServiceMacroOverride::where('service_id', $service->id)
|
||||
|
|
@ -57,7 +57,7 @@ public function destroy(Service $service, Request $request): JsonResponse
|
|||
public function storeAssignment(Request $request, Service $service): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item'],
|
||||
'part_type' => ['required', 'in:information,moderation,sermon,song,agenda_item,abspann'],
|
||||
'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'],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Relax the `part_type` enum to a plain string so any controller-validated
|
||||
* value (including the new 'abspann' part type) is accepted across MySQL and
|
||||
* SQLite. The enum previously rejected 'abspann' via a MySQL enum definition
|
||||
* or a SQLite check-constraint.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('macro_assignments', function (Blueprint $table) {
|
||||
$table->string('part_type')->change();
|
||||
});
|
||||
|
||||
Schema::table('service_macro_overrides', function (Blueprint $table) {
|
||||
$table->string('part_type')->change();
|
||||
});
|
||||
|
||||
Schema::table('service_macro_assignments', function (Blueprint $table) {
|
||||
$table->string('part_type')->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort restore of the original enum. Any 'abspann' rows would be lost
|
||||
* on downgrade; a lossy down is acceptable for this local/dev project.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$original = ['information', 'moderation', 'sermon', 'song', 'agenda_item'];
|
||||
|
||||
Schema::table('macro_assignments', function (Blueprint $table) use ($original) {
|
||||
$table->enum('part_type', $original)->change();
|
||||
});
|
||||
|
||||
Schema::table('service_macro_overrides', function (Blueprint $table) use ($original) {
|
||||
$table->enum('part_type', $original)->change();
|
||||
});
|
||||
|
||||
Schema::table('service_macro_assignments', function (Blueprint $table) use ($original) {
|
||||
$table->enum('part_type', $original)->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -18,6 +18,7 @@ const parts = [
|
|||
{ key: 'sermon', label: 'Predigt' },
|
||||
{ key: 'song', label: 'Lieder' },
|
||||
{ key: 'agenda_item', label: 'Agenda-Items' },
|
||||
{ key: 'abspann', label: 'Abspann' },
|
||||
]
|
||||
|
||||
const positions = [
|
||||
|
|
|
|||
|
|
@ -30,6 +30,39 @@
|
|||
expect(MacroAssignment::first()->part_type)->toBe('song');
|
||||
});
|
||||
|
||||
test('store creates abspann macro assignment', function () {
|
||||
$user = User::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson(route('settings.macro-assignments.store'), [
|
||||
'part_type' => 'abspann',
|
||||
'macro_id' => $macro->id,
|
||||
'position' => 'all_slides',
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
$response->assertStatus(200)->assertJson(['success' => true]);
|
||||
expect(MacroAssignment::where('part_type', 'abspann')->count())->toBe(1);
|
||||
expect(MacroAssignment::first()->part_type)->toBe('abspann');
|
||||
});
|
||||
|
||||
test('store rejects invalid part_type', function () {
|
||||
$user = User::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson(route('settings.macro-assignments.store'), [
|
||||
'part_type' => 'bogus',
|
||||
'macro_id' => $macro->id,
|
||||
'position' => 'all_slides',
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
expect(MacroAssignment::count())->toBe(0);
|
||||
});
|
||||
|
||||
test('store with by_label position and label_id', function () {
|
||||
$user = User::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
|
|
|
|||
Loading…
Reference in a new issue