diff --git a/app/Activity/Models/View.php b/app/Activity/Models/View.php index a6bc2139e..512e08295 100644 --- a/app/Activity/Models/View.php +++ b/app/Activity/Models/View.php @@ -54,12 +54,4 @@ class View extends Model return $view->views; } - - /** - * Clear all views from the system. - */ - public static function clearAll() - { - static::query()->truncate(); - } } diff --git a/app/Console/Commands/CleanupImages.php b/app/Console/Commands/CleanupImagesCommand.php similarity index 61% rename from app/Console/Commands/CleanupImages.php rename to app/Console/Commands/CleanupImagesCommand.php index 722150197..fe924b0f4 100644 --- a/app/Console/Commands/CleanupImages.php +++ b/app/Console/Commands/CleanupImagesCommand.php @@ -6,7 +6,7 @@ use BookStack\Uploads\ImageService; use Illuminate\Console\Command; use Symfony\Component\Console\Output\OutputInterface; -class CleanupImages extends Command +class CleanupImagesCommand extends Command { /** * The name and signature of the console command. @@ -25,60 +25,49 @@ class CleanupImages extends Command */ protected $description = 'Cleanup images and drawings'; - protected $imageService; - - /** - * Create a new command instance. - * - * @param \BookStack\Uploads\ImageService $imageService - */ - public function __construct(ImageService $imageService) - { - $this->imageService = $imageService; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(ImageService $imageService): int { - $checkRevisions = $this->option('all') ? false : true; - $dryRun = $this->option('force') ? false : true; + $checkRevisions = !$this->option('all'); + $dryRun = !$this->option('force'); if (!$dryRun) { - $proceed = $this->confirm("This operation is destructive and is not guaranteed to be fully accurate.\nEnsure you have a backup of your images.\nAre you sure you want to proceed?"); + $this->warn("This operation is destructive and is not guaranteed to be fully accurate.\nEnsure you have a backup of your images.\n"); + $proceed = $this->confirm("Are you sure you want to proceed?"); if (!$proceed) { - return; + return 0; } } - $deleted = $this->imageService->deleteUnusedImages($checkRevisions, $dryRun); + $deleted = $imageService->deleteUnusedImages($checkRevisions, $dryRun); $deleteCount = count($deleted); if ($dryRun) { - $this->comment('Dry run, No images have been deleted'); + $this->comment('Dry run, no images have been deleted'); $this->comment($deleteCount . ' images found that would have been deleted'); $this->showDeletedImages($deleted); $this->comment('Run with -f or --force to perform deletions'); - return; + return 0; } $this->showDeletedImages($deleted); $this->comment($deleteCount . ' images deleted'); + return 0; } - protected function showDeletedImages($paths) + protected function showDeletedImages($paths): void { if ($this->getOutput()->getVerbosity() <= OutputInterface::VERBOSITY_NORMAL) { return; } + if (count($paths) > 0) { $this->line('Images to delete:'); } + foreach ($paths as $path) { $this->line($path); } diff --git a/app/Console/Commands/ClearActivity.php b/app/Console/Commands/ClearActivityCommand.php similarity index 57% rename from app/Console/Commands/ClearActivity.php rename to app/Console/Commands/ClearActivityCommand.php index 5ccf6e972..54085c12b 100644 --- a/app/Console/Commands/ClearActivity.php +++ b/app/Console/Commands/ClearActivityCommand.php @@ -5,7 +5,7 @@ namespace BookStack\Console\Commands; use BookStack\Activity\Models\Activity; use Illuminate\Console\Command; -class ClearActivity extends Command +class ClearActivityCommand extends Command { /** * The name and signature of the console command. @@ -21,27 +21,13 @@ class ClearActivity extends Command */ protected $description = 'Clear user activity from the system'; - protected $activity; - - /** - * Create a new command instance. - * - * @param Activity $activity - */ - public function __construct(Activity $activity) - { - $this->activity = $activity; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): int { - $this->activity->newQuery()->truncate(); + Activity::query()->truncate(); $this->comment('System activity cleared'); + return 0; } } diff --git a/app/Console/Commands/ClearRevisions.php b/app/Console/Commands/ClearRevisionsCommand.php similarity index 61% rename from app/Console/Commands/ClearRevisions.php rename to app/Console/Commands/ClearRevisionsCommand.php index 681a7564b..ad001fdb1 100644 --- a/app/Console/Commands/ClearRevisions.php +++ b/app/Console/Commands/ClearRevisionsCommand.php @@ -5,7 +5,7 @@ namespace BookStack\Console\Commands; use BookStack\Entities\Models\PageRevision; use Illuminate\Console\Command; -class ClearRevisions extends Command +class ClearRevisionsCommand extends Command { /** * The name and signature of the console command. @@ -23,28 +23,14 @@ class ClearRevisions extends Command */ protected $description = 'Clear page revisions'; - protected $pageRevision; - - /** - * Create a new command instance. - * - * @param PageRevision $pageRevision - */ - public function __construct(PageRevision $pageRevision) - { - $this->pageRevision = $pageRevision; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): int { $deleteTypes = $this->option('all') ? ['version', 'update_draft'] : ['version']; - $this->pageRevision->newQuery()->whereIn('type', $deleteTypes)->delete(); + PageRevision::query()->whereIn('type', $deleteTypes)->delete(); $this->comment('Revisions deleted'); + return 0; } } diff --git a/app/Console/Commands/ClearViews.php b/app/Console/Commands/ClearViewsCommand.php similarity index 68% rename from app/Console/Commands/ClearViews.php rename to app/Console/Commands/ClearViewsCommand.php index c76b78d23..87ea503dc 100644 --- a/app/Console/Commands/ClearViews.php +++ b/app/Console/Commands/ClearViewsCommand.php @@ -5,7 +5,7 @@ namespace BookStack\Console\Commands; use BookStack\Activity\Models\View; use Illuminate\Console\Command; -class ClearViews extends Command +class ClearViewsCommand extends Command { /** * The name and signature of the console command. @@ -21,22 +21,13 @@ class ClearViews extends Command */ protected $description = 'Clear all view-counts for all entities'; - /** - * Create a new command instance. - */ - public function __construct() - { - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): int { - View::clearAll(); + View::query()->truncate(); $this->comment('Views cleared'); + return 0; } } diff --git a/app/Console/Commands/CopyShelfPermissions.php b/app/Console/Commands/CopyShelfPermissionsCommand.php similarity index 78% rename from app/Console/Commands/CopyShelfPermissions.php rename to app/Console/Commands/CopyShelfPermissionsCommand.php index ec4c875ff..fc11484bd 100644 --- a/app/Console/Commands/CopyShelfPermissions.php +++ b/app/Console/Commands/CopyShelfPermissionsCommand.php @@ -6,7 +6,7 @@ use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Tools\PermissionsUpdater; use Illuminate\Console\Command; -class CopyShelfPermissions extends Command +class CopyShelfPermissionsCommand extends Command { /** * The name and signature of the console command. @@ -25,25 +25,10 @@ class CopyShelfPermissions extends Command */ protected $description = 'Copy shelf permissions to all child books'; - protected PermissionsUpdater $permissionsUpdater; - - /** - * Create a new command instance. - * - * @return void - */ - public function __construct(PermissionsUpdater $permissionsUpdater) - { - $this->permissionsUpdater = $permissionsUpdater; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(PermissionsUpdater $permissionsUpdater): int { $shelfSlug = $this->option('slug'); $cascadeAll = $this->option('all'); @@ -52,7 +37,7 @@ class CopyShelfPermissions extends Command if (!$cascadeAll && !$shelfSlug) { $this->error('Either a --slug or --all option must be provided.'); - return; + return 1; } if ($cascadeAll) { @@ -63,7 +48,7 @@ class CopyShelfPermissions extends Command ); if (!$continue && !$this->hasOption('no-interaction')) { - return; + return 0; } $shelves = Bookshelf::query()->get(['id']); @@ -77,10 +62,11 @@ class CopyShelfPermissions extends Command } foreach ($shelves as $shelf) { - $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf, false); + $permissionsUpdater->updateBookPermissionsFromShelf($shelf, false); $this->info('Copied permissions for shelf [' . $shelf->id . ']'); } $this->info('Permissions copied for ' . $shelves->count() . ' shelves.'); + return 0; } } diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdminCommand.php similarity index 81% rename from app/Console/Commands/CreateAdmin.php rename to app/Console/Commands/CreateAdminCommand.php index 377207ed7..82b6e50aa 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdminCommand.php @@ -2,7 +2,6 @@ namespace BookStack\Console\Commands; -use BookStack\Exceptions\NotFoundException; use BookStack\Users\Models\Role; use BookStack\Users\UserRepo; use Illuminate\Console\Command; @@ -10,9 +9,8 @@ use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use Illuminate\Validation\Rules\Password; use Illuminate\Validation\Rules\Unique; -use Symfony\Component\Console\Command\Command as SymfonyCommand; -class CreateAdmin extends Command +class CreateAdminCommand extends Command { /** * The name and signature of the console command. @@ -32,25 +30,10 @@ class CreateAdmin extends Command */ protected $description = 'Add a new admin user to the system'; - protected $userRepo; - - /** - * Create a new command instance. - */ - public function __construct(UserRepo $userRepo) - { - $this->userRepo = $userRepo; - parent::__construct(); - } - /** * Execute the console command. - * - * @throws NotFoundException - * - * @return mixed */ - public function handle() + public function handle(UserRepo $userRepo): int { $details = $this->snakeCaseOptions(); @@ -82,17 +65,17 @@ class CreateAdmin extends Command $this->error($error); } - return SymfonyCommand::FAILURE; + return 1; } - $user = $this->userRepo->createWithoutActivity($validator->validated()); + $user = $userRepo->createWithoutActivity($validator->validated()); $user->attachRole(Role::getSystemRole('admin')); $user->email_confirmed = true; $user->save(); $this->info("Admin account with email \"{$user->email}\" successfully created!"); - return SymfonyCommand::SUCCESS; + return 0; } protected function snakeCaseOptions(): array diff --git a/app/Console/Commands/DeleteUsers.php b/app/Console/Commands/DeleteUsers.php deleted file mode 100644 index c16a5d9a6..000000000 --- a/app/Console/Commands/DeleteUsers.php +++ /dev/null @@ -1,53 +0,0 @@ -userRepo = $userRepo; - parent::__construct(); - } - - public function handle() - { - $confirm = $this->ask('This will delete all users from the system that are not "admin" or system users. Are you sure you want to continue? (Type "yes" to continue)'); - $numDeleted = 0; - if (strtolower(trim($confirm)) === 'yes') { - $totalUsers = User::query()->count(); - $users = User::query()->whereNull('system_name')->with('roles')->get(); - foreach ($users as $user) { - if ($user->hasSystemRole('admin')) { - // don't delete users with "admin" role - continue; - } - $this->userRepo->destroy($user); - $numDeleted++; - } - $this->info("Deleted $numDeleted of $totalUsers total users."); - } else { - $this->info('Exiting...'); - } - } -} diff --git a/app/Console/Commands/DeleteUsersCommand.php b/app/Console/Commands/DeleteUsersCommand.php new file mode 100644 index 000000000..d5c85dc8c --- /dev/null +++ b/app/Console/Commands/DeleteUsersCommand.php @@ -0,0 +1,53 @@ +warn('This will delete all users from the system that are not "admin" or system users.'); + $confirm = $this->confirm('Are you sure you want to continue?'); + + if (!$confirm) { + return 0; + } + + $totalUsers = User::query()->count(); + $numDeleted = 0; + $users = User::query()->whereNull('system_name')->with('roles')->get(); + + foreach ($users as $user) { + if ($user->hasSystemRole('admin')) { + // don't delete users with "admin" role + continue; + } + $userRepo->destroy($user); + $numDeleted++; + } + + $this->info("Deleted $numDeleted of $totalUsers total users."); + return 0; + } +} diff --git a/app/Console/Commands/RegenerateCommentContent.php b/app/Console/Commands/RegenerateCommentContentCommand.php similarity index 63% rename from app/Console/Commands/RegenerateCommentContent.php rename to app/Console/Commands/RegenerateCommentContentCommand.php index 3052559e3..f7ec42620 100644 --- a/app/Console/Commands/RegenerateCommentContent.php +++ b/app/Console/Commands/RegenerateCommentContentCommand.php @@ -7,14 +7,15 @@ use BookStack\Activity\Models\Comment; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -class RegenerateCommentContent extends Command +class RegenerateCommentContentCommand extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'bookstack:regenerate-comment-content {--database= : The database connection to use.}'; + protected $signature = 'bookstack:regenerate-comment-content + {--database= : The database connection to use}'; /** * The console command description. @@ -23,35 +24,19 @@ class RegenerateCommentContent extends Command */ protected $description = 'Regenerate the stored HTML of all comments'; - /** - * @var CommentRepo - */ - protected $commentRepo; - - /** - * Create a new command instance. - */ - public function __construct(CommentRepo $commentRepo) - { - $this->commentRepo = $commentRepo; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(CommentRepo $commentRepo): int { $connection = DB::getDefaultConnection(); if ($this->option('database') !== null) { DB::setDefaultConnection($this->option('database')); } - Comment::query()->chunk(100, function ($comments) { + Comment::query()->chunk(100, function ($comments) use ($commentRepo) { foreach ($comments as $comment) { - $comment->html = $this->commentRepo->commentToHtml($comment->text); + $comment->html = $commentRepo->commentToHtml($comment->text); $comment->save(); } }); diff --git a/app/Console/Commands/RegeneratePermissions.php b/app/Console/Commands/RegeneratePermissionsCommand.php similarity index 58% rename from app/Console/Commands/RegeneratePermissions.php rename to app/Console/Commands/RegeneratePermissionsCommand.php index 27dd8ea65..856e943c5 100644 --- a/app/Console/Commands/RegeneratePermissions.php +++ b/app/Console/Commands/RegeneratePermissionsCommand.php @@ -6,14 +6,15 @@ use BookStack\Permissions\JointPermissionBuilder; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -class RegeneratePermissions extends Command +class RegeneratePermissionsCommand extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'bookstack:regenerate-permissions {--database= : The database connection to use.}'; + protected $signature = 'bookstack:regenerate-permissions + {--database= : The database connection to use}'; /** * The console command description. @@ -22,23 +23,10 @@ class RegeneratePermissions extends Command */ protected $description = 'Regenerate all system permissions'; - protected JointPermissionBuilder $permissionBuilder; - - /** - * Create a new command instance. - */ - public function __construct(JointPermissionBuilder $permissionBuilder) - { - $this->permissionBuilder = $permissionBuilder; - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(JointPermissionBuilder $permissionBuilder): int { $connection = DB::getDefaultConnection(); @@ -46,7 +34,7 @@ class RegeneratePermissions extends Command DB::setDefaultConnection($this->option('database')); } - $this->permissionBuilder->rebuildForAll(); + $permissionBuilder->rebuildForAll(); DB::setDefaultConnection($connection); $this->comment('Permissions regenerated'); diff --git a/app/Console/Commands/RegenerateReferences.php b/app/Console/Commands/RegenerateReferencesCommand.php similarity index 59% rename from app/Console/Commands/RegenerateReferences.php rename to app/Console/Commands/RegenerateReferencesCommand.php index 805fd922d..ea8ff8e00 100644 --- a/app/Console/Commands/RegenerateReferences.php +++ b/app/Console/Commands/RegenerateReferencesCommand.php @@ -6,14 +6,15 @@ use BookStack\References\ReferenceStore; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -class RegenerateReferences extends Command +class RegenerateReferencesCommand extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'bookstack:regenerate-references {--database= : The database connection to use.}'; + protected $signature = 'bookstack:regenerate-references + {--database= : The database connection to use}'; /** * The console command description. @@ -22,25 +23,10 @@ class RegenerateReferences extends Command */ protected $description = 'Regenerate all the cross-item model reference index'; - protected ReferenceStore $references; - - /** - * Create a new command instance. - * - * @return void - */ - public function __construct(ReferenceStore $references) - { - $this->references = $references; - parent::__construct(); - } - /** * Execute the console command. - * - * @return int */ - public function handle() + public function handle(ReferenceStore $references): int { $connection = DB::getDefaultConnection(); @@ -48,7 +34,7 @@ class RegenerateReferences extends Command DB::setDefaultConnection($this->option('database')); } - $this->references->updateForAllPages(); + $references->updateForAllPages(); DB::setDefaultConnection($connection); diff --git a/app/Console/Commands/RegenerateSearch.php b/app/Console/Commands/RegenerateSearchCommand.php similarity index 61% rename from app/Console/Commands/RegenerateSearch.php rename to app/Console/Commands/RegenerateSearchCommand.php index ff584da56..f67a51e3d 100644 --- a/app/Console/Commands/RegenerateSearch.php +++ b/app/Console/Commands/RegenerateSearchCommand.php @@ -7,14 +7,15 @@ use BookStack\Search\SearchIndex; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -class RegenerateSearch extends Command +class RegenerateSearchCommand extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'bookstack:regenerate-search {--database= : The database connection to use.}'; + protected $signature = 'bookstack:regenerate-search + {--database= : The database connection to use}'; /** * The console command description. @@ -23,33 +24,17 @@ class RegenerateSearch extends Command */ protected $description = 'Re-index all content for searching'; - /** - * @var SearchIndex - */ - protected $searchIndex; - - /** - * Create a new command instance. - */ - public function __construct(SearchIndex $searchIndex) - { - parent::__construct(); - $this->searchIndex = $searchIndex; - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(SearchIndex $searchIndex): int { $connection = DB::getDefaultConnection(); if ($this->option('database') !== null) { DB::setDefaultConnection($this->option('database')); } - $this->searchIndex->indexAllEntities(function (Entity $model, int $processed, int $total): void { + $searchIndex->indexAllEntities(function (Entity $model, int $processed, int $total): void { $this->info('Indexed ' . class_basename($model) . ' entries (' . $processed . '/' . $total . ')'); }); diff --git a/app/Console/Commands/ResetMfa.php b/app/Console/Commands/ResetMfaCommand.php similarity index 80% rename from app/Console/Commands/ResetMfa.php rename to app/Console/Commands/ResetMfaCommand.php index 4b1813099..b8076d2d6 100644 --- a/app/Console/Commands/ResetMfa.php +++ b/app/Console/Commands/ResetMfaCommand.php @@ -5,7 +5,7 @@ namespace BookStack\Console\Commands; use BookStack\Users\Models\User; use Illuminate\Console\Command; -class ResetMfa extends Command +class ResetMfaCommand extends Command { /** * The name and signature of the console command. @@ -24,22 +24,10 @@ class ResetMfa extends Command */ protected $description = 'Reset & Clear any configured MFA methods for the given user'; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - } - /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): int { $id = $this->option('id'); $email = $this->option('email'); @@ -66,13 +54,13 @@ class ResetMfa extends Command $this->info("This will delete any configure multi-factor authentication methods for user: \n- ID: {$user->id}\n- Name: {$user->name}\n- Email: {$user->email}\n"); $this->info('If multi-factor authentication is required for this user they will be asked to reconfigure their methods on next login.'); $confirm = $this->confirm('Are you sure you want to proceed?'); - if ($confirm) { - $user->mfaValues()->delete(); - $this->info('User MFA methods have been reset.'); - - return 0; + if (!$confirm) { + return 1; } - return 1; + $user->mfaValues()->delete(); + $this->info('User MFA methods have been reset.'); + + return 0; } } diff --git a/app/Console/Commands/UpdateUrl.php b/app/Console/Commands/UpdateUrlCommand.php similarity index 97% rename from app/Console/Commands/UpdateUrl.php rename to app/Console/Commands/UpdateUrlCommand.php index 0d218b380..27f84cc89 100644 --- a/app/Console/Commands/UpdateUrl.php +++ b/app/Console/Commands/UpdateUrlCommand.php @@ -5,7 +5,7 @@ namespace BookStack\Console\Commands; use Illuminate\Console\Command; use Illuminate\Database\Connection; -class UpdateUrl extends Command +class UpdateUrlCommand extends Command { /** * The name and signature of the console command. @@ -26,10 +26,8 @@ class UpdateUrl extends Command /** * Execute the console command. - * - * @return mixed */ - public function handle(Connection $db) + public function handle(Connection $db): int { $oldUrl = str_replace("'", '', $this->argument('oldUrl')); $newUrl = str_replace("'", '', $this->argument('newUrl')); diff --git a/app/Console/Commands/UpgradeDatabaseEncoding.php b/app/Console/Commands/UpgradeDatabaseEncodingCommand.php similarity index 69% rename from app/Console/Commands/UpgradeDatabaseEncoding.php rename to app/Console/Commands/UpgradeDatabaseEncodingCommand.php index 32808729a..245ce57c6 100644 --- a/app/Console/Commands/UpgradeDatabaseEncoding.php +++ b/app/Console/Commands/UpgradeDatabaseEncodingCommand.php @@ -5,14 +5,15 @@ namespace BookStack\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; -class UpgradeDatabaseEncoding extends Command +class UpgradeDatabaseEncodingCommand extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'bookstack:db-utf8mb4 {--database= : The database connection to use.}'; + protected $signature = 'bookstack:db-utf8mb4 + {--database= : The database connection to use}'; /** * The console command description. @@ -21,20 +22,11 @@ class UpgradeDatabaseEncoding extends Command */ protected $description = 'Generate SQL commands to upgrade the database to UTF8mb4'; - /** - * Create a new command instance. - */ - public function __construct() - { - parent::__construct(); - } /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): int { $connection = DB::getDefaultConnection(); if ($this->option('database') !== null) { @@ -48,9 +40,11 @@ class UpgradeDatabaseEncoding extends Command $key = 'Tables_in_' . $database; foreach ($tables as $table) { $tableName = $table->$key; - $this->line('ALTER TABLE `' . $tableName . '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); + $this->line("ALTER TABLE `{$tableName}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"); } DB::setDefaultConnection($connection); + + return 0; } } diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index 1d04582c0..5458779e9 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -462,6 +462,7 @@ class ImageService Image::query()->whereIn('type', $types) ->chunk(1000, function ($images) use ($checkRevisions, &$deletedPaths, $dryRun) { + /** @var Image $image */ foreach ($images as $image) { $searchQuery = '%' . basename($image->path) . '%'; $inPage = DB::table('pages') diff --git a/tests/Commands/CleanupImagesCommandTest.php b/tests/Commands/CleanupImagesCommandTest.php new file mode 100644 index 000000000..a1a5ab985 --- /dev/null +++ b/tests/Commands/CleanupImagesCommandTest.php @@ -0,0 +1,49 @@ +entities->page(); + $image = Image::factory()->create(['uploaded_to' => $page->id]); + + $this->artisan('bookstack:cleanup-images -v') + ->expectsOutput('Dry run, no images have been deleted') + ->expectsOutput('1 images found that would have been deleted') + ->expectsOutputToContain($image->path) + ->assertExitCode(0); + + $this->assertDatabaseHas('images', ['id' => $image->id]); + } + + public function test_command_force_run() + { + $page = $this->entities->page(); + $image = Image::factory()->create(['uploaded_to' => $page->id]); + + $this->artisan('bookstack:cleanup-images --force') + ->expectsOutputToContain('This operation is destructive and is not guaranteed to be fully accurate') + ->expectsConfirmation('Are you sure you want to proceed?', 'yes') + ->expectsOutput('1 images deleted') + ->assertExitCode(0); + + $this->assertDatabaseMissing('images', ['id' => $image->id]); + } + + public function test_command_force_run_negative_confirmation() + { + $page = $this->entities->page(); + $image = Image::factory()->create(['uploaded_to' => $page->id]); + + $this->artisan('bookstack:cleanup-images --force') + ->expectsConfirmation('Are you sure you want to proceed?', 'no') + ->assertExitCode(0); + + $this->assertDatabaseHas('images', ['id' => $image->id]); + } +} diff --git a/tests/Commands/CopyShelfPermissionsCommandTest.php b/tests/Commands/CopyShelfPermissionsCommandTest.php index c4b9fe6f3..5c21a2e34 100644 --- a/tests/Commands/CopyShelfPermissionsCommandTest.php +++ b/tests/Commands/CopyShelfPermissionsCommandTest.php @@ -11,7 +11,7 @@ class CopyShelfPermissionsCommandTest extends TestCase { $this->artisan('bookstack:copy-shelf-permissions') ->expectsOutput('Either a --slug or --all option must be provided.') - ->assertExitCode(0); + ->assertExitCode(1); } public function test_copy_shelf_permissions_command_using_slug() diff --git a/tests/Commands/DeleteUsersCommandTest.php b/tests/Commands/DeleteUsersCommandTest.php new file mode 100644 index 000000000..a959df95d --- /dev/null +++ b/tests/Commands/DeleteUsersCommandTest.php @@ -0,0 +1,44 @@ +count(); + $normalUsers = $this->getNormalUsers(); + + $normalUserCount = $userCount - count($normalUsers); + $this->artisan('bookstack:delete-users') + ->expectsConfirmation('Are you sure you want to continue?', 'yes') + ->expectsOutputToContain("Deleted $normalUserCount of $userCount total users.") + ->assertExitCode(0); + + $this->assertDatabaseMissing('users', ['id' => $normalUsers->first()->id]); + } + + public function test_command_requires_confirmation() + { + $normalUsers = $this->getNormalUsers(); + + $this->artisan('bookstack:delete-users') + ->expectsConfirmation('Are you sure you want to continue?', 'no') + ->assertExitCode(0); + + $this->assertDatabaseHas('users', ['id' => $normalUsers->first()->id]); + } + + protected function getNormalUsers(): Collection + { + return User::query()->whereNull('system_name') + ->get() + ->filter(function (User $user) { + return !$user->hasSystemRole('admin'); + }); + } +} diff --git a/tests/Commands/RegenerateSearchCommandTest.php b/tests/Commands/RegenerateSearchCommandTest.php new file mode 100644 index 000000000..418327ebe --- /dev/null +++ b/tests/Commands/RegenerateSearchCommandTest.php @@ -0,0 +1,29 @@ +entities->page(); + SearchTerm::truncate(); + + $this->assertDatabaseMissing('search_terms', ['entity_id' => $page->id]); + + $this->artisan('bookstack:regenerate-search') + ->expectsOutput('Search index regenerated!') + ->assertExitCode(0); + + $this->assertDatabaseHas('search_terms', [ + 'entity_type' => 'page', + 'entity_id' => $page->id + ]); + DB::beginTransaction(); + } +} diff --git a/tests/Commands/UpgradeDatabaseEncodingCommandTest.php b/tests/Commands/UpgradeDatabaseEncodingCommandTest.php new file mode 100644 index 000000000..b7fe4eb6c --- /dev/null +++ b/tests/Commands/UpgradeDatabaseEncodingCommandTest.php @@ -0,0 +1,15 @@ +artisan('bookstack:db-utf8mb4') + ->expectsOutputToContain('ALTER DATABASE') + ->expectsOutputToContain('ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); + } +}