From 22a9cf1e482d493d4080357be58ef7649cce8fb1 Mon Sep 17 00:00:00 2001
From: Dan Brown <email@danb.me>
Date: Fri, 17 Nov 2023 13:45:57 +0000
Subject: [PATCH] LogicalTheme: Added events for registering web routes

Added to allow easier registration of routes.
Added for normal web and authed routes.
Included testing to cover.
---
 app/App/Providers/RouteServiceProvider.php | 12 +++++++-
 app/App/Providers/ThemeServiceProvider.php |  1 +
 app/Theming/ThemeEvents.php                | 19 ++++++++++++
 tests/ThemeTest.php                        | 34 ++++++++++++++++++++++
 4 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/app/App/Providers/RouteServiceProvider.php b/app/App/Providers/RouteServiceProvider.php
index 913dfa435..abd556244 100644
--- a/app/App/Providers/RouteServiceProvider.php
+++ b/app/App/Providers/RouteServiceProvider.php
@@ -2,9 +2,12 @@
 
 namespace BookStack\App\Providers;
 
+use BookStack\Facades\Theme;
+use BookStack\Theming\ThemeEvents;
 use Illuminate\Cache\RateLimiting\Limit;
 use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
 use Illuminate\Http\Request;
+use Illuminate\Routing\Router;
 use Illuminate\Support\Facades\RateLimiter;
 use Illuminate\Support\Facades\Route;
 
@@ -46,8 +49,15 @@ class RouteServiceProvider extends ServiceProvider
         Route::group([
             'middleware' => 'web',
             'namespace'  => $this->namespace,
-        ], function ($router) {
+        ], function (Router $router) {
             require base_path('routes/web.php');
+            Theme::dispatch(ThemeEvents::ROUTES_REGISTER_WEB, $router);
+        });
+
+        Route::group([
+            'middleware' => ['web', 'auth'],
+        ], function (Router $router) {
+            Theme::dispatch(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, $router);
         });
     }
 
diff --git a/app/App/Providers/ThemeServiceProvider.php b/app/App/Providers/ThemeServiceProvider.php
index 4c657d912..c15b43a6b 100644
--- a/app/App/Providers/ThemeServiceProvider.php
+++ b/app/App/Providers/ThemeServiceProvider.php
@@ -4,6 +4,7 @@ namespace BookStack\App\Providers;
 
 use BookStack\Theming\ThemeEvents;
 use BookStack\Theming\ThemeService;
+use Illuminate\Support\Facades\Route;
 use Illuminate\Support\ServiceProvider;
 
 class ThemeServiceProvider extends ServiceProvider
diff --git a/app/Theming/ThemeEvents.php b/app/Theming/ThemeEvents.php
index 4b56b2f56..9e14707de 100644
--- a/app/Theming/ThemeEvents.php
+++ b/app/Theming/ThemeEvents.php
@@ -98,6 +98,25 @@ class ThemeEvents
      */
     const PAGE_INCLUDE_PARSE = 'page_include_parse';
 
+    /**
+     * Routes register web event.
+     * Called when standard web (browser/non-api) app routes are registered.
+     * Provides an app router, so you can register your own web routes.
+     *
+     * @param \Illuminate\Routing\Router
+     */
+    const ROUTES_REGISTER_WEB = 'routes_register_web';
+
+    /**
+     * Routes register web auth event.
+     * Called when auth-required web (browser/non-api) app routes can be registered.
+     * These are routes that typically require login to access (unless the instance is made public).
+     * Provides an app router, so you can register your own web routes.
+     *
+     * @param \Illuminate\Routing\Router
+     */
+    const ROUTES_REGISTER_WEB_AUTH = 'routes_register_web_auth';
+
     /**
      * Web before middleware action.
      * Runs before the request is handled but after all other middleware apart from those
diff --git a/tests/ThemeTest.php b/tests/ThemeTest.php
index 53361e351..73b901439 100644
--- a/tests/ThemeTest.php
+++ b/tests/ThemeTest.php
@@ -256,6 +256,40 @@ class ThemeTest extends TestCase
         $this->assertEquals($otherPage->id, $args[3]->id);
     }
 
+    public function test_event_routes_register_web_and_web_auth()
+    {
+        $functionsContent = <<<'END'
+<?php
+use BookStack\Theming\ThemeEvents;
+use BookStack\Facades\Theme;
+use Illuminate\Routing\Router;
+Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB, function (Router $router) {
+    $router->get('/cat', fn () => 'cat')->name('say.cat');
+});
+Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, function (Router $router) {
+    $router->get('/dog', fn () => 'dog')->name('say.dog');
+});
+END;
+
+        $this->usingThemeFolder(function () use ($functionsContent) {
+
+            $functionsFile = theme_path('functions.php');
+            file_put_contents($functionsFile, $functionsContent);
+
+            $app = $this->createApplication();
+            /** @var \Illuminate\Routing\Router $router */
+            $router = $app->get('router');
+
+            /** @var \Illuminate\Routing\Route $catRoute */
+            $catRoute = $router->getRoutes()->getRoutesByName()['say.cat'];
+            $this->assertEquals(['web'], $catRoute->middleware());
+
+            /** @var \Illuminate\Routing\Route $dogRoute */
+            $dogRoute = $router->getRoutes()->getRoutesByName()['say.dog'];
+            $this->assertEquals(['web', 'auth'], $dogRoute->middleware());
+        });
+    }
+
     public function test_add_social_driver()
     {
         Theme::addSocialDriver('catnet', [