1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-03-20 06:39:38 +01:00

Properly migrate existing API tokens, adjust register user command

This commit is contained in:
Kovah 2022-07-20 10:39:39 +02:00
parent 2dd2810a30
commit d37307785f
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
5 changed files with 106 additions and 39 deletions

View File

@ -3,43 +3,57 @@
namespace App\Console\Commands;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Settings\SetDefaultSettingsForUser;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Validation\ValidationException;
class RegisterUserCommand extends Command
{
protected $signature = 'registeruser {name? : Username} {email? : User email address}';
protected $description = 'Register a new user with a given user name and an email address.';
private ?string $userName;
private ?string $userEmail;
private ?string $userPassword;
private bool $validationFailed = false;
public function handle(): void
{
$name = $this->argument('name');
$email = $this->argument('email');
$this->userName = $this->argument('name');
$this->userEmail = $this->argument('email');
if (empty($name)) {
$name = $this->ask('Please enter the user name');
do {
$this->askForUserDetails();
try {
(new CreateNewUser)->create([
'name' => $this->userName,
'email' => $this->userEmail,
'password' => $this->userPassword,
'password_confirmation' => $this->userPassword,
]);
$this->validationFailed = false;
} catch (ValidationException $e) {
$this->validationFailed = true;
foreach ($e->errors() as $error) {
$this->error(implode(' ', $error));
}
}
} while ($this->validationFailed);
$this->info('User ' . $this->userName . ' registered.');
}
protected function askForUserDetails(): void
{
if (empty($this->userName) || $this->validationFailed) {
$this->userName = $this->ask('Please enter the user name containing only alpha-numeric characters, dashes or underscores', $this->userName);
}
if (empty($email)) {
$email = $this->ask('Please enter the user email address');
if (empty($this->userEmail) || $this->validationFailed) {
$this->userEmail = $this->ask('Please enter the user email address', $this->userEmail);
}
// Check if the user exists
if (User::where('email', $email)->first()) {
$this->error('An user with the email address "' . $email . '" already exists!');
return;
}
$password = $this->secret('Please enter a password for ' . $name);
(new CreateNewUser)->create([
'name' => $name,
'email' => $email,
'password' => $password,
'password_confirmation' => $password,
]);
$this->info('User ' . $name . ' registered.');
$this->userPassword = $this->secret('Please enter a password for ' . $this->userName);
}
}

View File

@ -22,7 +22,6 @@ use Spatie\Permission\Traits\HasRoles;
* @property string $email
* @property string $password
* @property string|null $remember_token
* @property string|null $api_token
* @property string|null $two_factor_recovery_codes
* @property string|null $two_factor_secret
* @property Carbon|null $created_at
@ -42,14 +41,12 @@ class User extends Authenticatable implements Auditable
'name',
'email',
'password',
'api_token',
'blocked_at',
];
protected $hidden = [
'password',
'remember_token',
'api_token',
];
protected $casts = [

View File

@ -1,5 +1,6 @@
<?php
use App\Enums\ApiToken;
use App\Enums\ModelAttribute;
use App\Enums\Role;
use App\Models\LinkList;
@ -8,11 +9,12 @@ use App\Models\Tag;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
class MigrateUserData extends Migration
{
private bool $guestAccessEnabled;
private bool $guestAccessEnabled = false;
public function up()
{
@ -24,6 +26,7 @@ class MigrateUserData extends Migration
$this->migrateNoteVisibility();
$this->addUserRoles();
$this->migrateApiTokens();
}
protected function migrateLinkVisibility(): void
@ -54,7 +57,7 @@ class MigrateUserData extends Migration
$table->integer('visibility')->default(ModelAttribute::VISIBILITY_PRIVATE)->after('is_private');
});
LinkList::withTrashed()->get()->each(function ($list) {
LinkList::withTrashed()->get()->each(function (LinkList $list) {
$list->visibility = match ((bool)$list->is_private) {
true => ModelAttribute::VISIBILITY_PRIVATE,
false => $this->guestAccessEnabled
@ -74,7 +77,7 @@ class MigrateUserData extends Migration
$table->integer('visibility')->default(ModelAttribute::VISIBILITY_PRIVATE)->after('is_private');
});
Tag::withTrashed()->get()->each(function ($tag) {
Tag::withTrashed()->get()->each(function (Tag $tag) {
$tag->visibility = match ((bool)$tag->is_private) {
true => ModelAttribute::VISIBILITY_PRIVATE,
false => $this->guestAccessEnabled
@ -94,7 +97,7 @@ class MigrateUserData extends Migration
$table->integer('visibility')->default(ModelAttribute::VISIBILITY_PRIVATE)->after('is_private');
});
Note::withTrashed()->get()->each(function ($note) {
Note::withTrashed()->get()->each(function (Note $note) {
$note->visibility = match ((bool)$note->is_private) {
true => ModelAttribute::VISIBILITY_PRIVATE,
false => $this->guestAccessEnabled
@ -110,7 +113,7 @@ class MigrateUserData extends Migration
protected function addUserRoles(): void
{
\Illuminate\Support\Facades\Artisan::call('db:seed', ['--class' => 'RolesAndPermissionsSeeder']);
Artisan::call('db:seed', ['--class' => 'RolesAndPermissionsSeeder']);
Schema::table('users', function (Blueprint $table) {
$table->timestamp('blocked_at')->nullable()->after('api_token');
@ -122,4 +125,19 @@ class MigrateUserData extends Migration
$newAdmin->assignRole(Role::ADMIN);
}
}
public function migrateApiTokens(): void
{
User::all()->each(function (User $user) {
$user->tokens()->create([
'name' => 'MigratedApiToken',
'token' => hash('sha256', $user->api_token),
'abilities' => [ApiToken::ABILITY_USER_ACCESS],
]);
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('api_token');
});
}
}

View File

@ -3,7 +3,6 @@
namespace Tests\Commands;
use App\Models\User;
use App\Settings\SettingsAudit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
@ -25,8 +24,6 @@ class RegisterUserCommandTest extends TestCase
$databaseUser = User::latest('id')->first();
//var_dump(User::all());
$this->assertEquals('Test', $databaseUser->name);
$this->assertEquals('test@linkace.org', $databaseUser->email);
}
@ -36,7 +33,7 @@ class RegisterUserCommandTest extends TestCase
User::factory()->create(); // Create admin dummy user
$this->artisan('registeruser')
->expectsQuestion('Please enter the user name', 'Test')
->expectsQuestion('Please enter the user name containing only alpha-numeric characters, dashes or underscores', 'Test')
->expectsQuestion('Please enter the user email address', 'test@linkace.org')
->expectsQuestion('Please enter a password for Test', 'testpassword')
->expectsOutput('User Test registered.')
@ -50,13 +47,20 @@ class RegisterUserCommandTest extends TestCase
public function testCommandWithDuplicateUser(): void
{
User::factory()->create(['email' => 'test@linkace.org']);
User::factory()->create(['name' => 'Test', 'email' => 'test@linkace.org']);
$this->artisan('registeruser', [
'name' => 'Test',
'email' => 'test@linkace.org',
])
->expectsOutput('An user with the email address "test@linkace.org" already exists!')
->assertExitCode(0);
->expectsQuestion('Please enter a password for Test', 'testpassword')
->expectsOutput('The name has already been taken.')
->expectsOutput('The email has already been taken.')
->expectsQuestion('Please enter the user name containing only alpha-numeric characters, dashes or underscores', 'Test2')
->expectsQuestion('Please enter the user email address', 'test2@linkace.org')
->expectsQuestion('Please enter a password for Test2', 'testpassword')
->expectsOutput('User Test2 registered.')
->assertExitCode(0)
;
}
}

View File

@ -6,7 +6,11 @@ use App\Models\Link;
use App\Models\LinkList;
use App\Models\Note;
use App\Models\Tag;
use App\Models\User;
use App\Settings\SystemSettings;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\Sanctum;
use Laravel\Sanctum\SanctumServiceProvider;
use Tests\TestCase;
class UserDataMigrationTest extends TestCase
@ -260,4 +264,34 @@ class UserDataMigrationTest extends TestCase
'visibility' => 1, // is public
]);
}
public function testUserApiTokenMigration(): void
{
$this->migrateUpTo('2022_06_23_112431_migrate_user_data.php');
DB::table('users')->insert([
'name' => 'test',
'email' => 'test@linkace.org',
'password' => 'test',
'api_token' => 'testApiToken',
'created_at' => now(),
'updated_at' => now(),
]);
$this->artisan('migrate');
$this->assertDatabaseHas('personal_access_tokens', [
'tokenable_type' => 'App\Models\User',
'tokenable_id' => '1',
'name' => 'MigratedApiToken',
'abilities' => '["user_access"]',
]);
// Test if the token is valid
Link::factory()->create(['url' => 'https://token-test.com']);
$this->get('links/feed', [
'Authorization' => 'Bearer testApiToken'
])->assertOk()->assertSee('https://token-test.com');
}
}