Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117750098
D4752.1775181844.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
24 KB
Referenced Files
None
Subscribers
None
D4752.1775181844.diff
View Options
diff --git a/src/app/Console/Command.php b/src/app/Console/Command.php
--- a/src/app/Console/Command.php
+++ b/src/app/Console/Command.php
@@ -29,6 +29,12 @@
*/
protected $dangerous = false;
+ /**
+ * Tenant context for the command
+ *
+ * @var ?int
+ */
+ protected $tenantId;
/**
* Apply current tenant context to the query
@@ -43,21 +49,26 @@
return $object;
}
+ if (!$this->tenantId) {
+ return $object;
+ }
+
$modelsWithOwner = [
\App\Wallet::class,
];
- $tenantId = \config('app.tenant_id');
-
// Add tenant filter
if (in_array(\App\Traits\BelongsToTenantTrait::class, class_uses($object::class))) {
- $object = $object->withEnvTenantContext();
+ $context = new \App\User();
+ $context->tenant_id = $this->tenantId;
+
+ $object = $object->withObjectTenantContext($context);
} elseif (in_array($object::class, $modelsWithOwner)) {
- $object = $object->whereExists(function ($query) use ($tenantId) {
+ $object = $object->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('users')
->whereRaw('wallets.user_id = users.id')
- ->whereRaw('users.tenant_id ' . ($tenantId ? "= $tenantId" : 'is null'));
+ ->whereRaw("users.tenant_id = {$this->tenantId}");
});
}
@@ -138,6 +149,10 @@
->where($objectTitle, $objectIdOrTitle)->first();
}
+ if (!$this->tenantId && $object && !empty($object->tenant_id)) {
+ $this->tenantId = $object->tenant_id;
+ }
+
return $object;
}
@@ -227,13 +242,11 @@
if (!$confirmation) {
$this->info("Better safe than sorry.");
- return false;
+ exit(0);
}
$this->info("Vámonos!");
}
-
- return true;
}
/**
diff --git a/src/app/Console/Commands/Data/Import/LdifCommand.php b/src/app/Console/Commands/Data/Import/LdifCommand.php
--- a/src/app/Console/Commands/Data/Import/LdifCommand.php
+++ b/src/app/Console/Commands/Data/Import/LdifCommand.php
@@ -14,7 +14,7 @@
*
* @var string
*/
- protected $signature = 'data:import:ldif {file} {owner} {--force}';
+ protected $signature = 'data:import:ldif {file} {owner} {--force} {--tenant=}';
/**
* The console command description.
@@ -49,6 +49,16 @@
*/
public function handle()
{
+ if ($tenantId = $this->option('tenant')) {
+ $tenant = $this->getObject(\App\Tenant::class, $tenantId, 'title');
+ if (!$tenant) {
+ $this->error("Tenant {$tenantId} not found");
+ return 1;
+ }
+
+ $this->tenantId = $tenant->id;
+ }
+
ini_set("memory_limit", "2048M");
// (Re-)create temporary table
@@ -207,10 +217,11 @@
continue;
}
- $domain = \App\Domain::create([
- 'namespace' => $data->namespace,
- 'type' => \App\Domain::TYPE_EXTERNAL,
- ]);
+ $domain = new \App\Domain();
+ $domain->namespace = $data->namespace;
+ $domain->type = \App\Domain::TYPE_EXTERNAL;
+ $domain->tenant_id = $this->tenantId;
+ $domain->save();
// Entitlements
$domain->assignPackageAndWallet($this->packages['domain'], $this->wallet);
@@ -227,10 +238,11 @@
continue;
}
- $domain = \App\Domain::create([
- 'namespace' => $alias,
- 'type' => \App\Domain::TYPE_EXTERNAL,
- ]);
+ $domain = new \App\Domain();
+ $domain->namespace = $alias;
+ $domain->type = \App\Domain::TYPE_EXTERNAL;
+ $domain->tenant_id = $this->tenantId;
+ $domain->save();
// Entitlements
$domain->assignPackageAndWallet($this->packages['domain'], $this->wallet);
@@ -280,11 +292,12 @@
continue;
}
- $group = \App\Group::create([
- 'name' => $data->name,
- 'email' => $data->email,
- 'members' => $members,
- ]);
+ $group = new \App\Group();
+ $group->name = $data->name;
+ $group->email = $data->email;
+ $group->members = $members;
+ $group->tenant_id = $this->tenantId;
+ $group->save();
$group->assignToWallet($this->wallet);
@@ -344,6 +357,7 @@
$resource = new \App\Resource();
$resource->name = $data->name;
$resource->domainName = $data->domain;
+ $resource->tenant_id = $this->tenantId;
$resource->save();
$resource->assignToWallet($this->wallet);
@@ -398,6 +412,7 @@
$folder->name = $data->name;
$folder->type = $data->type ?? 'mail';
$folder->domainName = $data->domain;
+ $folder->tenant_id = $this->tenantId;
$folder->save();
$folder->assignToWallet($this->wallet);
@@ -940,30 +955,30 @@
protected function preparePackagesAndSkus(): void
{
// Find the tenant
- if (empty($this->ownerDN)) {
- if ($user = $this->getUser($this->argument('owner'))) {
- $tenant_id = $user->tenant_id;
+ if (empty($this->tenantId)) {
+ if (empty($this->ownerDN)) {
+ if ($user = $this->getUser($this->argument('owner'))) {
+ $this->tenantId = $user->tenant_id;
+ }
}
- }
- // TODO: Tenant id could be a command option
-
- if (empty($tenant_id)) {
- $tenant_id = \config('app.tenant_id');
+ if (empty($this->tenantId)) {
+ $this->tenantId = \config('app.tenant_id');
+ }
}
// TODO: We should probably make package titles configurable with command options
$this->packages = [
- 'user' => \App\Package::where('title', 'kolab')->where('tenant_id', $tenant_id)->first(),
- 'domain' => \App\Package::where('title', 'domain-hosting')->where('tenant_id', $tenant_id)->first(),
+ 'user' => \App\Package::where('title', 'kolab')->where('tenant_id', $this->tenantId)->first(),
+ 'domain' => \App\Package::where('title', 'domain-hosting')->where('tenant_id', $this->tenantId)->first(),
];
// Count storage skus
$sku = $this->packages['user']->skus()->where('title', 'storage')->first();
$this->packages['quota'] = $sku ? $sku->pivot->qty : 0;
- $this->packages['storage'] = \App\Sku::where('title', 'storage')->where('tenant_id', $tenant_id)->first();
+ $this->packages['storage'] = \App\Sku::where('title', 'storage')->where('tenant_id', $this->tenantId)->first();
}
/**
diff --git a/src/app/Console/Commands/Domain/CreateCommand.php b/src/app/Console/Commands/Domain/CreateCommand.php
--- a/src/app/Console/Commands/Domain/CreateCommand.php
+++ b/src/app/Console/Commands/Domain/CreateCommand.php
@@ -3,6 +3,9 @@
namespace App\Console\Commands\Domain;
use App\Console\Command;
+use App\Domain;
+use App\Entitlement;
+use App\Tenant;
class CreateCommand extends Command
{
@@ -11,7 +14,7 @@
*
* @var string
*/
- protected $signature = 'domain:create {domain} {--force}';
+ protected $signature = 'domain:create {domain} {--force} {--tenant=}';
/**
* The console command description.
@@ -30,7 +33,7 @@
$namespace = \strtolower($this->argument('domain'));
// must use withTrashed(), because unique constraint
- $domain = \App\Domain::withTrashed()->where('namespace', $namespace)->first();
+ $domain = Domain::withTrashed()->where('namespace', $namespace)->first();
if ($domain && !$this->option('force')) {
$this->error("Domain {$namespace} already exists.");
@@ -40,14 +43,14 @@
if ($domain) {
if ($domain->trashed()) {
// set the status back to new
- $domain->status = \App\Domain::STATUS_NEW;
+ $domain->status = Domain::STATUS_NEW;
$domain->save();
// remove existing entitlement
- $entitlement = \App\Entitlement::withTrashed()->where(
+ $entitlement = Entitlement::withTrashed()->where(
[
'entitleable_id' => $domain->id,
- 'entitleable_type' => \App\Domain::class
+ 'entitleable_type' => Domain::class
]
)->first();
@@ -70,12 +73,19 @@
return 1;
}
} else {
- $domain = \App\Domain::create(
- [
- 'namespace' => $namespace,
- 'type' => \App\Domain::TYPE_EXTERNAL,
- ]
- );
+ if ($tenantId = $this->option('tenant')) {
+ $tenant = $this->getObject(Tenant::class, $tenantId, 'title');
+ if (!$tenant) {
+ $this->error("Tenant {$tenantId} not found");
+ return 1;
+ }
+ }
+
+ $domain = new Domain();
+ $domain->namespace = $namespace;
+ $domain->type = Domain::TYPE_EXTERNAL;
+ $domain->tenant_id = !empty($tenant) ? $tenant->id : null;
+ $domain->save();
$this->info(
sprintf(
diff --git a/src/app/Console/Commands/Group/CreateCommand.php b/src/app/Console/Commands/Group/CreateCommand.php
--- a/src/app/Console/Commands/Group/CreateCommand.php
+++ b/src/app/Console/Commands/Group/CreateCommand.php
@@ -78,6 +78,7 @@
$group = new Group();
$group->email = $email;
$group->members = $members;
+ $group->tenant_id = $domain->tenant_id;
$group->save();
$group->assignToWallet($owner->wallets->first());
diff --git a/src/app/Console/Commands/Meet/RoomCreate.php b/src/app/Console/Commands/Meet/RoomCreate.php
--- a/src/app/Console/Commands/Meet/RoomCreate.php
+++ b/src/app/Console/Commands/Meet/RoomCreate.php
@@ -3,6 +3,7 @@
namespace App\Console\Commands\Meet;
use App\Console\Command;
+use App\Meet\Room;
class RoomCreate extends Command
{
@@ -40,16 +41,17 @@
return 1;
}
- $room = \App\Meet\Room::where('name', $roomName)->first();
+ $room = Room::where('name', $roomName)->first();
if ($room) {
$this->error("Room already exists.");
return 1;
}
- $room = \App\Meet\Room::create([
- 'name' => $roomName,
- ]);
+ $room = new Room();
+ $room->name = $roomName;
+ $room->tenant_id = $user->tenant_id;
+ $room->save();
$room->assignToWallet($user->wallets()->first());
}
diff --git a/src/app/Console/Commands/Scalpel/Entitlement/CreateCommand.php b/src/app/Console/Commands/Scalpel/Entitlement/CreateCommand.php
--- a/src/app/Console/Commands/Scalpel/Entitlement/CreateCommand.php
+++ b/src/app/Console/Commands/Scalpel/Entitlement/CreateCommand.php
@@ -29,6 +29,7 @@
if (!array_key_exists('entitleable_id', $this->properties)) {
$this->error("Specify --entitleable_id");
+ return 1;
}
if (array_key_exists('sku_id', $this->properties)) {
@@ -39,7 +40,7 @@
return 1;
}
- if ($this->properties['cost'] == null) {
+ if ($this->properties['cost'] === null) {
$this->properties['cost'] = $sku->cost;
}
}
diff --git a/src/app/Console/Commands/SharedFolder/CreateCommand.php b/src/app/Console/Commands/SharedFolder/CreateCommand.php
--- a/src/app/Console/Commands/SharedFolder/CreateCommand.php
+++ b/src/app/Console/Commands/SharedFolder/CreateCommand.php
@@ -80,6 +80,7 @@
$folder->name = $name;
$folder->type = $type;
$folder->domainName = $domainName;
+ $folder->tenant_id = $domain->tenant_id;
$folder->save();
$folder->assignToWallet($owner->wallets->first());
diff --git a/src/app/Console/Commands/User/CreateCommand.php b/src/app/Console/Commands/User/CreateCommand.php
--- a/src/app/Console/Commands/User/CreateCommand.php
+++ b/src/app/Console/Commands/User/CreateCommand.php
@@ -33,7 +33,7 @@
{
$email = $this->argument('email');
$packages = $this->option('package');
- $password = $this->option('password');
+ $password = $this->option('password') ?: \App\Utils::generatePassphrase();
$role = $this->option('role');
$existingDeletedUser = null;
@@ -61,6 +61,9 @@
$owner = $domain->wallet()->owner;
}
+ // Tenant context for the getObject() call below, and for the new user
+ $this->tenantId = $domain->tenant_id;
+
foreach ($packages as $package) {
$userPackage = $this->getObject(\App\Package::class, $package, 'title', false);
if (!$userPackage) {
@@ -71,15 +74,12 @@
}
}
- if (!$password) {
- $password = \App\Utils::generatePassphrase();
- }
-
try {
$user = new \App\User();
$user->email = $email;
$user->password = $password;
$user->role = $role;
+ $user->tenant_id = $this->tenantId;
} catch (\Exception $e) {
$this->error($e->getMessage());
return 1;
diff --git a/src/app/Console/ObjectCommand.php b/src/app/Console/ObjectCommand.php
--- a/src/app/Console/ObjectCommand.php
+++ b/src/app/Console/ObjectCommand.php
@@ -42,12 +42,4 @@
* @var string
*/
protected $objectTitle;
-
- /**
- * Placeholder for column name attributes for objects, from which command-line switches and attribute names can be
- * generated.
- *
- * @var array
- */
- protected $properties;
}
diff --git a/src/app/Console/ObjectCreateCommand.php b/src/app/Console/ObjectCreateCommand.php
--- a/src/app/Console/ObjectCreateCommand.php
+++ b/src/app/Console/ObjectCreateCommand.php
@@ -7,6 +7,9 @@
*/
abstract class ObjectCreateCommand extends ObjectCommand
{
+ /** @var ?array Object properties */
+ protected $properties;
+
public function __construct()
{
$this->description = "Create a {$this->objectName}";
@@ -16,26 +19,43 @@
$this->objectName
);
- $class = new $this->objectClass();
-
- foreach ($class->getFillable() as $fillable) {
+ foreach ($this->getClassProperties() as $fillable) {
$this->signature .= " {--{$fillable}=}";
}
parent::__construct();
}
- protected function getProperties()
+ /**
+ * Return list of fillable properties for the specified object type
+ */
+ protected function getClassProperties(): array
{
- if (!empty($this->properties)) {
- return $this->properties;
+ $class = new $this->objectClass();
+
+ $properties = $class->getFillable();
+
+ if ($this->commandPrefix == 'scalpel'
+ && in_array(\App\Traits\BelongsToTenantTrait::class, class_uses($this->objectClass))
+ ) {
+ $properties[] = 'tenant_id';
}
- $class = new $this->objectClass();
+ return $properties;
+ }
+
+ /**
+ * Return object properties from the input
+ */
+ protected function getProperties(): array
+ {
+ if (is_array($this->properties)) {
+ return $this->properties;
+ }
$this->properties = [];
- foreach ($class->getFillable() as $fillable) {
+ foreach ($this->getClassProperties() as $fillable) {
$this->properties[$fillable] = $this->option($fillable);
}
@@ -47,12 +67,19 @@
*/
public function handle()
{
- $object = $this->objectClass::create($this->getProperties());
+ $object = new $this->objectClass();
+
+ try {
+ foreach ($this->getProperties() as $name => $value) {
+ $object->{$name} = $value;
+ }
+
+ $object->save();
- if ($object) {
$this->info($object->{$object->getKeyName()});
- } else {
+ } catch (\Exception $e) {
$this->error("Object could not be created.");
+ return 1;
}
}
}
diff --git a/src/app/Console/ObjectDeleteCommand.php b/src/app/Console/ObjectDeleteCommand.php
--- a/src/app/Console/ObjectDeleteCommand.php
+++ b/src/app/Console/ObjectDeleteCommand.php
@@ -31,11 +31,7 @@
*/
public function handle()
{
- $result = parent::handle();
-
- if (!$result) {
- return 1;
- }
+ parent::handle();
$argument = $this->argument($this->objectName);
diff --git a/src/app/Console/ObjectListCommand.php b/src/app/Console/ObjectListCommand.php
--- a/src/app/Console/ObjectListCommand.php
+++ b/src/app/Console/ObjectListCommand.php
@@ -20,6 +20,10 @@
$this->signature .= "{$this->objectName}s";
}
+ if (in_array(\App\Traits\BelongsToTenantTrait::class, class_uses($this->objectClass))) {
+ $this->signature .= " {--tenant= : Limit results to the specified tenant}";
+ }
+
if ($this->isSoftDeletable($this->objectClass)) {
$this->signature .= " {--with-deleted : Include deleted {$this->objectName}s}";
}
@@ -43,7 +47,11 @@
$objects = new $this->objectClass();
}
- $objects = $this->applyTenant($objects);
+ // @phpstan-ignore-next-line
+ if ($this->hasOption('tenant') && ($tenant = intval($this->option('tenant')))) {
+ $this->tenantId = $tenant;
+ $objects = $this->applyTenant($objects);
+ }
foreach ($this->option('filter') as $filter) {
$objects = $this->applyFilter($objects, $filter);
diff --git a/src/app/Console/ObjectUpdateCommand.php b/src/app/Console/ObjectUpdateCommand.php
--- a/src/app/Console/ObjectUpdateCommand.php
+++ b/src/app/Console/ObjectUpdateCommand.php
@@ -7,6 +7,9 @@
*/
abstract class ObjectUpdateCommand extends ObjectCommand
{
+ /** @var ?array Object properties */
+ protected $properties;
+
public function __construct()
{
$this->description = "Update a {$this->objectName}";
@@ -77,14 +80,15 @@
return $list;
}
- public function getProperties()
+ /**
+ * Get object properties from the input
+ */
+ public function getProperties(): array
{
- if (!empty($this->properties)) {
+ if (is_array($this->properties)) {
return $this->properties;
}
- $class = new $this->objectClass();
-
$this->properties = [];
foreach ($this->getClassProperties() as $property) {
diff --git a/src/app/Traits/BelongsToTenantTrait.php b/src/app/Traits/BelongsToTenantTrait.php
--- a/src/app/Traits/BelongsToTenantTrait.php
+++ b/src/app/Traits/BelongsToTenantTrait.php
@@ -10,7 +10,9 @@
protected static function bootBelongsToTenantTrait()
{
static::creating(function ($model) {
- $model->tenant_id = \config('app.tenant_id');
+ if (empty($model->tenant_id)) {
+ $model->tenant_id = \config('app.tenant_id');
+ }
});
}
diff --git a/src/tests/Feature/Console/Domain/CreateTest.php b/src/tests/Feature/Console/Domain/CreateTest.php
--- a/src/tests/Feature/Console/Domain/CreateTest.php
+++ b/src/tests/Feature/Console/Domain/CreateTest.php
@@ -82,5 +82,18 @@
$this->assertTrue($domain->isNew());
$this->assertFalse($domain->isActive());
$this->assertFalse($domain->trashed());
+
+ $this->deleteTestDomain('domain-delete.com');
+
+ // Test --tenant option
+ $tenant = \App\Tenant::orderBy('id', 'desc')->first();
+ $code = \Artisan::call("domain:create domain-delete.com --tenant={$tenant->id}");
+ $output = trim(\Artisan::output());
+ $this->assertSame(0, $code);
+
+ $domain = \App\Domain::where('namespace', 'domain-delete.com')->first();
+
+ $this->assertTrue($domain->isNew());
+ $this->assertSame($tenant->id, $domain->tenant_id);
}
}
diff --git a/src/tests/Feature/Console/DomainsTest.php b/src/tests/Feature/Console/DomainsTest.php
--- a/src/tests/Feature/Console/DomainsTest.php
+++ b/src/tests/Feature/Console/DomainsTest.php
@@ -11,18 +11,27 @@
*/
public function testHandle(): void
{
- $domain = \App\Domain::where('namespace', 'kolab.org')->first();
+ $domain1 = \App\Domain::where('namespace', 'kolab.org')->first();
+ $domain2 = \App\Domain::whereNot('tenant_id', $domain1->tenant_id)->first();
- // Existing domain
- $code = \Artisan::call("domains");
+ // List domains for a specified tenant
+ $code = \Artisan::call("domains --tenant={$domain1->tenant_id}");
$output = trim(\Artisan::output());
+
$this->assertSame(0, $code);
+ $this->assertStringContainsString((string) $domain1->id, $output);
+ $this->assertStringNotContainsString((string) $domain2->id, $output);
+
+ // List domains of all tenants
+ $code = \Artisan::call("domains");
+ $output = trim(\Artisan::output());
- $this->assertTrue(strpos($output, (string) $domain->id) !== false);
+ $this->assertSame(0, $code);
+ $this->assertStringContainsString((string) $domain1->id, $output);
+ $this->assertStringContainsString((string) $domain2->id, $output);
- // TODO: Test --deleted argument
+ // TODO: Test --with-deleted argument
// TODO: Test output format and other attributes
- // TODO: Test tenant context
$this->markTestIncomplete();
}
}
diff --git a/src/tests/Feature/Console/Scalpel/Domain/CreateCommandTest.php b/src/tests/Feature/Console/Scalpel/Domain/CreateCommandTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Feature/Console/Scalpel/Domain/CreateCommandTest.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Tests\Feature\Console\Scalpel\Domain;
+
+use App\Domain;
+use Tests\TestCase;
+
+class CreateCommandTest extends TestCase
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->deleteTestDomain('domain-delete.com');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ $this->deleteTestDomain('domain-delete.com');
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test the command execution
+ */
+ public function testHandle(): void
+ {
+ // Test --help argument
+ $code = \Artisan::call("scalpel:domain:create --help");
+ $output = trim(\Artisan::output());
+
+ $this->assertSame(0, $code);
+ $this->assertStringContainsString('--namespace[=NAMESPACE]', $output);
+ $this->assertStringContainsString('--type[=TYPE]', $output);
+ $this->assertStringContainsString('--status[=STATUS]', $output);
+ $this->assertStringContainsString('--tenant_id[=TENANT_ID]', $output);
+
+ $tenant = \App\Tenant::orderBy('id', 'desc')->first();
+
+ // Test successful domain creation
+ $code = \Artisan::call("scalpel:domain:create"
+ . " --namespace=domain-delete.com"
+ . " --type=" . Domain::TYPE_PUBLIC
+ . " --tenant_id={$tenant->id}"
+ );
+
+ $output = trim(\Artisan::output());
+
+ $domain = $this->getTestDomain('domain-delete.com');
+
+ $this->assertSame(0, $code);
+ $this->assertSame($output, (string) $domain->id);
+ $this->assertSame('domain-delete.com', $domain->namespace);
+ $this->assertSame(Domain::TYPE_PUBLIC, $domain->type);
+ $this->assertSame($domain->tenant_id, $tenant->id);
+ }
+}
diff --git a/src/tests/Feature/Console/Scalpel/Domain/UpdateCommandTest.php b/src/tests/Feature/Console/Scalpel/Domain/UpdateCommandTest.php
--- a/src/tests/Feature/Console/Scalpel/Domain/UpdateCommandTest.php
+++ b/src/tests/Feature/Console/Scalpel/Domain/UpdateCommandTest.php
@@ -15,6 +15,7 @@
parent::setUp();
$this->deleteTestDomain('domain-delete.com');
+ $this->deleteTestDomain('domain-delete-mod.com');
}
/**
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 2:04 AM (1 d, 21 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18818883
Default Alt Text
D4752.1775181844.diff (24 KB)
Attached To
Mode
D4752: Make CLI commands tenant independent
Attached
Detach File
Event Timeline