Skip to content

Commit 55ee7d8

Browse files
authored
Merge branch 'master' into add-log-bootstrapper
2 parents 6e474ac + 652bc98 commit 55ee7d8

27 files changed

Lines changed: 729 additions & 122 deletions

assets/TenancyServiceProvider.stub.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ public function events()
5353
])->send(function (Events\TenantCreated $event) {
5454
return $event->tenant;
5555
})->shouldBeQueued(false),
56-
57-
// Listeners\CreateTenantStorage::class,
5856
],
5957
Events\SavingTenant::class => [],
6058
Events\TenantSaved::class => [],
@@ -63,12 +61,11 @@ public function events()
6361
Events\DeletingTenant::class => [
6462
JobPipeline::make([
6563
Jobs\DeleteDomains::class,
64+
// Jobs\DeleteTenantStorage::class,
6665
// Jobs\RemoveStorageSymlinks::class,
6766
])->send(function (Events\DeletingTenant $event) {
6867
return $event->tenant;
6968
})->shouldBeQueued(false),
70-
71-
// Listeners\DeleteTenantStorage::class,
7269
],
7370
Events\TenantDeleted::class => [
7471
JobPipeline::make([

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ services:
8080
mssql:
8181
image: mcr.microsoft.com/mssql/server:2022-latest
8282
environment:
83-
- ACCEPT_EULA=Y
84-
- SA_PASSWORD=P@ssword # must be the same as TENANCY_TEST_SQLSRV_PASSWORD
83+
ACCEPT_EULA: "Y"
84+
SA_PASSWORD: "P@ssword" # must be the same as TENANCY_TEST_SQLSRV_PASSWORD
8585
healthcheck: # https://github.com/Microsoft/mssql-docker/issues/133#issuecomment-1995615432
8686
test: timeout 2 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/1433'
8787
interval: 10s

src/Bootstrappers/UrlGeneratorBootstrapper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* Makes the app use TenancyUrlGenerator (instead of Illuminate\Routing\UrlGenerator) which:
1818
* - prefixes route names with the tenant route name prefix (PathTenantResolver::tenantRouteNamePrefix() by default)
19-
* - passes the tenant parameter to the link generated by route() and temporarySignedRoute() (PathTenantResolver::tenantParameterName() by default).
19+
* - passes the tenant parameter (PathTenantResolver::tenantParameterName() by default) to the link generated by the affected methods like route() and temporarySignedRoute().
2020
*
2121
* Used with path and query string identification.
2222
*

src/Commands/Run.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class Run extends Command
1717
protected $description = 'Run a command for tenant(s)';
1818

1919
protected $signature = 'tenants:run {commandname : The artisan command.}
20-
{--tenants=* : The tenant(s) to run the command for. Default: all}';
20+
{--tenants=* : The tenant(s) to run the command for. Default: all}
21+
{--skip-tenants=* : The tenant(s) to skip}';
2122

2223
public function handle(): int
2324
{

src/Concerns/HasTenantOptions.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
use Symfony\Component\Console\Input\InputOption;
1111

1212
/**
13-
* Adds 'tenants' and 'with-pending' options.
13+
* Adds 'tenants', 'skip-tenants', and 'with-pending' options.
1414
*/
1515
trait HasTenantOptions
1616
{
1717
protected function getOptions()
1818
{
1919
return array_merge([
20-
new InputOption('tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to run this command for. Leave empty for all tenants', null),
21-
new InputOption('with-pending', null, InputOption::VALUE_NONE, 'Include pending tenants in query'), // todo@pending should we also offer without-pending? if we add this, mention in docs
20+
new InputOption('tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to run this command for. Leave empty for all tenants', null),
21+
new InputOption('skip-tenants', null, InputOption::VALUE_IS_ARRAY|InputOption::VALUE_OPTIONAL, 'The tenants to skip when running this command', null),
22+
new InputOption('with-pending', null, InputOption::VALUE_OPTIONAL, 'Include pending tenants in query if true/1, exclude if false/0. Defaults to the tenancy.pending.include_in_queries config value.'),
2223
], parent::getOptions());
2324
}
2425

@@ -42,8 +43,15 @@ protected function getTenantsQuery(?array $tenantKeys = null): Builder
4243
->when($this->option('tenants'), function ($query) {
4344
$query->whereIn(tenancy()->model()->getTenantKeyName(), $this->option('tenants'));
4445
})
46+
->when($this->option('skip-tenants'), function ($query) {
47+
$query->whereNotIn(tenancy()->model()->getTenantKeyName(), $this->option('skip-tenants'));
48+
})
4549
->when(tenancy()->model()::hasGlobalScope(PendingScope::class), function ($query) {
46-
$query->withPending(config('tenancy.pending.include_in_queries') ?: $this->option('with-pending'));
50+
$includePending = $this->input->hasParameterOption('--with-pending')
51+
? filter_var($this->option('with-pending') ?? true, FILTER_VALIDATE_BOOLEAN)
52+
: config('tenancy.pending.include_in_queries');
53+
54+
$query->withPending($includePending);
4755
});
4856
}
4957

src/Database/Concerns/HasPending.php

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ trait HasPending
2828
public static function bootHasPending(): void
2929
{
3030
static::addGlobalScope(new PendingScope());
31+
32+
static::creating(function (self $tenant): void {
33+
if ($tenant->pending()) {
34+
event(new CreatingPendingTenant($tenant));
35+
}
36+
});
37+
38+
static::created(function (self $tenant): void {
39+
if ($tenant->pending()) {
40+
event(new PendingTenantCreated($tenant));
41+
}
42+
});
3143
}
3244

3345
/** Initialize the trait. */
@@ -49,22 +61,11 @@ public function pending(): bool
4961
*/
5062
public static function createPending(array $attributes = []): Model&Tenant
5163
{
52-
$tenant = null;
53-
54-
try {
55-
$tenant = static::create(array_merge(static::getPendingAttributes($attributes), $attributes));
56-
event(new CreatingPendingTenant($tenant));
57-
} finally {
58-
// Update the pending_since value only after the tenant is created so it's
59-
// not marked as pending until after migrations, seeders, etc are run.
60-
$tenant?->update([
61-
'pending_since' => now()->timestamp,
62-
]);
63-
}
64-
65-
event(new PendingTenantCreated($tenant));
66-
67-
return $tenant;
64+
return static::create(array_merge(
65+
static::getPendingAttributes($attributes),
66+
$attributes,
67+
['pending_since' => now()->timestamp],
68+
));
6869
}
6970

7071
/**

src/Database/Concerns/PendingScope.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class PendingScope implements Scope
1414
/**
1515
* Apply the scope to a given Eloquent query builder.
1616
*
17-
* @param Builder<Model> $builder
17+
* @param Builder<covariant Model> $builder
1818
*
1919
* @return void
2020
*/
@@ -58,8 +58,10 @@ protected function addWithoutPending(Builder $builder): void
5858
{
5959
$builder->macro('withoutPending', function (Builder $builder) {
6060
$builder->withoutGlobalScope(static::class)
61-
->whereNull($builder->getModel()->getColumnForQuery('pending_since'))
62-
->orWhereNull($builder->getModel()->getDataColumn());
61+
->where(function (Builder $query) {
62+
$query->whereNull($query->getModel()->getColumnForQuery('pending_since'))
63+
->orWhereNull($query->getModel()->getDataColumn());
64+
});
6365

6466
return $builder;
6567
});

src/Database/ParentModelScope.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class ParentModelScope implements Scope
1313
{
1414
/**
15-
* @param Builder<Model> $builder
15+
* @param Builder<covariant Model> $builder
1616
*/
1717
public function apply(Builder $builder, Model $model): void
1818
{

src/Database/TenantScope.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
class TenantScope implements Scope
1414
{
1515
/**
16-
* @param Builder<Model> $builder
16+
* @param Builder<covariant Model> $builder
1717
*/
1818
public function apply(Builder $builder, Model $model)
1919
{

src/Features/UserImpersonation.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Stancl\Tenancy\Features;
66

7+
use Exception;
78
use Illuminate\Database\Eloquent\Model;
89
use Illuminate\Http\RedirectResponse;
910
use Illuminate\Support\Facades\Auth;
@@ -61,9 +62,9 @@ public static function makeResponse(#[\SensitiveParameter] string|Model $token,
6162

6263
Auth::guard($token->auth_guard)->loginUsingId($token->user_id, $token->remember);
6364

64-
$token->delete();
65+
session()->put('tenancy_impersonation_guard', $token->auth_guard);
6566

66-
session()->put('tenancy_impersonating', true);
67+
$token->delete();
6768

6869
return redirect($token->redirect_url);
6970
}
@@ -76,16 +77,30 @@ public static function modelClass(): string
7677

7778
public static function isImpersonating(): bool
7879
{
79-
return session()->has('tenancy_impersonating');
80+
return session()->has('tenancy_impersonation_guard');
8081
}
8182

8283
/**
83-
* Logout from the current domain and forget impersonation session.
84+
* Stop user impersonation by forgetting the impersonation session.
85+
*
86+
* When $logout is true, the user will also be logged out
87+
* from the impersonation guard stored in the session.
88+
*
89+
* Throws an exception if impersonation is not active
90+
* (= the impersonation guard is not in the session).
8491
*/
85-
public static function stopImpersonating(): void
92+
public static function stopImpersonating(bool $logout = true): void
8693
{
87-
auth()->logout();
94+
if (! static::isImpersonating()) {
95+
throw new Exception('Not currently impersonating any user.');
96+
}
97+
98+
if ($logout) {
99+
$guard = session()->get('tenancy_impersonation_guard');
100+
101+
auth($guard)->logout();
102+
}
88103

89-
session()->forget('tenancy_impersonating');
104+
session()->forget('tenancy_impersonation_guard');
90105
}
91106
}

0 commit comments

Comments
 (0)