From dd060138ae36f48f590218efbb46af0e89761059 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Fri, 21 Oct 2022 06:17:13 -0400 Subject: [PATCH 1/3] Adhoc speedtest button on dashboard page (#55) --- app/Filament/Pages/Dashboard.php | 32 +++++++++++++++++++ config/filament.php | 2 +- .../views/filament/pages/dashboard.blade.php | 5 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 app/Filament/Pages/Dashboard.php create mode 100644 resources/views/filament/pages/dashboard.blade.php diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php new file mode 100644 index 000000000..e7601168f --- /dev/null +++ b/app/Filament/Pages/Dashboard.php @@ -0,0 +1,32 @@ +label('Queue Speedtest') + ->action('queueSpeedtest'), + ]; + } + + public function queueSpeedtest() + { + ExecSpeedtest::dispatch(); + + Notification::make() + ->title('Speedtest added to the queue') + ->success() + ->send(); + } +} diff --git a/config/filament.php b/config/filament.php index 8a64ea931..40c4a1b44 100644 --- a/config/filament.php +++ b/config/filament.php @@ -105,7 +105,7 @@ 'namespace' => 'App\\Filament\\Pages', 'path' => app_path('Filament/Pages'), 'register' => [ - Pages\Dashboard::class, + // Pages\Dashboard::class, ], ], diff --git a/resources/views/filament/pages/dashboard.blade.php b/resources/views/filament/pages/dashboard.blade.php new file mode 100644 index 000000000..37ebb09e0 --- /dev/null +++ b/resources/views/filament/pages/dashboard.blade.php @@ -0,0 +1,5 @@ + +

+ 👋 Welcome to Speedtest Tracker, here you can track your internet speed using Ookla's Speedtest service. Keep in mind that this is still work in progress so make sure to check out the documentation and follow along on GitHub for updates. +

+
From 195142c590d0350a66ff4684c60f11d5f192e064 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Fri, 21 Oct 2022 06:45:57 -0400 Subject: [PATCH 2/3] Moved latest test widgets to the dashboard (#57) --- app/Filament/Pages/Dashboard.php | 8 ++++++ app/Filament/Resources/ResultResource.php | 12 +-------- .../ResultResource/Widgets/StatsOverview.php | 21 --------------- app/Filament/Widgets/StatsOverview.php | 26 +++++++++++++++++++ app/Providers/FilamentServiceProvider.php | 1 - 5 files changed, 35 insertions(+), 33 deletions(-) delete mode 100644 app/Filament/Resources/ResultResource/Widgets/StatsOverview.php create mode 100644 app/Filament/Widgets/StatsOverview.php diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index e7601168f..5051f8dcb 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -2,6 +2,7 @@ namespace App\Filament\Pages; +use App\Filament\Widgets\StatsOverview; use App\Jobs\ExecSpeedtest; use Filament\Notifications\Notification; use Filament\Pages\Actions\Action; @@ -20,6 +21,13 @@ protected function getActions(): array ]; } + public function getHeaderWidgets(): array + { + return [ + StatsOverview::class, + ]; + } + public function queueSpeedtest() { ExecSpeedtest::dispatch(); diff --git a/app/Filament/Resources/ResultResource.php b/app/Filament/Resources/ResultResource.php index 91757eabd..c33a32501 100644 --- a/app/Filament/Resources/ResultResource.php +++ b/app/Filament/Resources/ResultResource.php @@ -3,7 +3,6 @@ namespace App\Filament\Resources; use App\Filament\Resources\ResultResource\Pages; -use App\Filament\Resources\ResultResource\Widgets\StatsOverview; use App\Models\Result; use Filament\Resources\Resource; use Filament\Resources\Table; @@ -15,11 +14,9 @@ class ResultResource extends Resource { protected static ?string $model = Result::class; - protected static ?string $navigationGroup = 'Data'; - protected static ?string $navigationIcon = 'heroicon-o-table'; - protected static ?string $navigationLabel = 'Speedtest Results'; + protected static ?string $navigationLabel = 'Results'; public static function table(Table $table): Table { @@ -63,11 +60,4 @@ public static function getPages(): array 'index' => Pages\ListResults::route('/'), ]; } - - public static function getWidgets(): array - { - return [ - StatsOverview::class, - ]; - } } diff --git a/app/Filament/Resources/ResultResource/Widgets/StatsOverview.php b/app/Filament/Resources/ResultResource/Widgets/StatsOverview.php deleted file mode 100644 index 86a25a762..000000000 --- a/app/Filament/Resources/ResultResource/Widgets/StatsOverview.php +++ /dev/null @@ -1,21 +0,0 @@ -first()?->download ?: 0)).'ps'), - Card::make('Latest upload', formatBits(formatBytesToBits(Result::latest()->first()?->upload ?: 0)).'ps'), - Card::make('Latest ping', round(Result::latest()->first()?->ping ?: 0, 2)), - ]; - } -} diff --git a/app/Filament/Widgets/StatsOverview.php b/app/Filament/Widgets/StatsOverview.php new file mode 100644 index 000000000..6473bde2a --- /dev/null +++ b/app/Filament/Widgets/StatsOverview.php @@ -0,0 +1,26 @@ +first(); + + return [ + Card::make('Latest download', fn (): string => ! blank($result) ? formatBits(formatBytesToBits($result->download)).'ps' : 'n/a') + ->icon('heroicon-o-download'), + Card::make('Latest upload', fn (): string => ! blank($result) ? formatBits(formatBytesToBits($result->upload)).'ps' : 'n/a') + ->icon('heroicon-o-upload'), + Card::make('Latest ping', fn (): string => ! blank($result) ? round($result->ping, 2).'ms' : 'n/a') + ->icon('heroicon-o-clock'), + ]; + } +} diff --git a/app/Providers/FilamentServiceProvider.php b/app/Providers/FilamentServiceProvider.php index 49459661d..83fd0fe49 100644 --- a/app/Providers/FilamentServiceProvider.php +++ b/app/Providers/FilamentServiceProvider.php @@ -27,7 +27,6 @@ public function boot() { Filament::serving(function () { Filament::registerNavigationGroups([ - 'Data', 'Links', ]); From 58c160e270966def088c8ff5fc0d56010ebb369e Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Fri, 21 Oct 2022 09:49:32 -0400 Subject: [PATCH 3/3] Replace config.yml with settings UI (#58) --- .dockerignore | 1 - .gitignore | 2 +- .phpstorm.meta.php | 66 ++ app/Console/Commands/TestInfluxDB.php | 23 +- app/Filament/Pages/Dashboard.php | 11 +- app/Filament/Pages/Settings/General.php | 89 ++ app/Filament/Pages/Settings/InfluxDb.php | 82 ++ app/Jobs/SearchForSpeedtests.php | 43 +- app/Observers/ResultObserver.php | 28 +- app/Providers/FilamentServiceProvider.php | 1 + app/Settings/GeneralSettings.php | 23 + app/Settings/InfluxDbSettings.php | 23 + composer.json | 4 +- composer.lock | 943 +++++++++++++----- config.example.yml | 20 - config/settings.php | 80 ++ ...022_10_21_104903_create_settings_table.php | 27 + ...2_10_21_105703_create_general_settings.php | 15 + ..._10_21_130121_create_influxdb_settings.php | 15 + docker/deploy/etc/s6-overlay/scripts/startup | 9 - 20 files changed, 1166 insertions(+), 339 deletions(-) create mode 100644 app/Filament/Pages/Settings/General.php create mode 100644 app/Filament/Pages/Settings/InfluxDb.php create mode 100644 app/Settings/GeneralSettings.php create mode 100644 app/Settings/InfluxDbSettings.php delete mode 100644 config.example.yml create mode 100644 config/settings.php create mode 100644 database/migrations/2022_10_21_104903_create_settings_table.php create mode 100644 database/settings/2022_10_21_105703_create_general_settings.php create mode 100644 database/settings/2022_10_21_130121_create_influxdb_settings.php diff --git a/.dockerignore b/.dockerignore index d89ac53be..1a8d61ec4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -16,7 +16,6 @@ _ide_helper.php .env.backup .phpstorm.meta.php .phpunit.result.cache -config.yml auth.json docker-compose.yml Homestead.json diff --git a/.gitignore b/.gitignore index 554ebe677..f185879f4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ /public/storage /storage/*.key /vendor -config.yml + .env .env.backup .phpunit.result.cache diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php index cdad6ebb5..2932c8632 100644 --- a/.phpstorm.meta.php +++ b/.phpstorm.meta.php @@ -11,6 +11,8 @@ */ override(new \Illuminate\Contracts\Container\Container, map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -148,6 +150,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -198,6 +204,8 @@ ])); override(\Illuminate\Container\Container::makeWith(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -335,6 +343,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -385,6 +397,8 @@ ])); override(\Illuminate\Contracts\Container\Container::get(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -522,6 +536,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -572,6 +590,8 @@ ])); override(\Illuminate\Contracts\Container\Container::make(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -709,6 +729,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -759,6 +783,8 @@ ])); override(\Illuminate\Contracts\Container\Container::makeWith(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -896,6 +922,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -946,6 +976,8 @@ ])); override(\App::get(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -1083,6 +1115,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -1133,6 +1169,8 @@ ])); override(\App::make(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -1270,6 +1308,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -1320,6 +1362,8 @@ ])); override(\App::makeWith(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -1457,6 +1501,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -1507,6 +1555,8 @@ ])); override(\app(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -1644,6 +1694,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -1694,6 +1748,8 @@ ])); override(\resolve(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -1831,6 +1887,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, @@ -1881,6 +1941,8 @@ ])); override(\Psr\Container\ContainerInterface::get(0), map([ '' => '@', + 'App\Settings\GeneralSettings' => \App\Settings\GeneralSettings::class, + 'App\Settings\InfluxDbSettings' => \App\Settings\InfluxDbSettings::class, 'BladeUI\Icons\Factory' => \BladeUI\Icons\Factory::class, 'BladeUI\Icons\IconsManifest' => \BladeUI\Icons\IconsManifest::class, 'Filament\Http\Responses\Auth\Contracts\LoginResponse' => \Filament\Http\Responses\Auth\LoginResponse::class, @@ -2018,6 +2080,10 @@ 'Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder' => \Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder::class, 'Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder' => \Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder::class, 'Spatie\LaravelIgnition\Support\SentReports' => \Spatie\LaravelIgnition\Support\SentReports::class, + 'Spatie\LaravelSettings\SettingsCache' => \Spatie\LaravelSettings\SettingsCache::class, + 'Spatie\LaravelSettings\SettingsMapper' => \Spatie\LaravelSettings\SettingsMapper::class, + 'Spatie\LaravelSettings\SettingsRepositories\SettingsRepository' => \Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'Squire\RepositoryManager' => \Squire\RepositoryManager::class, 'Whoops\Handler\HandlerInterface' => \Spatie\LaravelIgnition\Renderers\IgnitionWhoopsHandler::class, 'auth' => \Illuminate\Auth\AuthManager::class, 'auth.password' => \Illuminate\Auth\Passwords\PasswordBrokerManager::class, diff --git a/app/Console/Commands/TestInfluxDB.php b/app/Console/Commands/TestInfluxDB.php index f89bbd06f..752a16b37 100644 --- a/app/Console/Commands/TestInfluxDB.php +++ b/app/Console/Commands/TestInfluxDB.php @@ -3,9 +3,8 @@ namespace App\Console\Commands; use App\Models\Result; +use App\Settings\InfluxDbSettings; use Illuminate\Console\Command; -use Illuminate\Support\Facades\File; -use Symfony\Component\Yaml\Yaml; class TestInfluxDB extends Command { @@ -28,19 +27,15 @@ class TestInfluxDB extends Command * * @return int */ - public function handle() + public function handle(InfluxDbSettings $settings) { - if (File::exists(base_path().'/config.yml')) { - $config = Yaml::parseFile( - base_path().'/config.yml' - ); - } - - if (File::exists('/app/config.yml')) { - $config = Yaml::parseFile('/app/config.yml'); - } - - $influxdb = $config['influxdb']; + $influxdb = [ + 'enabled' => $settings->v2_enabled, + 'url' => optional($settings)->v2_url, + 'org' => optional($settings)->v2_org, + 'bucket' => optional($settings)->v2_bucket, + 'token' => optional($settings)->v2_token, + ]; if ($influxdb['enabled'] == true) { $result = Result::factory()->create(); diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php index 5051f8dcb..29a71ccd0 100644 --- a/app/Filament/Pages/Dashboard.php +++ b/app/Filament/Pages/Dashboard.php @@ -4,6 +4,7 @@ use App\Filament\Widgets\StatsOverview; use App\Jobs\ExecSpeedtest; +use App\Settings\GeneralSettings; use Filament\Notifications\Notification; use Filament\Pages\Actions\Action; use Filament\Pages\Dashboard as BasePage; @@ -28,9 +29,15 @@ public function getHeaderWidgets(): array ]; } - public function queueSpeedtest() + public function queueSpeedtest(GeneralSettings $settings) { - ExecSpeedtest::dispatch(); + $speedtest = [ + 'enabled' => ! blank($settings->speedtest_schedule), + 'schedule' => optional($settings)->speedtest_schedule, + 'ookla_server_id' => optional($settings)->speedtest_server, + ]; + + ExecSpeedtest::dispatch(speedtest: $speedtest, scheduled: false); Notification::make() ->title('Speedtest added to the queue') diff --git a/app/Filament/Pages/Settings/General.php b/app/Filament/Pages/Settings/General.php new file mode 100644 index 000000000..5247d155f --- /dev/null +++ b/app/Filament/Pages/Settings/General.php @@ -0,0 +1,89 @@ + 1, + 'md' => 3, + ]) + ->schema([ + Grid::make([ + 'default' => 1, + ]) + ->schema([ + Section::make('Site Settings') + ->collapsible() + ->schema([ + TextInput::make('site_name') + ->maxLength(50) + ->required() + ->columnSpan(['md' => 2]), + Select::make('timezone') + ->options(Timezone::all()->pluck('code', 'code')) + ->searchable() + ->required() + ->columnSpan(1), + ]) + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + + Section::make('Speedtest Settings') + ->collapsible() + ->schema([ + TextInput::make('speedtest_schedule') + ->helperText('Leave empty to disable the schedule. You can also use the cron expression generator [HERE](https://crontab.cronhub.io/) to help you make schedules.') + ->nullable() + ->columnSpan(1), + TextInput::make('speedtest_server') + ->helperText('Leave empty to let the system pick the best server.') + ->nullable() + ->columnSpan(1), + ]) + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + ]) + ->columnSpan([ + 'md' => 2, + ]), + + Card::make() + ->schema([ + Toggle::make('auth_enabled') + ->label('Authentication enabled') + ->helperText("NOTE: Authentication is currently required. It's on the roadmap to be able to disabled it though.") + ->disabled(), + ]) + ->columnSpan([ + 'md' => 1, + ]), + ]), + ]; + } +} diff --git a/app/Filament/Pages/Settings/InfluxDb.php b/app/Filament/Pages/Settings/InfluxDb.php new file mode 100644 index 000000000..e0dddd097 --- /dev/null +++ b/app/Filament/Pages/Settings/InfluxDb.php @@ -0,0 +1,82 @@ + 1, + 'md' => 3, + ]) + ->schema([ + Grid::make([ + 'default' => 1, + ]) + ->schema([ + Section::make('InfluxDB v2 Settings') + ->collapsible() + ->schema([ + TextInput::make('v2_url') + ->label('URL') + ->placeholder('http://your-influxdb-instance') + ->maxLength(255) + ->columnSpan(['md' => 2]), + TextInput::make('v2_org') + ->label('Org') + ->maxLength(255) + ->columnSpan(1), + TextInput::make('v2_bucket') + ->placeholder('speedtest-tracker') + ->label('Bucket') + ->maxLength(255) + ->columnSpan(1), + TextInput::make('v2_token') + ->label('Token') + ->maxLength(255) + ->password() + ->disableAutocomplete() + ->columnSpan(['md' => 2]), + ]) + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + ]) + ->columnSpan([ + 'md' => 2, + ]), + + Card::make() + ->schema([ + Toggle::make('v2_enabled') + ->label('v2 enabled') + ->helperText('NOTE: At this time only InfluxDB v2 is supported'), + ]) + ->columnSpan([ + 'md' => 1, + ]), + ]), + ]; + } +} diff --git a/app/Jobs/SearchForSpeedtests.php b/app/Jobs/SearchForSpeedtests.php index 1a99da0b9..eccbf2757 100644 --- a/app/Jobs/SearchForSpeedtests.php +++ b/app/Jobs/SearchForSpeedtests.php @@ -2,52 +2,37 @@ namespace App\Jobs; +use App\Settings\GeneralSettings; use Cron\CronExpression; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\File; -use Symfony\Component\Yaml\Yaml; class SearchForSpeedtests implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct() - { - // - } - /** * Execute the job. * * @return void */ - public function handle() + public function handle(GeneralSettings $settings) { - if (File::exists(base_path().'/config.yml')) { - $config = Yaml::parseFile( - base_path().'/config.yml' - ); - } - - if (File::exists('/app/config.yml')) { - $config = Yaml::parseFile('/app/config.yml'); - } - - $speedtest = $config['speedtest']; - - $cron = new CronExpression($speedtest['schedule']); - - if ($cron->isDue() && $speedtest['enabled']) { - ExecSpeedtest::dispatch(speedtest: $speedtest, scheduled: true); + $speedtest = [ + 'enabled' => ! blank($settings->speedtest_schedule), + 'schedule' => optional($settings)->speedtest_schedule, + 'ookla_server_id' => optional($settings)->speedtest_server, + ]; + + if ($speedtest['enabled']) { + $cron = new CronExpression($speedtest['schedule']); + + if ($cron->isDue()) { + ExecSpeedtest::dispatch(speedtest: $speedtest, scheduled: true); + } } } } diff --git a/app/Observers/ResultObserver.php b/app/Observers/ResultObserver.php index 0089a3182..c00c95e6a 100644 --- a/app/Observers/ResultObserver.php +++ b/app/Observers/ResultObserver.php @@ -3,10 +3,9 @@ namespace App\Observers; use App\Models\Result; -use Illuminate\Support\Facades\File; +use App\Settings\InfluxDbSettings; use Illuminate\Support\Facades\Log; use InfluxDB2\Client; -use Symfony\Component\Yaml\Yaml; class ResultObserver { @@ -17,6 +16,13 @@ class ResultObserver */ public $afterCommit = true; + public $settings; + + public function __construct(InfluxDbSettings $settings) + { + $this->settings = $settings; + } + /** * Handle the Result "created" event. * @@ -25,17 +31,13 @@ class ResultObserver */ public function created(Result $result) { - if (File::exists(base_path().'/config.yml')) { - $config = Yaml::parseFile( - base_path().'/config.yml' - ); - } - - if (File::exists('/app/config.yml')) { - $config = Yaml::parseFile('/app/config.yml'); - } - - $influxdb = $config['influxdb']; + $influxdb = [ + 'enabled' => $this->settings->v2_enabled, + 'url' => optional($this->settings)->v2_url, + 'org' => optional($this->settings)->v2_org, + 'bucket' => optional($this->settings)->v2_bucket, + 'token' => optional($this->settings)->v2_token, + ]; if ($influxdb['enabled'] == true) { $client = new Client([ diff --git a/app/Providers/FilamentServiceProvider.php b/app/Providers/FilamentServiceProvider.php index 83fd0fe49..ca37a3c7f 100644 --- a/app/Providers/FilamentServiceProvider.php +++ b/app/Providers/FilamentServiceProvider.php @@ -27,6 +27,7 @@ public function boot() { Filament::serving(function () { Filament::registerNavigationGroups([ + 'Settings', 'Links', ]); diff --git a/app/Settings/GeneralSettings.php b/app/Settings/GeneralSettings.php new file mode 100644 index 000000000..191f6deba --- /dev/null +++ b/app/Settings/GeneralSettings.php @@ -0,0 +1,23 @@ +=8.1", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/console": "<5.4" - }, - "require-dev": { - "symfony/console": "^5.4|^6.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" - }, - "bin": [ - "Resources/bin/yaml-lint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Loads and dumps YAML files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v6.1.6" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-10-07T08:04:03+00:00" - }, { "name": "tgalopin/html-sanitizer", "version": "1.5.0", @@ -7872,114 +8425,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" - }, - "time": "2022-10-14T12:47:21+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "9.2.17", diff --git a/config.example.yml b/config.example.yml deleted file mode 100644 index 4a35b5305..000000000 --- a/config.example.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -authentication: true -influxdb: - enabled: false - version: 2 # Only InfluxDB2 is supported right now - url: 'http://your-influxdb-instance' # Full url to your InfluxDB instance, sometimes this includes a port number - org: '' # Organization name, usually created when you installed InfluxDB - bucket: 'speedtest-tracker' # A name location to store the speedtest data in - token: '' # This is your API token -notifications: - channels: - discord: - webhook_url: null # Set as null to disable - slack: - webhook_url: null # Set as null to disable -speedtest: - enabled: true - schedule: '*/60 * * * *' # every hour - ookla_server_id: null # specify a server ID to use a specific server -tz: 'UTC' diff --git a/config/settings.php b/config/settings.php new file mode 100644 index 000000000..89cb1e076 --- /dev/null +++ b/config/settings.php @@ -0,0 +1,80 @@ + [ + + ], + + /* + * In these directories settings migrations will be stored and ran when migrating. A settings + * migration created via the make:settings-migration command will be stored in the first path or + * a custom defined path when running the command. + */ + 'migrations_paths' => [ + database_path('settings'), + ], + + /* + * When no repository was set for a settings class the following repository + * will be used for loading and saving settings. + */ + 'default_repository' => 'database', + + /* + * Settings will be stored and loaded from these repositories. + */ + 'repositories' => [ + 'database' => [ + 'type' => Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, + 'model' => null, + 'table' => null, + 'connection' => null, + ], + 'redis' => [ + 'type' => Spatie\LaravelSettings\SettingsRepositories\RedisSettingsRepository::class, + 'connection' => null, + 'prefix' => null, + ], + ], + + /* + * The contents of settings classes can be cached through your application, + * settings will be stored within a provided Laravel store and can have an + * additional prefix. + */ + 'cache' => [ + 'enabled' => env('SETTINGS_CACHE_ENABLED', false), + 'store' => null, + 'prefix' => null, + 'ttl' => null, + ], + + /* + * These global casts will be automatically used whenever a property within + * your settings class isn't a default PHP type. + */ + 'global_casts' => [ + DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class, + DateTimeZone::class => Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast::class, + Spatie\DataTransferObject\DataTransferObject::class => Spatie\LaravelSettings\SettingsCasts\DtoCast::class, + ], + + /* + * The package will look for settings in these paths and automatically + * register them. + */ + 'auto_discover_settings' => [ + app()->path(), + ], + + /* + * Automatically discovered settings classes can be cached so they don't + * need to be searched each time the application boots up. + */ + 'discovered_settings_cache_path' => storage_path('app/laravel-settings'), +]; diff --git a/database/migrations/2022_10_21_104903_create_settings_table.php b/database/migrations/2022_10_21_104903_create_settings_table.php new file mode 100644 index 000000000..d420e1eaa --- /dev/null +++ b/database/migrations/2022_10_21_104903_create_settings_table.php @@ -0,0 +1,27 @@ +id(); + + $table->string('group')->index(); + $table->string('name'); + $table->boolean('locked'); + $table->json('payload'); + + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('settings'); + } +} diff --git a/database/settings/2022_10_21_105703_create_general_settings.php b/database/settings/2022_10_21_105703_create_general_settings.php new file mode 100644 index 000000000..eeda81475 --- /dev/null +++ b/database/settings/2022_10_21_105703_create_general_settings.php @@ -0,0 +1,15 @@ +migrator->add('general.auth_enabled', true); + $this->migrator->add('general.site_name', 'Speedtest Tracker'); + $this->migrator->add('general.speedtest_schedule', '0 * * * *'); // every hour + $this->migrator->add('general.speedtest_server', null); + $this->migrator->add('general.timezone', 'UTC'); + } +} diff --git a/database/settings/2022_10_21_130121_create_influxdb_settings.php b/database/settings/2022_10_21_130121_create_influxdb_settings.php new file mode 100644 index 000000000..75b6aa89b --- /dev/null +++ b/database/settings/2022_10_21_130121_create_influxdb_settings.php @@ -0,0 +1,15 @@ +migrator->add('influxdb.v2_enabled', false); + $this->migrator->add('influxdb.v2_url', null); + $this->migrator->add('influxdb.v2_org', null); + $this->migrator->add('influxdb.v2_bucket', 'speedtest-tracker'); + $this->migrator->add('influxdb.v2_token', null); + } +} diff --git a/docker/deploy/etc/s6-overlay/scripts/startup b/docker/deploy/etc/s6-overlay/scripts/startup index 630c96d12..b1f61901a 100644 --- a/docker/deploy/etc/s6-overlay/scripts/startup +++ b/docker/deploy/etc/s6-overlay/scripts/startup @@ -39,19 +39,10 @@ else echo "✅ Environment file exists" fi -# Check for config file -if [ ! -f /config/config.yml ]; then - echo "🙄 Config file not found, creating..." - cp $WEBUSER_HOME/config.example.yml /config/config.yml -else - echo "✅ Environment file exists" -fi - # create symlinks echo "🔗 Creating symlinks to config and log files" symlinks=( \ /var/www/html/.env \ -/var/www/html/config.yml \ /var/www/html/storage/logs/laravel.log )