Page MenuHomePhorge

D2918.1775203532.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D2918.1775203532.diff

diff --git a/src/app/Console/Commands/OwnerSwapCommand.php b/src/app/Console/Commands/OwnerSwapCommand.php
new file mode 100644
--- /dev/null
+++ b/src/app/Console/Commands/OwnerSwapCommand.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Console\Command;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Queue;
+
+class OwnerSwapCommand extends Command
+{
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'owner:swap {current-user} {target-user}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Swap account owner (to another user)';
+
+ /**
+ * Execute the console command.
+ *
+ * @return mixed
+ */
+ public function handle()
+ {
+ if ($this->argument('current-user') == $this->argument('target-user')) {
+ $this->error('Users cannot be the same.');
+ return 1;
+ }
+
+ $user = $this->getUser($this->argument('current-user'));
+
+ if (!$user) {
+ $this->error('User not found.');
+ return 1;
+ }
+
+ $target = $this->getUser($this->argument('target-user'));
+
+ if (!$target) {
+ $this->error('User not found.');
+ return 1;
+ }
+
+ $wallet = $user->wallets->first();
+ $target_wallet = $target->wallets->first();
+
+ if ($wallet->id != $target->wallet()->id) {
+ $this->error('The target user does not belong to the same account.');
+ return 1;
+ }
+
+ Queue::fake();
+
+ DB::beginTransaction();
+
+ // Switch wallet for existing entitlements
+ $wallet->entitlements()->withTrashed()->update(['wallet_id' => $target_wallet->id]);
+
+ // Update target user created_at
+ $dt = \now()->subMonthsWithoutOverflow(1);
+ if ($target->created_at >= $dt) {
+ $target->created_at = $dt;
+ $target->save();
+ }
+
+ // Migrate wallet properties
+ $target_wallet->balance = $wallet->balance;
+ $target_wallet->currency = $wallet->currency;
+ $target_wallet->save();
+
+ $wallet->balance = 0;
+ $wallet->save();
+
+ // Migrate wallet settings
+ $settings = $wallet->settings()->get();
+
+ \App\WalletSetting::where('wallet_id', $wallet->id)->delete();
+ \App\WalletSetting::where('wallet_id', $target_wallet->id)->delete();
+
+ foreach ($settings as $setting) {
+ $target_wallet->setSetting($setting->key, $setting->value);
+ }
+
+ // TODO: Update mollie/stripe customer email (which contains the old wallet id)
+
+ DB::commit();
+ }
+}
diff --git a/src/tests/Feature/Console/OwnerSwapTest.php b/src/tests/Feature/Console/OwnerSwapTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Feature/Console/OwnerSwapTest.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Tests\Feature\Console;
+
+use Illuminate\Support\Facades\Queue;
+use Tests\TestCase;
+
+class OwnerSwapTest extends TestCase
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->deleteTestUser('user1@owner-swap.com');
+ $this->deleteTestUser('user2@owner-swap.com');
+ $this->deleteTestDomain('owner-swap.com');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('user1@owner-swap.com');
+ $this->deleteTestUser('user2@owner-swap.com');
+ $this->deleteTestDomain('owner-swap.com');
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test the command
+ */
+ public function testHandle(): void
+ {
+ Queue::fake();
+
+ // Create some sample account
+ $owner = $this->getTestUser('user1@owner-swap.com');
+ $user = $this->getTestUser('user2@owner-swap.com');
+ $domain = $this->getTestDomain('owner-swap.com', [
+ 'status' => \App\Domain::STATUS_NEW,
+ 'type' => \App\Domain::TYPE_HOSTED,
+ ]);
+ $package_kolab = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first();
+ $package_domain = \App\Package::withEnvTenantContext()->where('title', 'domain-hosting')->first();
+ $owner->assignPackage($package_kolab);
+ $owner->assignPackage($package_kolab, $user);
+ $domain->assignPackage($package_domain, $owner);
+ $wallet = $owner->wallets()->first();
+ $wallet->currency = 'USD';
+ $wallet->balance = 100;
+ $wallet->save();
+ $wallet->setSetting('test', 'test');
+ $target_wallet = $user->wallets()->first();
+
+ $entitlements = $wallet->entitlements()->orderBy('id')->pluck('id')->all();
+ $this->assertCount(15, $entitlements);
+ $this->assertSame(0, $target_wallet->entitlements()->count());
+
+ // Non-existing target user
+ $code = \Artisan::call("owner:swap user1@owner-swap.com unknown@unknown.org");
+ $output = trim(\Artisan::output());
+ $this->assertSame(1, $code);
+ $this->assertSame("User not found.", $output);
+
+ // The same user
+ $code = \Artisan::call("owner:swap user1@owner-swap.com user1@owner-swap.com");
+ $output = trim(\Artisan::output());
+ $this->assertSame(1, $code);
+ $this->assertSame("Users cannot be the same.", $output);
+
+ // Success
+ $code = \Artisan::call("owner:swap user1@owner-swap.com user2@owner-swap.com");
+ $output = trim(\Artisan::output());
+ $this->assertSame(0, $code);
+ $this->assertSame("", $output);
+
+ $user->refresh();
+ $target_wallet->refresh();
+ $target_entitlements = $target_wallet->entitlements()->orderBy('id')->pluck('id')->all();
+
+ $this->assertSame($target_entitlements, $entitlements);
+ $this->assertSame(0, $wallet->entitlements()->count());
+ $this->assertSame($wallet->balance, $target_wallet->balance);
+ $this->assertSame($wallet->currency, $target_wallet->currency);
+ $this->assertTrue($user->created_at <= \now()->subMonthsWithoutOverflow(1));
+ $this->assertSame('test', $target_wallet->getSetting('test'));
+
+ $wallet->refresh();
+ $this->assertSame(null, $wallet->getSetting('test'));
+ $this->assertSame(0, $wallet->balance);
+
+ // TODO: Test case when the target user does not belong to the same account
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 8:05 AM (1 d, 15 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18823132
Default Alt Text
D2918.1775203532.diff (6 KB)

Event Timeline