Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
},
"require": {
"statamic/cms": "^6.5",
"statamic/cms": "^6.25",
"spatie/simple-excel": "^3.7",
"symfony/dom-crawler": "^7.1",
"pixelfear/composer-dist-plugin": "^0.1.5",
Expand Down
4 changes: 2 additions & 2 deletions src/Fieldtypes/ImportMappingsFieldtype.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ private function fields(): Collection
$import = $this->field()->parent();

$row = match ($import->get('type')) {
'csv' => (new Csv($import))->getItems($import->get('path'))->first(),
'xml' => (new Xml($import))->getItems($import->get('path'))->first(),
'csv' => (new Csv($import))->getItems($import->getLocalFilePath())->first(),
'xml' => (new Xml($import))->getItems($import->getLocalFilePath())->first(),
};

return $import->mappingFields()->all()
Expand Down
26 changes: 14 additions & 12 deletions src/Http/Controllers/ImportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,18 @@ public function store(Request $request)

$file = $request->file[0];

$type = match (Storage::disk('local')->mimeType("statamic/file-uploads/{$file}")) {
$uploadsDisk = config('statamic.system.file_uploads_disk', 'local');
$uploadsPath = config('statamic.system.file_uploads_path', 'statamic/file-uploads');

$type = match (Storage::disk($uploadsDisk)->mimeType("{$uploadsPath}/{$file}")) {
'text/csv', 'application/csv', 'text/plain' => 'csv',
'application/xml', 'text/xml' => 'xml',
};

Storage::disk('local')->move(
from: "statamic/file-uploads/{$file}",
to: $path = "statamic/imports/{$id}/".basename($file)
);
$path = "statamic/imports/{$id}/".basename($file);

$path = Storage::disk('local')->path($path);
Storage::disk('local')->put($path, Storage::disk($uploadsDisk)->get("{$uploadsPath}/{$file}"));
Storage::disk($uploadsDisk)->delete("{$uploadsPath}/{$file}");

$values = $fields
->process()
Expand Down Expand Up @@ -150,17 +151,18 @@ public function update(Request $request, Import $import)
$path = $import->get('path');

if (($request->file && $file = $request->file[0]) && $file !== basename($path)) {
$type = match (Storage::disk('local')->mimeType("statamic/file-uploads/{$file}")) {
$uploadsDisk = config('statamic.system.file_uploads_disk', 'local');
$uploadsPath = config('statamic.system.file_uploads_path', 'statamic/file-uploads');

$type = match (Storage::disk($uploadsDisk)->mimeType("{$uploadsPath}/{$file}")) {
'text/csv', 'application/csv', 'text/plain' => 'csv',
'application/xml', 'text/xml' => 'xml',
};

Storage::disk('local')->move(
from: "statamic/file-uploads/{$file}",
to: $path = "statamic/imports/{$import->id()}/".basename($file)
);
$path = "statamic/imports/{$import->id()}/".basename($file);

$path = Storage::disk('local')->path($path);
Storage::disk('local')->put($path, Storage::disk($uploadsDisk)->get("{$uploadsPath}/{$file}"));
Storage::disk($uploadsDisk)->delete("{$uploadsPath}/{$file}");
}

$values = $fields
Expand Down
4 changes: 2 additions & 2 deletions src/Importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public static function run(Import $import): void
}

$items = match ($import->get('type')) {
'csv' => (new Csv($import))->getItems($import->get('path')),
'xml' => (new Xml($import))->getItems($import->get('path')),
'csv' => (new Csv($import))->getItems($import->getLocalFilePath()),
'xml' => (new Xml($import))->getItems($import->getLocalFilePath()),
};

$items
Expand Down
8 changes: 5 additions & 3 deletions src/Imports/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ function (string $attribute, mixed $value, Closure $fail) use ($import) {
return;
}

$path = "statamic/file-uploads/{$value[0]}";
$disk = config('statamic.system.file_uploads_disk', 'local');
$basePath = config('statamic.system.file_uploads_path', 'statamic/file-uploads');
$path = "{$basePath}/{$value[0]}";

if (! Storage::disk('local')->exists($path)) {
if (! Storage::disk($disk)->exists($path)) {
$fail('importer::validation.file_type_not_allowed')->translate();
}

if (! in_array(Storage::disk('local')->mimeType($path), static::$allowedMimeTypes)) {
if (! in_array(Storage::disk($disk)->mimeType($path), static::$allowedMimeTypes)) {
$fail('importer::validation.uploaded_file_not_found')->translate();
}
},
Expand Down
21 changes: 21 additions & 0 deletions src/Imports/Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
use Illuminate\Bus\Batch;
use Illuminate\Support\Collection as SupportCollection;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Storage;
use Statamic\Facades\Collection;
use Statamic\Facades\Path;
use Statamic\Facades\Taxonomy;
use Statamic\Facades\User;
use Statamic\Fields\Blueprint as StatamicBlueprint;
Expand Down Expand Up @@ -75,6 +77,25 @@ public function allBatchesHaveFinished(): bool
return $this->batches()->every(fn (Batch $batch) => $batch->finished());
}

public function getLocalFilePath(): string
{
return $this->hasAbsoluteFilePath()
? $this->get('path')
: Storage::disk('local')->path($this->get('path'));
}

public function deleteFile(): bool
{
return $this->hasAbsoluteFilePath()
? @unlink($this->get('path'))
: Storage::disk('local')->delete($this->get('path'));
}

private function hasAbsoluteFilePath(): bool
{
return Path::isAbsolute($this->get('path'));
}

public function fileData(): array
{
return collect([
Expand Down
5 changes: 1 addition & 4 deletions src/Imports/ImportRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Statamic\Facades\YAML;

Expand Down Expand Up @@ -55,9 +54,7 @@ public function delete(Import $import): void
{
File::delete($import->path());

if (Storage::disk('local')->exists($import->get('path'))) {
Storage::disk('local')->delete($import->get('path'));
}
$import->deleteFile();
}

public function path(): string
Expand Down
4 changes: 2 additions & 2 deletions src/Transformers/AssetsTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ public function fieldItems(): array

if ($assetContainer->blueprint()->hasField('alt')) {
$row = match ($this->import?->get('type')) {
'csv' => (new Csv($this->import))->getItems($this->import->get('path'))->first(),
'xml' => (new Xml($this->import))->getItems($this->import->get('path'))->first(),
'csv' => (new Csv($this->import))->getItems($this->import->getLocalFilePath())->first(),
'xml' => (new Xml($this->import))->getItems($this->import->getLocalFilePath())->first(),
};

$fieldItems['alt'] = [
Expand Down
4 changes: 2 additions & 2 deletions src/Transformers/DateTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ public function fieldItems(): array
{
if ($this->field->get('mode') === 'range') {
$row = match ($this->import?->get('type')) {
'csv' => (new Csv($this->import))->getItems($this->import->get('path'))->first(),
'xml' => (new Xml($this->import))->getItems($this->import->get('path'))->first(),
'csv' => (new Csv($this->import))->getItems($this->import->getLocalFilePath())->first(),
'xml' => (new Xml($this->import))->getItems($this->import->getLocalFilePath())->first(),
};

// To prevent the field mapping from being filtered out, the Start Date is the "normal" key,
Expand Down
55 changes: 55 additions & 0 deletions tests/Imports/ImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Statamic\Importer\Tests\Imports;

use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use PHPUnit\Framework\Attributes\Test;
use Statamic\Importer\Facades\Import;
use Statamic\Importer\Tests\TestCase;
Expand All @@ -14,6 +15,8 @@ protected function setUp(): void
parent::setUp();

File::deleteDirectory(storage_path('statamic/importer'));

Storage::disk('local')->deleteDirectory('statamic/imports');
}

#[Test]
Expand Down Expand Up @@ -63,4 +66,56 @@ public function can_delete_import()

$this->assertFileDoesNotExist($import->path());
}

#[Test]
public function get_local_file_path_resolves_a_relative_path_via_the_local_disk()
{
Storage::disk('local')->put('statamic/imports/posts/import.csv', '');

$import = Import::make()->name('Posts')->config(['type' => 'csv', 'path' => 'statamic/imports/posts/import.csv']);

$this->assertEquals(
Storage::disk('local')->path('statamic/imports/posts/import.csv'),
$import->getLocalFilePath()
);
}

#[Test]
public function get_local_file_path_returns_a_legacy_absolute_path_as_is()
{
$absolutePath = Storage::disk('local')->path('statamic/imports/posts/import.csv');

$import = Import::make()->name('Posts')->config(['type' => 'csv', 'path' => $absolutePath]);

$this->assertEquals($absolutePath, $import->getLocalFilePath());
}

#[Test]
public function can_delete_file_with_a_relative_path()
{
Storage::disk('local')->put('statamic/imports/posts/import.csv', '');

$import = Import::make()->name('Posts')->config(['type' => 'csv', 'path' => 'statamic/imports/posts/import.csv']);

Storage::disk('local')->assertExists('statamic/imports/posts/import.csv');

$import->deleteFile();

Storage::disk('local')->assertMissing('statamic/imports/posts/import.csv');
}

#[Test]
public function can_delete_file_with_a_legacy_absolute_path()
{
$absolutePath = Storage::disk('local')->path('statamic/imports/posts/import.csv');
Storage::disk('local')->put('statamic/imports/posts/import.csv', '');

$import = Import::make()->name('Posts')->config(['type' => 'csv', 'path' => $absolutePath]);

$this->assertFileExists($absolutePath);

$import->deleteFile();

$this->assertFileDoesNotExist($absolutePath);
}
}
38 changes: 34 additions & 4 deletions tests/Imports/StoreImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function it_stores_a_collection_import()
$this->assertNotNull($import);
$this->assertEquals('Posts', $import->name());
$this->assertEquals('csv', $import->get('type'));
$this->assertEquals(Storage::path('statamic/imports/posts/import.csv'), $import->get('path'));
$this->assertEquals('statamic/imports/posts/import.csv', $import->get('path'));
$this->assertEquals(['create', 'update'], $import->get('strategy'));
}

Expand Down Expand Up @@ -91,7 +91,7 @@ public function it_stores_a_collection_import_with_a_site()
$this->assertNotNull($import);
$this->assertEquals('Posts', $import->name());
$this->assertEquals('csv', $import->get('type'));
$this->assertEquals(Storage::path('statamic/imports/posts/import.csv'), $import->get('path'));
$this->assertEquals('statamic/imports/posts/import.csv', $import->get('path'));
$this->assertEquals(['create', 'update'], $import->get('strategy'));

$this->assertEquals('en', $import->get('destination.site'));
Expand Down Expand Up @@ -185,7 +185,7 @@ public function it_stores_a_taxonomy_import()
$this->assertNotNull($import);
$this->assertEquals('Categories', $import->name());
$this->assertEquals('csv', $import->get('type'));
$this->assertEquals(Storage::path('statamic/imports/categories/import.csv'), $import->get('path'));
$this->assertEquals('statamic/imports/categories/import.csv', $import->get('path'));
$this->assertEquals(['create', 'update'], $import->get('strategy'));
}

Expand All @@ -212,7 +212,7 @@ public function it_stores_a_user_import()
$this->assertNotNull($import);
$this->assertEquals('Users', $import->name());
$this->assertEquals('csv', $import->get('type'));
$this->assertEquals(Storage::path('statamic/imports/users/import.csv'), $import->get('path'));
$this->assertEquals('statamic/imports/users/import.csv', $import->get('path'));
$this->assertEquals(['create', 'update'], $import->get('strategy'));
}

Expand Down Expand Up @@ -286,4 +286,34 @@ public function validation_error_is_thrown_without_an_import_strategy()

$this->assertNull(Import::find('foo'));
}

#[Test]
public function it_reads_uploaded_file_from_configured_disk()
{
config(['statamic.system.file_uploads_disk' => 'uploads']);
config(['statamic.system.file_uploads_path' => 'temp-uploads']);

Storage::fake('uploads');
Storage::disk('uploads')->put('temp-uploads/123456789/import.csv', '');

$this
->actingAs(User::make()->makeSuper()->save())
->post('/cp/utilities/importer', [
'name' => 'Users',
'file' => ['123456789/import.csv'],
'destination' => [
'type' => 'users',
],
'strategy' => ['create', 'update'],
])
->assertJsonStructure(['saved', 'redirect']);

$import = Import::find('users');

$this->assertNotNull($import);

// File should have been moved from uploads disk to local disk
Storage::disk('uploads')->assertMissing('temp-uploads/123456789/import.csv');
Storage::disk('local')->assertExists('statamic/imports/users/import.csv');
}
}
37 changes: 37 additions & 0 deletions tests/Imports/UpdateImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,43 @@ public function can_replace_the_file()
Storage::disk('local')->assertExists('statamic/imports/posts/latest-posts.csv');
}

