mirror of
https://github.com/archtechx/tenancy.git
synced 2026-05-06 16:24:03 +00:00
Guard against accidental central storage deletion
Also fix and improve related test.
This commit is contained in:
parent
a28593af17
commit
33c28405ad
2 changed files with 55 additions and 5 deletions
|
|
@ -12,6 +12,13 @@ use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Stancl\Tenancy\Contracts\Tenant;
|
use Stancl\Tenancy\Contracts\Tenant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only delete the tenant storage if storage path suffixing is enabled
|
||||||
|
* and the tenant's storage path is different from the central storage path.
|
||||||
|
*
|
||||||
|
* This is to prevent accidental deletion of the central storage when
|
||||||
|
* a tenant's storage path is not properly suffixed.
|
||||||
|
*/
|
||||||
class DeleteTenantStorage implements ShouldQueue
|
class DeleteTenantStorage implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
@ -22,9 +29,18 @@ class DeleteTenantStorage implements ShouldQueue
|
||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
|
// Skip storage deletion if path suffixing is disabled
|
||||||
|
if (config('tenancy.filesystem.suffix_storage_path') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$centralPath = tenancy()->central(fn () => storage_path());
|
||||||
$path = tenancy()->run($this->tenant, fn () => storage_path());
|
$path = tenancy()->run($this->tenant, fn () => storage_path());
|
||||||
|
|
||||||
if (is_dir($path)) {
|
// Skip storage deletion if tenant's storage path is the same as central storage path
|
||||||
|
$tenantPathIsCentral = realpath($path) === realpath($centralPath);
|
||||||
|
|
||||||
|
if (is_dir($path) && ! $tenantPathIsCentral) {
|
||||||
File::deleteDirectory($path);
|
File::deleteDirectory($path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -206,19 +206,53 @@ test('tenant storage gets created when TenantCreated listens to CreateTenantStor
|
||||||
});
|
});
|
||||||
|
|
||||||
test('tenant storage can get deleted after the tenant when DeletingTenant listens to DeleteTenantStorage', function() {
|
test('tenant storage can get deleted after the tenant when DeletingTenant listens to DeleteTenantStorage', function() {
|
||||||
config([
|
|
||||||
'tenancy.bootstrappers' => [FilesystemTenancyBootstrapper::class],
|
|
||||||
]);
|
|
||||||
|
|
||||||
Event::listen(DeletingTenant::class,
|
Event::listen(DeletingTenant::class,
|
||||||
JobPipeline::make([DeleteTenantStorage::class])->send(function (DeletingTenant $event) {
|
JobPipeline::make([DeleteTenantStorage::class])->send(function (DeletingTenant $event) {
|
||||||
return $event->tenant;
|
return $event->tenant;
|
||||||
})->shouldBeQueued(false)->toListener()
|
})->shouldBeQueued(false)->toListener()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$centralStoragePath = storage_path();
|
||||||
|
tenancy()->initialize(Tenant::create());
|
||||||
|
|
||||||
|
// FilesystemTenancyBootstrapper not enabled,
|
||||||
|
// tenant and central storage path is the same,
|
||||||
|
// the storage deletion will be skipped.
|
||||||
|
$tenantStoragePath = storage_path();
|
||||||
|
expect($tenantStoragePath)->toBe($centralStoragePath);
|
||||||
|
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
||||||
|
tenant()->delete();
|
||||||
|
|
||||||
|
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
||||||
|
|
||||||
|
config([
|
||||||
|
'tenancy.bootstrappers' => [FilesystemTenancyBootstrapper::class],
|
||||||
|
'tenancy.filesystem.suffix_storage_path' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
tenancy()->initialize(Tenant::create());
|
||||||
|
|
||||||
|
$tenantStoragePath = storage_path();
|
||||||
|
|
||||||
|
// FilesystemTenancyBootstrapper enabled,
|
||||||
|
// but tenant and central storage path is still the same
|
||||||
|
// because suffix_storage_path is false.
|
||||||
|
// The storage deletion will be skipped.
|
||||||
|
expect($tenantStoragePath)->toBe($centralStoragePath);
|
||||||
|
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
||||||
|
tenant()->delete();
|
||||||
|
|
||||||
|
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
||||||
|
|
||||||
|
config([
|
||||||
|
'tenancy.bootstrappers' => [FilesystemTenancyBootstrapper::class],
|
||||||
|
'tenancy.filesystem.suffix_storage_path' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
tenancy()->initialize(Tenant::create());
|
tenancy()->initialize(Tenant::create());
|
||||||
$tenantStoragePath = storage_path();
|
$tenantStoragePath = storage_path();
|
||||||
|
|
||||||
|
expect($centralStoragePath)->not()->toBe($tenantStoragePath);
|
||||||
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
expect(File::isDirectory($tenantStoragePath))->toBeTrue();
|
||||||
|
|
||||||
tenant()->delete();
|
tenant()->delete();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue