feat(services): add LabelsImportService, MacrosImportService, MacroResolutionService
This commit is contained in:
parent
bdbf0c65e3
commit
81b2a9caf6
12
app/Services/DTO/LabelImportResult.php
Normal file
12
app/Services/DTO/LabelImportResult.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\DTO;
|
||||
|
||||
final class LabelImportResult
|
||||
{
|
||||
public function __construct(
|
||||
public readonly int $newCount,
|
||||
public readonly int $updatedCount,
|
||||
public readonly int $totalInFile,
|
||||
) {}
|
||||
}
|
||||
14
app/Services/DTO/MacroImportResult.php
Normal file
14
app/Services/DTO/MacroImportResult.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\DTO;
|
||||
|
||||
final class MacroImportResult
|
||||
{
|
||||
public function __construct(
|
||||
public readonly int $new,
|
||||
public readonly int $updated,
|
||||
public readonly int $disabled,
|
||||
public readonly int $reEnabled,
|
||||
public readonly array $warnings,
|
||||
) {}
|
||||
}
|
||||
49
app/Services/LabelsImportService.php
Normal file
49
app/Services/LabelsImportService.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\Setting;
|
||||
use App\Services\DTO\LabelImportResult;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use ProPresenter\Parser\LabelsFileReader;
|
||||
|
||||
class LabelsImportService
|
||||
{
|
||||
public function import(string $filePath, string $originalFilename): LabelImportResult
|
||||
{
|
||||
$library = LabelsFileReader::read($filePath);
|
||||
$newCount = 0;
|
||||
$updatedCount = 0;
|
||||
|
||||
DB::transaction(function () use ($library, &$newCount, &$updatedCount): void {
|
||||
foreach ($library->getLabels() as $parserLabel) {
|
||||
$name = $parserLabel->getName();
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
$color = $parserLabel->getColorHex();
|
||||
$existing = Label::whereRaw('LOWER(name) = ?', [strtolower($name)])->first();
|
||||
if ($existing === null) {
|
||||
Label::create([
|
||||
'name' => $name,
|
||||
'color' => $color,
|
||||
'last_imported_at' => now(),
|
||||
]);
|
||||
$newCount++;
|
||||
} else {
|
||||
$existing->update([
|
||||
'color' => $color,
|
||||
'last_imported_at' => now(),
|
||||
]);
|
||||
$updatedCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Setting::set('labels_last_imported_at', now()->toIso8601String());
|
||||
Setting::set('labels_last_imported_filename', $originalFilename);
|
||||
|
||||
return new LabelImportResult($newCount, $updatedCount, count($library->getLabels()));
|
||||
}
|
||||
}
|
||||
85
app/Services/MacroResolutionService.php
Normal file
85
app/Services/MacroResolutionService.php
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Macro;
|
||||
use App\Models\MacroAssignment;
|
||||
use App\Models\Service;
|
||||
use App\Models\ServiceMacroAssignment;
|
||||
use App\Models\ServiceMacroOverride;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class MacroResolutionService
|
||||
{
|
||||
/**
|
||||
* Returns active (non-hidden) assignments for a given service + part type.
|
||||
* Uses service-specific assignments if an override exists, otherwise global defaults.
|
||||
*/
|
||||
public function resolveAssignmentsForPart(Service $service, string $partType): Collection
|
||||
{
|
||||
$hasOverride = ServiceMacroOverride::where('service_id', $service->id)
|
||||
->where('part_type', $partType)
|
||||
->exists();
|
||||
|
||||
if ($hasOverride) {
|
||||
$rows = ServiceMacroAssignment::with(['macro', 'label'])
|
||||
->where('service_id', $service->id)
|
||||
->where('part_type', $partType)
|
||||
->orderBy('order')
|
||||
->get();
|
||||
} else {
|
||||
$rows = MacroAssignment::with(['macro', 'label'])
|
||||
->where('part_type', $partType)
|
||||
->orderBy('order')
|
||||
->get();
|
||||
}
|
||||
|
||||
return $rows
|
||||
->reject(fn ($r) => $r->macro === null || $r->macro->isHidden())
|
||||
->reject(fn ($r) => $r->position === 'by_label' && ($r->label === null || $r->label->isHidden()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the macro export data for macros that apply to a specific slide.
|
||||
*
|
||||
* @param array $slideContext ['index' => int, 'total' => int, 'label_id' => int|null]
|
||||
* @return array<int, array{name: string, uuid: string, collectionName: string, collectionUuid: string}>
|
||||
*/
|
||||
public function macrosForSlide(Service $service, string $partType, array $slideContext): array
|
||||
{
|
||||
$assignments = $this->resolveAssignmentsForPart($service, $partType);
|
||||
|
||||
$matched = $assignments->filter(function ($a) use ($slideContext) {
|
||||
return match ($a->position) {
|
||||
'all_slides' => true,
|
||||
'first_slide' => $slideContext['index'] === 0,
|
||||
'last_slide' => $slideContext['index'] === $slideContext['total'] - 1,
|
||||
'by_label' => isset($slideContext['label_id'])
|
||||
&& (int) $a->label_id === (int) $slideContext['label_id'],
|
||||
default => false,
|
||||
};
|
||||
});
|
||||
|
||||
return $matched->map(fn ($a) => $this->toExportArray($a->macro))->values()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the count of active assignments for a service + part (for UI badges).
|
||||
*/
|
||||
public function countAssignmentsForPart(Service $service, string $partType): int
|
||||
{
|
||||
return $this->resolveAssignmentsForPart($service, $partType)->count();
|
||||
}
|
||||
|
||||
private function toExportArray(Macro $macro): array
|
||||
{
|
||||
$collection = $macro->collections()->first();
|
||||
|
||||
return [
|
||||
'name' => $macro->name,
|
||||
'uuid' => $macro->uuid,
|
||||
'collectionName' => $collection?->name ?? '--MAIN--',
|
||||
'collectionUuid' => $collection?->uuid ?? '8D02FC57-83F8-4042-9B90-81C229728426',
|
||||
];
|
||||
}
|
||||
}
|
||||
110
app/Services/MacrosImportService.php
Normal file
110
app/Services/MacrosImportService.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Macro;
|
||||
use App\Models\MacroAssignment;
|
||||
use App\Models\MacroCollection;
|
||||
use App\Models\Setting;
|
||||
use App\Services\DTO\MacroImportResult;
|
||||
use App\Support\MacroColorConverter;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use ProPresenter\Parser\MacrosFileReader;
|
||||
|
||||
class MacrosImportService
|
||||
{
|
||||
public function import(string $filePath, string $originalFilename): MacroImportResult
|
||||
{
|
||||
$library = MacrosFileReader::read($filePath);
|
||||
$stats = ['new' => 0, 'updated' => 0, 'disabled' => 0, 'reEnabled' => 0];
|
||||
$importedUuids = [];
|
||||
|
||||
DB::transaction(function () use ($library, &$stats, &$importedUuids, $originalFilename): void {
|
||||
foreach ($library->getMacros() as $parserMacro) {
|
||||
$uuid = strtoupper($parserMacro->getUuid());
|
||||
if ($uuid === '') {
|
||||
continue;
|
||||
}
|
||||
$importedUuids[] = $uuid;
|
||||
$color = MacroColorConverter::fromRgba($parserMacro->getColor());
|
||||
$data = [
|
||||
'uuid' => $uuid,
|
||||
'name' => $parserMacro->getName(),
|
||||
'color' => $color,
|
||||
'trigger_on_startup' => $parserMacro->getTriggerOnStartup(),
|
||||
'image_type' => $parserMacro->getImageType(),
|
||||
'action_count' => $parserMacro->getActionCount(),
|
||||
'last_imported_at' => now(),
|
||||
'last_imported_filename' => $originalFilename,
|
||||
'hidden_at' => null,
|
||||
];
|
||||
|
||||
$existing = Macro::where('uuid', $uuid)->first();
|
||||
if ($existing === null) {
|
||||
Macro::create($data);
|
||||
$stats['new']++;
|
||||
} else {
|
||||
$wasHidden = $existing->isHidden();
|
||||
$existing->update($data);
|
||||
if ($wasHidden) {
|
||||
$stats['reEnabled']++;
|
||||
} else {
|
||||
$stats['updated']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($importedUuids)) {
|
||||
$stats['disabled'] = Macro::whereNotIn('uuid', $importedUuids)
|
||||
->whereNull('hidden_at')
|
||||
->update(['hidden_at' => now()]);
|
||||
}
|
||||
|
||||
foreach ($library->getCollections() as $parserCollection) {
|
||||
$collUuid = strtoupper($parserCollection->getUuid());
|
||||
if ($collUuid === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$collection = MacroCollection::updateOrCreate(
|
||||
['uuid' => $collUuid],
|
||||
['name' => $parserCollection->getName(), 'last_imported_at' => now()],
|
||||
);
|
||||
|
||||
$collection->macros()->detach();
|
||||
foreach ($parserCollection->getMacroUuids() as $idx => $macroUuid) {
|
||||
$macro = Macro::where('uuid', strtoupper($macroUuid))->first();
|
||||
if ($macro) {
|
||||
$collection->macros()->attach($macro->id, ['order' => $idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Setting::set('macros_last_imported_at', now()->toIso8601String());
|
||||
Setting::set('macros_last_imported_filename', $originalFilename);
|
||||
|
||||
$warnings = $this->buildAssignmentWarnings();
|
||||
|
||||
return new MacroImportResult(
|
||||
$stats['new'],
|
||||
$stats['updated'],
|
||||
$stats['disabled'],
|
||||
$stats['reEnabled'],
|
||||
$warnings,
|
||||
);
|
||||
}
|
||||
|
||||
private function buildAssignmentWarnings(): array
|
||||
{
|
||||
return MacroAssignment::whereHas('macro', fn ($q) => $q->whereNotNull('hidden_at'))
|
||||
->with('macro')
|
||||
->get()
|
||||
->map(fn ($a) => [
|
||||
'macro_name' => $a->macro->name,
|
||||
'macro_uuid' => $a->macro->uuid,
|
||||
'part_type' => $a->part_type,
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
53
tests/Feature/LabelsImportServiceTest.php
Normal file
53
tests/Feature/LabelsImportServiceTest.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\Setting;
|
||||
use App\Services\LabelsImportService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('import creates new labels from file', function () {
|
||||
$service = app(LabelsImportService::class);
|
||||
$result = $service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
|
||||
expect($result->newCount)->toBeGreaterThanOrEqual(1);
|
||||
expect($result->updatedCount)->toBe(0);
|
||||
expect(Label::count())->toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('import updates color of existing labels', function () {
|
||||
Label::create(['name' => 'Copyright', 'color' => '#000000']);
|
||||
|
||||
$service = app(LabelsImportService::class);
|
||||
$service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
|
||||
$label = Label::where('name', 'Copyright')->first();
|
||||
if ($label) {
|
||||
expect($label->color)->not->toBe('#000000');
|
||||
}
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
|
||||
test('import stores last imported metadata in settings', function () {
|
||||
$service = app(LabelsImportService::class);
|
||||
$service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
|
||||
expect(Setting::get('labels_last_imported_at'))->not->toBeNull();
|
||||
expect(Setting::get('labels_last_imported_filename'))->toBe('labels-sample.bin');
|
||||
});
|
||||
|
||||
test('re-import is idempotent — no duplicates', function () {
|
||||
$service = app(LabelsImportService::class);
|
||||
$service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
$countAfterFirst = Label::count();
|
||||
$service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
|
||||
expect(Label::count())->toBe($countAfterFirst);
|
||||
});
|
||||
|
||||
test('empty label names are skipped', function () {
|
||||
$service = app(LabelsImportService::class);
|
||||
$result = $service->import(base_path('tests/fixtures/labels-sample.bin'), 'labels-sample.bin');
|
||||
expect($result->totalInFile)->toBeGreaterThan(0);
|
||||
});
|
||||
115
tests/Feature/MacroResolutionServiceTest.php
Normal file
115
tests/Feature/MacroResolutionServiceTest.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\Macro;
|
||||
use App\Models\MacroAssignment;
|
||||
use App\Models\Service;
|
||||
use App\Models\ServiceMacroAssignment;
|
||||
use App\Models\ServiceMacroOverride;
|
||||
use App\Services\MacroResolutionService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('returns empty when no assignments exist', function () {
|
||||
$service = Service::factory()->create();
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
expect($resolver->resolveAssignmentsForPart($service, 'song'))->toBeEmpty();
|
||||
});
|
||||
|
||||
test('returns global assignments when no override', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
$resolved = $resolver->resolveAssignmentsForPart($service, 'song');
|
||||
|
||||
expect($resolved)->toHaveCount(1);
|
||||
expect($resolved->first()->macro->id)->toBe($macro->id);
|
||||
});
|
||||
|
||||
test('override wins over globals', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macroA = Macro::factory()->create(['name' => 'Global']);
|
||||
$macroB = Macro::factory()->create(['name' => 'Override']);
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macroA->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
ServiceMacroOverride::create(['service_id' => $service->id, 'part_type' => 'song']);
|
||||
ServiceMacroAssignment::create(['service_id' => $service->id, 'part_type' => 'song', 'macro_id' => $macroB->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
$resolved = $resolver->resolveAssignmentsForPart($service, 'song');
|
||||
|
||||
expect($resolved)->toHaveCount(1);
|
||||
expect($resolved->first()->macro->name)->toBe('Override');
|
||||
});
|
||||
|
||||
test('hidden macros are filtered out', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro = Macro::factory()->create(['hidden_at' => now()]);
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
expect($resolver->resolveAssignmentsForPart($service, 'song'))->toBeEmpty();
|
||||
});
|
||||
|
||||
test('macrosForSlide with all_slides matches every slide', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
$result = $resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]);
|
||||
|
||||
expect($result)->toHaveCount(1);
|
||||
expect($result[0]['uuid'])->toBe($macro->uuid);
|
||||
});
|
||||
|
||||
test('macrosForSlide with first_slide only matches index 0', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'first_slide', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
|
||||
expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]))->toHaveCount(1);
|
||||
expect($resolver->macrosForSlide($service, 'song', ['index' => 1, 'total' => 3, 'label_id' => null]))->toHaveCount(0);
|
||||
});
|
||||
|
||||
test('macrosForSlide stacking — multiple matching assignments produce multiple macros', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro1 = Macro::factory()->create();
|
||||
$macro2 = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro1->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro2->id, 'position' => 'first_slide', 'order' => 1]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
$result = $resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => null]);
|
||||
|
||||
expect($result)->toHaveCount(2);
|
||||
});
|
||||
|
||||
test('macrosForSlide with by_label matches only matching label_id', function () {
|
||||
$service = Service::factory()->create();
|
||||
$label = Label::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'by_label', 'label_id' => $label->id, 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
|
||||
expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => $label->id]))->toHaveCount(1);
|
||||
expect($resolver->macrosForSlide($service, 'song', ['index' => 0, 'total' => 3, 'label_id' => 9999]))->toHaveCount(0);
|
||||
});
|
||||
|
||||
test('countAssignmentsForPart returns correct count', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macro = Macro::factory()->create();
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
MacroAssignment::create(['part_type' => 'sermon', 'macro_id' => $macro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$resolver = app(MacroResolutionService::class);
|
||||
|
||||
expect($resolver->countAssignmentsForPart($service, 'song'))->toBe(1);
|
||||
expect($resolver->countAssignmentsForPart($service, 'sermon'))->toBe(1);
|
||||
expect($resolver->countAssignmentsForPart($service, 'information'))->toBe(0);
|
||||
});
|
||||
69
tests/Feature/MacrosImportServiceTest.php
Normal file
69
tests/Feature/MacrosImportServiceTest.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Macro;
|
||||
use App\Models\MacroAssignment;
|
||||
use App\Models\Setting;
|
||||
use App\Services\MacrosImportService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('import creates new macros from file', function () {
|
||||
$service = app(MacrosImportService::class);
|
||||
$result = $service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect($result->new)->toBeGreaterThanOrEqual(1);
|
||||
expect($result->updated)->toBe(0);
|
||||
expect(Macro::count())->toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('import stores hex color on macros', function () {
|
||||
$service = app(MacrosImportService::class);
|
||||
$service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect(Macro::whereNotNull('color')->where('color', 'like', '#%')->count())->toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('import marks missing macros as hidden', function () {
|
||||
$existing = Macro::factory()->create(['uuid' => 'FAKE-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'hidden_at' => null]);
|
||||
|
||||
$service = app(MacrosImportService::class);
|
||||
$result = $service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect($existing->fresh()->isHidden())->toBeTrue();
|
||||
expect($result->disabled)->toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('import re-enables previously hidden macros that appear in file', function () {
|
||||
$service = app(MacrosImportService::class);
|
||||
$result = $service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
$firstMacro = Macro::first();
|
||||
$firstMacro->update(['hidden_at' => now()]);
|
||||
|
||||
$result = $service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect($result->reEnabled)->toBeGreaterThanOrEqual(1);
|
||||
expect($firstMacro->fresh()->isHidden())->toBeFalse();
|
||||
});
|
||||
|
||||
test('import builds warnings for disabled macros with active assignments', function () {
|
||||
$service = app(MacrosImportService::class);
|
||||
$service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
$hiddenMacro = Macro::factory()->create(['uuid' => 'WARN-FFFF-FFFF-FFFF-FFFFFFFFFFFF', 'hidden_at' => now()]);
|
||||
MacroAssignment::create(['part_type' => 'song', 'macro_id' => $hiddenMacro->id, 'position' => 'all_slides', 'order' => 0]);
|
||||
|
||||
$result = $service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect(count($result->warnings))->toBeGreaterThanOrEqual(1);
|
||||
$warning = collect($result->warnings)->firstWhere('macro_uuid', 'WARN-FFFF-FFFF-FFFF-FFFFFFFFFFFF');
|
||||
expect($warning)->not->toBeNull();
|
||||
});
|
||||
|
||||
test('import stores last imported metadata in settings', function () {
|
||||
$service = app(MacrosImportService::class);
|
||||
$service->import(base_path('tests/fixtures/macros-sample.bin'), 'macros.bin');
|
||||
|
||||
expect(Setting::get('macros_last_imported_at'))->not->toBeNull();
|
||||
expect(Setting::get('macros_last_imported_filename'))->toBe('macros.bin');
|
||||
});
|
||||
Loading…
Reference in a new issue