From 573bc3ec45dcfa754be5768ca62deffac421f635 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Sat, 6 May 2023 23:05:25 +0100
Subject: [PATCH] Added force option for update-url command

Includes test to cover.
Closes #4223
---
 app/Console/Commands/UpdateUrl.php      | 43 ++++++++++++-------------
 tests/Commands/UpdateUrlCommandTest.php |  8 +++++
 2 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/app/Console/Commands/UpdateUrl.php b/app/Console/Commands/UpdateUrl.php
index a4bb6cf22..facb4cc41 100644
--- a/app/Console/Commands/UpdateUrl.php
+++ b/app/Console/Commands/UpdateUrl.php
@@ -14,7 +14,8 @@ class UpdateUrl extends Command
      */
     protected $signature = 'bookstack:update-url
                             {oldUrl : URL to replace}
-                            {newUrl : URL to use as the replacement}';
+                            {newUrl : URL to use as the replacement}
+                            {--force : Force the operation to run, ignoring confirmations}';
 
     /**
      * The console command description.
@@ -23,25 +24,12 @@ class UpdateUrl extends Command
      */
     protected $description = 'Find and replace the given URLs in your BookStack database';
 
-    protected $db;
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct(Connection $db)
-    {
-        $this->db = $db;
-        parent::__construct();
-    }
-
     /**
      * Execute the console command.
      *
      * @return mixed
      */
-    public function handle()
+    public function handle(Connection $db)
     {
         $oldUrl = str_replace("'", '', $this->argument('oldUrl'));
         $newUrl = str_replace("'", '', $this->argument('newUrl'));
@@ -67,7 +55,7 @@ class UpdateUrl extends Command
 
         foreach ($columnsToUpdateByTable as $table => $columns) {
             foreach ($columns as $column) {
-                $changeCount = $this->replaceValueInTable($table, $column, $oldUrl, $newUrl);
+                $changeCount = $this->replaceValueInTable($db, $table, $column, $oldUrl, $newUrl);
                 $this->info("Updated {$changeCount} rows in {$table}->{$column}");
             }
         }
@@ -80,7 +68,7 @@ class UpdateUrl extends Command
             foreach ($columns as $column) {
                 $oldJson = trim(json_encode($oldUrl), '"');
                 $newJson = trim(json_encode($newUrl), '"');
-                $changeCount = $this->replaceValueInTable($table, $column, $oldJson, $newJson);
+                $changeCount = $this->replaceValueInTable($db, $table, $column, $oldJson, $newJson);
                 $this->info("Updated {$changeCount} JSON encoded rows in {$table}->{$column}");
             }
         }
@@ -97,13 +85,18 @@ class UpdateUrl extends Command
      * Perform a find+replace operations in the provided table and column.
      * Returns the count of rows changed.
      */
-    protected function replaceValueInTable(string $table, string $column, string $oldUrl, string $newUrl): int
-    {
-        $oldQuoted = $this->db->getPdo()->quote($oldUrl);
-        $newQuoted = $this->db->getPdo()->quote($newUrl);
+    protected function replaceValueInTable(
+        Connection $db,
+        string     $table,
+        string     $column,
+        string     $oldUrl,
+        string     $newUrl
+    ): int {
+        $oldQuoted = $db->getPdo()->quote($oldUrl);
+        $newQuoted = $db->getPdo()->quote($newUrl);
 
-        return $this->db->table($table)->update([
-            $column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"),
+        return $db->table($table)->update([
+            $column => $db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"),
         ]);
     }
 
@@ -113,6 +106,10 @@ class UpdateUrl extends Command
      */
     protected function checkUserOkayToProceed(string $oldUrl, string $newUrl): bool
     {
+        if ($this->option('force')) {
+            return true;
+        }
+
         $dangerWarning = "This will search for \"{$oldUrl}\" in your database and replace it with  \"{$newUrl}\".\n";
         $dangerWarning .= 'Are you sure you want to proceed?';
         $backupConfirmation = 'This operation could cause issues if used incorrectly. Have you made a backup of your existing database?';
diff --git a/tests/Commands/UpdateUrlCommandTest.php b/tests/Commands/UpdateUrlCommandTest.php
index 1788e9452..280c81feb 100644
--- a/tests/Commands/UpdateUrlCommandTest.php
+++ b/tests/Commands/UpdateUrlCommandTest.php
@@ -2,6 +2,7 @@
 
 namespace Tests\Commands;
 
+use Illuminate\Support\Facades\Artisan;
 use Symfony\Component\Console\Exception\RuntimeException;
 use Tests\TestCase;
 
@@ -34,6 +35,13 @@ class UpdateUrlCommandTest extends TestCase
         $this->artisan('bookstack:update-url https://cats.example.com');
     }
 
+    public function test_command_force_option_skips_prompt()
+    {
+        $this->artisan('bookstack:update-url --force https://cats.example.com/donkey https://cats.example.com/monkey')
+            ->expectsOutputToContain('URL update procedure complete')
+            ->assertSuccessful();
+    }
+
     public function test_command_updates_settings()
     {
         setting()->put('my-custom-item', 'https://example.com/donkey/cat');