server status included into the admin settings

This commit is contained in:
Čarodej
2022-02-15 09:33:53 +01:00
parent da74a38605
commit b897eaf482
14 changed files with 347 additions and 90 deletions

View File

@@ -67,5 +67,6 @@
"/js/chunks/shared-with-me.js": "/js/chunks/shared-with-me.js",
"/js/chunks/invitation.js": "/js/chunks/invitation.js",
"/css/tailwind.css": "/css/tailwind.css",
"/css/app.css": "/css/app.css"
"/css/app.css": "/css/app.css",
"/js/chunks/app-server.js": "/js/chunks/app-server.js"
}

View File

@@ -321,6 +321,15 @@ const routesAdmin = [
title: 'Adsense',
},
},
{
name: 'AppServer',
path: '/admin/settings/server',
component: () => import(/* webpackChunkName: "chunks/app-server" */ '../views/Admin/AppSettings/AppSettingsTabs/Server'),
meta: {
requiresAuth: true,
title: 'Server',
},
},
],
},
{

View File

@@ -45,6 +45,10 @@ export default {
title: this.$t('admin_settings.tabs.email'),
route: 'AppEmail',
},
{
title: this.$t('Server'),
route: 'AppServer',
},
],
}
},

View File

@@ -0,0 +1,165 @@
<template>
<PageTab v-if="! isLoading">
<!--PHP version and ini check-->
<div class="card shadow-card">
<FormLabel>
PHP Version & php.ini
</FormLabel>
<div class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<div class="text-left">
<b class="text-sm font-bold block">PHP Version</b>
<small v-if="!phpVersion.acceptable" class="text-xs text-gray-600">
You need PHP version at least {{ phpVersion.minimal }}.
</small>
</div>
<div class="flex items-center">
<check-icon v-if="phpVersion.acceptable" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!phpVersion.acceptable" size="16" class="vue-feather text-red-600" />
<span class="ml-3 text-sm font-bold" :class="phpVersion.acceptable ? 'text-green-600' : 'text-red-600'">
{{ phpVersion.current }}
</span>
</div>
</div>
<div v-for="(values, setting, i) in ini" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<div class="text-left">
<b class="text-sm font-bold block">{{ setting }}</b>
<small v-if="!values.status" class="text-xs text-gray-600">
We recommend set this value at least {{ values.minimal }}.
</small>
</div>
<div class="flex items-center">
<check-icon v-if="values.status" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!values.status" size="16" class="vue-feather text-red-600" />
<span class="ml-3 text-sm font-bold" :class="values.status ? 'text-green-600' : 'text-red-600'">
{{ values.current }}{{ setting !== 'max_execution_time' ? 'M' : '' }}
</span>
</div>
</div>
</div>
<!--PHP Extension info-->
<div class="card shadow-card">
<FormLabel>
Required PHP Extensions
</FormLabel>
<div v-if="modules" v-for="(value, module, i) in modules" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<b class="text-sm font-bold">
{{ module }}
</b>
<div class="flex items-center">
<check-icon v-if="value" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!value" size="16" class="vue-feather text-red-600"/>
<span class="ml-3 text-sm font-bold" :class="value ? 'text-green-600' : 'text-red-600'">
{{ value ? 'Module Installed' : 'Missing Module' }}
</span>
</div>
</div>
</div>
<!--API check-->
<div class="card shadow-card">
<FormLabel>
Others
</FormLabel>
<div class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<div class="text-left">
<b class="text-sm font-bold block">API</b>
<small v-if="isCheckedAPI && !apiRunning" class="text-xs text-gray-600">
We detect, your domain root is not set correctly, please check it.
</small>
</div>
<div v-if="isCheckedAPI" class="flex items-center">
<check-icon v-if="apiRunning" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!apiRunning" size="16" class="vue-feather text-red-600" />
<span class="ml-3 text-sm font-bold" :class="apiRunning ? 'text-green-600' : 'text-red-600'">
{{ apiRunning ? 'Working correctly' : "Doesn't work" }}
</span>
</div>
<span v-if="!isCheckedAPI" class="ml-3 text-sm font-bold text-gray-600">Checking your API...</span>
</div>
<div class="pt-3 flex items-center justify-between">
<div class="text-left">
<b class="text-sm font-bold block">Cron</b>
<small v-if="!cron.running" class="text-xs text-gray-600">
We detect, your cron jobs probably doesn't work correctly, please check it.
</small>
<small v-if="cron.running" class="text-xs text-gray-600">
Latest Update: {{ cron.lastUpdate }}
</small>
</div>
<div class="flex items-center">
<check-icon v-if="cron.running" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!cron.running" size="16" class="vue-feather text-red-600" />
<span class="ml-3 text-sm font-bold" :class="cron.running ? 'text-green-600' : 'text-red-600'">
{{ cron.running ? 'Working correctly' : "Doesn't work" }}
</span>
</div>
</div>
</div>
</PageTab>
</template>
<script>
import { CheckIcon, XIcon } from 'vue-feather-icons'
import FormLabel from '../../../../components/Others/Forms/FormLabel'
import PageTab from '../../../../components/Others/Layout/PageTab'
import { mapGetters } from 'vuex'
import axios from "axios";
export default {
name: 'Server',
components: {
FormLabel,
PageTab,
CheckIcon,
XIcon,
},
computed: {
...mapGetters(['config']),
isCheckedAPI() {
return typeof this.apiRunning !== 'undefined'
},
},
data() {
return {
isLoading: true,
ini: undefined,
cron: undefined,
modules: undefined,
phpVersion: undefined,
apiRunning: undefined,
}
},
created() {
// Get status
axios.get('/api/admin/status')
.then(response => {
this.isLoading = false
this.ini = response.data.ini
this.cron = response.data.cron
this.modules = response.data.modules
this.phpVersion = response.data.php_version
})
// Ping API
axios
.get('/api/ping')
.then((response) => {
this.apiRunning = response.data === 'pong';
})
.catch(() => {
this.apiRunning = false
})
},
}
</script>

