diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php index 9cae80617..287c83877 100644 --- a/app/Api/ApiDocsGenerator.php +++ b/app/Api/ApiDocsGenerator.php @@ -2,6 +2,7 @@ namespace BookStack\Api; +use BookStack\App\AppVersion; use BookStack\Http\ApiController; use Exception; use Illuminate\Contracts\Container\BindingResolutionException; @@ -25,7 +26,7 @@ class ApiDocsGenerator */ public static function generateConsideringCache(): Collection { - $appVersion = trim(file_get_contents(base_path('version'))); + $appVersion = AppVersion::get(); $cacheKey = 'api-docs::' . $appVersion; $isProduction = config('app.env') === 'production'; $cacheVal = $isProduction ? Cache::get($cacheKey) : null; diff --git a/app/App/AppVersion.php b/app/App/AppVersion.php new file mode 100644 index 000000000..af422f641 --- /dev/null +++ b/app/App/AppVersion.php @@ -0,0 +1,24 @@ +json([ + 'version' => AppVersion::get(), + 'instance_id' => setting('instance-id'), + 'app_name' => setting('app-name'), + 'app_logo' => $logo, + 'base_url' => url('/'), + ]); + } +} diff --git a/app/App/helpers.php b/app/App/helpers.php index eec86553f..2305c2d72 100644 --- a/app/App/helpers.php +++ b/app/App/helpers.php @@ -1,5 +1,6 @@ phpversion(), 'BookStack Version' => $this->safeReturn(function () { - $versionFile = base_path('version'); - - return trim(file_get_contents($versionFile)); + return AppVersion::get(); }, 'unknown'), 'Theme Configured' => $this->safeReturn(function () { return config('view.theme'); diff --git a/app/Exports/ZipExports/ZipExportBuilder.php b/app/Exports/ZipExports/ZipExportBuilder.php index 9a52c9a3c..9937d1589 100644 --- a/app/Exports/ZipExports/ZipExportBuilder.php +++ b/app/Exports/ZipExports/ZipExportBuilder.php @@ -2,6 +2,7 @@ namespace BookStack\Exports\ZipExports; +use BookStack\App\AppVersion; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; @@ -70,7 +71,7 @@ class ZipExportBuilder $this->data['exported_at'] = date(DATE_ATOM); $this->data['instance'] = [ 'id' => setting('instance-id', ''), - 'version' => trim(file_get_contents(base_path('version'))), + 'version' => AppVersion::get(), ]; $zipFile = tempnam(sys_get_temp_dir(), 'bszip-'); diff --git a/app/Settings/MaintenanceController.php b/app/Settings/MaintenanceController.php index 0382ae08a..ac9dd20cc 100644 --- a/app/Settings/MaintenanceController.php +++ b/app/Settings/MaintenanceController.php @@ -3,6 +3,7 @@ namespace BookStack\Settings; use BookStack\Activity\ActivityType; +use BookStack\App\AppVersion; use BookStack\Entities\Tools\TrashCan; use BookStack\Http\Controller; use BookStack\References\ReferenceStore; @@ -19,14 +20,11 @@ class MaintenanceController extends Controller $this->checkPermission('settings-manage'); $this->setPageTitle(trans('settings.maint')); - // Get application version - $version = trim(file_get_contents(base_path('version'))); - // Recycle bin details $recycleStats = $trashCan->getTrashedCounts(); return view('settings.maintenance', [ - 'version' => $version, + 'version' => AppVersion::get(), 'recycleStats' => $recycleStats, ]); } diff --git a/app/Settings/SettingController.php b/app/Settings/SettingController.php index 1c5f13bc6..3b7ba74d5 100644 --- a/app/Settings/SettingController.php +++ b/app/Settings/SettingController.php @@ -3,6 +3,7 @@ namespace BookStack\Settings; use BookStack\Activity\ActivityType; +use BookStack\App\AppVersion; use BookStack\Http\Controller; use BookStack\Users\Models\User; use Illuminate\Http\Request; @@ -26,12 +27,9 @@ class SettingController extends Controller $this->checkPermission('settings-manage'); $this->setPageTitle(trans('settings.settings')); - // Get application version - $version = trim(file_get_contents(base_path('version'))); - return view('settings.categories.' . $category, [ 'category' => $category, - 'version' => $version, + 'version' => AppVersion::get(), 'guestUser' => User::getGuest(), ]); } diff --git a/dev/api/responses/system-read.json b/dev/api/responses/system-read.json new file mode 100644 index 000000000..4687d6ffc --- /dev/null +++ b/dev/api/responses/system-read.json @@ -0,0 +1,7 @@ +{ + "version": "v25.02.4", + "instance_id": "1234abcd-cc12-7808-af0a-264cb0cbd611", + "app_name": "My BookStack Instance", + "app_logo": "https://docs.example.com/uploads/images/system/2025-05/cat-icon.png", + "base_url": "https://docs.example.com" +} \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 710364855..85e872ba4 100644 --- a/routes/api.php +++ b/routes/api.php @@ -8,6 +8,7 @@ use BookStack\Activity\Controllers\AuditLogApiController; use BookStack\Api\ApiDocsController; +use BookStack\App\SystemApiController; use BookStack\Entities\Controllers as EntityControllers; use BookStack\Exports\Controllers as ExportControllers; use BookStack\Permissions\ContentPermissionApiController; @@ -92,3 +93,5 @@ Route::get('content-permissions/{contentType}/{contentId}', [ContentPermissionAp Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']); Route::get('audit-log', [AuditLogApiController::class, 'list']); + +Route::get('system', [SystemApiController::class, 'read']); diff --git a/tests/Api/SystemApiTest.php b/tests/Api/SystemApiTest.php new file mode 100644 index 000000000..21e378d61 --- /dev/null +++ b/tests/Api/SystemApiTest.php @@ -0,0 +1,25 @@ +actingAsApiEditor()->get('/api/system'); + $data = $resp->json(); + + $this->assertStringStartsWith('v', $data['version']); + $this->assertEquals(setting('instance-id'), $data['instance_id']); + $this->assertEquals(setting('app-name'), $data['app_name']); + $this->assertEquals(url('/logo.png'), $data['app_logo']); + $this->assertEquals(url('/'), $data['base_url']); + } +}