Skip to content

Commit

Permalink
Web Installer (#504)
Browse files Browse the repository at this point in the history
* simplify setup command

* add installer page

* add route for installer

* adjust gitignore

* set colors globally

* add "unsaved data changes" alert

* add helper method to check if panel is installed

* make nicer

* redis username isn't required

* bring back db settings command

* store current date in "installed" file

* only redirect if install was successfull

* remove fpm requirement

* change "installed" marker to env variable

* improve requirements step

* add commands to change cache, queue or session drivers respectively

* removed `grouped` for better mobile view
  • Loading branch information
Boy132 authored Aug 3, 2024
1 parent 18cf6e9 commit 496eaaa
Show file tree
Hide file tree
Showing 17 changed files with 778 additions and 131 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ APP_KEY=
APP_TIMEZONE=UTC
APP_URL=http://panel.test
APP_LOCALE=en
APP_INSTALLED=false

LOG_CHANNEL=daily
LOG_STACK=single
Expand Down
135 changes: 14 additions & 121 deletions app/Console/Commands/Environment/AppSettingsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,155 +3,48 @@
namespace App\Console\Commands\Environment;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use App\Traits\Commands\EnvironmentWriterTrait;
use Illuminate\Support\Facades\Artisan;

class AppSettingsCommand extends Command
{
use EnvironmentWriterTrait;

public const CACHE_DRIVERS = [
'file' => 'Filesystem (recommended)',
'redis' => 'Redis',
];

public const SESSION_DRIVERS = [
'file' => 'Filesystem (recommended)',
'redis' => 'Redis',
'database' => 'Database',
'cookie' => 'Cookie',
];

public const QUEUE_DRIVERS = [
'database' => 'Database (recommended)',
'redis' => 'Redis',
'sync' => 'Synchronous',
];

protected $description = 'Configure basic environment settings for the Panel.';

protected $signature = 'p:environment:setup
{--url= : The URL that this Panel is running on.}
{--cache= : The cache driver backend to use.}
{--session= : The session driver backend to use.}
{--queue= : The queue driver backend to use.}
{--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';
{--url= : The URL that this Panel is running on.}';

protected array $variables = [];

/**
* AppSettingsCommand constructor.
*/
public function __construct(private Kernel $console)
{
parent::__construct();
}

/**
* Handle command execution.
*
* @throws \App\Exceptions\PanelException
*/
public function handle(): int
public function handle(): void
{
$this->variables['APP_TIMEZONE'] = 'UTC';

$this->output->comment(__('commands.appsettings.comment.url'));
$this->variables['APP_URL'] = $this->option('url') ?? $this->ask(
'Application URL',
config('app.url', 'https://example.com')
);

$selected = config('cache.default', 'file');
$this->variables['CACHE_STORE'] = $this->option('cache') ?? $this->choice(
'Cache Driver',
self::CACHE_DRIVERS,
array_key_exists($selected, self::CACHE_DRIVERS) ? $selected : null
);

$selected = config('session.driver', 'file');
$this->variables['SESSION_DRIVER'] = $this->option('session') ?? $this->choice(
'Session Driver',
self::SESSION_DRIVERS,
array_key_exists($selected, self::SESSION_DRIVERS) ? $selected : null
);

$selected = config('queue.default', 'database');
$this->variables['QUEUE_CONNECTION'] = $this->option('queue') ?? $this->choice(
'Queue Driver',
self::QUEUE_DRIVERS,
array_key_exists($selected, self::QUEUE_DRIVERS) ? $selected : null
);

// Make sure session cookies are set as "secure" when using HTTPS
if (str_starts_with($this->variables['APP_URL'], 'https://')) {
$this->variables['SESSION_SECURE_COOKIE'] = 'true';
}

$redisUsed = count(collect($this->variables)->filter(function ($item) {
return $item === 'redis';
})) !== 0;

if ($redisUsed) {
$this->requestRedisSettings();
}

$path = base_path('.env');
if (!file_exists($path)) {
$this->comment('Copying example .env file');
copy($path . '.example', $path);
}

$this->writeToEnvironment($this->variables);

if (!config('app.key')) {
$this->comment('Generating app key');
Artisan::call('key:generate');
}

if ($this->variables['QUEUE_CONNECTION'] !== 'sync') {
$this->call('p:environment:queue-service', [
'--use-redis' => $redisUsed,
]);
}

$this->info($this->console->output());

return 0;
}
$this->variables['APP_TIMEZONE'] = 'UTC';

/**
* Request redis connection details and verify them.
*/
private function requestRedisSettings(): void
{
$this->output->note(__('commands.appsettings.redis.note'));
$this->variables['REDIS_HOST'] = $this->option('redis-host') ?? $this->ask(
'Redis Host',
config('database.redis.default.host')
$this->variables['APP_URL'] = $this->option('url') ?? $this->ask(
'Application URL',
config('app.url', 'https://example.com')
);

$askForRedisPassword = true;
if (!empty(config('database.redis.default.password'))) {
$this->variables['REDIS_PASSWORD'] = config('database.redis.default.password');
$askForRedisPassword = $this->confirm('It seems a password is already defined for Redis, would you like to change it?');
}

if ($askForRedisPassword) {
$this->output->comment(__('commands.appsettings.redis.comment'));
$this->variables['REDIS_PASSWORD'] = $this->option('redis-pass') ?? $this->output->askHidden(
'Redis Password'
);
// Make sure session cookies are set as "secure" when using HTTPS
if (str_starts_with($this->variables['APP_URL'], 'https://')) {
$this->variables['SESSION_SECURE_COOKIE'] = 'true';
}

if (empty($this->variables['REDIS_PASSWORD'])) {
$this->variables['REDIS_PASSWORD'] = 'null';
}
$this->comment('Writing variables to .env file');
$this->writeToEnvironment($this->variables);

$this->variables['REDIS_PORT'] = $this->option('redis-port') ?? $this->ask(
'Redis Port',
config('database.redis.default.port')
);
$this->info("Setup complete. Vist {$this->variables['APP_URL']}/installer to complete the installation");
}
}
68 changes: 68 additions & 0 deletions app/Console/Commands/Environment/CacheSettingsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace App\Console\Commands\Environment;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use App\Traits\Commands\EnvironmentWriterTrait;
use App\Traits\Commands\RequestRedisSettingsTrait;

class CacheSettingsCommand extends Command
{
use EnvironmentWriterTrait;
use RequestRedisSettingsTrait;

public const CACHE_DRIVERS = [
'file' => 'Filesystem (default)',
'database' => 'Database',
'redis' => 'Redis',
];

protected $description = 'Configure cache settings for the Panel.';

protected $signature = 'p:environment:cache
{--driver= : The cache driver backend to use.}
{--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';

protected array $variables = [];

/**
* CacheSettingsCommand constructor.
*/
public function __construct(private Kernel $console)
{
parent::__construct();
}

/**
* Handle command execution.
*/
public function handle(): int
{
$selected = config('cache.default', 'file');
$this->variables['CACHE_STORE'] = $this->option('driver') ?? $this->choice(
'Cache Driver',
self::CACHE_DRIVERS,
array_key_exists($selected, self::CACHE_DRIVERS) ? $selected : null
);

if ($this->variables['CACHE_STORE'] === 'redis') {
$this->requestRedisSettings();

if (config('queue.default') !== 'sync') {
$this->call('p:environment:queue-service', [
'--use-redis' => true,
'--overwrite' => true,
]);
}
}

$this->writeToEnvironment($this->variables);

$this->info($this->console->output());

return 0;
}
}
66 changes: 66 additions & 0 deletions app/Console/Commands/Environment/QueueSettingsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Console\Commands\Environment;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use App\Traits\Commands\EnvironmentWriterTrait;
use App\Traits\Commands\RequestRedisSettingsTrait;

class QueueSettingsCommand extends Command
{
use EnvironmentWriterTrait;
use RequestRedisSettingsTrait;

public const QUEUE_DRIVERS = [
'database' => 'Database (default)',
'redis' => 'Redis',
'sync' => 'Synchronous',
];

protected $description = 'Configure queue settings for the Panel.';

protected $signature = 'p:environment:queue
{--driver= : The queue driver backend to use.}
{--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';

protected array $variables = [];

/**
* QueueSettingsCommand constructor.
*/
public function __construct(private Kernel $console)
{
parent::__construct();
}

/**
* Handle command execution.
*/
public function handle(): int
{
$selected = config('queue.default', 'database');
$this->variables['QUEUE_CONNECTION'] = $this->option('driver') ?? $this->choice(
'Queue Driver',
self::QUEUE_DRIVERS,
array_key_exists($selected, self::QUEUE_DRIVERS) ? $selected : null
);

if ($this->variables['QUEUE_CONNECTION'] === 'redis') {
$this->requestRedisSettings();

$this->call('p:environment:queue-service', [
'--use-redis' => true,
'--overwrite' => true,
]);
}

$this->writeToEnvironment($this->variables);

$this->info($this->console->output());

return 0;
}
}
69 changes: 69 additions & 0 deletions app/Console/Commands/Environment/SessionSettingsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace App\Console\Commands\Environment;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use App\Traits\Commands\EnvironmentWriterTrait;
use App\Traits\Commands\RequestRedisSettingsTrait;

class SessionSettingsCommand extends Command
{
use EnvironmentWriterTrait;
use RequestRedisSettingsTrait;

public const SESSION_DRIVERS = [
'file' => 'Filesystem (default)',
'redis' => 'Redis',
'database' => 'Database',
'cookie' => 'Cookie',
];

protected $description = 'Configure session settings for the Panel.';

protected $signature = 'p:environment:session
{--driver= : The session driver backend to use.}
{--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';

protected array $variables = [];

/**
* SessionSettingsCommand constructor.
*/
public function __construct(private Kernel $console)
{
parent::__construct();
}

/**
* Handle command execution.
*/
public function handle(): int
{
$selected = config('session.driver', 'file');
$this->variables['SESSION_DRIVER'] = $this->option('driver') ?? $this->choice(
'Session Driver',
self::SESSION_DRIVERS,
array_key_exists($selected, self::SESSION_DRIVERS) ? $selected : null
);

if ($this->variables['SESSION_DRIVER'] === 'redis') {
$this->requestRedisSettings();

if (config('queue.default') !== 'sync') {
$this->call('p:environment:queue-service', [
'--use-redis' => true,
'--overwrite' => true,
]);
}
}

$this->writeToEnvironment($this->variables);

$this->info($this->console->output());

return 0;
}
}
Loading

0 comments on commit 496eaaa

Please sign in to comment.