View File

@@ -37,11 +37,18 @@
</div>
</div>
<!--Create metered plan alert-->
<div v-if="config.subscriptionType === 'metered' && config.isEmptyPlans" class="p-5 bg-rose-200 rounded-xl shadow-card mb-6 flex items-center">
<alert-octagon-icon size="18" class="vue-feather text-rose-700 mr-4 shrink-0"/>
<p class="text-sm text-rose-700">As you installed app with metered subscription type, you have to <router-link :to="{name: 'CreateMeteredPlan'}" class="font-bold underline text-sm">create your plan</router-link> as soon as possible to prevent new user registration without automatically assigned subscription plan.</p>
</div>
<!--Cron Alert-->
<div v-if="! data.app.isRunningCron && !config.isDev" class="p-5 bg-rose-200 rounded-xl shadow-card mb-6 flex items-center">
<alert-octagon-icon size="18" class="vue-feather text-rose-700 mr-4 shrink-0"/>
<p class="text-sm text-rose-700">We detect your cron jobs probably doesn't work correctly, please check it, you need it for running app correctly. If you set your cron job, please get back one minute later.</p>
</div>
<!--Metric widgets-->
<div class="mb-2 md:mb-6 md:flex md:space-x-6">
<div class="card mb-4 w-full shadow-card md:mb-0">

View File

