Standardised logic for reading app version to its own static class.
namespace BookStack\Api;
+use BookStack\App\AppVersion;
use BookStack\Http\ApiController;
use Exception;
use Illuminate\Contracts\Container\BindingResolutionException;
*/
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;
--- /dev/null
+<?php
+
+namespace BookStack\App;
+
+class AppVersion
+{
+ protected static string $version = '';
+
+ /**
+ * Get the application's version number from its top-level `version` text file.
+ */
+ public static function get(): string
+ {
+ if (!empty(static::$version)) {
+ return static::$version;
+ }
+
+ $versionFile = base_path('version');
+ $version = trim(file_get_contents($versionFile));
+ static::$version = $version;
+
+ return $version;
+ }
+}
--- /dev/null
+<?php
+
+namespace BookStack\App;
+
+use BookStack\Http\ApiController;
+use Illuminate\Http\JsonResponse;
+
+class SystemApiController extends ApiController
+{
+ /**
+ * Read details regarding the BookStack instance.
+ * Some details may be null where not set, like the app logo for example.
+ */
+ public function read(): JsonResponse
+ {
+ $logoSetting = setting('app-logo', '');
+ if ($logoSetting === 'none') {
+ $logo = null;
+ } else {
+ $logo = $logoSetting ? url($logoSetting) : url('/logo.png');
+ }
+
+ return response()->json([
+ 'version' => AppVersion::get(),
+ 'instance_id' => setting('instance-id'),
+ 'app_name' => setting('app-name'),
+ 'app_logo' => $logo,
+ 'base_url' => url('/'),
+ ]);
+ }
+}
<?php
+use BookStack\App\AppVersion;
use BookStack\App\Model;
use BookStack\Facades\Theme;
use BookStack\Permissions\PermissionApplicator;
*/
function versioned_asset(string $file = ''): string
{
- static $version = null;
-
- if (is_null($version)) {
- $versionFile = base_path('version');
- $version = trim(file_get_contents($versionFile));
- }
+ $version = AppVersion::get();
$additional = '';
if (config('app.env') === 'development') {
namespace BookStack\Exceptions;
+use BookStack\App\AppVersion;
use Illuminate\Contracts\Foundation\ExceptionRenderer;
class BookStackExceptionHandlerPage implements ExceptionRenderer
return [
'PHP Version' => 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');
namespace BookStack\Exports\ZipExports;
+use BookStack\App\AppVersion;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
$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-');
namespace BookStack\Settings;
use BookStack\Activity\ActivityType;
+use BookStack\App\AppVersion;
use BookStack\Entities\Tools\TrashCan;
use BookStack\Http\Controller;
use BookStack\References\ReferenceStore;
$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,
]);
}
namespace BookStack\Settings;
use BookStack\Activity\ActivityType;
+use BookStack\App\AppVersion;
use BookStack\Http\Controller;
use BookStack\Users\Models\User;
use Illuminate\Http\Request;
$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(),
]);
}
--- /dev/null
+{
+ "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
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;
Route::put('content-permissions/{contentType}/{contentId}', [ContentPermissionApiController::class, 'update']);
Route::get('audit-log', [AuditLogApiController::class, 'list']);
+
+Route::get('system', [SystemApiController::class, 'read']);