Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit 7eb8166

Browse files
authored
Merge pull request #399 from aspirepress/issue-359/import-package-endpoint
2 parents db0c3ba + 29011da commit 7eb8166

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Actions\Admin\API\V1;
6+
7+
use App\Http\JsonLines;
8+
use App\Http\JsonResponses;
9+
use App\Models\Package;
10+
use App\Values\Packages\FairMetadata;
11+
use App\Values\Packages\PackageData;
12+
use Exception;
13+
use Illuminate\Http\JsonResponse;
14+
use Illuminate\Http\Request;
15+
use Illuminate\Pipeline\Pipeline;
16+
use Illuminate\Support\Facades\DB;
17+
use Illuminate\Support\Facades\Log;
18+
19+
use function Safe\ini_set;
20+
21+
class BulkPackageImport
22+
{
23+
use JsonResponses;
24+
use JsonLines;
25+
26+
public function __invoke(Request $request, Pipeline $pipeline): JsonResponse
27+
{
28+
ini_set('memory_limit', '2G');
29+
ini_set('max_execution_time', '300');
30+
31+
$currentLine = 0;
32+
$imported = 0;
33+
$errors = [];
34+
35+
$request_info = ['userid' => auth()->user()->id, 'ip' => $request->ip()];
36+
37+
Log::info('Beginning package import', $request_info);
38+
39+
foreach ($this->lazyJsonLines($request) as $metadata) {
40+
$currentLine++;
41+
try {
42+
$package = DB::transaction(fn() => $this->loadOne($metadata));
43+
Log::debug(
44+
"Imported {$package->did}",
45+
['slug' => $package->slug, 'type' => $package->type],
46+
);
47+
$imported++;
48+
} catch (Exception $e) {
49+
$errors[$currentLine] = $e->getMessage();
50+
}
51+
}
52+
53+
Log::info('Bulk import complete', [...$request_info, 'imported' => $imported, 'errors' => $errors]);
54+
55+
return $errors ? $this->error(compact('errors', 'imported')) : $this->success(['imported' => $imported]);
56+
}
57+
58+
/** @param array<string, mixed> $metadata */
59+
private function loadOne(array $metadata): Package
60+
{
61+
$did = $metadata['id'];
62+
63+
$package = Package::query()->where('did', $did)->first();
64+
$package?->delete();
65+
66+
$fairMetadata = FairMetadata::from($metadata);
67+
return Package::fromPackageData(PackageData::from($fairMetadata));
68+
}
69+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace App\Services\Packages;
4+
5+
use App\Models\Package;
6+
use App\Values\Packages\PackageData;
7+
use App\Values\Packages\FairMetadata;
8+
9+
class PackageImportService
10+
{
11+
public function importPackage(string $json, bool $validateOnly = false, bool $newOnly = false): ?Package
12+
{
13+
$metadata = \Safe\json_decode($json, true);
14+
// Force validation.
15+
$fairMetadata = FairMetadata::from($metadata);
16+
17+
if ($validateOnly) {
18+
return null;
19+
}
20+
21+
$did = $metadata['id'];
22+
23+
$package = Package::query()->where('did', $did)->first();
24+
if ($package && $newOnly) {
25+
return null;
26+
}
27+
$package?->delete();
28+
29+
//$this->info("LOAD: $did");
30+
31+
$package = Package::fromPackageData(PackageData::from($fairMetadata));
32+
return $package;
33+
}
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace App\Values\Packages;
4+
5+
use App\Values\DTO;
6+
use Bag\Attributes\StripExtraParameters;
7+
use Bag\Attributes\Transforms;
8+
use Illuminate\Http\Request;
9+
10+
#[StripExtraParameters]
11+
readonly class PackageImportRequest extends DTO
12+
{
13+
public const ACTION = 'package_import';
14+
15+
public function __construct(
16+
public string $data,
17+
) {}
18+
19+
/** @return array<string, mixed> */
20+
#[Transforms(Request::class)]
21+
public static function fromRequest(Request $request): array
22+
{
23+
// Bag throws 500 (RuntimeException) for missing fields, this throws a friendlier 422
24+
return $request->validate(['data' => 'required']);
25+
}
26+
}

routes/inc/admin-api.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types=1);
44

55
use App\Actions\Admin\API\V1\BulkImport;
6+
use App\Actions\Admin\API\V1\BulkPackageImport;
67
use App\Auth\Permission;
78
use App\Http\Middleware\RequireJson;
89
use Illuminate\Routing\Router;
@@ -16,6 +17,7 @@
1617
])
1718
->group(function (Router $router) {
1819
$router->post('/import', BulkImport::class)->can(Permission::BulkImport);
20+
$router->post('/packages/import', BulkPackageImport::class)->can(Permission::BulkImport);
1921
});
2022

2123

0 commit comments

Comments
 (0)