From d0836f3ee360a836f815c59ea755f288501dc517 Mon Sep 17 00:00:00 2001
From: Yassine Doghri <yassine@doghri.fr>
Date: Tue, 18 Oct 2022 16:53:51 +0000
Subject: [PATCH] feat: add about page in admin with instance info + database
 update button

---
 app/Config/Autoload.php                       |  1 +
 .../2023-04-09-110000_testing_update.php      | 35 ++++++++++
 app/Resources/icons/information.svg           |  4 ++
 docs/src/getting-started/update.md            | 40 +++++++----
 modules/Admin/Config/Routes.php               | 10 +++
 modules/Admin/Controllers/AboutController.php | 67 +++++++++++++++++++
 modules/Admin/Language/en/AboutCastopod.php   | 22 ++++++
 modules/Admin/Language/en/Breadcrumb.php      |  1 +
 modules/Admin/Language/en/Navigation.php      |  1 +
 modules/Update/Commands/DatabaseUpdate.php    | 32 +++++++++
 themes/cp_admin/_sidebar.php                  |  4 ++
 themes/cp_admin/about.php                     | 35 ++++++++++
 themes/cp_install/_layout.php                 |  4 +-
 13 files changed, 242 insertions(+), 14 deletions(-)
 create mode 100644 app/Database/Migrations/2023-04-09-110000_testing_update.php
 create mode 100644 app/Resources/icons/information.svg
 create mode 100644 modules/Admin/Controllers/AboutController.php
 create mode 100644 modules/Admin/Language/en/AboutCastopod.php
 create mode 100644 modules/Update/Commands/DatabaseUpdate.php
 create mode 100644 themes/cp_admin/about.php

diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php
index f314d3d20c..1b4bab5512 100644
--- a/app/Config/Autoload.php
+++ b/app/Config/Autoload.php
@@ -48,6 +48,7 @@ class Autoload extends AutoloadConfig
         'Modules\Auth' => ROOTPATH . 'modules/Auth/',
         'Modules\Analytics' => ROOTPATH . 'modules/Analytics/',
         'Modules\Install' => ROOTPATH . 'modules/Install/',
+        'Modules\Update' => ROOTPATH . 'modules/Update/',
         'Modules\Fediverse' => ROOTPATH . 'modules/Fediverse/',
         'Modules\WebSub' => ROOTPATH . 'modules/WebSub/',
         'Modules\Api\Rest\V1' => ROOTPATH . 'modules/Api/Rest/V1',
diff --git a/app/Database/Migrations/2023-04-09-110000_testing_update.php b/app/Database/Migrations/2023-04-09-110000_testing_update.php
new file mode 100644
index 0000000000..446811983f
--- /dev/null
+++ b/app/Database/Migrations/2023-04-09-110000_testing_update.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * Class AddCreatedByToPosts Adds created_by field to posts table in database
+ *
+ * @copyright  2020 Ad Aures
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Database\Migrations;
+
+use CodeIgniter\Database\Migration;
+
+class AddTestingUpdate extends Migration
+{
+    public function up(): void
+    {
+        $this->forge->addColumn('podcasts', [
+            'cool_update' => [
+                'type' => 'INT',
+                'unsigned' => true,
+                'null' => true,
+                'after' => 'custom_rss',
+            ],
+        ]);
+    }
+
+    public function down(): void
+    {
+        $this->forge->dropColumn('podcasts', 'cool_update');
+    }
+}
diff --git a/app/Resources/icons/information.svg b/app/Resources/icons/information.svg
new file mode 100644
index 0000000000..39f02fbd91
--- /dev/null
+++ b/app/Resources/icons/information.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+    <path fill="none" d="M0 0h24v24H0z"/>
+    <path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z"/>
+</svg>
diff --git a/docs/src/getting-started/update.md b/docs/src/getting-started/update.md
index 1f48e27492..98e019fbc7 100644
--- a/docs/src/getting-started/update.md
+++ b/docs/src/getting-started/update.md
@@ -9,11 +9,13 @@ After installing Castopod, you may want to update your instance to the latest
 version in order to enjoy the latest features ✨, bug fixes 🐛 and performance
 improvements âš¡.
 
-## Automatic update instructions
+## Update instructions
 
-> Coming soon... 👀
+0. ⚠️ Before any update, we highly recommend you backup your Castopod files and
+   database.
 
