- 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.
109 lines
3.6 KiB
PHP
109 lines
3.6 KiB
PHP
<?php
|
|
|
|
use App\Models\Label;
|
|
use App\Models\Macro;
|
|
use App\Models\MacroAssignment;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
test('store requires authentication', function () {
|
|
$response = $this->post(route('settings.macro-assignments.store'), []);
|
|
$response->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('store creates macro assignment', function () {
|
|
$user = User::factory()->create();
|
|
$macro = Macro::factory()->create();
|
|
|
|
$response = $this->actingAs($user)
|
|
->postJson(route('settings.macro-assignments.store'), [
|
|
'part_type' => 'song',
|
|
'macro_id' => $macro->id,
|
|
'position' => 'all_slides',
|
|
'order' => 0,
|
|
]);
|
|
|
|
$response->assertStatus(200)->assertJson(['success' => true]);
|
|
expect(MacroAssignment::count())->toBe(1);
|
|
expect(MacroAssignment::first()->part_type)->toBe('song');
|
|
});
|
|
|
|
test('store with by_label position and label_id', function () {
|
|
$user = User::factory()->create();
|
|
$macro = Macro::factory()->create();
|
|
$label = Label::factory()->create();
|
|
|
|
$response = $this->actingAs($user)
|
|
->postJson(route('settings.macro-assignments.store'), [
|
|
'part_type' => 'sermon',
|
|
'macro_id' => $macro->id,
|
|
'position' => 'by_label',
|
|
'label_id' => $label->id,
|
|
'order' => 1,
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
$assignment = MacroAssignment::first();
|
|
expect($assignment->label_id)->toBe($label->id);
|
|
expect($assignment->position)->toBe('by_label');
|
|
});
|
|
|
|
test('update modifies existing assignment', function () {
|
|
$user = User::factory()->create();
|
|
$macro = Macro::factory()->create();
|
|
$assignment = MacroAssignment::create([
|
|
'part_type' => 'song',
|
|
'macro_id' => $macro->id,
|
|
'position' => 'all_slides',
|
|
'order' => 0,
|
|
]);
|
|
|
|
$response = $this->actingAs($user)
|
|
->patchJson(route('settings.macro-assignments.update', $assignment), [
|
|
'position' => 'first_slide',
|
|
'order' => 5,
|
|
]);
|
|
|
|
$response->assertStatus(200)->assertJson(['success' => true]);
|
|
expect($assignment->fresh()->position)->toBe('first_slide');
|
|
expect($assignment->fresh()->order)->toBe(5);
|
|
});
|
|
|
|
test('destroy deletes macro assignment', function () {
|
|
$user = User::factory()->create();
|
|
$macro = Macro::factory()->create();
|
|
$assignment = MacroAssignment::create([
|
|
'part_type' => 'song',
|
|
'macro_id' => $macro->id,
|
|
'position' => 'all_slides',
|
|
'order' => 0,
|
|
]);
|
|
|
|
$response = $this->actingAs($user)
|
|
->deleteJson(route('settings.macro-assignments.destroy', $assignment));
|
|
|
|
$response->assertStatus(200)->assertJson(['success' => true]);
|
|
expect(MacroAssignment::count())->toBe(0);
|
|
});
|
|
|
|
test('reorder updates order on multiple assignments', function () {
|
|
$user = User::factory()->create();
|
|
$macro = Macro::factory()->create();
|
|
$a1 = MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
|
$a2 = MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 1]);
|
|
|
|
$response = $this->actingAs($user)
|
|
->postJson(route('settings.macro-assignments.reorder'), [
|
|
'assignments' => [
|
|
['id' => $a1->id, 'order' => 5],
|
|
['id' => $a2->id, 'order' => 3],
|
|
],
|
|
]);
|
|
|
|
$response->assertStatus(200);
|
|
expect($a1->fresh()->order)->toBe(5);
|
|
expect($a2->fresh()->order)->toBe(3);
|
|
});
|