@@ -10,31 +10,6 @@
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<!--PHP Extension info-->
<div class="card shadow-card">
<FormLabel>
Required PHP Extensions
</FormLabel>
<InfoBox class="!mb-2">
<p>Those PHP modules are needed for accurate running VueFileManager on your server, please check and install if some is missing.</p>
</InfoBox>
<div v-if="modules" v-for="(value, module, i) in modules" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<b class="text-sm font-bold">
{{ module }}
</b>
<div class="flex items-center">
<check-icon v-if="value" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!value" size="16" class="vue-feather text-red-600"/>
<span class="ml-3 text-sm font-bold" :class="value ? 'text-green-600' : 'text-red-600'">
{{ value ? 'Module Installed' : 'Missing Module' }}
</span>
</div>
</div>
</div>
<!--PHP version and ini check-->
<div class="card shadow-card">
<FormLabel>
@@ -80,6 +55,31 @@
</div>
</div>
<!--PHP Extension info-->
<div class="card shadow-card">
<FormLabel>
Required PHP Extensions
</FormLabel>
<InfoBox class="!mb-2">
<p>Those PHP modules are needed for accurate running VueFileManager on your server, please check and install if some is missing.</p>
</InfoBox>
<div v-if="modules" v-for="(value, module, i) in modules" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<b class="text-sm font-bold">
{{ module }}
</b>
<div class="flex items-center">
<check-icon v-if="value" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!value" size="16" class="vue-feather text-red-600"/>
<span class="ml-3 text-sm font-bold" :class="value ? 'text-green-600' : 'text-red-600'">
{{ value ? 'Module Installed' : 'Missing Module' }}
</span>
</div>
</div>
</div>
<!--API check-->
<div class="card shadow-card">
<FormLabel>
@@ -126,12 +126,11 @@ import FormLabel from '../../components/Others/Forms/FormLabel'
import InfoBox from '../../components/Others/Forms/InfoBox'
import AuthContent from '../../components/Auth/AuthContent'
import AuthButton from '../../components/Auth/AuthButton'
import { SettingsIcon } from 'vue-feather-icons'
import { required } from 'vee-validate/dist/rules'
import Headline from '../Auth/Headline'
import { mapGetters } from 'vuex'
import axios from 'axios'
import { CheckIcon, XIcon } from 'vue-feather-icons'
import { CheckIcon, XIcon, SettingsIcon } from 'vue-feather-icons'
export default {
name: 'StatusCheck',
@@ -187,11 +186,7 @@ export default {
axios
.get('/api/ping')
.then((response) => {
if (response.data === 'pong') {
this.apiRunning = true
} else {
this.apiRunning = false
}
this.apiRunning = response.data === 'pong';
})
.catch(() => {
this.apiRunning = false

View File

@@ -2,6 +2,7 @@
use Domain\Admin\Controllers\Users\UserController;
use Domain\Pages\Controllers\AdminPagesController;
use Domain\Settings\Controllers\GetServerStatusController;
use Domain\Settings\Controllers\StoreEmailCredentialsController;
use Domain\Settings\Controllers\FlushCacheController;
use Domain\Localization\Controllers\LanguageController;
@@ -57,3 +58,6 @@ Route::group(['prefix' => 'settings'], function () {
// Language
Route::patch('/languages/{language}/strings', UpdateLanguageStringController::class);
Route::apiResource('/languages', LanguageController::class);
// Server Status
Route::get('/status', GetServerStatusController::class);

View File

@@ -1,6 +1,7 @@
<?php
namespace App\Console;
use Carbon\Carbon;
use Illuminate\Console\Scheduling\Schedule;
use App\Console\Commands\SetupDevEnvironment;
use App\Console\Commands\SetupProdEnvironment;
@@ -59,9 +60,13 @@ class Kernel extends ConsoleKernel
$schedule->command('backup:clean')
->daily()
->at('00:15');
$schedule->command('backup:run --only-db')
->daily()
->at('00:20');
// Store latest cron timestamp
cache()->set('latest_cron_update', now()->toString());
}
/**

View File

@@ -39,10 +39,11 @@ class GetDashboardDataController extends Controller
'records' => $upload,
],
],
'app' => [
'license' => get_settings('license'),
'version' => config('vuefilemanager.version'),
'earnings' => format_currency($totalEarnings, 'USD'), // todo: refactor currency to global setup
'app' => [
'isRunningCron' => isRunningCron(),
'license' => get_settings('license'),
'version' => config('vuefilemanager.version'),
'earnings' => format_currency($totalEarnings, 'USD'), // todo: refactor currency to global setup or plan currency
],
]);
}

View File

@@ -7,9 +7,14 @@ use Domain\Pages\Models\Page;
use Illuminate\Contracts\View\View;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\Foundation\Application;
use Support\Status\Actions\GetServerSetupStatusAction;
class IndexController
{
public function __construct(
public GetServerSetupStatusAction $getServerSetupStatus,
) {}
/**
* Show index page
*/
@@ -32,58 +37,7 @@ class IndexController
} catch (PDOException $e) {}
if ($setup_status === 'installation-needed') {
// Required parameters
$upload_max_filesize = 128;
$post_max_size = 128;
$memory_limit = 512;
$max_execution_time = 600;
$php_version = '8.0';
$status_check = [
'modules' => [
'tokenizer' => extension_loaded('tokenizer'),
'fileinfo' => extension_loaded('fileinfo'),
'mbstring' => extension_loaded('mbstring'),
'openssl' => extension_loaded('openssl'),
'sqlite3' => extension_loaded('sqlite3'),
'bcmath' => extension_loaded('bcmath'),
'ctype' => extension_loaded('ctype'),
'json' => extension_loaded('json'),
'exif' => extension_loaded('exif'),
'intl' => extension_loaded('intl'),
'pdo' => extension_loaded('pdo'),
'xml' => extension_loaded('xml'),
'gd' => extension_loaded('gd'),
],
'ini' => [
'upload_max_filesize' => [
'current' => intval(ini_get('upload_max_filesize')),
'minimal' => $upload_max_filesize,
'status' => intval(ini_get('upload_max_filesize')) >= $upload_max_filesize,
],
'post_max_size' => [
'current' => intval(ini_get('post_max_size')),
'minimal' => $post_max_size,
'status' => intval(ini_get('post_max_size')) >= $post_max_size,
],
'memory_limit' => [
'current' => intval(ini_get('memory_limit')),
'minimal' => $memory_limit,
'status' => intval(ini_get('memory_limit')) >= $memory_limit,
],
'max_execution_time' => [
'current' => intval(ini_get('max_execution_time')),
'minimal' => $max_execution_time,
'status' => intval(ini_get('max_execution_time')) >= $max_execution_time,
],
],
'php_version' => [
'acceptable' => version_compare(PHP_VERSION, $php_version, '>='),
'current' => phpversion(),
'minimal' => $php_version,
],
];
$status_check = ($this->getServerSetupStatus)();
}
return view('index')

View File

@@ -0,0 +1,27 @@
<?php
namespace Domain\Settings\Controllers;
use Carbon\Carbon;
use Support\Status\Actions\GetServerSetupStatusAction;
class GetServerStatusController
{
public function __construct(
public GetServerSetupStatusAction $getServerSetupStatus,
) {}
public function __invoke(): array
{
// Get server data
$status = ($this->getServerSetupStatus)();
// Add cron info
$status['cron'] = [
'running' => isRunningCron(),
'lastUpdate' => isRunningCron() ? format_date(cache()->get('latest_cron_update')) : '',
];
return $status;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Support\Status\Actions;
class GetServerSetupStatusAction
{
public function __invoke()
{
// Required parameters
$upload_max_filesize = 128;
$post_max_size = 128;
$memory_limit = 512;
$max_execution_time = 600;
$php_version = '8.0';
return [
'modules' => [
'tokenizer' => extension_loaded('tokenizer'),
'fileinfo' => extension_loaded('fileinfo'),
'mbstring' => extension_loaded('mbstring'),
'openssl' => extension_loaded('openssl'),
'sqlite3' => extension_loaded('sqlite3'),
'bcmath' => extension_loaded('bcmath'),
'ctype' => extension_loaded('ctype'),
'json' => extension_loaded('json'),
'exif' => extension_loaded('exif'),
'intl' => extension_loaded('intl'),
'pdo' => extension_loaded('pdo'),
'xml' => extension_loaded('xml'),
'gd' => extension_loaded('gd'),
],
'ini' => [
'upload_max_filesize' => [
'current' => intval(ini_get('upload_max_filesize')),
'minimal' => $upload_max_filesize,
'status' => intval(ini_get('upload_max_filesize')) >= $upload_max_filesize,
],
'post_max_size' => [
'current' => intval(ini_get('post_max_size')),
'minimal' => $post_max_size,
'status' => intval(ini_get('post_max_size')) >= $post_max_size,
],
'memory_limit' => [
'current' => intval(ini_get('memory_limit')),
'minimal' => $memory_limit,
'status' => intval(ini_get('memory_limit')) >= $memory_limit,
],
'max_execution_time' => [
'current' => intval(ini_get('max_execution_time')),
'minimal' => $max_execution_time,
'status' => intval(ini_get('max_execution_time')) >= $max_execution_time,
],
],
'php_version' => [
'acceptable' => version_compare(PHP_VERSION, $php_version, '>='),
'current' => phpversion(),
'minimal' => $php_version,
],
];
}
}

View File

@@ -17,6 +17,16 @@ use Domain\Localization\Models\Language;
use Intervention\Image\ImageManagerStatic as Image;
use Illuminate\Database\Eloquent\ModelNotFoundException;
if (! function_exists('isRunningCron')) {
/**
* Check if cron is running
*/
function isRunningCron(): bool
{
return cache()->has('latest_cron_update') && Carbon::parse(cache()->get('latest_cron_update'))->diffInMinutes(now()) < 5;
}
}
if (! function_exists('obfuscate_email')) {
/**
* Obfuscate email

View File

@@ -14,6 +14,21 @@ use App\Users\Notifications\ResetPassword;
class AdminTest extends TestCase
{
/**
* @test
*/
public function it_get_server_status()
{
$admin = User::factory()
->hasSettings()
->create(['role' => 'admin']);
$this
->actingAs($admin)
->getJson("/api/admin/status")
->assertOk();
}
/**
* @test
*/
@@ -53,7 +68,6 @@ class AdminTest extends TestCase
->hasSettings()
->create(['role' => 'admin']);
// TODO: pridat exactjson po refaktorovani userresource
$this
->actingAs($admin)
->getJson("/api/admin/users/$user->id")