#[Test]
public function can_replace_the_file_from_configured_disk()
{
config(['statamic.system.file_uploads_disk' => 'uploads']);
config(['statamic.system.file_uploads_path' => 'temp-uploads']);

Storage::fake('uploads');
Storage::disk('uploads')->put('temp-uploads/123456789/latest-posts.csv', '');

$this
->actingAs(User::make()->makeSuper()->save())
->patch("/cp/utilities/importer/{$this->import->id()}", [
'name' => 'Posts',
'file' => ['123456789/latest-posts.csv'],
'destination' => ['type' => 'entries', 'collection' => ['posts'], 'blueprint' => 'post'],
'strategy' => ['create', 'update'],
'source' => ['csv_delimiter' => ','],
'mappings' => [
'title' => ['key' => 'Title'],
'slug' => ['key' => 'Slug'],
'content' => ['key' => 'Content'],
'author' => ['key' => 'Author Email', 'related_field' => 'email'],
'foo' => ['key' => null],
],
'unique_field' => 'slug',
])
->assertOk();

$import = $this->import->fresh();

$this->assertEquals('latest-posts.csv', basename($import->get('path')));

// File should have been moved from uploads disk to local disk
Storage::disk('uploads')->assertMissing('temp-uploads/123456789/latest-posts.csv');
Storage::disk('local')->assertExists('statamic/imports/posts/latest-posts.csv');
}

#[Test]
public function validation_error_is_thrown_when_file_does_not_exist()
{
Expand Down