1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-07 01:04:03 +00:00

Merge branch 'master' into add-log-bootstrapper

This commit is contained in:
Samuel Štancl 2026-04-12 14:02:39 +02:00 committed by GitHub
commit 39fc72bea5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 1127 additions and 221 deletions

View file

@ -200,3 +200,60 @@ test('tenant storage can get deleted after the tenant when DeletingTenant listen
expect(File::isDirectory($tenantStoragePath))->toBeFalse();
});
test('the framework/cache directory is created when storage_path is scoped', function (bool $suffixStoragePath) {
config([
'tenancy.bootstrappers' => [
FilesystemTenancyBootstrapper::class,
],
'tenancy.filesystem.suffix_storage_path' => $suffixStoragePath
]);
$centralStoragePath = storage_path();
tenancy()->initialize($tenant = Tenant::create());
if ($suffixStoragePath) {
expect(storage_path('framework/cache'))->toBe($centralStoragePath . "/tenant{$tenant->id}/framework/cache");
expect(is_dir($centralStoragePath . "/tenant{$tenant->id}/framework/cache"))->toBeTrue();
} else {
expect(storage_path('framework/cache'))->toBe($centralStoragePath . '/framework/cache');
expect(is_dir($centralStoragePath . "/tenant{$tenant->id}/framework/cache"))->toBeFalse();
}
})->with([true, false]);
test('scoped disks are scoped per tenant', function () {
config([
'tenancy.bootstrappers' => [
FilesystemTenancyBootstrapper::class,
],
'filesystems.disks.scoped_disk' => [
'driver' => 'scoped',
'disk' => 'public',
'prefix' => 'scoped_disk_prefix',
],
]);
$tenant = Tenant::create();
Storage::disk('scoped_disk')->put('foo.txt', 'central');
expect(Storage::disk('scoped_disk')->get('foo.txt'))->toBe('central');
expect(file_get_contents(storage_path() . "/app/public/scoped_disk_prefix/foo.txt"))->toBe('central');
tenancy()->initialize($tenant);
expect(Storage::disk('scoped_disk')->get('foo.txt'))->toBe(null);
Storage::disk('scoped_disk')->put('foo.txt', 'tenant');
expect(file_get_contents(storage_path() . "/app/public/scoped_disk_prefix/foo.txt"))->toBe('tenant');
expect(Storage::disk('scoped_disk')->get('foo.txt'))->toBe('tenant');
tenancy()->end();
expect(Storage::disk('scoped_disk')->get('foo.txt'))->toBe('central');
Storage::disk('scoped_disk')->put('foo.txt', 'central2');
expect(Storage::disk('scoped_disk')->get('foo.txt'))->toBe('central2');
expect(file_get_contents(storage_path() . "/app/public/scoped_disk_prefix/foo.txt"))->toBe('central2');
expect(file_get_contents(storage_path() . "/tenant{$tenant->id}/app/public/scoped_disk_prefix/foo.txt"))->toBe('tenant');
});

View file

@ -2,6 +2,7 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\URL;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
@ -18,7 +19,6 @@ use Stancl\Tenancy\Bootstrappers\UrlGeneratorBootstrapper;
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByRequestDataException;
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
use Stancl\Tenancy\Resolvers\RequestDataTenantResolver;
use function Stancl\Tenancy\Tests\pest;
beforeEach(function () {
@ -26,12 +26,16 @@ beforeEach(function () {
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
TenancyUrlGenerator::$prefixRouteNames = false;
TenancyUrlGenerator::$passTenantParameterToRoutes = false;
TenancyUrlGenerator::$overrides = [];
TenancyUrlGenerator::$bypassParameter = 'central';
UrlGeneratorBootstrapper::$addTenantParameterToDefaults = false;
});
afterEach(function () {
TenancyUrlGenerator::$prefixRouteNames = false;
TenancyUrlGenerator::$passTenantParameterToRoutes = false;
TenancyUrlGenerator::$overrides = [];
TenancyUrlGenerator::$bypassParameter = 'central';
UrlGeneratorBootstrapper::$addTenantParameterToDefaults = false;
});
@ -80,6 +84,44 @@ test('tenancy url generator can prefix route names passed to the route helper',
expect(route('home'))->toBe('http://localhost/central/home');
});
test('tenancy url generator inherits scheme from original url generator', function() {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
Route::get('/home', fn () => '')->name('home');
// No scheme forced, default is HTTP
expect(app('url')->formatScheme())->toBe('http://');
$tenant = Tenant::create();
// Force the original URL generator to use HTTPS
app('url')->forceScheme('https');
// Original generator uses HTTPS
expect(app('url')->formatScheme())->toBe('https://');
// Check that TenancyUrlGenerator inherits the HTTPS scheme
tenancy()->initialize($tenant);
expect(app('url')->formatScheme())->toBe('https://'); // Should inherit HTTPS
expect(route('home'))->toBe('https://localhost/home');
tenancy()->end();
// After ending tenancy, the original generator should still have the original scheme (HTTPS)
expect(route('home'))->toBe('https://localhost/home');
// Use HTTP scheme
app('url')->forceScheme('http');
expect(app('url')->formatScheme())->toBe('http://');
tenancy()->initialize($tenant);
expect(app('url')->formatScheme())->toBe('http://'); // Should inherit scheme (HTTP)
expect(route('home'))->toBe('http://localhost/home');
tenancy()->end();
expect(route('home'))->toBe('http://localhost/home');
});
test('path identification route helper behavior', function (bool $addTenantParameterToDefaults, bool $passTenantParameterToRoutes) {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
@ -322,3 +364,40 @@ test('both the name prefixing and the tenant parameter logic gets skipped when b
expect(route('home', ['bypassParameter' => false, 'tenant' => $tenant->getTenantKey()]))->toBe($tenantRouteUrl)
->not()->toContain('bypassParameter');
});
test('the temporarySignedRoute method can automatically prefix the passed route name', function() {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
Route::get('/{tenant}/foo', fn () => 'foo')->name('tenant.foo')->middleware([InitializeTenancyByPath::class]);
TenancyUrlGenerator::$prefixRouteNames = true;
$tenant = Tenant::create();
tenancy()->initialize($tenant);
// Route name ('foo') gets prefixed automatically (will be 'tenant.foo')
$tenantSignedUrl = URL::temporarySignedRoute('foo', now()->addMinutes(2), ['tenant' => $tenantKey = $tenant->getTenantKey()]);
expect($tenantSignedUrl)->toContain("localhost/{$tenantKey}/foo");
});
test('the bypass parameter works correctly with temporarySignedRoute', function() {
config(['tenancy.bootstrappers' => [UrlGeneratorBootstrapper::class]]);
Route::get('/foo', fn () => 'foo')->name('central.foo');
TenancyUrlGenerator::$prefixRouteNames = true;
TenancyUrlGenerator::$bypassParameter = 'central';
$tenant = Tenant::create();
tenancy()->initialize($tenant);
// Bypass parameter allows us to generate URL for the 'central.foo' route in tenant context
$centralSignedUrl = URL::temporarySignedRoute('central.foo', now()->addMinutes(2), ['central' => true]);
expect($centralSignedUrl)
->toContain('localhost/foo')
->not()->toContain('central='); // Bypass parameter gets removed from the generated URL
});