mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 19:14:03 +00:00
Merge branch 'master' into stein-j-readied-tenant
This commit is contained in:
commit
0d1a85005d
19 changed files with 180 additions and 52 deletions
|
|
@ -10,6 +10,7 @@ $rules = [
|
||||||
'operators' => [
|
'operators' => [
|
||||||
'=>' => null,
|
'=>' => null,
|
||||||
'|' => 'no_space',
|
'|' => 'no_space',
|
||||||
|
'&' => 'no_space',
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'blank_line_after_namespace' => true,
|
'blank_line_after_namespace' => true,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@
|
||||||
"docker-m1": "ln -s docker-compose-m1.override.yml docker-compose.override.yml",
|
"docker-m1": "ln -s docker-compose-m1.override.yml docker-compose.override.yml",
|
||||||
"coverage": "open coverage/phpunit/html/index.html",
|
"coverage": "open coverage/phpunit/html/index.html",
|
||||||
"phpstan": "vendor/bin/phpstan",
|
"phpstan": "vendor/bin/phpstan",
|
||||||
|
"cs": "php-cs-fixer fix --config=.php-cs-fixer.php",
|
||||||
"test": "PHP_VERSION=8.1 ./test --no-coverage",
|
"test": "PHP_VERSION=8.1 ./test --no-coverage",
|
||||||
"test-full": "PHP_VERSION=8.1 ./test"
|
"test-full": "PHP_VERSION=8.1 ./test"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use Exception;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\LazyCollection;
|
use Illuminate\Support\LazyCollection;
|
||||||
use Stancl\Tenancy\Concerns\DealsWithTenantSymlinks;
|
use Stancl\Tenancy\Concerns\DealsWithTenantSymlinks;
|
||||||
use Stancl\Tenancy\Database\Models\Tenant;
|
use Stancl\Tenancy\Contracts\Tenant;
|
||||||
use Stancl\Tenancy\Events\CreatingStorageSymlink;
|
use Stancl\Tenancy\Events\CreatingStorageSymlink;
|
||||||
use Stancl\Tenancy\Events\StorageSymlinkCreated;
|
use Stancl\Tenancy\Events\StorageSymlinkCreated;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace Stancl\Tenancy\Actions;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\LazyCollection;
|
use Illuminate\Support\LazyCollection;
|
||||||
use Stancl\Tenancy\Concerns\DealsWithTenantSymlinks;
|
use Stancl\Tenancy\Concerns\DealsWithTenantSymlinks;
|
||||||
use Stancl\Tenancy\Database\Models\Tenant;
|
use Stancl\Tenancy\Contracts\Tenant;
|
||||||
use Stancl\Tenancy\Events\RemovingStorageSymlink;
|
use Stancl\Tenancy\Events\RemovingStorageSymlink;
|
||||||
use Stancl\Tenancy\Events\StorageSymlinkRemoved;
|
use Stancl\Tenancy\Events\StorageSymlinkRemoved;
|
||||||
|
|
||||||
|
|
|
||||||
52
src/Commands/Down.php
Normal file
52
src/Commands/Down.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Console\DownCommand;
|
||||||
|
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
||||||
|
|
||||||
|
class Down extends DownCommand
|
||||||
|
{
|
||||||
|
use HasATenantsOption;
|
||||||
|
|
||||||
|
protected $signature = 'tenants:down
|
||||||
|
{--redirect= : The path that users should be redirected to}
|
||||||
|
{--retry= : The number of seconds after which the request may be retried}
|
||||||
|
{--refresh= : The number of seconds after which the browser may refresh}
|
||||||
|
{--secret= : The secret phrase that may be used to bypass maintenance mode}
|
||||||
|
{--status=503 : The status code that should be used when returning the maintenance mode response}';
|
||||||
|
|
||||||
|
protected $description = 'Put tenants into maintenance mode.';
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
// The base down command is heavily used. Instead of saving the data inside a file,
|
||||||
|
// the data is stored the tenant database, which means some Laravel features
|
||||||
|
// are not available with tenants.
|
||||||
|
|
||||||
|
$payload = $this->getDownDatabasePayload();
|
||||||
|
|
||||||
|
// This runs for all tenants if no --tenants are specified
|
||||||
|
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($payload) {
|
||||||
|
$this->line("Tenant: {$tenant['id']}");
|
||||||
|
$tenant->putDownForMaintenance($payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->comment('Tenants are now in maintenance mode.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the payload to be placed in the "down" file. */
|
||||||
|
protected function getDownDatabasePayload()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'except' => $this->excludedPaths(),
|
||||||
|
'redirect' => $this->redirectPath(),
|
||||||
|
'retry' => $this->getRetryTime(),
|
||||||
|
'refresh' => $this->option('refresh'),
|
||||||
|
'secret' => $this->option('secret'),
|
||||||
|
'status' => (int) $this->option('status', 503),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/Commands/Up.php
Normal file
27
src/Commands/Up.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
||||||
|
|
||||||
|
class Up extends Command
|
||||||
|
{
|
||||||
|
use HasATenantsOption;
|
||||||
|
|
||||||
|
protected $signature = 'tenants:up';
|
||||||
|
|
||||||
|
protected $description = 'Put tenants out of maintenance mode.';
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
tenancy()->runForMultiple($this->getTenants(), function ($tenant) {
|
||||||
|
$this->line("Tenant: {$tenant['id']}");
|
||||||
|
$tenant->bringUpFromMaintenance();
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->comment('Tenants are now out of maintenance mode.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,8 @@ trait DealsWithTenantSymlinks
|
||||||
* Tenants can have a symlink for each disk registered in the tenancy.filesystem.url_override config.
|
* Tenants can have a symlink for each disk registered in the tenancy.filesystem.url_override config.
|
||||||
*
|
*
|
||||||
* This is used for creating all possible tenant symlinks and removing all existing tenant symlinks.
|
* This is used for creating all possible tenant symlinks and removing all existing tenant symlinks.
|
||||||
|
*
|
||||||
|
* @return Collection<string, string>
|
||||||
*/
|
*/
|
||||||
protected static function possibleTenantSymlinks(Tenant $tenant): Collection
|
protected static function possibleTenantSymlinks(Tenant $tenant): Collection
|
||||||
{
|
{
|
||||||
|
|
@ -33,7 +35,7 @@ trait DealsWithTenantSymlinks
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $symlinks->mapWithKeys(fn ($item) => $item);
|
return $symlinks->mapWithKeys(fn ($item) => $item); // [[a => b], [c => d]] -> [a => b, c => d]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Determine if the provided path is an existing symlink. */
|
/** Determine if the provided path is an existing symlink. */
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,27 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Stancl\Tenancy\Database\Concerns;
|
namespace Stancl\Tenancy\Database\Concerns;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
/**
|
||||||
|
* @mixin \Illuminate\Database\Eloquent\Model
|
||||||
|
*/
|
||||||
trait MaintenanceMode
|
trait MaintenanceMode
|
||||||
{
|
{
|
||||||
public function putDownForMaintenance($data = [])
|
public function putDownForMaintenance($data = []): void
|
||||||
{
|
{
|
||||||
$this->update(['maintenance_mode' => [
|
$this->update([
|
||||||
'time' => $data['time'] ?? Carbon::now()->getTimestamp(),
|
'maintenance_mode' => [
|
||||||
'message' => $data['message'] ?? null,
|
'except' => $data['except'] ?? null,
|
||||||
|
'redirect' => $data['redirect'] ?? null,
|
||||||
'retry' => $data['retry'] ?? null,
|
'retry' => $data['retry'] ?? null,
|
||||||
'allowed' => $data['allowed'] ?? [],
|
'refresh' => $data['refresh'] ?? null,
|
||||||
]]);
|
'secret' => $data['secret'] ?? null,
|
||||||
|
'status' => $data['status'] ?? 503,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bringUpFromMaintenance(): void
|
||||||
|
{
|
||||||
|
$this->update(['maintenance_mode' => null]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use Exception;
|
||||||
|
|
||||||
class DomainOccupiedByOtherTenantException extends Exception
|
class DomainOccupiedByOtherTenantException extends Exception
|
||||||
{
|
{
|
||||||
public function __construct($domain)
|
public function __construct(string $domain)
|
||||||
{
|
{
|
||||||
parent::__construct("The $domain domain is occupied by another tenant.");
|
parent::__construct("The $domain domain is occupied by another tenant.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use Exception;
|
||||||
|
|
||||||
class TenancyNotInitializedException extends Exception
|
class TenancyNotInitializedException extends Exception
|
||||||
{
|
{
|
||||||
public function __construct($message = '')
|
public function __construct(string $message = '')
|
||||||
{
|
{
|
||||||
parent::__construct($message ?: 'Tenancy is not initialized.');
|
parent::__construct($message ?: 'Tenancy is not initialized.');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class CreateDatabase implements ShouldQueue
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(DatabaseManager $databaseManager)
|
public function handle(DatabaseManager $databaseManager): bool
|
||||||
{
|
{
|
||||||
event(new CreatingDatabase($this->tenant));
|
event(new CreatingDatabase($this->tenant));
|
||||||
|
|
||||||
|
|
@ -38,5 +38,7 @@ class CreateDatabase implements ShouldQueue
|
||||||
$this->tenant->database()->manager()->createDatabase($this->tenant);
|
$this->tenant->database()->manager()->createDatabase($this->tenant);
|
||||||
|
|
||||||
event(new DatabaseCreated($this->tenant));
|
event(new DatabaseCreated($this->tenant));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,12 @@ class CreateStorageSymlinks implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public Tenant $tenant;
|
public function __construct(
|
||||||
|
public Tenant $tenant,
|
||||||
/**
|
) {
|
||||||
* Create a new job instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(Tenant $tenant)
|
|
||||||
{
|
|
||||||
$this->tenant = $tenant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the job.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
CreateStorageSymlinksAction::handle($this->tenant);
|
CreateStorageSymlinksAction::handle($this->tenant);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,12 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Stancl\Tenancy\Database\Concerns\HasDomains;
|
|
||||||
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
||||||
|
|
||||||
class DeleteDomains
|
class DeleteDomains
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
/** @var TenantWithDatabase&Model&HasDomains */ // todo unresolvable type for phpstan
|
|
||||||
protected TenantWithDatabase&Model $tenant;
|
protected TenantWithDatabase&Model $tenant;
|
||||||
|
|
||||||
public function __construct(TenantWithDatabase&Model $tenant)
|
public function __construct(TenantWithDatabase&Model $tenant)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ namespace Stancl\Tenancy\Middleware;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
||||||
use Stancl\Tenancy\Exceptions\TenancyNotInitializedException;
|
use Stancl\Tenancy\Exceptions\TenancyNotInitializedException;
|
||||||
use Symfony\Component\HttpFoundation\IpUtils;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
class CheckTenantForMaintenanceMode extends CheckForMaintenanceMode
|
class CheckTenantForMaintenanceMode extends CheckForMaintenanceMode
|
||||||
|
|
@ -21,19 +20,38 @@ class CheckTenantForMaintenanceMode extends CheckForMaintenanceMode
|
||||||
if (tenant('maintenance_mode')) {
|
if (tenant('maintenance_mode')) {
|
||||||
$data = tenant('maintenance_mode');
|
$data = tenant('maintenance_mode');
|
||||||
|
|
||||||
if (isset($data['allowed']) && IpUtils::checkIp($request->ip(), (array) $data['allowed'])) {
|
if (isset($data['secret']) && $request->path() === $data['secret']) {
|
||||||
|
return $this->bypassResponse($data['secret']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasValidBypassCookie($request, $data) ||
|
||||||
|
$this->inExceptArray($request)) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->inExceptArray($request)) {
|
if (isset($data['redirect'])) {
|
||||||
return $next($request);
|
$path = $data['redirect'] === '/'
|
||||||
|
? $data['redirect']
|
||||||
|
: trim($data['redirect'], '/');
|
||||||
|
|
||||||
|
if ($request->path() !== $path) {
|
||||||
|
return redirect($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['template'])) {
|
||||||
|
return response(
|
||||||
|
$data['template'],
|
||||||
|
(int) ($data['status'] ?? 503),
|
||||||
|
$this->getHeaders($data)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
503,
|
(int) ($data['status'] ?? 503),
|
||||||
'Service Unavailable',
|
'Service Unavailable',
|
||||||
null,
|
null,
|
||||||
isset($data['retry']) ? ['Retry-After' => $data['retry']] : []
|
$this->getHeaders($data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||||
namespace Stancl\Tenancy\Middleware;
|
namespace Stancl\Tenancy\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
|
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
|
||||||
use Stancl\Tenancy\Contracts\TenantResolver;
|
use Stancl\Tenancy\Contracts\TenantResolver;
|
||||||
use Stancl\Tenancy\Tenancy;
|
use Stancl\Tenancy\Tenancy;
|
||||||
|
|
@ -17,7 +18,8 @@ abstract class IdentificationMiddleware
|
||||||
{
|
{
|
||||||
public static ?Closure $onFail = null;
|
public static ?Closure $onFail = null;
|
||||||
|
|
||||||
public function initializeTenancy($request, $next, ...$resolverArguments)
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
|
public function initializeTenancy(Request $request, Closure $next, mixed ...$resolverArguments): mixed
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->tenancy->initialize(
|
$this->tenancy->initialize(
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use Stancl\Tenancy\Exceptions\TenancyNotInitializedException;
|
||||||
|
|
||||||
class ScopeSessions
|
class ScopeSessions
|
||||||
{
|
{
|
||||||
public static $tenantIdKey = '_tenant_id';
|
public static string $tenantIdKey = '_tenant_id';
|
||||||
|
|
||||||
/** @return \Illuminate\Http\Response|mixed */
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
public function handle(Request $request, Closure $next): mixed
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,9 @@ class TenancyServiceProvider extends ServiceProvider
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
$this->commands([
|
$this->commands([
|
||||||
|
Commands\Up::class,
|
||||||
Commands\Run::class,
|
Commands\Run::class,
|
||||||
|
Commands\Down::class,
|
||||||
Commands\Link::class,
|
Commands\Link::class,
|
||||||
Commands\Seed::class,
|
Commands\Seed::class,
|
||||||
Commands\Install::class,
|
Commands\Install::class,
|
||||||
|
|
@ -86,8 +88,8 @@ class TenancyServiceProvider extends ServiceProvider
|
||||||
Commands\TenantList::class,
|
Commands\TenantList::class,
|
||||||
Commands\TenantDump::class,
|
Commands\TenantDump::class,
|
||||||
Commands\MigrateFresh::class,
|
Commands\MigrateFresh::class,
|
||||||
Commands\CreatePendingTenants::class,
|
|
||||||
Commands\ClearPendingTenants::class,
|
Commands\ClearPendingTenants::class,
|
||||||
|
Commands\CreatePendingTenants::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->publishes([
|
$this->publishes([
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use Stancl\Tenancy\Database\Contracts\TenantWithDatabase;
|
||||||
use Stancl\Tenancy\Database\Concerns\HasDatabase;
|
use Stancl\Tenancy\Database\Concerns\HasDatabase;
|
||||||
use Stancl\Tenancy\Database\Concerns\HasDomains;
|
use Stancl\Tenancy\Database\Concerns\HasDomains;
|
||||||
use Stancl\Tenancy\Database\Concerns\HasPending;
|
use Stancl\Tenancy\Database\Concerns\HasPending;
|
||||||
|
use Stancl\Tenancy\Database\Concerns\MaintenanceMode;
|
||||||
use Stancl\Tenancy\Database\Models;
|
use Stancl\Tenancy\Database\Models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -15,5 +16,5 @@ use Stancl\Tenancy\Database\Models;
|
||||||
*/
|
*/
|
||||||
class Tenant extends Models\Tenant implements TenantWithDatabase
|
class Tenant extends Models\Tenant implements TenantWithDatabase
|
||||||
{
|
{
|
||||||
use HasDatabase, HasDomains, HasPending;
|
use HasDatabase, HasDomains, HasPending, MaintenanceMode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Stancl\Tenancy\Database\Concerns\MaintenanceMode;
|
use Stancl\Tenancy\Database\Concerns\MaintenanceMode;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Stancl\Tenancy\Middleware\CheckTenantForMaintenanceMode;
|
use Stancl\Tenancy\Middleware\CheckTenantForMaintenanceMode;
|
||||||
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
|
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
|
||||||
use Stancl\Tenancy\Tests\Etc\Tenant;
|
use Stancl\Tenancy\Tests\Etc\Tenant;
|
||||||
|
|
||||||
test('tenant can be in maintenance mode', function () {
|
test('tenants can be in maintenance mode', function () {
|
||||||
Route::get('/foo', function () {
|
Route::get('/foo', function () {
|
||||||
return 'bar';
|
return 'bar';
|
||||||
})->middleware([InitializeTenancyByDomain::class, CheckTenantForMaintenanceMode::class]);
|
})->middleware([InitializeTenancyByDomain::class, CheckTenantForMaintenanceMode::class]);
|
||||||
|
|
@ -19,16 +19,40 @@ test('tenant can be in maintenance mode', function () {
|
||||||
'domain' => 'acme.localhost',
|
'domain' => 'acme.localhost',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
pest()->get('http://acme.localhost/foo')
|
pest()->get('http://acme.localhost/foo')->assertStatus(200);
|
||||||
->assertSuccessful();
|
|
||||||
|
|
||||||
tenancy()->end(); // flush stored tenant instance
|
|
||||||
|
|
||||||
$tenant->putDownForMaintenance();
|
$tenant->putDownForMaintenance();
|
||||||
|
|
||||||
pest()->expectException(HttpException::class);
|
tenancy()->end(); // End tenancy before making a request
|
||||||
pest()->withoutExceptionHandling()
|
pest()->get('http://acme.localhost/foo')->assertStatus(503);
|
||||||
->get('http://acme.localhost/foo');
|
|
||||||
|
$tenant->bringUpFromMaintenance();
|
||||||
|
|
||||||
|
tenancy()->end(); // End tenancy before making a request
|
||||||
|
pest()->get('http://acme.localhost/foo')->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tenants can be put into maintenance mode using artisan commands', function() {
|
||||||
|
Route::get('/foo', function () {
|
||||||
|
return 'bar';
|
||||||
|
})->middleware([InitializeTenancyByDomain::class, CheckTenantForMaintenanceMode::class]);
|
||||||
|
|
||||||
|
$tenant = MaintenanceTenant::create();
|
||||||
|
$tenant->domains()->create([
|
||||||
|
'domain' => 'acme.localhost',
|
||||||
|
]);
|
||||||
|
|
||||||
|
pest()->get('http://acme.localhost/foo')->assertStatus(200);
|
||||||
|
|
||||||
|
Artisan::call('tenants:down');
|
||||||
|
|
||||||
|
tenancy()->end(); // End tenancy before making a request
|
||||||
|
pest()->get('http://acme.localhost/foo')->assertStatus(503);
|
||||||
|
|
||||||
|
Artisan::call('tenants:up');
|
||||||
|
|
||||||
|
tenancy()->end(); // End tenancy before making a request
|
||||||
|
pest()->get('http://acme.localhost/foo')->assertStatus(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
class MaintenanceTenant extends Tenant
|
class MaintenanceTenant extends Tenant
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue