diff --git a/.github/workflows/queue.yml b/.github/workflows/queue.yml index 4bd30f02..2b3a63c5 100644 --- a/.github/workflows/queue.yml +++ b/.github/workflows/queue.yml @@ -11,7 +11,7 @@ jobs: - name: Prepare composer version constraint prefix run: | BRANCH=${GITHUB_REF#refs/heads/} - if [[ $BRANCH =~ ^[0-9] ]]; then + if [[ $BRANCH =~ ^[0-9]\.x$ ]]; then echo "VERSION_PREFIX=${BRANCH}-dev" >> $GITHUB_ENV else echo "VERSION_PREFIX=dev-${BRANCH}" >> $GITHUB_ENV diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index 3d53529e..708e4450 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -145,24 +145,19 @@ class TenancyServiceProvider extends ServiceProvider */ protected function overrideUrlInTenantContext(): void { - /** - * Import your tenant model! - * - * \Stancl\Tenancy\Bootstrappers\RootUrlBootstrapper::$rootUrlOverride = function (Tenant $tenant, string $originalRootUrl) { - * $tenantDomain = $tenant instanceof \Stancl\Tenancy\Contracts\SingleDomainTenant - * ? $tenant->domain - * : $tenant->domains->first()->domain; - * - * $scheme = str($originalRootUrl)->before('://'); - * - * // If you're using domain identification: - * return $scheme . '://' . $tenantDomain . '/'; - * - * // If you're using subdomain identification: - * $originalDomain = str($originalRootUrl)->after($scheme . '://'); - * return $scheme . '://' . $tenantDomain . '.' . $originalDomain . '/'; - * }; - */ + // \Stancl\Tenancy\Bootstrappers\RootUrlBootstrapper::$rootUrlOverride = function (Tenant $tenant, string $originalRootUrl) { + // $tenantDomain = $tenant instanceof \Stancl\Tenancy\Contracts\SingleDomainTenant + // ? $tenant->domain + // : $tenant->domains->first()->domain; + // $scheme = str($originalRootUrl)->before('://'); + // + // // If you're using domain identification: + // return $scheme . '://' . $tenantDomain . '/'; + // + // // If you're using subdomain identification: + // $originalDomain = str($originalRootUrl)->after($scheme . '://'); + // return $scheme . '://' . $tenantDomain . '.' . $originalDomain . '/'; + // }; } public function register() @@ -178,32 +173,17 @@ class TenancyServiceProvider extends ServiceProvider $this->makeTenancyMiddlewareHighestPriority(); $this->overrideUrlInTenantContext(); - /** - * Include soft deleted resources in synced resource queries. - * - * ResourceSyncing\Listeners\UpdateOrCreateSyncedResource::$scopeGetModelQuery = function (Builder $query) { - * if ($query->hasMacro('withTrashed')) { - * $query->withTrashed(); - * } - * }; - */ + // // Include soft deleted resources in synced resource queries. + // ResourceSyncing\Listeners\UpdateOrCreateSyncedResource::$scopeGetModelQuery = function (Builder $query) { + // if ($query->hasMacro('withTrashed')) { + // $query->withTrashed(); + // } + // }; - /** - * To make Livewire v3 work with Tenancy, make the update route universal. - * - * Livewire::setUpdateRoute(function ($handle) { - * return RouteFacade::post('/livewire/update', $handle)->middleware(['web', 'universal']); - * }); - */ - - // if (InitializeTenancyByRequestData::inGlobalStack()) { - // FortifyRouteBootstrapper::$fortifyHome = 'dashboard'; - // TenancyUrlGenerator::$prefixRouteNames = false; - // } - - if (tenancy()->globalStackHasMiddleware(config('tenancy.identification.path_identification_middleware'))) { - TenancyUrlGenerator::$prefixRouteNames = true; - } + // // To make Livewire v3 work with Tenancy, make the update route universal. + // Livewire::setUpdateRoute(function ($handle) { + // return RouteFacade::post('/livewire/update', $handle)->middleware(['web', 'universal', \Stancl\Tenancy::defaultMiddleware()]); + // }); } protected function bootEvents() @@ -228,10 +208,7 @@ class TenancyServiceProvider extends ServiceProvider ->group(base_path('routes/tenant.php')); } - // Delete this condition when using route-level path identification - if (tenancy()->globalStackHasMiddleware(config('tenancy.identification.path_identification_middleware'))) { - $this->cloneRoutes(); - } + // $this->cloneRoutes(); }); } @@ -245,16 +222,13 @@ class TenancyServiceProvider extends ServiceProvider /** @var CloneRoutesAsTenant $cloneRoutes */ $cloneRoutes = $this->app->make(CloneRoutesAsTenant::class); - /** - * You can provide a closure for cloning a specific route, e.g.: - * $cloneRoutes->cloneUsing('welcome', function () { - * RouteFacade::get('/tenant-welcome', fn () => 'Current tenant: ' . tenant()->getTenantKey()) - * ->middleware(['universal', InitializeTenancyByPath::class]) - * ->name('tenant.welcome'); - * }); - * - * To see the default behavior of cloning the universal routes, check out the cloneRoute() method in CloneRoutesAsTenant. - */ + // // You can provide a closure for cloning a specific route, e.g.: + // $cloneRoutes->cloneUsing('welcome', function () { + // RouteFacade::get('/tenant-welcome', fn () => 'Current tenant: ' . tenant()->getTenantKey()) + // ->middleware(['universal', InitializeTenancyByPath::class]) + // ->name('tenant.welcome'); + // }); + // // To see the default behavior of cloning the universal routes, check out the cloneRoute() method in CloneRoutesAsTenant. $cloneRoutes->handle(); } diff --git a/assets/config.php b/assets/config.php index 9a70647e..db3820bf 100644 --- a/assets/config.php +++ b/assets/config.php @@ -91,7 +91,7 @@ return [ /** * Identification middleware tenancy recognizes as path identification middleware. * - * This is used during determining whether whether a path identification is used + * This is used for determining if a path identification middleware is used * during operations specific to path identification, e.g. forgetting the tenant parameter in ForgetTenantParameter. * * If you're using a custom path identification middleware, add it here. @@ -118,6 +118,7 @@ return [ Resolvers\PathTenantResolver::class => [ 'tenant_parameter_name' => 'tenant', 'tenant_model_column' => null, // null = tenant key + 'tenant_route_name_prefix' => null, // null = 'tenant.' 'allowed_extra_model_columns' => [], // used with binding route fields 'cache' => false, @@ -130,8 +131,6 @@ return [ 'cache_store' => null, // null = default ], ], - - // todo@docs update integration guides to use Stancl\Tenancy::defaultMiddleware() ], /** @@ -215,7 +214,14 @@ return [ // 'pgsql' => Stancl\Tenancy\Database\TenantDatabaseManagers\PermissionControlledPostgreSQLSchemaManager::class, // Also permission controlled ], - // todo@docblock + /* + * Drop tenant databases when `php artisan migrate:fresh` is used. + * You may want to use this locally since deleting tenants only + * deletes their databases when they're deleted individually, not + * when the records are mass deleted from the database. + * + * Note: This overrides the default MigrateFresh command. + */ 'drop_tenant_databases_on_migrate_fresh' => false, ], @@ -320,7 +326,6 @@ return [ */ 'url_override' => [ // Note that the local disk you add must exist in the tenancy.filesystem.root_override config - // todo@v4 Rename url_override to something that describes the config key better 'public' => 'public-%tenant%', ], @@ -356,7 +361,7 @@ return [ * leave asset() helper tenancy disabled and explicitly use tenant_asset() calls in places * where you want to use tenant-specific assets (product images, avatars, etc). */ - 'asset_helper_tenancy' => false, // todo@rename asset_helper_override? + 'asset_helper_override' => false, ], /** diff --git a/src/Bootstrappers/FilesystemTenancyBootstrapper.php b/src/Bootstrappers/FilesystemTenancyBootstrapper.php index ab7dc856..d5088c5c 100644 --- a/src/Bootstrappers/FilesystemTenancyBootstrapper.php +++ b/src/Bootstrappers/FilesystemTenancyBootstrapper.php @@ -92,7 +92,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper protected function assetHelper(string|false $suffix): void { - if (! $this->app['config']['tenancy.filesystem.asset_helper_tenancy']) { + if (! $this->app['config']['tenancy.filesystem.asset_helper_override']) { return; } diff --git a/src/Bootstrappers/Integrations/FortifyRouteBootstrapper.php b/src/Bootstrappers/Integrations/FortifyRouteBootstrapper.php index 2c5712ee..05f3fa11 100644 --- a/src/Bootstrappers/Integrations/FortifyRouteBootstrapper.php +++ b/src/Bootstrappers/Integrations/FortifyRouteBootstrapper.php @@ -7,54 +7,52 @@ namespace Stancl\Tenancy\Bootstrappers\Integrations; use Illuminate\Config\Repository; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; -use Stancl\Tenancy\Enums\Context; use Stancl\Tenancy\Resolvers\PathTenantResolver; /** - * Allows customizing Fortify action redirects - * so that they can also redirect to tenant routes instead of just the central routes. + * Allows customizing Fortify action redirects so that they can also redirect + * to tenant routes instead of just the central routes. * - * Works with path and query string identification. + * This should be used with path/query string identification OR when using Fortify + * universally, including with domains. + * + * When using domain identification, there's no need to pass the tenant parameter, + * you only want to customize the routes being used, so you can set $passTenantParameter + * to false. */ class FortifyRouteBootstrapper implements TenancyBootstrapper { /** - * Make Fortify actions redirect to custom routes. + * Fortify redirects that should be used in tenant context. * - * For each route redirect, specify the intended route context (central or tenant). - * Based on the provided context, we pass the tenant parameter to the route (or not). - * The tenant parameter is only passed to the route when you specify its context as tenant. - * - * The route redirects should be in the following format: - * - * 'fortify_action' => [ - * 'route_name' => 'tenant.route', - * 'context' => Context::TENANT, - * ] - * - * For example: - * - * FortifyRouteBootstrapper::$fortifyRedirectMap = [ - * // On logout, redirect the user to the "bye" route in the central app - * 'logout' => [ - * 'route_name' => 'bye', - * 'context' => Context::CENTRAL, - * ], - * - * // On login, redirect the user to the "welcome" route in the tenant app - * 'login' => [ - * 'route_name' => 'welcome', - * 'context' => Context::TENANT, - * ], - * ]; + * Syntax: ['redirect_name' => 'tenant_route_name'] */ public static array $fortifyRedirectMap = []; + /** + * Should the tenant parameter be passed to fortify routes in the tenant context. + * + * This should be enabled with path/query string identification and disabled with domain identification. + * + * You may also disable this when using path/query string identification if passing the tenant parameter + * is handled in another way (TenancyUrlGenerator::$passTenantParameter for both, + * UrlGeneratorBootstrapper:$addTenantParameterToDefaults for path identification). + */ + public static bool $passTenantParameter = true; + /** * Tenant route that serves as Fortify's home (e.g. a tenant dashboard route). * This route will always receive the tenant parameter. */ - public static string $fortifyHome = 'tenant.dashboard'; + public static string|null $fortifyHome = 'tenant.dashboard'; + + /** + * Use default parameter names ('tenant' name and tenant key value) instead of the parameter name + * and column name configured in the path resolver config. + * + * You want to enable this when using query string identification while having customized that config. + */ + public static bool $defaultParameterNames = false; protected array $originalFortifyConfig = []; @@ -76,27 +74,22 @@ class FortifyRouteBootstrapper implements TenancyBootstrapper protected function useTenantRoutesInFortify(Tenant $tenant): void { - $tenantKey = $tenant->getTenantKey(); - $tenantParameterName = PathTenantResolver::tenantParameterName(); + $tenantParameterName = static::$defaultParameterNames ? 'tenant' : PathTenantResolver::tenantParameterName(); + $tenantParameterValue = static::$defaultParameterNames ? $tenant->getTenantKey() : PathTenantResolver::tenantParameterValue($tenant); - $generateLink = function (array $redirect) use ($tenantKey, $tenantParameterName) { - // Specifying the context is only required with query string identification - // because with path identification, the tenant parameter should always present - $passTenantParameter = $redirect['context'] === Context::TENANT; - - // Only pass the tenant parameter when the user should be redirected to a tenant route - return route($redirect['route_name'], $passTenantParameter ? [$tenantParameterName => $tenantKey] : []); + $generateLink = function (string $redirect) use ($tenantParameterValue, $tenantParameterName) { + return route($redirect, static::$passTenantParameter ? [$tenantParameterName => $tenantParameterValue] : []); }; // Get redirect URLs for the configured redirect routes $redirects = array_merge( $this->originalFortifyConfig['redirects'] ?? [], // Fortify config redirects - array_map(fn (array $redirect) => $generateLink($redirect), static::$fortifyRedirectMap), // Mapped redirects + array_map(fn (string $redirect) => $generateLink($redirect), static::$fortifyRedirectMap), // Mapped redirects ); if (static::$fortifyHome) { // Generate the home route URL with the tenant parameter and make it the Fortify home route - $this->config->set('fortify.home', route(static::$fortifyHome, [$tenantParameterName => $tenantKey])); + $this->config->set('fortify.home', route(static::$fortifyHome, static::$passTenantParameter ? [$tenantParameterName => $tenantParameterValue] : [])); } $this->config->set('fortify.redirects', $redirects); diff --git a/src/Bootstrappers/RootUrlBootstrapper.php b/src/Bootstrappers/RootUrlBootstrapper.php index f45b8d74..5958737c 100644 --- a/src/Bootstrappers/RootUrlBootstrapper.php +++ b/src/Bootstrappers/RootUrlBootstrapper.php @@ -36,13 +36,8 @@ class RootUrlBootstrapper implements TenancyBootstrapper protected string|null $originalRootUrl = null; /** - * You may want to selectively enable or disable this bootstrapper in specific tests. - * For instance, when using `Livewire::test()` this bootstrapper can cause problems, - * due to an internal Livewire route, so you may want to disable it, while in tests - * that are generating URLs in things like mails, the bootstrapper should be used - * just like in any queued job. - * - * todo@revisit + * Overriding the root url may cause issues in *some* tests, so you can disable + * the behavior by setting this property to false. */ public static bool $rootUrlOverrideInTests = true; diff --git a/src/Bootstrappers/UrlGeneratorBootstrapper.php b/src/Bootstrappers/UrlGeneratorBootstrapper.php index 6158f22a..b5289904 100644 --- a/src/Bootstrappers/UrlGeneratorBootstrapper.php +++ b/src/Bootstrappers/UrlGeneratorBootstrapper.php @@ -69,7 +69,10 @@ class UrlGeneratorBootstrapper implements TenancyBootstrapper if (static::$addTenantParameterToDefaults) { $defaultParameters = array_merge( $defaultParameters, - [PathTenantResolver::tenantParameterName() => $tenant->getTenantKey()] + [ + PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue($tenant), // path identification + 'tenant' => $tenant->getTenantKey(), // query string identification + ], ); } diff --git a/src/Database/Concerns/CreatesDatabaseUsers.php b/src/Database/Concerns/CreatesDatabaseUsers.php index 8e102fd0..73d8e777 100644 --- a/src/Database/Concerns/CreatesDatabaseUsers.php +++ b/src/Database/Concerns/CreatesDatabaseUsers.php @@ -10,16 +10,11 @@ trait CreatesDatabaseUsers { public function createDatabase(TenantWithDatabase $tenant): bool { - parent::createDatabase($tenant); - - return $this->createUser($tenant->database()); + return parent::createDatabase($tenant) && $this->createUser($tenant->database()); } public function deleteDatabase(TenantWithDatabase $tenant): bool { - // Some DB engines require the user to be deleted before the database (e.g. Postgres) - $this->deleteUser($tenant->database()); - - return parent::deleteDatabase($tenant); + return $this->deleteUser($tenant->database()) && parent::deleteDatabase($tenant); } } diff --git a/src/Database/Concerns/HasPending.php b/src/Database/Concerns/HasPending.php index 8142e0ea..ffb35f0c 100644 --- a/src/Database/Concerns/HasPending.php +++ b/src/Database/Concerns/HasPending.php @@ -23,6 +23,8 @@ use Stancl\Tenancy\Events\PullingPendingTenant; */ trait HasPending { + public static string $pendingSinceCast = 'timestamp'; + /** Boot the trait. */ public static function bootHasPending(): void { @@ -32,7 +34,7 @@ trait HasPending /** Initialize the trait. */ public function initializeHasPending(): void { - $this->casts['pending_since'] = 'timestamp'; + $this->casts['pending_since'] = static::$pendingSinceCast; } /** Determine if the model instance is in a pending state. */ diff --git a/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php index 1e5426ea..da993956 100644 --- a/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php @@ -11,8 +11,6 @@ class MicrosoftSQLDatabaseManager extends TenantDatabaseManager public function createDatabase(TenantWithDatabase $tenant): bool { $database = $tenant->database()->getName(); - $charset = $this->connection()->getConfig('charset'); - $collation = $this->connection()->getConfig('collation'); // todo check why these are not used return $this->connection()->statement("CREATE DATABASE [{$database}]"); } diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php index 5462eafe..933740ed 100644 --- a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php +++ b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php @@ -32,6 +32,8 @@ class PermissionControlledPostgreSQLSchemaManager extends PostgreSQLSchemaManage // Grant permissions to any existing tables. This is used with RLS // todo@samuel refactor this along with the todo in TenantDatabaseManager // and move the grantPermissions() call inside the condition in `ManagesPostgresUsers::createUser()` + // but maybe moving it inside $createUser is wrong because some central user may migrate new tables + // while the RLS user should STILL get access to those tables foreach ($tables as $table) { $tableName = $table->table_name; diff --git a/src/Events/Contracts/TenantEvent.php b/src/Events/Contracts/TenantEvent.php index e07708b7..fd48ac10 100644 --- a/src/Events/Contracts/TenantEvent.php +++ b/src/Events/Contracts/TenantEvent.php @@ -7,15 +7,11 @@ namespace Stancl\Tenancy\Events\Contracts; use Illuminate\Queue\SerializesModels; use Stancl\Tenancy\Contracts\Tenant; -abstract class TenantEvent // todo we could add a feature to JobPipeline that automatically gets data for the send() from here +abstract class TenantEvent { use SerializesModels; - /** @var Tenant */ - public $tenant; - - public function __construct(Tenant $tenant) - { - $this->tenant = $tenant; - } + public function __construct( + public Tenant $tenant, + ) {} } diff --git a/src/Exceptions/TenantCouldNotBeIdentifiedByIdException.php b/src/Exceptions/TenantCouldNotBeIdentifiedByIdException.php index b344be53..6f61455e 100644 --- a/src/Exceptions/TenantCouldNotBeIdentifiedByIdException.php +++ b/src/Exceptions/TenantCouldNotBeIdentifiedByIdException.php @@ -2,8 +2,6 @@ declare(strict_types=1); -// todo perhaps create Identification namespace - namespace Stancl\Tenancy\Exceptions; use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException; diff --git a/src/Features/UserImpersonation.php b/src/Features/UserImpersonation.php index fd608cc4..2e0fedbf 100644 --- a/src/Features/UserImpersonation.php +++ b/src/Features/UserImpersonation.php @@ -62,7 +62,7 @@ class UserImpersonation implements Feature /** * Logout from the current domain and forget impersonation session. */ - public static function leave(): void // todo@name possibly rename + public static function stopImpersonating(): void { auth()->logout(); diff --git a/src/Listeners/ForgetTenantParameter.php b/src/Listeners/ForgetTenantParameter.php index 424b1440..0b1d1440 100644 --- a/src/Listeners/ForgetTenantParameter.php +++ b/src/Listeners/ForgetTenantParameter.php @@ -8,6 +8,8 @@ use Illuminate\Routing\Events\RouteMatched; use Stancl\Tenancy\Enums\RouteMode; use Stancl\Tenancy\Resolvers\PathTenantResolver; +// todo@earlyIdReview + /** * Remove the tenant parameter from the matched route when path identification is used globally. * diff --git a/src/Middleware/PreventAccessFromUnwantedDomains.php b/src/Middleware/PreventAccessFromUnwantedDomains.php index 05e0dbaa..91ebff05 100644 --- a/src/Middleware/PreventAccessFromUnwantedDomains.php +++ b/src/Middleware/PreventAccessFromUnwantedDomains.php @@ -68,7 +68,7 @@ class PreventAccessFromUnwantedDomains return in_array($request->getHost(), config('tenancy.identification.central_domains'), true); } - // todo@samuel + // todo@samuel technically not an identification middleware but probably ok to keep this here public function requestHasTenant(Request $request): bool { return false; diff --git a/src/Overrides/CacheManager.php b/src/Overrides/CacheManager.php index 9c78288e..dfbe1c71 100644 --- a/src/Overrides/CacheManager.php +++ b/src/Overrides/CacheManager.php @@ -6,8 +6,6 @@ namespace Stancl\Tenancy\Overrides; use Illuminate\Cache\CacheManager as BaseCacheManager; -// todo@move move to Cache namespace? - class CacheManager extends BaseCacheManager { /** diff --git a/src/Overrides/TenancyUrlGenerator.php b/src/Overrides/TenancyUrlGenerator.php index 53798c4e..4c6120a8 100644 --- a/src/Overrides/TenancyUrlGenerator.php +++ b/src/Overrides/TenancyUrlGenerator.php @@ -85,6 +85,14 @@ class TenancyUrlGenerator extends UrlGenerator */ public static array $overrides = []; + /** + * Use default parameter names ('tenant' name and tenant key value) instead of the parameter name + * and column name configured in the path resolver config. + * + * You want to enable this when using query string identification while having customized that config. + */ + public static bool $defaultParameterNames = false; + /** * Override the route() method so that the route name gets prefixed * and the tenant parameter gets added when in tenant context. @@ -166,7 +174,15 @@ class TenancyUrlGenerator extends UrlGenerator */ protected function addTenantParameter(array $parameters): array { - return tenant() && static::$passTenantParameterToRoutes ? array_merge($parameters, [PathTenantResolver::tenantParameterName() => tenant()->getTenantKey()]) : $parameters; + if (tenant() && static::$passTenantParameterToRoutes) { + if (static::$defaultParameterNames) { + return array_merge($parameters, ['tenant' => tenant()->getTenantKey()]); + } else { + return array_merge($parameters, [PathTenantResolver::tenantParameterName() => PathTenantResolver::tenantParameterValue(tenant())]); + } + } else { + return $parameters; + } } protected function routeNameOverride(string $name): string|null diff --git a/src/Resolvers/PathTenantResolver.php b/src/Resolvers/PathTenantResolver.php index 556ec4a6..773154e4 100644 --- a/src/Resolvers/PathTenantResolver.php +++ b/src/Resolvers/PathTenantResolver.php @@ -73,7 +73,7 @@ class PathTenantResolver extends Contracts\CachedTenantResolver public static function tenantRouteNamePrefix(): string { - return config('tenancy.identification.resolvers.' . static::class . '.tenant_route_name_prefix') ?? static::tenantParameterName() . '.'; + return config('tenancy.identification.resolvers.' . static::class . '.tenant_route_name_prefix') ?? 'tenant.'; } public static function tenantModelColumn(): string @@ -81,6 +81,11 @@ class PathTenantResolver extends Contracts\CachedTenantResolver return config('tenancy.identification.resolvers.' . static::class . '.tenant_model_column') ?? tenancy()->model()->getTenantKeyName(); } + public static function tenantParameterValue(Tenant $tenant): string + { + return $tenant->getAttribute(static::tenantModelColumn()); + } + /** @return string[] */ public static function allowedExtraModelColumns(): array { diff --git a/src/ResourceSyncing/SyncMaster.php b/src/ResourceSyncing/SyncMaster.php index 9a373930..882aeb54 100644 --- a/src/ResourceSyncing/SyncMaster.php +++ b/src/ResourceSyncing/SyncMaster.php @@ -9,8 +9,6 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Stancl\Tenancy\Database\Contracts\TenantWithDatabase; -// todo@move move all resource syncing-related things to a separate namespace? - /** * @property-read TenantWithDatabase[]|Collection $tenants */ diff --git a/tests/Bootstrappers/FortifyRouteBootstrapperTest.php b/tests/Bootstrappers/FortifyRouteBootstrapperTest.php index 63a08c2f..1942a1c5 100644 --- a/tests/Bootstrappers/FortifyRouteBootstrapperTest.php +++ b/tests/Bootstrappers/FortifyRouteBootstrapperTest.php @@ -13,6 +13,14 @@ use Stancl\Tenancy\Bootstrappers\Integrations\FortifyRouteBootstrapper; beforeEach(function () { Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); + FortifyRouteBootstrapper::$passTenantParameter = true; +}); + +afterEach(function () { + FortifyRouteBootstrapper::$passTenantParameter = true; + FortifyRouteBootstrapper::$fortifyRedirectMap = []; + FortifyRouteBootstrapper::$fortifyHome = 'tenant.dashboard'; + FortifyRouteBootstrapper::$defaultParameterNames = false; }); test('fortify route tenancy bootstrapper updates fortify config correctly', function() { @@ -25,53 +33,31 @@ test('fortify route tenancy bootstrapper updates fortify config correctly', func return true; })->name($homeRouteName = 'home'); - Route::get('/{tenant}/home', function () { - return true; - })->name($pathIdHomeRouteName = 'tenant.home'); - Route::get('/welcome', function () { return true; })->name($welcomeRouteName = 'welcome'); - Route::get('/{tenant}/welcome', function () { - return true; - })->name($pathIdWelcomeRouteName = 'path.welcome'); - FortifyRouteBootstrapper::$fortifyHome = $homeRouteName; + FortifyRouteBootstrapper::$fortifyRedirectMap['login'] = $welcomeRouteName; - // Make login redirect to the central welcome route - FortifyRouteBootstrapper::$fortifyRedirectMap['login'] = [ - 'route_name' => $welcomeRouteName, - 'context' => Context::CENTRAL, - ]; + expect(config('fortify.home'))->toBe($originalFortifyHome); + expect(config('fortify.redirects'))->toBe($originalFortifyRedirects); + FortifyRouteBootstrapper::$passTenantParameter = true; tenancy()->initialize($tenant = Tenant::create()); - // The bootstraper makes fortify.home always receive the tenant parameter expect(config('fortify.home'))->toBe('http://localhost/home?tenant=' . $tenant->getTenantKey()); - - // The login redirect route has the central context specified, so it doesn't receive the tenant parameter - expect(config('fortify.redirects'))->toEqual(['login' => 'http://localhost/welcome']); + expect(config('fortify.redirects'))->toEqual(['login' => 'http://localhost/welcome?tenant=' . $tenant->getTenantKey()]); tenancy()->end(); expect(config('fortify.home'))->toBe($originalFortifyHome); expect(config('fortify.redirects'))->toBe($originalFortifyRedirects); - // Making a route's context will pass the tenant parameter to the route - FortifyRouteBootstrapper::$fortifyRedirectMap['login']['context'] = Context::TENANT; - + FortifyRouteBootstrapper::$passTenantParameter = false; tenancy()->initialize($tenant); - - expect(config('fortify.redirects'))->toEqual(['login' => 'http://localhost/welcome?tenant=' . $tenant->getTenantKey()]); - - // Make the home and login route accept the tenant as a route parameter - // To confirm that tenant route parameter gets filled automatically too (path identification works as well as query string) - FortifyRouteBootstrapper::$fortifyHome = $pathIdHomeRouteName; - FortifyRouteBootstrapper::$fortifyRedirectMap['login']['route_name'] = $pathIdWelcomeRouteName; + expect(config('fortify.home'))->toBe('http://localhost/home'); + expect(config('fortify.redirects'))->toEqual(['login' => 'http://localhost/welcome']); tenancy()->end(); - - tenancy()->initialize($tenant); - - expect(config('fortify.home'))->toBe("http://localhost/{$tenant->getTenantKey()}/home"); - expect(config('fortify.redirects'))->toEqual(['login' => "http://localhost/{$tenant->getTenantKey()}/welcome"]); + expect(config('fortify.home'))->toBe($originalFortifyHome); + expect(config('fortify.redirects'))->toBe($originalFortifyRedirects); }); diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php index f7191831..bcdc701b 100644 --- a/tests/TenantAssetTest.php +++ b/tests/TenantAssetTest.php @@ -65,7 +65,7 @@ test('asset can be accessed using the url returned by the tenant asset helper', test('asset helper returns a link to tenant asset controller when asset url is null', function () { config(['app.asset_url' => null]); - config(['tenancy.filesystem.asset_helper_tenancy' => true]); + config(['tenancy.filesystem.asset_helper_override' => true]); $tenant = Tenant::create(); tenancy()->initialize($tenant); @@ -78,7 +78,7 @@ test('asset helper returns a link to tenant asset controller when asset url is n test('asset helper returns a link to an external url when asset url is not null', function () { config(['app.asset_url' => 'https://an-s3-bucket']); - config(['tenancy.filesystem.asset_helper_tenancy' => true]); + config(['tenancy.filesystem.asset_helper_override' => true]); $tenant = Tenant::create(); tenancy()->initialize($tenant); @@ -93,7 +93,7 @@ test('asset helper works correctly with path identification', function (bool $ke TenancyUrlGenerator::$prefixRouteNames = true; TenancyUrlGenerator::$passTenantParameterToRoutes = true; - config(['tenancy.filesystem.asset_helper_tenancy' => true]); + config(['tenancy.filesystem.asset_helper_override' => true]); config(['tenancy.identification.default_middleware' => InitializeTenancyByPath::class]); config(['tenancy.bootstrappers' => array_merge([UrlGeneratorBootstrapper::class], config('tenancy.bootstrappers'))]); @@ -165,7 +165,7 @@ test('asset helper tenancy can be disabled', function () { config([ 'app.asset_url' => null, - 'tenancy.filesystem.asset_helper_tenancy' => false, + 'tenancy.filesystem.asset_helper_override' => false, ]); $tenant = Tenant::create(); diff --git a/tests/TenantUserImpersonationTest.php b/tests/TenantUserImpersonationTest.php index 1e72c604..8d4f5794 100644 --- a/tests/TenantUserImpersonationTest.php +++ b/tests/TenantUserImpersonationTest.php @@ -88,7 +88,7 @@ test('tenant user can be impersonated on a tenant domain', function () { expect(session('tenancy_impersonating'))->toBeTrue(); // Leave impersonation - UserImpersonation::leave(); + UserImpersonation::stopImpersonating(); expect(UserImpersonation::isImpersonating())->toBeFalse(); expect(session('tenancy_impersonating'))->toBeNull(); @@ -134,7 +134,7 @@ test('tenant user can be impersonated on a tenant path', function () { expect(session('tenancy_impersonating'))->toBeTrue(); // Leave impersonation - UserImpersonation::leave(); + UserImpersonation::stopImpersonating(); expect(UserImpersonation::isImpersonating())->toBeFalse(); expect(session('tenancy_impersonating'))->toBeNull();