Page MenuHomePhorge

D4752.1775181844.diff
No OneTemporary

Authored By
Unknown
Size
24 KB
Referenced Files
None
Subscribers
None

D4752.1775181844.diff

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

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)

Event Timeline