-## Manual update instructions
+   - cf.
+     [Should I make a backup before updating?](#should-i-make-a-backup-before-updating)
 
 1. Go to the
    [releases page](https://code.castopod.org/adaures/castopod/-/releases) and
@@ -26,6 +28,8 @@ improvements âš¡.
    between the `zip` or `tar.gz` archives
 
    - ⚠️ Make sure you download the Castopod Package and **NOT** the Source Code
+   - Note that you can also download the latest package from
+     [castopod.org](https://castopod.org/)
 
 3. On your server:
 
@@ -39,19 +43,31 @@ improvements âš¡.
 
      :::
 
-4. Releases may come with additional update instructions (see
-   [releases page](https://code.castopod.org/adaures/castopod/-/releases)). They
-   are usually database migration scripts in `.sql` format to update your
-   database schema.
+4. Update your database schema from your `Castopod Admin` > `About` page or by
+   running:
 
-   - 👉 Make sure you run the scripts on your phpmyadmin panel or using command
-     line to update the database along with the package files!
-   - cf.
-     [I haven't updated my instance in a long time… What should I do?](#i-havent-updated-my-instance-in-a-long-time-what-should-i-do)
+   ```bash
+   php spark castopod:database-update
+   ```
 
-5. If you are using redis, clear your cache.
+5. Clear your cache from your `Castopod Admin` > `Settings` > `general` >
+   `Housekeeping`
 6. ✨ Enjoy your fresh instance, you're all done!
 
+::: info Note
+
+Releases may come with additional update instructions (see
+[releases page](https://code.castopod.org/adaures/castopod/-/releases)).
+
+- cf.
+  [I haven't updated my instance in a long time… What should I do?](#i-havent-updated-my-instance-in-a-long-time-what-should-i-do)
+
+:::
+
+## Fully Automated updates
+
+> Coming soon... 👀
+
 ## Frequently asked questions (FAQ)
 
 ### Where can I find my Castopod version?
diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php
index 7bf2216689..586272ead6 100644
--- a/modules/Admin/Config/Routes.php
+++ b/modules/Admin/Config/Routes.php
@@ -644,5 +644,15 @@ $routes->group(
                 ]);
             });
         });
+
+        $routes->get('about', 'AboutController', [
+            'as' => 'admin-about',
+            'filter' => 'permission:admin.settings',
+        ]);
+
+        $routes->post('update', 'AboutController::updateAction', [
+            'as' => 'update',
+            'filter' => 'permission:admin.settings',
+        ]);
     },
 );
diff --git a/modules/Admin/Controllers/AboutController.php b/modules/Admin/Controllers/AboutController.php
new file mode 100644
index 0000000000..02be5c9e59
--- /dev/null
+++ b/modules/Admin/Controllers/AboutController.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2022 Ad Aures
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace Modules\Admin\Controllers;
+
+use CodeIgniter\HTTP\RedirectResponse;
+use Config\Services;
+
+class AboutController extends BaseController
+{
+    public function index(): string
+    {
+        $instanceInfo = [
+            'host_name' => current_domain(),
+            'version' => CP_VERSION,
+            'php_version' => PHP_VERSION,
+            'os' => PHP_OS,
+            'languages' => implode(', ', config('App')->supportedLocales),
+        ];
+
+        return view('about', [
+            'info' => $instanceInfo,
+        ]);
+    }
+
+    public function updateAction(): RedirectResponse
+    {
+        if ($this->request->getPost('action') === 'database') {
+            return $this->migrateDatabase();
+        }
+
+        return redirect()->back()
+            ->with('error', lang('Security.disallowedAction'));
+    }
+
+    public function migrateDatabase(): RedirectResponse
+    {
+        $migrate = Services::migrations();
+
+        $migrate->setNamespace('CodeIgniter\Settings')
+            ->latest();
+        $migrate->setNamespace('CodeIgniter\Shield')
+            ->latest();
+        $migrate->setNamespace('Modules\Fediverse')
+            ->latest();
+        $migrate->setNamespace(APP_NAMESPACE)
+            ->latest();
+        $migrate->setNamespace('Modules\WebSub')
+            ->latest();
+        $migrate->setNamespace('Modules\Auth')
+            ->latest();
+        $migrate->setNamespace('Modules\PremiumPodcasts')
+            ->latest();
+        $migrate->setNamespace('Modules\Analytics')
+            ->latest();
+
+        return redirect()->back()
+            ->with('message', lang('AboutCastopod.messages.databaseUpdateSuccess'));
+    }
+}
diff --git a/modules/Admin/Language/en/AboutCastopod.php b/modules/Admin/Language/en/AboutCastopod.php
new file mode 100644
index 0000000000..3fb62afffe
--- /dev/null
+++ b/modules/Admin/Language/en/AboutCastopod.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Ad Aures
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'title' => 'About Castopod',
+    'host_name' => 'Host name',
+    'version' => 'Castopod version',
+    'php_version' => 'PHP version',
+    'os' => 'Operating System',
+    'languages' => 'Languages',
+    'update_database' => 'Update database',
+    'messages' => [
+        'databaseUpdateSuccess' => 'Database is up to date!',
+    ],
+];
diff --git a/modules/Admin/Language/en/Breadcrumb.php b/modules/Admin/Language/en/Breadcrumb.php
index 823ccd65ac..b1742abfb1 100644
--- a/modules/Admin/Language/en/Breadcrumb.php
+++ b/modules/Admin/Language/en/Breadcrumb.php
@@ -19,6 +19,7 @@ return [
     'pages' => 'pages',
     'settings' => 'settings',
     'theme' => 'theme',
+    'about' => 'about',
     'add' => 'add',
     'new' => 'new',
     'edit' => 'edit',
diff --git a/modules/Admin/Language/en/Navigation.php b/modules/Admin/Language/en/Navigation.php
index 68d4609d5d..610f14345d 100644
--- a/modules/Admin/Language/en/Navigation.php
+++ b/modules/Admin/Language/en/Navigation.php
@@ -33,6 +33,7 @@ return [
     'settings' => 'Settings',
     'settings-general' => 'General',
     'settings-theme' => 'Theme',
+    'about' => 'About',
     'account' => [
         'my-account' => 'My account',
         'change-password' => 'Change password',
diff --git a/modules/Update/Commands/DatabaseUpdate.php b/modules/Update/Commands/DatabaseUpdate.php
new file mode 100644
index 0000000000..70a3ad0158
--- /dev/null
+++ b/modules/Update/Commands/DatabaseUpdate.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Modules\Update\Commands;
+
+use CodeIgniter\CLI\BaseCommand;
+
+class DatabaseUpdate extends BaseCommand
+{
+    /**
+     * @var string
+     */
+    protected $group = 'maintenance';
+
+    /**
+     * @var string
+     */
+    protected $name = 'castopod:database-update';
+
+    /**
+     * @var string
+     */
+    protected $description = 'Runs all new database migrations for Castopod.';
+
+    public function run(array $params): void
+    {
+        $this->call('migrate', [
+            'all' => true,
+        ]);
+    }
+}
diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php
index f557e5e9b4..af54525097 100644
--- a/themes/cp_admin/_sidebar.php
+++ b/themes/cp_admin/_sidebar.php
@@ -53,4 +53,8 @@ $navigation = [
         </ul>
     </div>
     <?php endforeach; ?>
+    <a class="inline-flex items-center w-full px-4 py-1 font-semibold focus:ring-accent" href="<?= route_to('admin-about') ?>">
+        <?= icon('information', 'opacity-60 text-2xl mr-4') ?>
+        <?= lang('Navigation.about') ?>
+    </a>
 </nav>
diff --git a/themes/cp_admin/about.php b/themes/cp_admin/about.php
new file mode 100644
index 0000000000..8df341bfdf
--- /dev/null
+++ b/themes/cp_admin/about.php
@@ -0,0 +1,35 @@
+<?= $this->extend('_layout') ?>
+
+<?= $this->section('title') ?>
+<?= lang('AboutCastopod.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('pageTitle') ?>
+<?= lang('AboutCastopod.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('content') ?>
+
+<form action="<?= route_to('update') ?>" method="POST">
+    <?= csrf_field() ?>
+    <button type="submit" name="action" value="database" class="inline-flex items-center px-4 py-2 text-lg font-semibold transition-colors rounded-full shadow group gap-x-2 bg-elevated hover:border-accent-hover focus:ring-accent border-3 border-subtle">
+        <div class="relative">
+            <Icon glyph="database" class="text-4xl text-accent-base" />
+            <Icon glyph="refresh" class="absolute bottom-0 right-0 rounded-full bg-elevated text-accent-base motion-safe:group-hover:animate-spin motion-safe:group-focus:animate-spin" />
+        </div>
+        <?= lang('AboutCastopod.update_database') ?>
+    </button>
+</form>
+
+<?php foreach ($info as $key => $value): ?>
+<div class="px-4 py-5">
+    <dt class="text-sm font-medium leading-5 text-skin-muted">
+    <?= lang('AboutCastopod.' . $key) ?>
+    </dt>
+    <dd class="mt-1 text-sm leading-5">
+        <?= $value ?>
+    </dd>
+</div>
+<?php endforeach; ?>
+
+<?= $this->endSection() ?>
diff --git a/themes/cp_install/_layout.php b/themes/cp_install/_layout.php
index 6d35f502cc..1065c588c4 100644
--- a/themes/cp_install/_layout.php
+++ b/themes/cp_install/_layout.php
@@ -6,8 +6,8 @@
     <meta charset="UTF-8"/>
     <meta name="robots" content="noindex">
 
-    <title>Castopod Install</title>
-    <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
+    <title><?= lang('Install.title') ?></title>
+
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
     <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
     <link rel="apple-touch-icon" href="/icon-180.png">
-- 
GitLab