diff --git a/app/Http/Controllers/SoftwareUpdateController.php b/app/Http/Controllers/SoftwareUpdateController.php new file mode 100644 index 000000000..e29359830 --- /dev/null +++ b/app/Http/Controllers/SoftwareUpdateController.php @@ -0,0 +1,21 @@ +middleware('auth'); + $this->middleware('admin'); + } + + public function getSoftwareUpdateCheck(Request $request) + { + $res = SoftwareUpdateService::get(); + return $res; + } +} diff --git a/app/Services/Internal/SoftwareUpdateService.php b/app/Services/Internal/SoftwareUpdateService.php new file mode 100644 index 000000000..40aaf867e --- /dev/null +++ b/app/Services/Internal/SoftwareUpdateService.php @@ -0,0 +1,68 @@ + $curVersion, + 'latest' => [ + 'version' => null, + 'published_at' => null, + 'url' => null, + ], + 'running_latest' => $hideWarning ? true : null + ]; + } + + return [ + 'current' => $curVersion, + 'latest' => [ + 'version' => $versions['latest']['version'], + 'published_at' => $versions['latest']['published_at'], + 'url' => $versions['latest']['url'], + ], + 'running_latest' => strval($versions['latest']['version']) === strval($curVersion) + ]; + } + + public static function fetchLatest() + { + try { + $res = Http::withOptions(['allow_redirects' => false]) + ->timeout(5) + ->connectTimeout(5) + ->retry(2, 500) + ->get('https://versions.pixelfed.org/versions.json'); + } catch (RequestException $e) { + return; + } catch (ConnectionException $e) { + return; + } catch (Exception $e) { + return; + } + + if(!$res->ok()) { + return; + } + + return $res->json(); + } +} diff --git a/config/instance.php b/config/instance.php index 7d5463055..d1566da4a 100644 --- a/config/instance.php +++ b/config/instance.php @@ -140,5 +140,9 @@ return [ 'max_children' => env('INSTANCE_PARENTAL_CONTROLS_MAX_CHILDREN', 1), 'auto_verify_email' => true, ], - ] + ], + + 'software-update' => [ + 'disable_failed_warning' => env('INSTANCE_SOFTWARE_UPDATE_DISABLE_FAILED_WARNING', false) + ], ]; diff --git a/resources/assets/components/Home.vue b/resources/assets/components/Home.vue index c75ed0a13..dac188281 100644 --- a/resources/assets/components/Home.vue +++ b/resources/assets/components/Home.vue @@ -9,6 +9,48 @@
+ + + @@ -59,7 +101,6 @@ "rightbar": Rightbar, "story-carousel": StoryCarousel, }, - data() { return { isLoaded: false, @@ -67,7 +108,10 @@ recommended: [], trending: [], storiesEnabled: false, - shouldRefresh: false + shouldRefresh: false, + showUpdateWarning: false, + showUpdateConnectionWarning: false, + updateInfo: undefined, } }, @@ -84,10 +128,33 @@ this.profile = window._sharedData.user; this.isLoaded = true; this.storiesEnabled = window.App?.config?.features?.hasOwnProperty('stories') ? window.App.config.features.stories : false; + + if(this.profile.is_admin) { + this.softwareUpdateCheck(); + } }, updateProfile(delta) { this.profile = Object.assign(this.profile, delta); + }, + + softwareUpdateCheck() { + axios.get('/api/web-admin/software-update/check') + .then(res => { + if(!res || !res.data || !res.data.hasOwnProperty('running_latest') || res.data.running_latest) { + return; + } + if(res.data.running_latest === null) { + this.updateInfo = res.data; + this.showUpdateConnectionWarning = true; + return; + } + this.updateInfo = res.data; + this.showUpdateWarning = !res.data.running_latest; + }) + .catch(err => { + this.showUpdateConnectionWarning = true; + }) } } } diff --git a/routes/web-api.php b/routes/web-api.php index f51762439..e19c36b6c 100644 --- a/routes/web-api.php +++ b/routes/web-api.php @@ -1,5 +1,7 @@ middleware(['validemail', 'twofactor', 'localization'])->group(function () { Route::group(['prefix' => 'api'], function () { Route::get('search', 'SearchController@searchAPI'); @@ -7,6 +9,10 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('v1/polls/{id}', 'PollController@getPoll'); Route::post('v1/polls/{id}/votes', 'PollController@vote'); + Route::group(['prefix' => 'web-admin'], function() { + Route::get('software-update/check', [SoftwareUpdateController::class, 'getSoftwareUpdateCheck']); + }); + Route::group(['prefix' => 'compose'], function() { Route::group(['prefix' => 'v0'], function() { Route::post('/media/upload', 'ComposeController@mediaUpload');