Page MenuHomePhorge

D5607.1775232020.diff
No OneTemporary

Authored By
Unknown
Size
12 KB
Referenced Files
None
Subscribers
None

D5607.1775232020.diff

diff --git a/src/app/Console/Commands/Data/Import/SignupTokensCommand.php b/src/app/Console/Commands/Data/Import/SignupTokensCommand.php
--- a/src/app/Console/Commands/Data/Import/SignupTokensCommand.php
+++ b/src/app/Console/Commands/Data/Import/SignupTokensCommand.php
@@ -14,7 +14,7 @@
*
* @var string
*/
- protected $signature = 'data:import:signup-tokens {plan} {file} {--tenant=}';
+ protected $signature = 'data:import:signup-tokens {file} {plan*} {--tenant=}';
/**
* The console command description.
@@ -35,16 +35,22 @@
{
parent::handle();
- $plan = $this->getObject(Plan::class, $this->argument('plan'), 'title', false);
+ $plans = [];
- if (!$plan) {
- $this->error("Plan not found");
- return 1;
- }
+ foreach ($this->argument('plan') as $p) {
+ $plan = $this->getObject(Plan::class, $p, 'title', false);
- if ($plan->mode != Plan::MODE_TOKEN) {
- $this->error("The plan is not for tokens");
- return 1;
+ if (!$plan) {
+ $this->error("Plan '{$p}' not found");
+ return 1;
+ }
+
+ if ($plan->mode != Plan::MODE_TOKEN) {
+ $this->error("Plan '{$p}' is not for tokens");
+ return 1;
+ }
+
+ $plans[] = $plan->id;
}
$file = $this->argument('file');
@@ -98,8 +104,9 @@
// Import tokens
foreach ($list as $token) {
- $plan->signupTokens()->create([
+ SignupToken::create([
'id' => $token,
+ 'plans' => $plans,
// This allows us to update counter when importing old tokens in migration.
// It can be removed later
'counter' => UserSetting::where('key', 'signup_token')
diff --git a/src/app/Plan.php b/src/app/Plan.php
--- a/src/app/Plan.php
+++ b/src/app/Plan.php
@@ -6,7 +6,6 @@
use App\Traits\UuidStrKeyTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
-use Illuminate\Database\Eloquent\Relations\HasMany;
use Spatie\Translatable\HasTranslations;
/**
@@ -135,14 +134,4 @@
return false;
}
-
- /**
- * The relationship to signup tokens.
- *
- * @return HasMany<SignupToken, $this>
- */
- public function signupTokens()
- {
- return $this->hasMany(SignupToken::class);
- }
}
diff --git a/src/app/Rules/SignupToken.php b/src/app/Rules/SignupToken.php
--- a/src/app/Rules/SignupToken.php
+++ b/src/app/Rules/SignupToken.php
@@ -3,6 +3,7 @@
namespace App\Rules;
use App\Plan;
+use App\SignupToken as Token;
use Illuminate\Contracts\Validation\Rule;
class SignupToken implements Rule
@@ -40,8 +41,9 @@
return false;
}
- // Check the token existence
- if (!$this->plan->signupTokens()->find($token)) {
+ // Check the token existence and its plan set
+ $signup_token = Token::find($token);
+ if (!$signup_token || !in_array($this->plan->id, $signup_token->plans)) {
$this->message = \trans('validation.signuptokeninvalid');
return false;
}
diff --git a/src/app/SignupToken.php b/src/app/SignupToken.php
--- a/src/app/SignupToken.php
+++ b/src/app/SignupToken.php
@@ -4,7 +4,6 @@
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* The eloquent definition of a SignupToken.
@@ -12,7 +11,7 @@
* @property Carbon $created_at The creation timestamp
* @property int $counter Count of signups on this token
* @property ?string $id Token
- * @property ?string $plan_id Plan identifier
+ * @property array $plans Plan identifiers
*/
class SignupToken extends Model
{
@@ -24,7 +23,7 @@
/** @var list<string> The attributes that are mass assignable */
protected $fillable = [
- 'plan_id',
+ 'plans',
'id',
'counter',
];
@@ -33,18 +32,9 @@
protected $casts = [
'created_at' => 'datetime:Y-m-d H:i:s',
'counter' => 'integer',
+ 'plans' => 'array',
];
/** @var bool Indicates if the model should be timestamped. */
public $timestamps = false;
-
- /**
- * The plan this token applies to
- *
- * @return BelongsTo<Plan, $this>
- */
- public function plan()
- {
- return $this->belongsTo(Plan::class);
- }
}
diff --git a/src/database/migrations/2025_09_15_100000_signup_tokens_plans.php b/src/database/migrations/2025_09_15_100000_signup_tokens_plans.php
new file mode 100644
--- /dev/null
+++ b/src/database/migrations/2025_09_15_100000_signup_tokens_plans.php
@@ -0,0 +1,57 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+ /**
+ * Run the migrations.
+ */
+ public function up(): void
+ {
+ Schema::table(
+ 'signup_tokens',
+ static function (Blueprint $table) {
+ $table->text('plans');
+ }
+ );
+
+ DB::table('signup_tokens')->update(['plans' => DB::raw("concat('[\"', `plan_id`, '\"]')")]);
+
+ Schema::table(
+ 'signup_tokens',
+ static function (Blueprint $table) {
+ $table->dropColumn('plan_id');
+ }
+ );
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table(
+ 'signup_tokens',
+ static function (Blueprint $table) {
+ $table->string('plan_id', 36);
+ }
+ );
+
+ DB::table('signup_tokens')->select('id', 'plans')->get()
+ ->each(static function ($token) {
+ $plan_id = json_decode($token->plans, true)[0];
+ DB::table('signup_tokens')->where('id', $token->id)->update(['plan_id' => $plan_id]);
+ });
+
+ Schema::table(
+ 'signup_tokens',
+ static function (Blueprint $table) {
+ $table->dropColumn('plans');
+ $table->index('plan_id');
+ }
+ );
+ }
+};
diff --git a/src/tests/Browser/SignupTest.php b/src/tests/Browser/SignupTest.php
--- a/src/tests/Browser/SignupTest.php
+++ b/src/tests/Browser/SignupTest.php
@@ -752,7 +752,7 @@
$plan->update(['mode' => Plan::MODE_TOKEN]);
// Register a valid token
- $plan->signupTokens()->create(['id' => '1234567890']);
+ SignupToken::create(['id' => '1234567890', 'plans' => [$plan->id]]);
$this->browse(static function (Browser $browser) {
$browser->visit(new Signup())
@@ -804,7 +804,7 @@
$plan->update(['mode' => Plan::MODE_TOKEN]);
// Register a valid token
- $plan->signupTokens()->create(['id' => 'abcdefghijk']);
+ SignupToken::create(['id' => 'abcdefghijk', 'plans' => [$plan->id]]);
$this->browse(static function (Browser $browser) {
$browser->visit(new Signup())
diff --git a/src/tests/Feature/Console/Data/Import/SignupTokensTest.php b/src/tests/Feature/Console/Data/Import/SignupTokensTest.php
--- a/src/tests/Feature/Console/Data/Import/SignupTokensTest.php
+++ b/src/tests/Feature/Console/Data/Import/SignupTokensTest.php
@@ -12,13 +12,15 @@
{
parent::setUp();
- Plan::where('title', 'test')->delete();
+ Plan::where('title', 'test1')->delete();
+ Plan::where('title', 'test2')->delete();
SignupToken::truncate();
}
protected function tearDown(): void
{
- Plan::where('title', 'test')->delete();
+ Plan::where('title', 'test1')->delete();
+ Plan::where('title', 'test2')->delete();
SignupToken::truncate();
@unlink(storage_path('test-tokens.txt'));
@@ -35,35 +37,42 @@
file_put_contents($file, '');
// Unknown plan
- $code = \Artisan::call("data:import:signup-tokens unknown {$file}");
+ $code = \Artisan::call("data:import:signup-tokens {$file} unknown");
$output = trim(\Artisan::output());
$this->assertSame(1, $code);
- $this->assertSame("Plan not found", $output);
+ $this->assertSame("Plan 'unknown' not found", $output);
// Plan not for tokens
- $code = \Artisan::call("data:import:signup-tokens individual {$file}");
+ $code = \Artisan::call("data:import:signup-tokens {$file} individual");
$output = trim(\Artisan::output());
$this->assertSame(1, $code);
- $this->assertSame("The plan is not for tokens", $output);
+ $this->assertSame("Plan 'individual' is not for tokens", $output);
- $plan = Plan::create([
- 'title' => 'test',
- 'name' => 'Test Account',
+ $plan1 = Plan::create([
+ 'title' => 'test1',
+ 'name' => 'Test Account 1',
+ 'description' => 'Test',
+ 'mode' => Plan::MODE_TOKEN,
+ ]);
+
+ $plan2 = Plan::create([
+ 'title' => 'test2',
+ 'name' => 'Test Account 2',
'description' => 'Test',
'mode' => Plan::MODE_TOKEN,
]);
// Non-existent input file
- $code = \Artisan::call("data:import:signup-tokens {$plan->title} nofile.txt");
+ $code = \Artisan::call("data:import:signup-tokens nofile.txt {$plan1->title}");
$output = trim(\Artisan::output());
$this->assertSame(1, $code);
$this->assertSame("File 'nofile.txt' does not exist", $output);
// Empty input file
- $code = \Artisan::call("data:import:signup-tokens {$plan->title} {$file}");
+ $code = \Artisan::call("data:import:signup-tokens {$file} {$plan1->title}");
$output = trim(\Artisan::output());
$this->assertSame(1, $code);
@@ -71,16 +80,21 @@
// Valid tokens
file_put_contents($file, "12345\r\nabcde");
- $code = \Artisan::call("data:import:signup-tokens {$plan->id} {$file}");
+ $code = \Artisan::call("data:import:signup-tokens {$file} {$plan1->id} {$plan2->title}");
$output = trim(\Artisan::output());
$this->assertSame(0, $code);
$this->assertStringContainsString("Validating tokens... DONE", $output);
$this->assertStringContainsString("Importing tokens... DONE", $output);
- $this->assertSame(['12345', 'ABCDE'], $plan->signupTokens()->orderBy('id')->pluck('id')->all());
+ $tokens = SignupToken::orderBy('id')->get();
+ $this->assertCount(2, $tokens);
+ $this->assertSame('12345', $tokens[0]->id);
+ $this->assertSame([$plan1->id, $plan2->id], $tokens[0]->plans);
+ $this->assertSame('ABCDE', $tokens[1]->id);
+ $this->assertSame([$plan1->id, $plan2->id], $tokens[1]->plans);
// Attempt the same tokens again
- $code = \Artisan::call("data:import:signup-tokens {$plan->id} {$file}");
+ $code = \Artisan::call("data:import:signup-tokens {$file} {$plan1->id}");
$output = trim(\Artisan::output());
$this->assertSame(0, $code);
diff --git a/src/tests/Feature/Controller/SignupTest.php b/src/tests/Feature/Controller/SignupTest.php
--- a/src/tests/Feature/Controller/SignupTest.php
+++ b/src/tests/Feature/Controller/SignupTest.php
@@ -1022,7 +1022,7 @@
$this->assertSame(['token' => ["The signup token is invalid."]], $json['errors']);
// Test valid token
- $plan->signupTokens()->create(['id' => 'abc']);
+ $token = SignupToken::create(['id' => 'abc', 'plans' => [$plan->id]]);
$post['plan'] = $plan->title;
$response = $this->post('/api/auth/signup', $post);
$response->assertStatus(200);
@@ -1036,11 +1036,11 @@
$user = User::where('email', 'test-inv@kolabnow.com')->first();
$this->assertNotEmpty($user);
$this->assertSame($plan->id, $user->getSetting('plan_id'));
- $this->assertSame($plan->signupTokens()->first()->id, $user->getSetting('signup_token'));
+ $this->assertSame($token->id, $user->getSetting('signup_token'));
$this->assertNull($user->getSetting('external_email'));
// Token's counter bumped up
- $this->assertSame(1, $plan->signupTokens()->first()->counter);
+ $this->assertSame(1, $token->fresh()->counter);
}
/**
diff --git a/src/tests/Unit/Rules/SignupTokenTest.php b/src/tests/Unit/Rules/SignupTokenTest.php
--- a/src/tests/Unit/Rules/SignupTokenTest.php
+++ b/src/tests/Unit/Rules/SignupTokenTest.php
@@ -41,8 +41,8 @@
'mode' => Plan::MODE_TOKEN,
]);
- $plan->signupTokens()->create(['id' => $tokens[0]]);
- $tokenPlan->signupTokens()->create(['id' => $tokens[1]]);
+ SignupToken::create(['id' => $tokens[0], 'plans' => [$plan->id]]);
+ SignupToken::create(['id' => $tokens[1], 'plans' => [$tokenPlan->id]]);
$rules = ['token' => [new SignupTokenRule(null)]];

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 4:00 PM (2 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18824615
Default Alt Text
D5607.1775232020.diff (12 KB)

Event Timeline