* Show the view to start a new import, and also list out the existing
* in progress imports that are visible to the user.
*/
- public function start(Request $request)
+ public function start()
{
- // TODO - Test visibility access for listed items
$imports = $this->imports->getVisibleImports();
$this->setPageTitle(trans('entities.import'));
*/
public function show(int $id)
{
- // TODO - Test visibility access
$import = $this->imports->findVisible($id);
$this->setPageTitle(trans('entities.import_continue'));
]);
}
+ public function run(int $id)
+ {
+ // TODO - Test access/visibility
+
+ $import = $this->imports->findVisible($id);
+
+ // TODO - Run import
+ // Validate again before
+ // TODO - Redirect to result
+ // TOOD - Or redirect back with errors
+ }
+
/**
* Delete an active pending import from the filesystem and database.
*/
public function delete(int $id)
{
- // TODO - Test visibility access
$import = $this->imports->findVisible($id);
$this->imports->deleteImport($import);
<main class="card content-wrap auto-height mt-xxl">
<h1 class="list-heading">{{ trans('entities.import_continue') }}</h1>
- <form action="{{ url('/import') }}" enctype="multipart/form-data" method="POST">
+ <p class="text-muted">{{ trans('entities.import_continue_desc') }}</p>
+
+ <div class="mb-m">
+ @php
+ $type = $import->getType();
+ @endphp
+ <div class="flex-container-row items-center justify-space-between wrap">
+ <div class="py-s">
+ <p class="text-{{ $type }} mb-xs bold">@icon($type) {{ $import->name }}</p>
+ @if($type === 'book')
+ <p class="text-chapter mb-xs ml-l">@icon('chapter') {{ trans_choice('entities.x_chapters', $import->chapter_count) }}</p>
+ @endif
+ @if($type === 'book' || $type === 'chapter')
+ <p class="text-page mb-xs ml-l">@icon('page') {{ trans_choice('entities.x_pages', $import->page_count) }}</p>
+ @endif
+ </div>
+ <div class="py-s">
+ <div class="opacity-80">
+ <strong>{{ trans('entities.import_size') }}</strong>
+ <span>{{ $import->getSizeString() }}</span>
+ </div>
+ <div class="opacity-80">
+ <strong>{{ trans('entities.import_uploaded_at') }}</strong>
+ <span title="{{ $import->created_at->toISOString() }}">{{ $import->created_at->diffForHumans() }}</span>
+ </div>
+ @if($import->createdBy)
+ <div class="opacity-80">
+ <strong>{{ trans('entities.import_uploaded_by') }}</strong>
+ <a href="{{ $import->createdBy->getProfileUrl() }}">{{ $import->createdBy->name }}</a>
+ </div>
+ @endif
+ </div>
+ </div>
+ </div>
+
+ <form id="import-run-form"
+ action="{{ $import->getUrl() }}"
+ method="POST">
{{ csrf_field() }}
</form>
<button type="submit" form="import-delete-form" class="text-link small text-item">{{ trans('common.confirm') }}</button>
</div>
</div>
- <button type="submit" class="button">{{ trans('entities.import_run') }}</button>
+ <button type="submit" form="import-run-form" class="button">{{ trans('entities.import_run') }}</button>
</div>
</main>
</div>
namespace Tests\Exports;
+use BookStack\Activity\ActivityType;
+use BookStack\Exports\Import;
use Illuminate\Http\UploadedFile;
use Illuminate\Testing\TestResponse;
use Tests\TestCase;
$resp->assertSeeText('Select ZIP file to upload');
}
+ public function test_import_page_pending_import_visibility_limited()
+ {
+ $user = $this->users->viewer();
+ $admin = $this->users->admin();
+ $userImport = Import::factory()->create(['name' => 'MySuperUserImport', 'created_by' => $user->id]);
+ $adminImport = Import::factory()->create(['name' => 'MySuperAdminImport', 'created_by' => $admin->id]);
+ $this->permissions->grantUserRolePermissions($user, ['content-import']);
+
+ $resp = $this->actingAs($user)->get('/import');
+ $resp->assertSeeText('MySuperUserImport');
+ $resp->assertDontSeeText('MySuperAdminImport');
+
+ $this->permissions->grantUserRolePermissions($user, ['settings-manage']);
+
+ $resp = $this->actingAs($user)->get('/import');
+ $resp->assertSeeText('MySuperUserImport');
+ $resp->assertSeeText('MySuperAdminImport');
+ }
+
public function test_zip_read_errors_are_shown_on_validation()
{
$invalidUpload = $this->files->uploadedImage('image.zip');
$resp->assertSeeText('[book.pages.1.tags.0.value]: The value must be a string.');
}
+ public function test_import_upload_success()
+ {
+ $admin = $this->users->admin();
+ $this->actingAs($admin);
+ $resp = $this->runImportFromFile($this->zipUploadFromData([
+ 'book' => [
+ 'name' => 'My great book name',
+ 'chapters' => [
+ [
+ 'name' => 'my chapter',
+ 'pages' => [
+ [
+ 'name' => 'my chapter page',
+ ]
+ ]
+ ]
+ ],
+ 'pages' => [
+ [
+ 'name' => 'My page',
+ ]
+ ],
+ ],
+ ]));
+
+ $this->assertDatabaseHas('imports', [
+ 'name' => 'My great book name',
+ 'book_count' => 1,
+ 'chapter_count' => 1,
+ 'page_count' => 2,
+ 'created_by' => $admin->id,
+ ]);
+
+ /** @var Import $import */
+ $import = Import::query()->latest()->first();
+ $resp->assertRedirect("/import/{$import->id}");
+ $this->assertFileExists(storage_path($import->path));
+ $this->assertActivityExists(ActivityType::IMPORT_CREATE);
+ }
+
+ public function test_import_show_page()
+ {
+ $import = Import::factory()->create(['name' => 'MySuperAdminImport']);
+
+ $resp = $this->asAdmin()->get("/import/{$import->id}");
+ $resp->assertOk();
+ $resp->assertSee('MySuperAdminImport');
+ }
+
+ public function test_import_show_page_access_limited()
+ {
+ $user = $this->users->viewer();
+ $admin = $this->users->admin();
+ $userImport = Import::factory()->create(['name' => 'MySuperUserImport', 'created_by' => $user->id]);
+ $adminImport = Import::factory()->create(['name' => 'MySuperAdminImport', 'created_by' => $admin->id]);
+ $this->actingAs($user);
+
+ $this->get("/import/{$userImport->id}")->assertRedirect('/');
+ $this->get("/import/{$adminImport->id}")->assertRedirect('/');
+
+ $this->permissions->grantUserRolePermissions($user, ['content-import']);
+
+ $this->get("/import/{$userImport->id}")->assertOk();
+ $this->get("/import/{$adminImport->id}")->assertStatus(404);
+
+ $this->permissions->grantUserRolePermissions($user, ['settings-manage']);
+
+ $this->get("/import/{$userImport->id}")->assertOk();
+ $this->get("/import/{$adminImport->id}")->assertOk();
+ }
+
+ public function test_import_delete()
+ {
+ $this->asAdmin();
+ $this->runImportFromFile($this->zipUploadFromData([
+ 'book' => [
+ 'name' => 'My great book name'
+ ],
+ ]));
+
+ /** @var Import $import */
+ $import = Import::query()->latest()->first();
+ $this->assertDatabaseHas('imports', [
+ 'id' => $import->id,
+ 'name' => 'My great book name'
+ ]);
+ $this->assertFileExists(storage_path($import->path));
+
+ $resp = $this->delete("/import/{$import->id}");
+
+ $resp->assertRedirect('/import');
+ $this->assertActivityExists(ActivityType::IMPORT_DELETE);
+ $this->assertDatabaseMissing('imports', [
+ 'id' => $import->id,
+ ]);
+ $this->assertFileDoesNotExist(storage_path($import->path));
+ }
+
+ public function test_import_delete_access_limited()
+ {
+ $user = $this->users->viewer();
+ $admin = $this->users->admin();
+ $userImport = Import::factory()->create(['name' => 'MySuperUserImport', 'created_by' => $user->id]);
+ $adminImport = Import::factory()->create(['name' => 'MySuperAdminImport', 'created_by' => $admin->id]);
+ $this->actingAs($user);
+
+ $this->delete("/import/{$userImport->id}")->assertRedirect('/');
+ $this->delete("/import/{$adminImport->id}")->assertRedirect('/');
+
+ $this->permissions->grantUserRolePermissions($user, ['content-import']);
+
+ $this->delete("/import/{$userImport->id}")->assertRedirect('/import');
+ $this->delete("/import/{$adminImport->id}")->assertStatus(404);
+
+ $this->permissions->grantUserRolePermissions($user, ['settings-manage']);
+
+ $this->delete("/import/{$adminImport->id}")->assertRedirect('/import');
+ }
+
protected function runImportFromFile(UploadedFile $file): TestResponse
{
return $this->call('POST', '/import', [], [], ['file' => $file]);