mirror of
https://github.com/pelican-dev/panel.git
synced 2025-07-03 10:41:07 +02:00
Merge branch 'main' into issue/68
# Conflicts: # app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php # app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php # app/Filament/Resources/ServerResource/Pages/CreateServer.php # app/Filament/Resources/ServerResource/Pages/EditServer.php # app/Filament/Resources/ServerResource/Pages/ListServers.php # app/Http/Requests/Admin/Node/AllocationFormRequest.php # app/Http/Requests/Api/Application/Allocations/StoreAllocationRequest.php # app/Models/AuditLog.php # app/Models/Server.php
This commit is contained in:
commit
45fcc2a09a
@ -24,7 +24,7 @@ class QueueWorkerServiceCommand extends Command
|
|||||||
|
|
||||||
$fileExists = file_exists($path);
|
$fileExists = file_exists($path);
|
||||||
if ($fileExists && !$this->option('overwrite') && !$this->confirm('The service file already exists. Do you want to overwrite it?')) {
|
if ($fileExists && !$this->option('overwrite') && !$this->confirm('The service file already exists. Do you want to overwrite it?')) {
|
||||||
$this->line('Creation of queue worker service file aborted because serive file already exists.');
|
$this->line('Creation of queue worker service file aborted because service file already exists.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -32,7 +32,8 @@ class QueueWorkerServiceCommand extends Command
|
|||||||
$user = $this->option('user') ?? $this->ask('Webserver User', 'www-data');
|
$user = $this->option('user') ?? $this->ask('Webserver User', 'www-data');
|
||||||
$group = $this->option('group') ?? $this->ask('Webserver Group', 'www-data');
|
$group = $this->option('group') ?? $this->ask('Webserver Group', 'www-data');
|
||||||
|
|
||||||
$afterRedis = $this->option('use-redis') ? '\nAfter=redis-server.service' : '';
|
$afterRedis = $this->option('use-redis') ? '
|
||||||
|
After=redis-server.service' : '';
|
||||||
|
|
||||||
$basePath = base_path();
|
$basePath = base_path();
|
||||||
|
|
||||||
|
@ -57,19 +57,19 @@ class MakeNodeCommand extends Command
|
|||||||
$data['public'] = $this->option('public') ?? $this->confirm(__('commands.make_node.public'), true);
|
$data['public'] = $this->option('public') ?? $this->confirm(__('commands.make_node.public'), true);
|
||||||
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm(__('commands.make_node.behind_proxy'));
|
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm(__('commands.make_node.behind_proxy'));
|
||||||
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm(__('commands.make_node.maintenance_mode'));
|
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm(__('commands.make_node.maintenance_mode'));
|
||||||
$data['memory'] = $this->option('maxMemory') ?? $this->ask(__('commands.make_node.memory'));
|
$data['memory'] = $this->option('maxMemory') ?? $this->ask(__('commands.make_node.memory'), '0');
|
||||||
$data['memory_overallocate'] = $this->option('overallocateMemory') ?? $this->ask(__('commands.make_node.memory_overallocate'));
|
$data['memory_overallocate'] = $this->option('overallocateMemory') ?? $this->ask(__('commands.make_node.memory_overallocate'), '-1');
|
||||||
$data['disk'] = $this->option('maxDisk') ?? $this->ask(__('commands.make_node.disk'));
|
$data['disk'] = $this->option('maxDisk') ?? $this->ask(__('commands.make_node.disk'), '0');
|
||||||
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask(__('commands.make_node.disk_overallocate'));
|
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask(__('commands.make_node.disk_overallocate'), '-1');
|
||||||
$data['cpu'] = $this->option('maxCpu') ?? $this->ask(__('commands.make_node.cpu'));
|
$data['cpu'] = $this->option('maxCpu') ?? $this->ask(__('commands.make_node.cpu'), '0');
|
||||||
$data['cpu_overallocate'] = $this->option('overallocateCpu') ?? $this->ask(__('commands.make_node.cpu_overallocate'));
|
$data['cpu_overallocate'] = $this->option('overallocateCpu') ?? $this->ask(__('commands.make_node.cpu_overallocate'), '-1');
|
||||||
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask(__('commands.make_node.upload_size'), '100');
|
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask(__('commands.make_node.upload_size'), '256');
|
||||||
$data['daemon_listen'] = $this->option('daemonListeningPort') ?? $this->ask(__('commands.make_node.daemonListen'), '8080');
|
$data['daemon_listen'] = $this->option('daemonListeningPort') ?? $this->ask(__('commands.make_node.daemonListen'), '8080');
|
||||||
$data['daemon_sftp'] = $this->option('daemonSFTPPort') ?? $this->ask(__('commands.make_node.daemonSFTP'), '2022');
|
$data['daemon_sftp'] = $this->option('daemonSFTPPort') ?? $this->ask(__('commands.make_node.daemonSFTP'), '2022');
|
||||||
$data['daemon_sftp_alias'] = $this->option('daemonSFTPAlias') ?? $this->ask(__('commands.make_node.daemonSFTPAlias'), '');
|
$data['daemon_sftp_alias'] = $this->option('daemonSFTPAlias') ?? $this->ask(__('commands.make_node.daemonSFTPAlias'), '');
|
||||||
$data['daemon_base'] = $this->option('daemonBase') ?? $this->ask(__('commands.make_node.daemonBase'), '/var/lib/pelican/volumes');
|
$data['daemon_base'] = $this->option('daemonBase') ?? $this->ask(__('commands.make_node.daemonBase'), '/var/lib/pelican/volumes');
|
||||||
|
|
||||||
$node = $this->creationService->handle($data);
|
$node = $this->creationService->handle($data);
|
||||||
$this->line(__('commands.make_node.succes1') . $data['name'] . __('commands.make_node.succes2') . $node->id . '.');
|
$this->line(__('commands.make_node.success', ['name' => $data['name'], 'id' => $node->id]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,14 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages;
|
|||||||
|
|
||||||
use App\Filament\Resources\DatabaseHostResource;
|
use App\Filament\Resources\DatabaseHostResource;
|
||||||
use App\Models\Objects\Endpoint;
|
use App\Models\Objects\Endpoint;
|
||||||
|
use App\Services\Databases\Hosts\HostCreationService;
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
use Filament\Forms;
|
use Filament\Forms;
|
||||||
use Filament\Forms\Components\Section;
|
use Filament\Forms\Components\Section;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
class CreateDatabaseHost extends CreateRecord
|
class CreateDatabaseHost extends CreateRecord
|
||||||
{
|
{
|
||||||
@ -37,7 +41,7 @@ class CreateDatabaseHost extends CreateRecord
|
|||||||
->required()
|
->required()
|
||||||
->live(onBlur: true)
|
->live(onBlur: true)
|
||||||
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('port')
|
Forms\Components\TextInput::make('port')
|
||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->helperText('The port that MySQL is running on for this host.')
|
->helperText('The port that MySQL is running on for this host.')
|
||||||
@ -58,12 +62,12 @@ class CreateDatabaseHost extends CreateRecord
|
|||||||
Forms\Components\TextInput::make('username')
|
Forms\Components\TextInput::make('username')
|
||||||
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->helperText('The password for the database user.')
|
->helperText('The password for the database user.')
|
||||||
->password()
|
->password()
|
||||||
->revealable()
|
->revealable()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->required(),
|
->required(),
|
||||||
Forms\Components\Select::make('node_id')
|
Forms\Components\Select::make('node_id')
|
||||||
->searchable()
|
->searchable()
|
||||||
@ -80,11 +84,30 @@ class CreateDatabaseHost extends CreateRecord
|
|||||||
return [
|
return [
|
||||||
$this->getCreateFormAction()->formId('form'),
|
$this->getCreateFormAction()->formId('form'),
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getFormActions(): array
|
protected function getFormActions(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleRecordCreation(array $data): Model
|
||||||
|
{
|
||||||
|
return resolve(HostCreationService::class)->handle($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exception($e, $stopPropagation): void
|
||||||
|
{
|
||||||
|
if ($e instanceof PDOException) {
|
||||||
|
Notification::make()
|
||||||
|
->title('Error connecting to database host')
|
||||||
|
->body($e->getMessage())
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-database')
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
$stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,15 @@ namespace App\Filament\Resources\DatabaseHostResource\Pages;
|
|||||||
use App\Filament\Resources\DatabaseHostResource;
|
use App\Filament\Resources\DatabaseHostResource;
|
||||||
use App\Models\DatabaseHost;
|
use App\Models\DatabaseHost;
|
||||||
use App\Models\Objects\Endpoint;
|
use App\Models\Objects\Endpoint;
|
||||||
|
use App\Services\Databases\Hosts\HostUpdateService;
|
||||||
use Filament\Actions;
|
use Filament\Actions;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
use Filament\Forms;
|
use Filament\Forms;
|
||||||
use Filament\Forms\Components\Section;
|
use Filament\Forms\Components\Section;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
class EditDatabaseHost extends EditRecord
|
class EditDatabaseHost extends EditRecord
|
||||||
{
|
{
|
||||||
@ -33,7 +37,7 @@ class EditDatabaseHost extends EditRecord
|
|||||||
->required()
|
->required()
|
||||||
->live(onBlur: true)
|
->live(onBlur: true)
|
||||||
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('port')
|
Forms\Components\TextInput::make('port')
|
||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->helperText('The port that MySQL is running on for this host.')
|
->helperText('The port that MySQL is running on for this host.')
|
||||||
@ -53,12 +57,12 @@ class EditDatabaseHost extends EditRecord
|
|||||||
Forms\Components\TextInput::make('username')
|
Forms\Components\TextInput::make('username')
|
||||||
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->helperText('The password for the database user.')
|
->helperText('The password for the database user.')
|
||||||
->password()
|
->password()
|
||||||
->revealable()
|
->revealable()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->required(),
|
->required(),
|
||||||
Forms\Components\Select::make('node_id')
|
Forms\Components\Select::make('node_id')
|
||||||
->searchable()
|
->searchable()
|
||||||
@ -91,4 +95,24 @@ class EditDatabaseHost extends EditRecord
|
|||||||
DatabaseHostResource\RelationManagers\DatabasesRelationManager::class,
|
DatabaseHostResource\RelationManagers\DatabasesRelationManager::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleRecordUpdate($record, array $data): Model
|
||||||
|
{
|
||||||
|
return resolve(HostUpdateService::class)->handle($record->id, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exception($e, $stopPropagation): void
|
||||||
|
{
|
||||||
|
if ($e instanceof PDOException) {
|
||||||
|
Notification::make()
|
||||||
|
->title('Error connecting to database host')
|
||||||
|
->body($e->getMessage())
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-database')
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
$stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@ class DatabasesRelationManager extends RelationManager
|
|||||||
->columns([
|
->columns([
|
||||||
Tables\Columns\TextColumn::make('database')->icon('tabler-database'),
|
Tables\Columns\TextColumn::make('database')->icon('tabler-database'),
|
||||||
Tables\Columns\TextColumn::make('username')->icon('tabler-user'),
|
Tables\Columns\TextColumn::make('username')->icon('tabler-user'),
|
||||||
//Tables\Columns\TextColumn::make('password'),
|
|
||||||
Tables\Columns\TextColumn::make('remote'),
|
Tables\Columns\TextColumn::make('remote'),
|
||||||
Tables\Columns\TextColumn::make('server.name')
|
Tables\Columns\TextColumn::make('server.name')
|
||||||
->icon('tabler-brand-docker')
|
->icon('tabler-brand-docker')
|
||||||
@ -55,7 +54,6 @@ class DatabasesRelationManager extends RelationManager
|
|||||||
->actions([
|
->actions([
|
||||||
Tables\Actions\DeleteAction::make(),
|
Tables\Actions\DeleteAction::make(),
|
||||||
Tables\Actions\ViewAction::make()->color('primary'),
|
Tables\Actions\ViewAction::make()->color('primary'),
|
||||||
//Tables\Actions\EditAction::make(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,14 +25,14 @@ class CreateDatabase extends CreateRecord
|
|||||||
->numeric(),
|
->numeric(),
|
||||||
Forms\Components\TextInput::make('database')
|
Forms\Components\TextInput::make('database')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('remote')
|
Forms\Components\TextInput::make('remote')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->default('%'),
|
->default('%'),
|
||||||
Forms\Components\TextInput::make('username')
|
Forms\Components\TextInput::make('username')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->password()
|
->password()
|
||||||
->revealable()
|
->revealable()
|
||||||
|
@ -26,14 +26,14 @@ class EditDatabase extends EditRecord
|
|||||||
->numeric(),
|
->numeric(),
|
||||||
Forms\Components\TextInput::make('database')
|
Forms\Components\TextInput::make('database')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('remote')
|
Forms\Components\TextInput::make('remote')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->default('%'),
|
->default('%'),
|
||||||
Forms\Components\TextInput::make('username')
|
Forms\Components\TextInput::make('username')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->password()
|
->password()
|
||||||
->revealable()
|
->revealable()
|
||||||
|
@ -25,11 +25,11 @@ class CreateEgg extends CreateRecord
|
|||||||
->schema([
|
->schema([
|
||||||
Forms\Components\TextInput::make('name')
|
Forms\Components\TextInput::make('name')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||||
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
||||||
Forms\Components\TextInput::make('author')
|
Forms\Components\TextInput::make('author')
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->required()
|
->required()
|
||||||
->email()
|
->email()
|
||||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||||
@ -88,7 +88,7 @@ class CreateEgg extends CreateRecord
|
|||||||
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
||||||
Forms\Components\TextInput::make('config_stop')
|
Forms\Components\TextInput::make('config_stop')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->label('Stop Command')
|
->label('Stop Command')
|
||||||
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
||||||
Forms\Components\Textarea::make('config_startup')->rows(10)->json()
|
Forms\Components\Textarea::make('config_startup')->rows(10)->json()
|
||||||
@ -140,7 +140,7 @@ class CreateEgg extends CreateRecord
|
|||||||
Forms\Components\TextInput::make('name')
|
Forms\Components\TextInput::make('name')
|
||||||
->live()
|
->live()
|
||||||
->debounce(750)
|
->debounce(750)
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->columnSpanFull()
|
->columnSpanFull()
|
||||||
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
|
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
|
||||||
)
|
)
|
||||||
@ -148,13 +148,13 @@ class CreateEgg extends CreateRecord
|
|||||||
Forms\Components\Textarea::make('description')->columnSpanFull(),
|
Forms\Components\Textarea::make('description')->columnSpanFull(),
|
||||||
Forms\Components\TextInput::make('env_variable')
|
Forms\Components\TextInput::make('env_variable')
|
||||||
->label('Environment Variable')
|
->label('Environment Variable')
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->prefix('{{')
|
->prefix('{{')
|
||||||
->suffix('}}')
|
->suffix('}}')
|
||||||
->hintIcon('tabler-code')
|
->hintIcon('tabler-code')
|
||||||
->hintIconTooltip(fn ($state) => "{{{$state}}}")
|
->hintIconTooltip(fn ($state) => "{{{$state}}}")
|
||||||
->required(),
|
->required(),
|
||||||
Forms\Components\TextInput::make('default_value')->maxLength(191),
|
Forms\Components\TextInput::make('default_value')->maxLength(255),
|
||||||
Forms\Components\Fieldset::make('User Permissions')
|
Forms\Components\Fieldset::make('User Permissions')
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'),
|
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'),
|
||||||
@ -173,7 +173,7 @@ class CreateEgg extends CreateRecord
|
|||||||
|
|
||||||
Forms\Components\TextInput::make('script_container')
|
Forms\Components\TextInput::make('script_container')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->default('alpine:3.4'),
|
->default('alpine:3.4'),
|
||||||
|
|
||||||
Forms\Components\Select::make('script_entry')
|
Forms\Components\Select::make('script_entry')
|
||||||
|
@ -4,7 +4,11 @@ namespace App\Filament\Resources\EggResource\Pages;
|
|||||||
|
|
||||||
use App\Filament\Resources\EggResource;
|
use App\Filament\Resources\EggResource;
|
||||||
use App\Models\Egg;
|
use App\Models\Egg;
|
||||||
|
use App\Services\Eggs\Sharing\EggImporterService;
|
||||||
|
use Exception;
|
||||||
use Filament\Actions;
|
use Filament\Actions;
|
||||||
|
use Filament\Forms\Components\Tabs;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
|
use AbdelhamidErrahmouni\FilamentMonacoEditor\MonacoEditor;
|
||||||
use App\Services\Eggs\Sharing\EggExporterService;
|
use App\Services\Eggs\Sharing\EggExporterService;
|
||||||
@ -25,7 +29,7 @@ class EditEgg extends EditRecord
|
|||||||
->schema([
|
->schema([
|
||||||
Forms\Components\TextInput::make('name')
|
Forms\Components\TextInput::make('name')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
|
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
|
||||||
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
||||||
Forms\Components\TextInput::make('uuid')
|
Forms\Components\TextInput::make('uuid')
|
||||||
@ -42,7 +46,7 @@ class EditEgg extends EditRecord
|
|||||||
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
|
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
|
||||||
Forms\Components\TextInput::make('author')
|
Forms\Components\TextInput::make('author')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->email()
|
->email()
|
||||||
->disabled()
|
->disabled()
|
||||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||||
@ -95,7 +99,7 @@ class EditEgg extends EditRecord
|
|||||||
->relationship('configFrom', 'name', ignoreRecord: true)
|
->relationship('configFrom', 'name', ignoreRecord: true)
|
||||||
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
||||||
Forms\Components\TextInput::make('config_stop')
|
Forms\Components\TextInput::make('config_stop')
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->label('Stop Command')
|
->label('Stop Command')
|
||||||
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
||||||
Forms\Components\Textarea::make('config_startup')->rows(10)->json()
|
Forms\Components\Textarea::make('config_startup')->rows(10)->json()
|
||||||
@ -143,7 +147,7 @@ class EditEgg extends EditRecord
|
|||||||
Forms\Components\TextInput::make('name')
|
Forms\Components\TextInput::make('name')
|
||||||
->live()
|
->live()
|
||||||
->debounce(750)
|
->debounce(750)
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->columnSpanFull()
|
->columnSpanFull()
|
||||||
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
|
->afterStateUpdated(fn (Forms\Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString())
|
||||||
)
|
)
|
||||||
@ -151,13 +155,13 @@ class EditEgg extends EditRecord
|
|||||||
Forms\Components\Textarea::make('description')->columnSpanFull(),
|
Forms\Components\Textarea::make('description')->columnSpanFull(),
|
||||||
Forms\Components\TextInput::make('env_variable')
|
Forms\Components\TextInput::make('env_variable')
|
||||||
->label('Environment Variable')
|
->label('Environment Variable')
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->prefix('{{')
|
->prefix('{{')
|
||||||
->suffix('}}')
|
->suffix('}}')
|
||||||
->hintIcon('tabler-code')
|
->hintIcon('tabler-code')
|
||||||
->hintIconTooltip(fn ($state) => "{{{$state}}}")
|
->hintIconTooltip(fn ($state) => "{{{$state}}}")
|
||||||
->required(),
|
->required(),
|
||||||
Forms\Components\TextInput::make('default_value')->maxLength(191),
|
Forms\Components\TextInput::make('default_value')->maxLength(255),
|
||||||
Forms\Components\Fieldset::make('User Permissions')
|
Forms\Components\Fieldset::make('User Permissions')
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'),
|
Forms\Components\Checkbox::make('user_viewable')->label('Viewable'),
|
||||||
@ -176,12 +180,12 @@ class EditEgg extends EditRecord
|
|||||||
|
|
||||||
Forms\Components\TextInput::make('script_container')
|
Forms\Components\TextInput::make('script_container')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->default('alpine:3.4'),
|
->default('alpine:3.4'),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('script_entry')
|
Forms\Components\TextInput::make('script_entry')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->default('ash'),
|
->default('ash'),
|
||||||
|
|
||||||
MonacoEditor::make('script_install')
|
MonacoEditor::make('script_install')
|
||||||
@ -199,20 +203,97 @@ class EditEgg extends EditRecord
|
|||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
Actions\DeleteAction::make()
|
Actions\DeleteAction::make('deleteEgg')
|
||||||
->disabled(fn (Egg $egg): bool => $egg->servers()->count() > 0)
|
->disabled(fn (Egg $egg): bool => $egg->servers()->count() > 0)
|
||||||
->label(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? 'Delete Egg' : 'Egg In Use'),
|
->label(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? 'Delete' : 'In Use'),
|
||||||
Actions\Action::make('export')
|
|
||||||
->icon('tabler-download')
|
Actions\Action::make('exportEgg')
|
||||||
->label('Export Egg')
|
->label('Export')
|
||||||
->color('primary')
|
->color('primary')
|
||||||
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
|
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
|
||||||
echo $service->handle($egg->id);
|
echo $service->handle($egg->id);
|
||||||
}, 'egg-' . $egg->getKebabName() . '.json')),
|
}, 'egg-' . $egg->getKebabName() . '.json')),
|
||||||
|
|
||||||
|
Actions\Action::make('importEgg')
|
||||||
|
->label('Import')
|
||||||
|
->form([
|
||||||
|
Forms\Components\Placeholder::make('warning')
|
||||||
|
->label('This will overwrite the current egg to the one you upload.'),
|
||||||
|
Tabs::make('Tabs')
|
||||||
|
->tabs([
|
||||||
|
Tabs\Tab::make('From File')
|
||||||
|
->icon('tabler-file-upload')
|
||||||
|
->schema([
|
||||||
|
Forms\Components\FileUpload::make('egg')
|
||||||
|
->label('Egg')
|
||||||
|
->hint('eg. minecraft.json')
|
||||||
|
->acceptedFileTypes(['application/json'])
|
||||||
|
->storeFiles(false),
|
||||||
|
]),
|
||||||
|
Tabs\Tab::make('From URL')
|
||||||
|
->icon('tabler-world-upload')
|
||||||
|
->schema([
|
||||||
|
Forms\Components\TextInput::make('url')
|
||||||
|
->label('URL')
|
||||||
|
->hint('Link to the egg file (eg. minecraft.json)')
|
||||||
|
->url(),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->contained(false),
|
||||||
|
|
||||||
|
])
|
||||||
|
->action(function (array $data, Egg $egg): void {
|
||||||
|
/** @var EggImporterService $eggImportService */
|
||||||
|
$eggImportService = resolve(EggImporterService::class);
|
||||||
|
|
||||||
|
if (!empty($data['egg'])) {
|
||||||
|
try {
|
||||||
|
$eggImportService->fromFile($data['egg'], $egg);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
Notification::make()
|
||||||
|
->title('Import Failed')
|
||||||
|
->body($exception->getMessage())
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
report($exception);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data['url'])) {
|
||||||
|
try {
|
||||||
|
$eggImportService->fromUrl($data['url'], $egg);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
Notification::make()
|
||||||
|
->title('Import Failed')
|
||||||
|
->body($exception->getMessage())
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
report($exception);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->refreshForm();
|
||||||
|
Notification::make()
|
||||||
|
->title('Import Success')
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
|
}),
|
||||||
|
|
||||||
$this->getSaveFormAction()->formId('form'),
|
$this->getSaveFormAction()->formId('form'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function refreshForm(): void
|
||||||
|
{
|
||||||
|
$this->fillForm();
|
||||||
|
}
|
||||||
|
|
||||||
protected function getFormActions(): array
|
protected function getFormActions(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
|
@ -29,8 +29,7 @@ class ListEggs extends ListRecords
|
|||||||
->columns([
|
->columns([
|
||||||
Tables\Columns\TextColumn::make('id')
|
Tables\Columns\TextColumn::make('id')
|
||||||
->label('Id')
|
->label('Id')
|
||||||
->searchable()
|
->hidden(),
|
||||||
->sortable(),
|
|
||||||
Tables\Columns\TextColumn::make('name')
|
Tables\Columns\TextColumn::make('name')
|
||||||
->icon('tabler-egg')
|
->icon('tabler-egg')
|
||||||
->description(fn ($record): ?string => (strlen($record->description) > 120) ? substr($record->description, 0, 120).'...' : $record->description)
|
->description(fn ($record): ?string => (strlen($record->description) > 120) ? substr($record->description, 0, 120).'...' : $record->description)
|
||||||
|
@ -48,11 +48,11 @@ class CreateMount extends CreateRecord
|
|||||||
Forms\Components\TextInput::make('source')
|
Forms\Components\TextInput::make('source')
|
||||||
->required()
|
->required()
|
||||||
->helperText('File path on the host system to mount to a container.')
|
->helperText('File path on the host system to mount to a container.')
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('target')
|
Forms\Components\TextInput::make('target')
|
||||||
->required()
|
->required()
|
||||||
->helperText('Where the mount will be accessible inside a container.')
|
->helperText('Where the mount will be accessible inside a container.')
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\ToggleButtons::make('user_mountable')
|
Forms\Components\ToggleButtons::make('user_mountable')
|
||||||
->hidden()
|
->hidden()
|
||||||
->label('User mountable?')
|
->label('User mountable?')
|
||||||
|
@ -45,11 +45,11 @@ class EditMount extends EditRecord
|
|||||||
Forms\Components\TextInput::make('source')
|
Forms\Components\TextInput::make('source')
|
||||||
->required()
|
->required()
|
||||||
->helperText('File path on the host system to mount to a container.')
|
->helperText('File path on the host system to mount to a container.')
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('target')
|
Forms\Components\TextInput::make('target')
|
||||||
->required()
|
->required()
|
||||||
->helperText('Where the mount will be accessible inside a container.')
|
->helperText('Where the mount will be accessible inside a container.')
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\ToggleButtons::make('user_mountable')
|
Forms\Components\ToggleButtons::make('user_mountable')
|
||||||
->hidden()
|
->hidden()
|
||||||
->label('User mountable?')
|
->label('User mountable?')
|
||||||
|
@ -93,7 +93,7 @@ class CreateNode extends CreateRecord
|
|||||||
|
|
||||||
$set('dns', false);
|
$set('dns', false);
|
||||||
})
|
})
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('ip')
|
Forms\Components\TextInput::make('ip')
|
||||||
->disabled()
|
->disabled()
|
||||||
@ -131,8 +131,8 @@ class CreateNode extends CreateRecord
|
|||||||
])
|
])
|
||||||
->label(trans('strings.port'))
|
->label(trans('strings.port'))
|
||||||
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
||||||
->minValue(0)
|
->minValue(1)
|
||||||
->maxValue(65536)
|
->maxValue(65535)
|
||||||
->default(8080)
|
->default(8080)
|
||||||
->required()
|
->required()
|
||||||
->integer(),
|
->integer(),
|
||||||
@ -158,7 +158,6 @@ class CreateNode extends CreateRecord
|
|||||||
'md' => 1,
|
'md' => 1,
|
||||||
'lg' => 1,
|
'lg' => 1,
|
||||||
])
|
])
|
||||||
->required()
|
|
||||||
->inline()
|
->inline()
|
||||||
->helperText(function (Forms\Get $get) {
|
->helperText(function (Forms\Get $get) {
|
||||||
if (request()->isSecure()) {
|
if (request()->isSecure()) {
|
||||||
@ -243,8 +242,8 @@ class CreateNode extends CreateRecord
|
|||||||
Forms\Components\TextInput::make('daemon_sftp')
|
Forms\Components\TextInput::make('daemon_sftp')
|
||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->label('SFTP Port')
|
->label('SFTP Port')
|
||||||
->minValue(0)
|
->minValue(1)
|
||||||
->maxValue(65536)
|
->maxValue(65535)
|
||||||
->default(2022)
|
->default(2022)
|
||||||
->required()
|
->required()
|
||||||
->integer(),
|
->integer(),
|
||||||
@ -279,7 +278,8 @@ class CreateNode extends CreateRecord
|
|||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->numeric()
|
->numeric()
|
||||||
->minValue(0)
|
->minValue(0)
|
||||||
->default(0),
|
->default(0)
|
||||||
|
->required(),
|
||||||
Forms\Components\TextInput::make('memory_overallocate')
|
Forms\Components\TextInput::make('memory_overallocate')
|
||||||
->dehydratedWhenHidden()
|
->dehydratedWhenHidden()
|
||||||
->label('Overallocate')->inlineLabel()
|
->label('Overallocate')->inlineLabel()
|
||||||
@ -291,7 +291,8 @@ class CreateNode extends CreateRecord
|
|||||||
->minValue(-1)
|
->minValue(-1)
|
||||||
->maxValue(100)
|
->maxValue(100)
|
||||||
->default(0)
|
->default(0)
|
||||||
->suffix('%'),
|
->suffix('%')
|
||||||
|
->required(),
|
||||||
]),
|
]),
|
||||||
Forms\Components\Grid::make()
|
Forms\Components\Grid::make()
|
||||||
->columns(6)
|
->columns(6)
|
||||||
@ -320,7 +321,8 @@ class CreateNode extends CreateRecord
|
|||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->numeric()
|
->numeric()
|
||||||
->minValue(0)
|
->minValue(0)
|
||||||
->default(0),
|
->default(0)
|
||||||
|
->required(),
|
||||||
Forms\Components\TextInput::make('disk_overallocate')
|
Forms\Components\TextInput::make('disk_overallocate')
|
||||||
->dehydratedWhenHidden()
|
->dehydratedWhenHidden()
|
||||||
->hidden(fn (Forms\Get $get) => $get('unlimited_disk'))
|
->hidden(fn (Forms\Get $get) => $get('unlimited_disk'))
|
||||||
@ -332,7 +334,8 @@ class CreateNode extends CreateRecord
|
|||||||
->minValue(-1)
|
->minValue(-1)
|
||||||
->maxValue(100)
|
->maxValue(100)
|
||||||
->default(0)
|
->default(0)
|
||||||
->suffix('%'),
|
->suffix('%')
|
||||||
|
->required(),
|
||||||
]),
|
]),
|
||||||
Forms\Components\Grid::make()
|
Forms\Components\Grid::make()
|
||||||
->columns(6)
|
->columns(6)
|
||||||
@ -361,7 +364,8 @@ class CreateNode extends CreateRecord
|
|||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->numeric()
|
->numeric()
|
||||||
->default(0)
|
->default(0)
|
||||||
->minValue(0),
|
->minValue(0)
|
||||||
|
->required(),
|
||||||
Forms\Components\TextInput::make('cpu_overallocate')
|
Forms\Components\TextInput::make('cpu_overallocate')
|
||||||
->dehydratedWhenHidden()
|
->dehydratedWhenHidden()
|
||||||
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu'))
|
->hidden(fn (Forms\Get $get) => $get('unlimited_cpu'))
|
||||||
@ -373,7 +377,8 @@ class CreateNode extends CreateRecord
|
|||||||
->default(0)
|
->default(0)
|
||||||
->minValue(-1)
|
->minValue(-1)
|
||||||
->maxValue(100)
|
->maxValue(100)
|
||||||
->suffix('%'),
|
->suffix('%')
|
||||||
|
->required(),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
])->columnSpanFull()
|
])->columnSpanFull()
|
||||||
|
@ -94,7 +94,7 @@ class EditNode extends EditRecord
|
|||||||
|
|
||||||
$set('dns', false);
|
$set('dns', false);
|
||||||
})
|
})
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('ip')
|
Forms\Components\TextInput::make('ip')
|
||||||
->disabled()
|
->disabled()
|
||||||
@ -132,8 +132,8 @@ class EditNode extends EditRecord
|
|||||||
])
|
])
|
||||||
->label(trans('strings.port'))
|
->label(trans('strings.port'))
|
||||||
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
||||||
->minValue(0)
|
->minValue(1)
|
||||||
->maxValue(65536)
|
->maxValue(65535)
|
||||||
->default(8080)
|
->default(8080)
|
||||||
->required()
|
->required()
|
||||||
->integer(),
|
->integer(),
|
||||||
@ -159,7 +159,6 @@ class EditNode extends EditRecord
|
|||||||
'md' => 1,
|
'md' => 1,
|
||||||
'lg' => 1,
|
'lg' => 1,
|
||||||
])
|
])
|
||||||
->required()
|
|
||||||
->inline()
|
->inline()
|
||||||
->helperText(function (Forms\Get $get) {
|
->helperText(function (Forms\Get $get) {
|
||||||
if (request()->isSecure()) {
|
if (request()->isSecure()) {
|
||||||
@ -218,8 +217,8 @@ class EditNode extends EditRecord
|
|||||||
Forms\Components\TextInput::make('daemon_sftp')
|
Forms\Components\TextInput::make('daemon_sftp')
|
||||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
|
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 3])
|
||||||
->label('SFTP Port')
|
->label('SFTP Port')
|
||||||
->minValue(0)
|
->minValue(1)
|
||||||
->maxValue(65536)
|
->maxValue(65535)
|
||||||
->default(2022)
|
->default(2022)
|
||||||
->required()
|
->required()
|
||||||
->integer(),
|
->integer(),
|
||||||
|
@ -65,7 +65,7 @@ class CreateServer extends CreateRecord
|
|||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\Select::make('owner_id')
|
Forms\Components\Select::make('owner_id')
|
||||||
->prefixIcon('tabler-user')
|
->prefixIcon('tabler-user')
|
||||||
@ -268,7 +268,7 @@ class CreateServer extends CreateRecord
|
|||||||
|
|
||||||
$text = Forms\Components\TextInput::make('variable_value')
|
$text = Forms\Components\TextInput::make('variable_value')
|
||||||
->hidden($this->shouldHideComponent(...))
|
->hidden($this->shouldHideComponent(...))
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->required(fn (Forms\Get $get) => in_array('required', explode('|', $get('rules'))))
|
->required(fn (Forms\Get $get) => in_array('required', explode('|', $get('rules'))))
|
||||||
->rules(
|
->rules(
|
||||||
fn (Forms\Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) {
|
fn (Forms\Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) {
|
||||||
@ -521,18 +521,21 @@ class CreateServer extends CreateRecord
|
|||||||
->suffixIcon('tabler-network')
|
->suffixIcon('tabler-network')
|
||||||
->required()
|
->required()
|
||||||
->numeric()
|
->numeric()
|
||||||
|
->minValue(0)
|
||||||
->default(0),
|
->default(0),
|
||||||
Forms\Components\TextInput::make('database_limit')
|
Forms\Components\TextInput::make('database_limit')
|
||||||
->label('Databases')
|
->label('Databases')
|
||||||
->suffixIcon('tabler-database')
|
->suffixIcon('tabler-database')
|
||||||
->required()
|
->required()
|
||||||
->numeric()
|
->numeric()
|
||||||
|
->minValue(0)
|
||||||
->default(0),
|
->default(0),
|
||||||
Forms\Components\TextInput::make('backup_limit')
|
Forms\Components\TextInput::make('backup_limit')
|
||||||
->label('Backups')
|
->label('Backups')
|
||||||
->suffixIcon('tabler-copy-check')
|
->suffixIcon('tabler-copy-check')
|
||||||
->required()
|
->required()
|
||||||
->numeric()
|
->numeric()
|
||||||
|
->minValue(0)
|
||||||
->default(0),
|
->default(0),
|
||||||
]),
|
]),
|
||||||
Forms\Components\Fieldset::make('Docker Settings')
|
Forms\Components\Fieldset::make('Docker Settings')
|
||||||
|
@ -6,6 +6,11 @@ use App\Models\Node;
|
|||||||
use App\Models\Objects\Endpoint;
|
use App\Models\Objects\Endpoint;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\HtmlString;
|
use Illuminate\Support\HtmlString;
|
||||||
|
use App\Models\Database;
|
||||||
|
use App\Services\Databases\DatabaseManagementService;
|
||||||
|
use App\Services\Databases\DatabasePasswordService;
|
||||||
|
use Filament\Forms\Components\Actions\Action;
|
||||||
|
use Filament\Forms\Components\Repeater;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use App\Filament\Resources\ServerResource;
|
use App\Filament\Resources\ServerResource;
|
||||||
use App\Http\Controllers\Admin\ServersController;
|
use App\Http\Controllers\Admin\ServersController;
|
||||||
@ -47,27 +52,6 @@ class EditServer extends EditRecord
|
|||||||
'lg' => 4,
|
'lg' => 4,
|
||||||
])
|
])
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\ToggleButtons::make('condition')
|
|
||||||
->label('')
|
|
||||||
->inline()
|
|
||||||
->formatStateUsing(fn (Server $server) => $server->condition)
|
|
||||||
->options(fn ($state) => collect(ContainerStatus::cases())->merge(ServerState::cases())
|
|
||||||
->filter(fn ($condition) => $condition->value === $state)
|
|
||||||
->mapWithKeys(fn ($state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()])
|
|
||||||
)
|
|
||||||
->colors(collect(ContainerStatus::cases())->merge(ServerState::cases())->mapWithKeys(
|
|
||||||
fn ($status) => [$status->value => $status->color()]
|
|
||||||
))
|
|
||||||
->icons(collect(ContainerStatus::cases())->merge(ServerState::cases())->mapWithKeys(
|
|
||||||
fn ($status) => [$status->value => $status->icon()]
|
|
||||||
))
|
|
||||||
->columnSpan([
|
|
||||||
'default' => 1,
|
|
||||||
'sm' => 2,
|
|
||||||
'md' => 2,
|
|
||||||
'lg' => 2,
|
|
||||||
]),
|
|
||||||
|
|
||||||
Tabs::make('Tabs')
|
Tabs::make('Tabs')
|
||||||
->persistTabInQueryString()
|
->persistTabInQueryString()
|
||||||
->columnSpan(6)
|
->columnSpan(6)
|
||||||
@ -96,27 +80,47 @@ class EditServer extends EditRecord
|
|||||||
}))
|
}))
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\Select::make('owner_id')
|
Forms\Components\Select::make('owner_id')
|
||||||
->prefixIcon('tabler-user')
|
->prefixIcon('tabler-user')
|
||||||
->label('Owner')
|
->label('Owner')
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 2,
|
||||||
])
|
])
|
||||||
->relationship('user', 'username')
|
->relationship('user', 'username')
|
||||||
->searchable()
|
->searchable()
|
||||||
->preload()
|
->preload()
|
||||||
->required(),
|
->required(),
|
||||||
|
|
||||||
|
Forms\Components\ToggleButtons::make('condition')
|
||||||
|
->label('Server Status')
|
||||||
|
->formatStateUsing(fn (Server $server) => $server->condition)
|
||||||
|
->options(fn ($state) => collect(array_merge(ContainerStatus::cases(), ServerState::cases()))
|
||||||
|
->filter(fn ($condition) => $condition->value === $state)
|
||||||
|
->mapWithKeys(fn ($state) => [$state->value => str($state->value)->replace('_', ' ')->ucwords()])
|
||||||
|
)
|
||||||
|
->colors(collect(array_merge(ContainerStatus::cases(), ServerState::cases()))->mapWithKeys(
|
||||||
|
fn ($status) => [$status->value => $status->color()]
|
||||||
|
))
|
||||||
|
->icons(collect(array_merge(ContainerStatus::cases(), ServerState::cases()))->mapWithKeys(
|
||||||
|
fn ($status) => [$status->value => $status->icon()]
|
||||||
|
))
|
||||||
|
->columnSpan([
|
||||||
|
'default' => 2,
|
||||||
|
'sm' => 1,
|
||||||
|
'md' => 1,
|
||||||
|
'lg' => 1,
|
||||||
|
]),
|
||||||
|
|
||||||
Forms\Components\Textarea::make('description')
|
Forms\Components\Textarea::make('description')
|
||||||
->label('Description')
|
->label('Description')
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
@ -125,7 +129,7 @@ class EditServer extends EditRecord
|
|||||||
->hintAction(CopyAction::make())
|
->hintAction(CopyAction::make())
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
@ -135,7 +139,7 @@ class EditServer extends EditRecord
|
|||||||
->hintAction(CopyAction::make())
|
->hintAction(CopyAction::make())
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
@ -144,17 +148,17 @@ class EditServer extends EditRecord
|
|||||||
->label('External ID')
|
->label('External ID')
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\Select::make('node_id')
|
Forms\Components\Select::make('node_id')
|
||||||
->label('Node')
|
->label('Node')
|
||||||
->relationship('node', 'name')
|
->relationship('node', 'name')
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 2,
|
'sm' => 1,
|
||||||
'md' => 2,
|
'md' => 2,
|
||||||
'lg' => 3,
|
'lg' => 3,
|
||||||
])
|
])
|
||||||
@ -362,14 +366,17 @@ class EditServer extends EditRecord
|
|||||||
Forms\Components\TextInput::make('allocation_limit')
|
Forms\Components\TextInput::make('allocation_limit')
|
||||||
->suffixIcon('tabler-network')
|
->suffixIcon('tabler-network')
|
||||||
->required()
|
->required()
|
||||||
|
->minValue(0)
|
||||||
->numeric(),
|
->numeric(),
|
||||||
Forms\Components\TextInput::make('database_limit')
|
Forms\Components\TextInput::make('database_limit')
|
||||||
->suffixIcon('tabler-database')
|
->suffixIcon('tabler-database')
|
||||||
->required()
|
->required()
|
||||||
|
->minValue(0)
|
||||||
->numeric(),
|
->numeric(),
|
||||||
Forms\Components\TextInput::make('backup_limit')
|
Forms\Components\TextInput::make('backup_limit')
|
||||||
->suffixIcon('tabler-copy-check')
|
->suffixIcon('tabler-copy-check')
|
||||||
->required()
|
->required()
|
||||||
|
->minValue(0)
|
||||||
->numeric(),
|
->numeric(),
|
||||||
]),
|
]),
|
||||||
Forms\Components\Fieldset::make('Docker Settings')
|
Forms\Components\Fieldset::make('Docker Settings')
|
||||||
@ -569,6 +576,7 @@ class EditServer extends EditRecord
|
|||||||
|
|
||||||
$text = Forms\Components\TextInput::make('variable_value')
|
$text = Forms\Components\TextInput::make('variable_value')
|
||||||
->hidden($this->shouldHideComponent(...))
|
->hidden($this->shouldHideComponent(...))
|
||||||
|
->required(fn (ServerVariable $serverVariable) => in_array('required', explode('|', $serverVariable->variable->rules)))
|
||||||
->rules([
|
->rules([
|
||||||
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
|
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
|
||||||
$validator = Validator::make(['validatorkey' => $value], [
|
$validator = Validator::make(['validatorkey' => $value], [
|
||||||
@ -618,9 +626,56 @@ class EditServer extends EditRecord
|
|||||||
Tabs\Tab::make('Databases')
|
Tabs\Tab::make('Databases')
|
||||||
->icon('tabler-database')
|
->icon('tabler-database')
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Placeholder::make('soon')
|
Repeater::make('databases')
|
||||||
->label('Soon™'),
|
->grid()
|
||||||
]),
|
->helperText(fn (Server $server) => $server->databases->isNotEmpty() ? '' : 'No Databases exist for this Server')
|
||||||
|
->columns(2)
|
||||||
|
->schema([
|
||||||
|
Forms\Components\TextInput::make('database')
|
||||||
|
->columnSpan(2)
|
||||||
|
->label('Database Name')
|
||||||
|
->disabled()
|
||||||
|
->formatStateUsing(fn ($record) => $record->database)
|
||||||
|
->hintAction(
|
||||||
|
Action::make('Delete')
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-trash')
|
||||||
|
->action(fn (DatabaseManagementService $databaseManagementService, $record) => $databaseManagementService->delete($record))
|
||||||
|
),
|
||||||
|
Forms\Components\TextInput::make('username')
|
||||||
|
->disabled()
|
||||||
|
->formatStateUsing(fn ($record) => $record->username)
|
||||||
|
->columnSpan(2),
|
||||||
|
Forms\Components\TextInput::make('password')
|
||||||
|
->disabled()
|
||||||
|
->hintAction(
|
||||||
|
Action::make('rotate')
|
||||||
|
->icon('tabler-refresh')
|
||||||
|
->requiresConfirmation()
|
||||||
|
->action(fn (DatabasePasswordService $service, $record, $set, $get) => $this->rotatePassword($service, $record, $set, $get))
|
||||||
|
)
|
||||||
|
->formatStateUsing(fn (Database $database) => $database->password)
|
||||||
|
->columnSpan(2),
|
||||||
|
Forms\Components\TextInput::make('remote')
|
||||||
|
->disabled()
|
||||||
|
->formatStateUsing(fn ($record) => $record->remote)
|
||||||
|
->columnSpan(1)
|
||||||
|
->label('Connections From'),
|
||||||
|
Forms\Components\TextInput::make('max_connections')
|
||||||
|
->disabled()
|
||||||
|
->formatStateUsing(fn ($record) => $record->max_connections)
|
||||||
|
->columnSpan(1),
|
||||||
|
Forms\Components\TextInput::make('JDBC')
|
||||||
|
->disabled()
|
||||||
|
->label('JDBC Connection String')
|
||||||
|
->columnSpan(2)
|
||||||
|
->formatStateUsing(fn (Forms\Get $get, $record) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($record->password) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database')),
|
||||||
|
])
|
||||||
|
->relationship('databases')
|
||||||
|
->deletable(false)
|
||||||
|
->addable(false)
|
||||||
|
->columnSpan(4),
|
||||||
|
])->columns(4),
|
||||||
Tabs\Tab::make('Actions')
|
Tabs\Tab::make('Actions')
|
||||||
->icon('tabler-settings')
|
->icon('tabler-settings')
|
||||||
->schema([
|
->schema([
|
||||||
@ -740,7 +795,7 @@ class EditServer extends EditRecord
|
|||||||
protected function transferServer(Form $form): Form
|
protected function transferServer(Form $form): Form
|
||||||
{
|
{
|
||||||
return $form
|
return $form
|
||||||
->columns(2)
|
->columns()
|
||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Select::make('toNode')
|
Forms\Components\Select::make('toNode')
|
||||||
->label('New Node'),
|
->label('New Node'),
|
||||||
@ -755,6 +810,8 @@ class EditServer extends EditRecord
|
|||||||
Actions\DeleteAction::make('Delete')
|
Actions\DeleteAction::make('Delete')
|
||||||
->successRedirectUrl(route('filament.admin.resources.servers.index'))
|
->successRedirectUrl(route('filament.admin.resources.servers.index'))
|
||||||
->color('danger')
|
->color('danger')
|
||||||
|
->disabled(fn (Server $server) => $server->databases()->count() > 0)
|
||||||
|
->label(fn (Server $server) => $server->databases()->count() > 0 ? 'Server has a Database' : 'Delete')
|
||||||
->after(fn (Server $server) => resolve(ServerDeletionService::class)->handle($server))
|
->after(fn (Server $server) => resolve(ServerDeletionService::class)->handle($server))
|
||||||
->requiresConfirmation(),
|
->requiresConfirmation(),
|
||||||
Actions\Action::make('console')
|
Actions\Action::make('console')
|
||||||
@ -920,4 +977,13 @@ class EditServer extends EditRecord
|
|||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function rotatePassword(DatabasePasswordService $service, $record, $set, $get): void
|
||||||
|
{
|
||||||
|
$newPassword = $service->handle($record);
|
||||||
|
$jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database');
|
||||||
|
|
||||||
|
$set('password', $newPassword);
|
||||||
|
$set('JDBC', $jdbcString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ use chillerlan\QRCode\Common\EccLevel;
|
|||||||
use chillerlan\QRCode\Common\Version;
|
use chillerlan\QRCode\Common\Version;
|
||||||
use chillerlan\QRCode\QRCode;
|
use chillerlan\QRCode\QRCode;
|
||||||
use chillerlan\QRCode\QROptions;
|
use chillerlan\QRCode\QROptions;
|
||||||
|
use DateTimeZone;
|
||||||
use Filament\Forms\Components\Actions\Action;
|
use Filament\Forms\Components\Actions\Action;
|
||||||
use Filament\Forms\Components\Grid;
|
use Filament\Forms\Components\Grid;
|
||||||
use Filament\Forms\Components\Placeholder;
|
use Filament\Forms\Components\Placeholder;
|
||||||
@ -52,7 +53,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
|||||||
->label(trans('strings.username'))
|
->label(trans('strings.username'))
|
||||||
->disabled()
|
->disabled()
|
||||||
->readOnly()
|
->readOnly()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->unique(ignoreRecord: true)
|
->unique(ignoreRecord: true)
|
||||||
->autofocus(),
|
->autofocus(),
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
|||||||
->label(trans('strings.email'))
|
->label(trans('strings.email'))
|
||||||
->email()
|
->email()
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191)
|
->maxLength(255)
|
||||||
->unique(ignoreRecord: true),
|
->unique(ignoreRecord: true),
|
||||||
|
|
||||||
TextInput::make('password')
|
TextInput::make('password')
|
||||||
@ -85,6 +86,12 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
|||||||
->visible(fn (Get $get): bool => filled($get('password')))
|
->visible(fn (Get $get): bool => filled($get('password')))
|
||||||
->dehydrated(false),
|
->dehydrated(false),
|
||||||
|
|
||||||
|
Select::make('timezone')
|
||||||
|
->required()
|
||||||
|
->prefixIcon('tabler-clock-pin')
|
||||||
|
->options(fn () => collect(DateTimeZone::listIdentifiers())->mapWithKeys(fn ($tz) => [$tz => $tz]))
|
||||||
|
->searchable(),
|
||||||
|
|
||||||
Select::make('language')
|
Select::make('language')
|
||||||
->label(trans('strings.language'))
|
->label(trans('strings.language'))
|
||||||
->required()
|
->required()
|
||||||
@ -193,8 +200,10 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
|
|||||||
->schema([
|
->schema([
|
||||||
Grid::make(5)->schema([
|
Grid::make(5)->schema([
|
||||||
Section::make('Create API Key')->columnSpan(3)->schema([
|
Section::make('Create API Key')->columnSpan(3)->schema([
|
||||||
|
|
||||||
TextInput::make('description')
|
TextInput::make('description')
|
||||||
->live(),
|
->live(),
|
||||||
|
|
||||||
TagsInput::make('allowed_ips')
|
TagsInput::make('allowed_ips')
|
||||||
->live()
|
->live()
|
||||||
->splitKeys([',', ' ', 'Tab'])
|
->splitKeys([',', ' ', 'Tab'])
|
||||||
|
@ -20,8 +20,8 @@ class EditUser extends EditRecord
|
|||||||
return $form
|
return $form
|
||||||
->schema([
|
->schema([
|
||||||
Section::make()->schema([
|
Section::make()->schema([
|
||||||
Forms\Components\TextInput::make('username')->required()->maxLength(191),
|
Forms\Components\TextInput::make('username')->required()->maxLength(255),
|
||||||
Forms\Components\TextInput::make('email')->email()->required()->maxLength(191),
|
Forms\Components\TextInput::make('email')->email()->required()->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->dehydrateStateUsing(fn (string $state): string => Hash::make($state))
|
->dehydrateStateUsing(fn (string $state): string => Hash::make($state))
|
||||||
|
@ -66,7 +66,7 @@ class ListUsers extends ListRecords
|
|||||||
->actions([
|
->actions([
|
||||||
Tables\Actions\EditAction::make(),
|
Tables\Actions\EditAction::make(),
|
||||||
])
|
])
|
||||||
->checkIfRecordIsSelectableUsing(fn (User $user) => !$user->servers_count)
|
->checkIfRecordIsSelectableUsing(fn (User $user) => auth()->user()->id !== $user->id && !$user->servers_count)
|
||||||
->bulkActions([
|
->bulkActions([
|
||||||
Tables\Actions\BulkActionGroup::make([
|
Tables\Actions\BulkActionGroup::make([
|
||||||
Tables\Actions\DeleteBulkAction::make(),
|
Tables\Actions\DeleteBulkAction::make(),
|
||||||
@ -85,12 +85,12 @@ class ListUsers extends ListRecords
|
|||||||
Forms\Components\TextInput::make('username')
|
Forms\Components\TextInput::make('username')
|
||||||
->alphaNum()
|
->alphaNum()
|
||||||
->required()
|
->required()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('email')
|
Forms\Components\TextInput::make('email')
|
||||||
->email()
|
->email()
|
||||||
->required()
|
->required()
|
||||||
->unique()
|
->unique()
|
||||||
->maxLength(191),
|
->maxLength(255),
|
||||||
|
|
||||||
Forms\Components\TextInput::make('password')
|
Forms\Components\TextInput::make('password')
|
||||||
->hintIcon('tabler-question-mark')
|
->hintIcon('tabler-question-mark')
|
||||||
|
@ -8,9 +8,9 @@ use Illuminate\Auth\AuthManager;
|
|||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use App\Facades\Activity;
|
use App\Facades\Activity;
|
||||||
use App\Services\Users\UserUpdateService;
|
use App\Services\Users\UserUpdateService;
|
||||||
use App\Transformers\Api\Client\AccountTransformer;
|
|
||||||
use App\Http\Requests\Api\Client\Account\UpdateEmailRequest;
|
use App\Http\Requests\Api\Client\Account\UpdateEmailRequest;
|
||||||
use App\Http\Requests\Api\Client\Account\UpdatePasswordRequest;
|
use App\Http\Requests\Api\Client\Account\UpdatePasswordRequest;
|
||||||
|
use App\Transformers\Api\Client\UserTransformer;
|
||||||
|
|
||||||
class AccountController extends ClientApiController
|
class AccountController extends ClientApiController
|
||||||
{
|
{
|
||||||
@ -25,7 +25,7 @@ class AccountController extends ClientApiController
|
|||||||
public function index(Request $request): array
|
public function index(Request $request): array
|
||||||
{
|
{
|
||||||
return $this->fractal->item($request->user())
|
return $this->fractal->item($request->user())
|
||||||
->transformWith($this->getTransformer(AccountTransformer::class))
|
->transformWith($this->getTransformer(UserTransformer::class))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ abstract class AbstractLoginController extends Controller
|
|||||||
'data' => [
|
'data' => [
|
||||||
'complete' => true,
|
'complete' => true,
|
||||||
'intended' => $this->redirectPath(),
|
'intended' => $this->redirectPath(),
|
||||||
'user' => $user->toVueObject(),
|
'user' => $user->toReactObject(),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,14 @@ class EggFormRequest extends AdminFormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:255',
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
'docker_images' => 'required|string',
|
'docker_images' => 'required|string',
|
||||||
'force_outgoing_ip' => 'sometimes|boolean',
|
'force_outgoing_ip' => 'sometimes|boolean',
|
||||||
'file_denylist' => 'array',
|
'file_denylist' => 'array',
|
||||||
'startup' => 'required|string',
|
'startup' => 'required|string',
|
||||||
'config_from' => 'sometimes|bail|nullable|numeric',
|
'config_from' => 'sometimes|bail|nullable|numeric',
|
||||||
'config_stop' => 'required_without:config_from|nullable|string|max:191',
|
'config_stop' => 'required_without:config_from|nullable|string|max:255',
|
||||||
'config_startup' => 'required_without:config_from|nullable|json',
|
'config_startup' => 'required_without:config_from|nullable|json',
|
||||||
'config_logs' => 'required_without:config_from|nullable|json',
|
'config_logs' => 'required_without:config_from|nullable|json',
|
||||||
'config_files' => 'required_without:config_from|nullable|json',
|
'config_files' => 'required_without:config_from|nullable|json',
|
||||||
|
@ -13,9 +13,9 @@ class EggVariableFormRequest extends AdminFormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'required|string|min:1|max:191',
|
'name' => 'required|string|min:1|max:255',
|
||||||
'description' => 'sometimes|nullable|string',
|
'description' => 'sometimes|nullable|string',
|
||||||
'env_variable' => 'required|regex:/^[\w]{1,191}$/|notIn:' . EggVariable::RESERVED_ENV_NAMES,
|
'env_variable' => 'required|regex:/^[\w]{1,255}$/|notIn:' . EggVariable::RESERVED_ENV_NAMES,
|
||||||
'options' => 'sometimes|required|array',
|
'options' => 'sometimes|required|array',
|
||||||
'rules' => 'bail|required|string',
|
'rules' => 'bail|required|string',
|
||||||
'default_value' => 'present',
|
'default_value' => 'present',
|
||||||
|
@ -13,8 +13,8 @@ class AdvancedSettingsFormRequest extends AdminFormRequest
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'recaptcha:enabled' => 'required|in:true,false',
|
'recaptcha:enabled' => 'required|in:true,false',
|
||||||
'recaptcha:secret_key' => 'required|string|max:191',
|
'recaptcha:secret_key' => 'required|string|max:255',
|
||||||
'recaptcha:website_key' => 'required|string|max:191',
|
'recaptcha:website_key' => 'required|string|max:255',
|
||||||
'panel:guzzle:timeout' => 'required|integer|between:1,60',
|
'panel:guzzle:timeout' => 'required|integer|between:1,60',
|
||||||
'panel:guzzle:connect_timeout' => 'required|integer|between:1,60',
|
'panel:guzzle:connect_timeout' => 'required|integer|between:1,60',
|
||||||
'panel:client_features:allocations:enabled' => 'required|in:true,false',
|
'panel:client_features:allocations:enabled' => 'required|in:true,false',
|
||||||
|
@ -13,7 +13,7 @@ class BaseSettingsFormRequest extends AdminFormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'app:name' => 'required|string|max:191',
|
'app:name' => 'required|string|max:255',
|
||||||
'panel:auth:2fa_required' => 'required|integer|in:0,1,2',
|
'panel:auth:2fa_required' => 'required|integer|in:0,1,2',
|
||||||
'app:locale' => ['required', 'string', Rule::in(array_keys($this->getAvailableLanguages()))],
|
'app:locale' => ['required', 'string', Rule::in(array_keys($this->getAvailableLanguages()))],
|
||||||
];
|
];
|
||||||
|
@ -16,10 +16,10 @@ class MailSettingsFormRequest extends AdminFormRequest
|
|||||||
'mail:mailers:smtp:host' => 'required|string',
|
'mail:mailers:smtp:host' => 'required|string',
|
||||||
'mail:mailers:smtp:port' => 'required|integer|between:1,65535',
|
'mail:mailers:smtp:port' => 'required|integer|between:1,65535',
|
||||||
'mail:mailers:smtp:encryption' => ['present', Rule::in([null, 'tls', 'ssl'])],
|
'mail:mailers:smtp:encryption' => ['present', Rule::in([null, 'tls', 'ssl'])],
|
||||||
'mail:mailers:smtp:username' => 'nullable|string|max:191',
|
'mail:mailers:smtp:username' => 'nullable|string|max:255',
|
||||||
'mail:mailers:smtp:password' => 'nullable|string|max:191',
|
'mail:mailers:smtp:password' => 'nullable|string|max:255',
|
||||||
'mail:from:address' => 'required|string|email',
|
'mail:from:address' => 'required|string|email',
|
||||||
'mail:from:name' => 'nullable|string|max:191',
|
'mail:from:name' => 'nullable|string|max:255',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class StoreBackupRequest extends ClientApiRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'nullable|string|max:191',
|
'name' => 'nullable|string|max:255',
|
||||||
'is_locked' => 'nullable|boolean',
|
'is_locked' => 'nullable|boolean',
|
||||||
'ignored' => 'nullable|string',
|
'ignored' => 'nullable|string',
|
||||||
];
|
];
|
||||||
|
@ -14,7 +14,7 @@ class StoreSubuserRequest extends SubuserRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email' => 'required|email|between:1,191',
|
'email' => 'required|email|between:1,255',
|
||||||
'permissions' => 'required|array',
|
'permissions' => 'required|array',
|
||||||
'permissions.*' => 'string',
|
'permissions.*' => 'string',
|
||||||
];
|
];
|
||||||
|
@ -24,7 +24,7 @@ class RunTaskJob extends Job implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function __construct(public Task $task, public bool $manualRun = false)
|
public function __construct(public Task $task, public bool $manualRun = false)
|
||||||
{
|
{
|
||||||
$this->queue = 'standard';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +46,7 @@ class DatabaseHost extends Model
|
|||||||
* Validation rules to assign to this model.
|
* Validation rules to assign to this model.
|
||||||
*/
|
*/
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:255',
|
||||||
'host' => 'required|string',
|
'host' => 'required|string',
|
||||||
'port' => 'required|numeric|between:1,65535',
|
'port' => 'required|numeric|between:1,65535',
|
||||||
'username' => 'required|string|max:32',
|
'username' => 'required|string|max:32',
|
||||||
|
@ -105,7 +105,7 @@ class Egg extends Model
|
|||||||
|
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'uuid' => 'required|string|size:36',
|
'uuid' => 'required|string|size:36',
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:255',
|
||||||
'description' => 'string|nullable',
|
'description' => 'string|nullable',
|
||||||
'features' => 'array|nullable',
|
'features' => 'array|nullable',
|
||||||
'author' => 'required|string|email',
|
'author' => 'required|string|email',
|
||||||
@ -115,7 +115,7 @@ class Egg extends Model
|
|||||||
'docker_images.*' => 'required|string',
|
'docker_images.*' => 'required|string',
|
||||||
'startup' => 'required|nullable|string',
|
'startup' => 'required|nullable|string',
|
||||||
'config_from' => 'sometimes|bail|nullable|numeric|exists:eggs,id',
|
'config_from' => 'sometimes|bail|nullable|numeric|exists:eggs,id',
|
||||||
'config_stop' => 'required_without:config_from|nullable|string|max:191',
|
'config_stop' => 'required_without:config_from|nullable|string|max:255',
|
||||||
'config_startup' => 'required_without:config_from|nullable|json',
|
'config_startup' => 'required_without:config_from|nullable|json',
|
||||||
'config_logs' => 'required_without:config_from|nullable|json',
|
'config_logs' => 'required_without:config_from|nullable|json',
|
||||||
'config_files' => 'required_without:config_from|nullable|json',
|
'config_files' => 'required_without:config_from|nullable|json',
|
||||||
|
@ -52,9 +52,9 @@ class EggVariable extends Model
|
|||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'egg_id' => 'exists:eggs,id',
|
'egg_id' => 'exists:eggs,id',
|
||||||
'sort' => 'nullable',
|
'sort' => 'nullable',
|
||||||
'name' => 'required|string|between:1,191',
|
'name' => 'required|string|between:1,255',
|
||||||
'description' => 'string',
|
'description' => 'string',
|
||||||
'env_variable' => 'required|alphaDash|between:1,191|notIn:' . self::RESERVED_ENV_NAMES,
|
'env_variable' => 'required|alphaDash|between:1,255|notIn:' . self::RESERVED_ENV_NAMES,
|
||||||
'default_value' => 'string',
|
'default_value' => 'string',
|
||||||
'user_viewable' => 'boolean',
|
'user_viewable' => 'boolean',
|
||||||
'user_editable' => 'boolean',
|
'user_editable' => 'boolean',
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\CarbonInterface;
|
||||||
|
use DateTimeInterface;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Date;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Container\Container;
|
use Illuminate\Container\Container;
|
||||||
@ -12,6 +16,7 @@ use App\Exceptions\Model\DataValidationException;
|
|||||||
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||||
use Illuminate\Validation\Factory as ValidationFactory;
|
use Illuminate\Validation\Factory as ValidationFactory;
|
||||||
use Illuminate\Validation\Validator;
|
use Illuminate\Validation\Validator;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
abstract class Model extends IlluminateModel
|
abstract class Model extends IlluminateModel
|
||||||
{
|
{
|
||||||
@ -64,6 +69,36 @@ abstract class Model extends IlluminateModel
|
|||||||
return 'uuid';
|
return 'uuid';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function asDateTime($value)
|
||||||
|
{
|
||||||
|
$timezone = auth()->user()?->timezone ?? config('app.timezone', 'UTC');
|
||||||
|
|
||||||
|
if ($value instanceof CarbonInterface) {
|
||||||
|
return Date::instance($value->timezone($timezone));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof DateTimeInterface) {
|
||||||
|
return Date::parse($value->format('Y-m-d H:i:s.u'), $timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return Date::createFromTimestamp($value, $timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isStandardDateFormat($value)) {
|
||||||
|
return Date::instance(Carbon::createFromFormat('Y-m-d', $value)->timezone($timezone)->startOfDay());
|
||||||
|
}
|
||||||
|
|
||||||
|
$format = $this->getDateFormat();
|
||||||
|
try {
|
||||||
|
$date = Date::createFromFormat($format, $value)->timezone($timezone);
|
||||||
|
} catch (InvalidArgumentException) {
|
||||||
|
$date = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date ?: Date::parse($value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the validator instance used by this model.
|
* Returns the validator instance used by this model.
|
||||||
*/
|
*/
|
||||||
|
@ -41,7 +41,7 @@ class Mount extends Model
|
|||||||
*/
|
*/
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'name' => 'required|string|min:2|max:64|unique:mounts,name',
|
'name' => 'required|string|min:2|max:64|unique:mounts,name',
|
||||||
'description' => 'nullable|string|max:191',
|
'description' => 'nullable|string|max:255',
|
||||||
'source' => 'required|string',
|
'source' => 'required|string',
|
||||||
'target' => 'required|string',
|
'target' => 'required|string',
|
||||||
'read_only' => 'sometimes|boolean',
|
'read_only' => 'sometimes|boolean',
|
||||||
|
@ -83,7 +83,7 @@ class Node extends Model
|
|||||||
'description' => 'string|nullable',
|
'description' => 'string|nullable',
|
||||||
'public' => 'boolean',
|
'public' => 'boolean',
|
||||||
'fqdn' => 'required|string',
|
'fqdn' => 'required|string',
|
||||||
'scheme' => 'required',
|
'scheme' => 'required|string|in:http,https',
|
||||||
'behind_proxy' => 'boolean',
|
'behind_proxy' => 'boolean',
|
||||||
'memory' => 'required|numeric|min:0',
|
'memory' => 'required|numeric|min:0',
|
||||||
'memory_overallocate' => 'required|numeric|min:-1',
|
'memory_overallocate' => 'required|numeric|min:-1',
|
||||||
|
@ -76,7 +76,7 @@ class Schedule extends Model
|
|||||||
|
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'server_id' => 'required|exists:servers,id',
|
'server_id' => 'required|exists:servers,id',
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:255',
|
||||||
'cron_day_of_week' => 'required|string',
|
'cron_day_of_week' => 'required|string',
|
||||||
'cron_month' => 'required|string',
|
'cron_month' => 'required|string',
|
||||||
'cron_day_of_month' => 'required|string',
|
'cron_day_of_month' => 'required|string',
|
||||||
|
@ -74,7 +74,6 @@ use App\Exceptions\Http\Server\ServerStateConflictException;
|
|||||||
* @property \App\Models\User $user
|
* @property \App\Models\User $user
|
||||||
* @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables
|
* @property \Illuminate\Database\Eloquent\Collection|\App\Models\EggVariable[] $variables
|
||||||
* @property int|null $variables_count
|
* @property int|null $variables_count
|
||||||
*
|
|
||||||
* @method static \Database\Factories\ServerFactory factory(...$parameters)
|
* @method static \Database\Factories\ServerFactory factory(...$parameters)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Server newModelQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|Server newModelQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Server newQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|Server newQuery()
|
||||||
@ -105,9 +104,9 @@ use App\Exceptions\Http\Server\ServerStateConflictException;
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|Server whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Server whereUpdatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Server whereUuid($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|Server whereuuid_short($value)
|
||||||
*
|
|
||||||
* @property array|null $docker_labels
|
* @property array|null $docker_labels
|
||||||
* @property Collection<Endpoint>|null $ports
|
* @property Collection<Endpoint>|null $ports
|
||||||
|
* @property-read mixed $condition
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EggVariable> $eggVariables
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EggVariable> $eggVariables
|
||||||
* @property-read int|null $egg_variables_count
|
* @property-read int|null $egg_variables_count
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ServerVariable> $serverVariables
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ServerVariable> $serverVariables
|
||||||
@ -149,9 +148,9 @@ class Server extends Model
|
|||||||
protected $guarded = ['id', self::CREATED_AT, self::UPDATED_AT, 'deleted_at', 'installed_at'];
|
protected $guarded = ['id', self::CREATED_AT, self::UPDATED_AT, 'deleted_at', 'installed_at'];
|
||||||
|
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'external_id' => 'sometimes|nullable|string|between:1,191|unique:servers',
|
'external_id' => 'sometimes|nullable|string|between:1,255|unique:servers',
|
||||||
'owner_id' => 'required|integer|exists:users,id',
|
'owner_id' => 'required|integer|exists:users,id',
|
||||||
'name' => 'required|string|min:1|max:191',
|
'name' => 'required|string|min:1|max:255',
|
||||||
'node_id' => 'required|exists:nodes,id',
|
'node_id' => 'required|exists:nodes,id',
|
||||||
'description' => 'string',
|
'description' => 'string',
|
||||||
'status' => 'nullable|string',
|
'status' => 'nullable|string',
|
||||||
@ -165,7 +164,7 @@ class Server extends Model
|
|||||||
'egg_id' => 'required|exists:eggs,id',
|
'egg_id' => 'required|exists:eggs,id',
|
||||||
'startup' => 'required|string',
|
'startup' => 'required|string',
|
||||||
'skip_scripts' => 'sometimes|boolean',
|
'skip_scripts' => 'sometimes|boolean',
|
||||||
'image' => 'required|string|max:191',
|
'image' => 'required|string|max:255',
|
||||||
'database_limit' => 'present|nullable|integer|min:0',
|
'database_limit' => 'present|nullable|integer|min:0',
|
||||||
'allocation_limit' => 'sometimes|nullable|integer|min:0',
|
'allocation_limit' => 'sometimes|nullable|integer|min:0',
|
||||||
'backup_limit' => 'present|nullable|integer|min:0',
|
'backup_limit' => 'present|nullable|integer|min:0',
|
||||||
@ -439,7 +438,6 @@ class Server extends Model
|
|||||||
|
|
||||||
return $this->status->color();
|
return $this->status->color();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPrimaryEndpoint(): ?Endpoint
|
public function getPrimaryEndpoint(): ?Endpoint
|
||||||
{
|
{
|
||||||
$endpoint = $this->ports->first();
|
$endpoint = $this->ports->first();
|
||||||
|
@ -21,7 +21,7 @@ class Setting extends Model
|
|||||||
protected $fillable = ['key', 'value'];
|
protected $fillable = ['key', 'value'];
|
||||||
|
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'key' => 'required|string|between:1,191',
|
'key' => 'required|string|between:1,255',
|
||||||
'value' => 'string',
|
'value' => 'string',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ use App\Notifications\SendPasswordReset as ResetPasswordNotification;
|
|||||||
* @property bool $use_totp
|
* @property bool $use_totp
|
||||||
* @property string|null $totp_secret
|
* @property string|null $totp_secret
|
||||||
* @property \Illuminate\Support\Carbon|null $totp_authenticated_at
|
* @property \Illuminate\Support\Carbon|null $totp_authenticated_at
|
||||||
* @property array $oauth
|
* @property array|null $oauth
|
||||||
* @property bool $gravatar
|
* @property bool $gravatar
|
||||||
* @property \Illuminate\Support\Carbon|null $created_at
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
@ -123,6 +123,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
'name_last',
|
'name_last',
|
||||||
'password',
|
'password',
|
||||||
'language',
|
'language',
|
||||||
|
'timezone',
|
||||||
'use_totp',
|
'use_totp',
|
||||||
'totp_secret',
|
'totp_secret',
|
||||||
'totp_authenticated_at',
|
'totp_authenticated_at',
|
||||||
@ -155,17 +156,17 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
*/
|
*/
|
||||||
public static array $validationRules = [
|
public static array $validationRules = [
|
||||||
'uuid' => 'nullable|string|size:36|unique:users,uuid',
|
'uuid' => 'nullable|string|size:36|unique:users,uuid',
|
||||||
'email' => 'required|email|between:1,191|unique:users,email',
|
'email' => 'required|email|between:1,255|unique:users,email',
|
||||||
'external_id' => 'sometimes|nullable|string|max:191|unique:users,external_id',
|
'external_id' => 'sometimes|nullable|string|max:255|unique:users,external_id',
|
||||||
'username' => 'required|between:1,191|unique:users,username',
|
'username' => 'required|between:1,255|unique:users,username',
|
||||||
'name_first' => 'nullable|string|between:0,191',
|
'name_first' => 'nullable|string|between:0,255',
|
||||||
'name_last' => 'nullable|string|between:0,191',
|
'name_last' => 'nullable|string|between:0,255',
|
||||||
'password' => 'sometimes|nullable|string',
|
'password' => 'sometimes|nullable|string',
|
||||||
'root_admin' => 'boolean',
|
'root_admin' => 'boolean',
|
||||||
'language' => 'string',
|
'language' => 'string',
|
||||||
'use_totp' => 'boolean',
|
'use_totp' => 'boolean',
|
||||||
'totp_secret' => 'nullable|string',
|
'totp_secret' => 'nullable|string',
|
||||||
'oauth' => 'array',
|
'oauth' => 'array|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
@ -215,9 +216,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the user model in a format that can be passed over to Vue templates.
|
* Return the user model in a format that can be passed over to React templates.
|
||||||
*/
|
*/
|
||||||
public function toVueObject(): array
|
public function toReactObject(): array
|
||||||
{
|
{
|
||||||
return collect($this->toArray())->except(['id', 'external_id'])->toArray();
|
return collect($this->toArray())->except(['id', 'external_id'])->toArray();
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ use Illuminate\Support\Facades\Broadcast;
|
|||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
use Illuminate\Support\Facades\URL;
|
||||||
use Illuminate\Support\Facades\View;
|
use Illuminate\Support\Facades\View;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
@ -32,8 +31,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
Schema::defaultStringLength(191);
|
|
||||||
|
|
||||||
$versionData = app(SoftwareVersionService::class)->versionData();
|
$versionData = app(SoftwareVersionService::class)->versionData();
|
||||||
View::share('appVersion', $versionData['version'] ?? 'undefined');
|
View::share('appVersion', $versionData['version'] ?? 'undefined');
|
||||||
View::share('appIsGit', $versionData['is_git'] ?? false);
|
View::share('appIsGit', $versionData['is_git'] ?? false);
|
||||||
|
@ -33,13 +33,13 @@ class HostCreationService
|
|||||||
'host' => array_get($data, 'host'),
|
'host' => array_get($data, 'host'),
|
||||||
'port' => array_get($data, 'port'),
|
'port' => array_get($data, 'port'),
|
||||||
'username' => array_get($data, 'username'),
|
'username' => array_get($data, 'username'),
|
||||||
'max_databases' => null,
|
'max_databases' => array_get($data, 'max_databases'),
|
||||||
'node_id' => array_get($data, 'node_id'),
|
'node_id' => array_get($data, 'node_id'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Confirm access using the provided credentials before saving data.
|
// Confirm access using the provided credentials before saving data.
|
||||||
$this->dynamic->set('dynamic', $host);
|
$this->dynamic->set('dynamic', $host);
|
||||||
$this->databaseManager->connection('dynamic')->select('SELECT 1 FROM dual');
|
$this->databaseManager->connection('dynamic')->getPdo();
|
||||||
|
|
||||||
return $host;
|
return $host;
|
||||||
});
|
});
|
||||||
|
@ -24,18 +24,21 @@ class HostUpdateService
|
|||||||
*
|
*
|
||||||
* @throws \Throwable
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function handle(int $hostId, array $data): DatabaseHost
|
public function handle(DatabaseHost|int $host, array $data): DatabaseHost
|
||||||
{
|
{
|
||||||
|
if (!$host instanceof DatabaseHost) {
|
||||||
|
$host = DatabaseHost::query()->findOrFail($host);
|
||||||
|
}
|
||||||
|
|
||||||
if (empty(array_get($data, 'password'))) {
|
if (empty(array_get($data, 'password'))) {
|
||||||
unset($data['password']);
|
unset($data['password']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->connection->transaction(function () use ($data, $hostId) {
|
return $this->connection->transaction(function () use ($data, $host) {
|
||||||
/** @var DatabaseHost $host */
|
|
||||||
$host = DatabaseHost::query()->findOrFail($hostId);
|
|
||||||
$host->update($data);
|
$host->update($data);
|
||||||
|
|
||||||
$this->dynamic->set('dynamic', $host);
|
$this->dynamic->set('dynamic', $host);
|
||||||
$this->databaseManager->connection('dynamic')->select('SELECT 1 FROM dual');
|
$this->databaseManager->connection('dynamic')->getPdo();
|
||||||
|
|
||||||
return $host;
|
return $host;
|
||||||
});
|
});
|
||||||
|
@ -164,7 +164,7 @@ class EggConfigurationService
|
|||||||
// variable from the server configuration.
|
// variable from the server configuration.
|
||||||
$plucked = Arr::get(
|
$plucked = Arr::get(
|
||||||
$structure,
|
$structure,
|
||||||
preg_replace('/^env\./', 'build.environment.', $key),
|
preg_replace('/^env\./', 'environment.', $key),
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ trait EnvironmentWriterTrait
|
|||||||
$saveContents = file_get_contents($path);
|
$saveContents = file_get_contents($path);
|
||||||
collect($values)->each(function ($value, $key) use (&$saveContents) {
|
collect($values)->each(function ($value, $key) use (&$saveContents) {
|
||||||
$key = strtoupper($key);
|
$key = strtoupper($key);
|
||||||
$saveValue = sprintf('%s=%s', $key, $this->escapeEnvironmentValue($value));
|
$saveValue = sprintf('%s=%s', $key, $this->escapeEnvironmentValue($value ?? ''));
|
||||||
|
|
||||||
if (preg_match_all('/^' . $key . '=(.*)$/m', $saveContents) < 1) {
|
if (preg_match_all('/^' . $key . '=(.*)$/m', $saveContents) < 1) {
|
||||||
$saveContents = $saveContents . PHP_EOL . $saveValue;
|
$saveContents = $saveContents . PHP_EOL . $saveValue;
|
||||||
|
@ -37,7 +37,8 @@ class UserTransformer extends BaseTransformer
|
|||||||
'last_name' => $user->name_last,
|
'last_name' => $user->name_last,
|
||||||
'language' => $user->language,
|
'language' => $user->language,
|
||||||
'root_admin' => (bool) $user->root_admin,
|
'root_admin' => (bool) $user->root_admin,
|
||||||
'2fa' => (bool) $user->use_totp,
|
'2fa_enabled' => (bool) $user->use_totp,
|
||||||
|
'2fa' => (bool) $user->use_totp, // deprecated, use "2fa_enabled"
|
||||||
'created_at' => $this->formatTimestamp($user->created_at),
|
'created_at' => $this->formatTimestamp($user->created_at),
|
||||||
'updated_at' => $this->formatTimestamp($user->updated_at),
|
'updated_at' => $this->formatTimestamp($user->updated_at),
|
||||||
];
|
];
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Transformers\Api\Client;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
|
|
||||||
class AccountTransformer extends BaseClientTransformer
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return the resource name for the JSONAPI output.
|
|
||||||
*/
|
|
||||||
public function getResourceName(): string
|
|
||||||
{
|
|
||||||
return 'user';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return basic information about the currently logged-in user.
|
|
||||||
*/
|
|
||||||
public function transform(User $model): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $model->id,
|
|
||||||
'admin' => $model->root_admin,
|
|
||||||
'username' => $model->username,
|
|
||||||
'email' => $model->email,
|
|
||||||
'first_name' => $model->name_first,
|
|
||||||
'last_name' => $model->name_last,
|
|
||||||
'language' => $model->language,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,15 +19,21 @@ class UserTransformer extends BaseClientTransformer
|
|||||||
* Transforms a User model into a representation that can be shown to regular
|
* Transforms a User model into a representation that can be shown to regular
|
||||||
* users of the API.
|
* users of the API.
|
||||||
*/
|
*/
|
||||||
public function transform(User $model): array
|
public function transform(User $user): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'uuid' => $model->uuid,
|
'uuid' => $user->uuid,
|
||||||
'username' => $model->username,
|
'username' => $user->username,
|
||||||
'email' => $model->email,
|
'email' => $user->email,
|
||||||
'image' => 'https://gravatar.com/avatar/' . md5(Str::lower($model->email)),
|
'first_name' => $user->name_first,
|
||||||
'2fa_enabled' => $model->use_totp,
|
'last_name' => $user->name_last,
|
||||||
'created_at' => $model->created_at->toAtomString(),
|
'language' => $user->language,
|
||||||
|
'image' => 'https://gravatar.com/avatar/' . md5(Str::lower($user->email)), // deprecated
|
||||||
|
'admin' => (bool) $user->root_admin, // deprecated, use "root_admin"
|
||||||
|
'root_admin' => (bool) $user->root_admin,
|
||||||
|
'2fa_enabled' => (bool) $user->use_totp,
|
||||||
|
'created_at' => $this->formatTimestamp($user->created_at),
|
||||||
|
'updated_at' => $this->formatTimestamp($user->updated_at),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('timezone')->default('UTC')->after('language');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('timezone');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
289
database/migrations/2024_06_11_220722_update_field_length.php
Normal file
289
database/migrations/2024_06_11_220722_update_field_length.php
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('activity_log_subjects', function (Blueprint $table) {
|
||||||
|
$table->string('subject_type')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('activity_logs', function (Blueprint $table) {
|
||||||
|
$table->string('event')->change();
|
||||||
|
$table->string('ip')->change();
|
||||||
|
$table->string('actor_type')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('allocations', function (Blueprint $table) {
|
||||||
|
$table->string('ip')->change();
|
||||||
|
$table->string('notes')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('audit_logs', function (Blueprint $table) {
|
||||||
|
$table->string('action')->change();
|
||||||
|
$table->string('subaction')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('backups', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('disk')->change();
|
||||||
|
$table->string('checksum')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('database_hosts', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('host')->change();
|
||||||
|
$table->string('username')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('databases', function (Blueprint $table) {
|
||||||
|
$table->string('database')->change();
|
||||||
|
$table->string('username')->change();
|
||||||
|
$table->string('remote')->default('%')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('egg_variables', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('env_variable')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('eggs', function (Blueprint $table) {
|
||||||
|
$table->string('author')->change();
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('config_stop')->nullable()->default(null)->change();
|
||||||
|
$table->string('script_container')->default('alpine:3.4')->change();
|
||||||
|
$table->string('script_entry')->default('ash')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('failed_jobs', function (Blueprint $table) {
|
||||||
|
$table->string('uuid')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('jobs', function (Blueprint $table) {
|
||||||
|
$table->string('queue')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('migrations', function (Blueprint $table) {
|
||||||
|
$table->string('migration')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('mounts', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('source')->change();
|
||||||
|
$table->string('target')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('nodes', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('fqdn')->change();
|
||||||
|
$table->string('scheme')->default('https')->change();
|
||||||
|
$table->string('daemon_sftp_alias')->nullable()->default(null)->change();
|
||||||
|
$table->string('daemon_base')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('notifications', function (Blueprint $table) {
|
||||||
|
$table->string('id')->change();
|
||||||
|
$table->string('type')->change();
|
||||||
|
$table->string('notifiable_type')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('password_resets', function (Blueprint $table) {
|
||||||
|
$table->string('email')->change();
|
||||||
|
$table->string('token')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('recovery_tokens', function (Blueprint $table) {
|
||||||
|
$table->string('token')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('schedules', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('cron_day_of_week')->change();
|
||||||
|
$table->string('cron_month')->change();
|
||||||
|
$table->string('cron_day_of_month')->change();
|
||||||
|
$table->string('cron_hour')->change();
|
||||||
|
$table->string('cron_minute')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->string('external_id')->nullable()->default(null)->change();
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('status')->nullable()->default(null)->change();
|
||||||
|
$table->string('threads')->nullable()->default(null)->change();
|
||||||
|
$table->string('image')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('sessions', function (Blueprint $table) {
|
||||||
|
$table->string('id')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('settings', function (Blueprint $table) {
|
||||||
|
$table->string('key')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('tasks', function (Blueprint $table) {
|
||||||
|
$table->string('action')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('user_ssh_keys', function (Blueprint $table) {
|
||||||
|
$table->string('name')->change();
|
||||||
|
$table->string('fingerprint')->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('external_id')->nullable()->default(null)->change();
|
||||||
|
$table->string('username')->change();
|
||||||
|
$table->string('email')->change();
|
||||||
|
$table->string('name_first')->nullable()->default(null)->change();
|
||||||
|
$table->string('name_last')->nullable()->default(null)->change();
|
||||||
|
$table->string('remember_token')->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('activity_log_subjects', function (Blueprint $table) {
|
||||||
|
$table->string('subject_type', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('activity_logs', function (Blueprint $table) {
|
||||||
|
$table->string('event', 191)->change();
|
||||||
|
$table->string('ip', 191)->change();
|
||||||
|
$table->string('actor_type', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('allocations', function (Blueprint $table) {
|
||||||
|
$table->string('ip', 191)->change();
|
||||||
|
$table->string('notes', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('audit_logs', function (Blueprint $table) {
|
||||||
|
$table->string('action', 191)->change();
|
||||||
|
$table->string('subaction', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('backups', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('disk', 191)->change();
|
||||||
|
$table->string('checksum', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
Schema::table('database_hosts', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('host', 191)->change();
|
||||||
|
$table->string('username', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('databases', function (Blueprint $table) {
|
||||||
|
$table->string('database', 191)->change();
|
||||||
|
$table->string('username', 191)->change();
|
||||||
|
$table->string('remote', 191)->default('%', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('egg_variables', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('env_variable', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('eggs', function (Blueprint $table) {
|
||||||
|
$table->string('author', 191)->change();
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('config_stop', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('script_container', 191)->default('alpine:3.4', 191)->change();
|
||||||
|
$table->string('script_entry', 191)->default('ash', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('failed_jobs', function (Blueprint $table) {
|
||||||
|
$table->string('uuid', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('jobs', function (Blueprint $table) {
|
||||||
|
$table->string('queue', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('migrations', function (Blueprint $table) {
|
||||||
|
$table->string('migration', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('mounts', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('source', 191)->change();
|
||||||
|
$table->string('target', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('nodes', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('fqdn', 191)->change();
|
||||||
|
$table->string('scheme', 191)->default('https', 191)->change();
|
||||||
|
$table->string('daemon_sftp_alias', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('daemon_base', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('notifications', function (Blueprint $table) {
|
||||||
|
$table->string('id', 191)->change();
|
||||||
|
$table->string('type', 191)->change();
|
||||||
|
$table->string('notifiable_type', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('password_resets', function (Blueprint $table) {
|
||||||
|
$table->string('email', 191)->change();
|
||||||
|
$table->string('token', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('recovery_tokens', function (Blueprint $table) {
|
||||||
|
$table->string('token', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('schedules', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('cron_day_of_week', 191)->change();
|
||||||
|
$table->string('cron_month', 191)->change();
|
||||||
|
$table->string('cron_day_of_month', 191)->change();
|
||||||
|
$table->string('cron_hour', 191)->change();
|
||||||
|
$table->string('cron_minute', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->string('external_id', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('status', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('threads', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('image', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('sessions', function (Blueprint $table) {
|
||||||
|
$table->string('id', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('settings', function (Blueprint $table) {
|
||||||
|
$table->string('key', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('tasks', function (Blueprint $table) {
|
||||||
|
$table->string('action', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('user_ssh_keys', function (Blueprint $table) {
|
||||||
|
$table->string('name', 191)->change();
|
||||||
|
$table->string('fingerprint', 191)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('external_id', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('username', 191)->change();
|
||||||
|
$table->string('email', 191)->change();
|
||||||
|
$table->string('name_first', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('name_last', 191)->nullable()->default(null)->change();
|
||||||
|
$table->string('remember_token', 191)->nullable()->default(null)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -12,7 +12,7 @@ return new class extends Migration
|
|||||||
public function up(): void
|
public function up(): void
|
||||||
{
|
{
|
||||||
Schema::table('users', function (Blueprint $table) {
|
Schema::table('users', function (Blueprint $table) {
|
||||||
$table->json('oauth')->after('totp_authenticated_at');
|
$table->json('oauth')->nullable()->after('totp_authenticated_at');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -39,8 +39,7 @@ return [
|
|||||||
'daemonSFTP' => 'Enter the daemon SFTP listening port',
|
'daemonSFTP' => 'Enter the daemon SFTP listening port',
|
||||||
'daemonSFTPAlias' => 'Enter the daemon SFTP alias (can be empty)',
|
'daemonSFTPAlias' => 'Enter the daemon SFTP alias (can be empty)',
|
||||||
'daemonBase' => 'Enter the base folder',
|
'daemonBase' => 'Enter the base folder',
|
||||||
'succes1' => 'Successfully created a new node with the name: ',
|
'success' => 'Successfully created a new node with the name :name and has an id of :id',
|
||||||
'succes2' => 'and has an id of: ',
|
|
||||||
],
|
],
|
||||||
'node_config' => [
|
'node_config' => [
|
||||||
'error_not_exist' => 'The selected node does not exist.',
|
'error_not_exist' => 'The selected node does not exist.',
|
||||||
|
@ -19,9 +19,13 @@ return [
|
|||||||
'button_issues' => 'Create Issue',
|
'button_issues' => 'Create Issue',
|
||||||
'button_features' => 'Discuss Features',
|
'button_features' => 'Discuss Features',
|
||||||
],
|
],
|
||||||
'intro-update' => [
|
'intro-update-available' => [
|
||||||
'heading' => 'Update available',
|
'heading' => 'Update available',
|
||||||
'content' => ':latestVersion is available! Read our documentation to update your Panel.',
|
'content' => ':latestVersion is now available! Read our documentation to update your Panel.',
|
||||||
|
],
|
||||||
|
'intro-no-update' => [
|
||||||
|
'heading' => 'Your Panel is up to date',
|
||||||
|
'content' => 'You are currently using :version. Your panel is up-to-date!',
|
||||||
],
|
],
|
||||||
'intro-first-node' => [
|
'intro-first-node' => [
|
||||||
'heading' => 'No Nodes Detected',
|
'heading' => 'No Nodes Detected',
|
||||||
|
9
lang/en/search.php
Normal file
9
lang/en/search.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'validation' => 'Please enter at least three characters to begin searching.',
|
||||||
|
'term' => [
|
||||||
|
'label' => 'Search term',
|
||||||
|
'description' => 'Enter a server name, uuid, or allocation to begin searching.',
|
||||||
|
],
|
||||||
|
];
|
@ -1,5 +1,4 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
|
|
||||||
<x-filament-panels::header
|
<x-filament-panels::header
|
||||||
:actions="$this->getCachedHeaderActions()"
|
:actions="$this->getCachedHeaderActions()"
|
||||||
:breadcrumbs="filament()->hasBreadcrumbs() ? $this->getBreadcrumbs() : []"
|
:breadcrumbs="filament()->hasBreadcrumbs() ? $this->getBreadcrumbs() : []"
|
||||||
@ -9,6 +8,31 @@
|
|||||||
|
|
||||||
<p>{{ trans('dashboard/index.expand_sections') }}</p>
|
<p>{{ trans('dashboard/index.expand_sections') }}</p>
|
||||||
|
|
||||||
|
@if (!$isLatest)
|
||||||
|
<x-filament::section
|
||||||
|
icon="tabler-info-circle"
|
||||||
|
icon-color="warning"
|
||||||
|
id="intro-update-available"
|
||||||
|
:header-actions="$updateActions"
|
||||||
|
>
|
||||||
|
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-update-available.heading') }}</x-slot>
|
||||||
|
|
||||||
|
<p>{{ trans('dashboard/index.sections.intro-update-available.content', ['latestVersion' => $latestVersion]) }}</p>
|
||||||
|
|
||||||
|
</x-filament::section>
|
||||||
|
@else
|
||||||
|
<x-filament::section
|
||||||
|
icon="tabler-checkbox"
|
||||||
|
icon-color="success"
|
||||||
|
id="intro-no-update"
|
||||||
|
>
|
||||||
|
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-no-update.heading') }}</x-slot>
|
||||||
|
|
||||||
|
<p>{{ trans('dashboard/index.sections.intro-no-update.content', ['version' => $version]) }}</p>
|
||||||
|
</x-filament::section>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
@if ($inDevelopment)
|
@if ($inDevelopment)
|
||||||
<x-filament::section
|
<x-filament::section
|
||||||
icon="tabler-code"
|
icon="tabler-code"
|
||||||
@ -21,27 +45,11 @@
|
|||||||
>
|
>
|
||||||
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-developers.heading') }}</x-slot>
|
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-developers.heading') }}</x-slot>
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-developers.content') }}</p>
|
<p>{{ trans('dashboard/index.sections.intro-developers.content') }}</p>
|
||||||
|
|
||||||
<p><br /></p>
|
<p><br /></p>
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-developers.extra_note') }}</p>
|
<p>{{ trans('dashboard/index.sections.intro-developers.extra_note') }}</p>
|
||||||
|
|
||||||
</x-filament::section>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (!$isLatest)
|
|
||||||
<x-filament::section
|
|
||||||
icon="tabler-info-circle"
|
|
||||||
icon-color="warning"
|
|
||||||
id="intro-update"
|
|
||||||
collapsible
|
|
||||||
persist-collapsed
|
|
||||||
:header-actions="$updateActions"
|
|
||||||
>
|
|
||||||
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-update.heading') }}</x-slot>
|
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-update.content', ['latestVersion' => $latestVersion]) }}</p>
|
|
||||||
|
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@endif
|
@endif
|
||||||
@ -58,14 +66,13 @@
|
|||||||
>
|
>
|
||||||
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-first-node.heading') }}</x-slot>
|
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-first-node.heading') }}</x-slot>
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-first-node.content') }}</p>
|
<p>{{ trans('dashboard/index.sections.intro-first-node.content') }}</p>
|
||||||
|
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- No Nodes Active --}}
|
{{-- No Nodes Active --}}
|
||||||
|
|
||||||
|
|
||||||
<x-filament::section
|
<x-filament::section
|
||||||
icon="tabler-heart-filled"
|
icon="tabler-heart-filled"
|
||||||
icon-color="danger"
|
icon-color="danger"
|
||||||
@ -76,16 +83,14 @@
|
|||||||
>
|
>
|
||||||
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-support.heading') }}</x-slot>
|
<x-slot name="heading">{{ trans('dashboard/index.sections.intro-support.heading') }}</x-slot>
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-support.content') }}</p>
|
<p>{{ trans('dashboard/index.sections.intro-support.content') }}</p>
|
||||||
|
|
||||||
<p><br /></p>
|
<p><br /></p>
|
||||||
|
|
||||||
<p>{{ trans('dashboard/index.sections.intro-support.extra_note') }}</p>
|
<p>{{ trans('dashboard/index.sections.intro-support.extra_note') }}</p>
|
||||||
|
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<x-filament::section
|
<x-filament::section
|
||||||
icon="tabler-question-mark"
|
icon="tabler-question-mark"
|
||||||
icon-color="info"
|
icon-color="info"
|
||||||
@ -103,7 +108,4 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
|
|
||||||
<div>
|
|
||||||
</div>
|
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
@section('user-data')
|
@section('user-data')
|
||||||
@if(!is_null(Auth::user()))
|
@if(!is_null(Auth::user()))
|
||||||
<script>
|
<script>
|
||||||
window.PanelUser = {!! json_encode(Auth::user()->toVueObject()) !!};
|
window.PanelUser = {!! json_encode(Auth::user()->toReactObject()) !!};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($siteConfiguration))
|
@if(!empty($siteConfiguration))
|
||||||
|
@ -20,7 +20,7 @@ Route::get('/password/reset/{token}', [Auth\LoginController::class, 'index'])->n
|
|||||||
|
|
||||||
// Endpoints for OAuth
|
// Endpoints for OAuth
|
||||||
Route::get('/oauth/redirect/{driver}', [Auth\OAuthController::class, 'redirect'])->name('auth.oauth.redirect');
|
Route::get('/oauth/redirect/{driver}', [Auth\OAuthController::class, 'redirect'])->name('auth.oauth.redirect');
|
||||||
Route::get('/oauth/callback/{driver}', [Auth\OAuthController::class, 'callback'])->name('auth.oauth.callback');
|
Route::get('/oauth/callback/{driver}', [Auth\OAuthController::class, 'callback'])->name('auth.oauth.callback')->withoutMiddleware('guest');
|
||||||
|
|
||||||
// Apply a throttle to authentication action endpoints, in addition to the
|
// Apply a throttle to authentication action endpoints, in addition to the
|
||||||
// recaptcha endpoints to slow down manual attack spammers even more. 🤷
|
// recaptcha endpoints to slow down manual attack spammers even more. 🤷
|
||||||
|
@ -24,8 +24,8 @@ class UserControllerTest extends ApplicationApiIntegrationTestCase
|
|||||||
$response->assertJsonStructure([
|
$response->assertJsonStructure([
|
||||||
'object',
|
'object',
|
||||||
'data' => [
|
'data' => [
|
||||||
['object', 'attributes' => ['id', 'external_id', 'uuid', 'username', 'email', 'first_name', 'last_name', 'language', 'root_admin', '2fa', 'created_at', 'updated_at']],
|
['object', 'attributes' => ['id', 'external_id', 'uuid', 'username', 'email', 'first_name', 'last_name', 'language', 'root_admin', '2fa_enabled', '2fa', 'created_at', 'updated_at']],
|
||||||
['object', 'attributes' => ['id', 'external_id', 'uuid', 'username', 'email', 'first_name', 'last_name', 'language', 'root_admin', '2fa', 'created_at', 'updated_at']],
|
['object', 'attributes' => ['id', 'external_id', 'uuid', 'username', 'email', 'first_name', 'last_name', 'language', 'root_admin', '2fa_enabled', '2fa', 'created_at', 'updated_at']],
|
||||||
],
|
],
|
||||||
'meta' => ['pagination' => ['total', 'count', 'per_page', 'current_page', 'total_pages']],
|
'meta' => ['pagination' => ['total', 'count', 'per_page', 'current_page', 'total_pages']],
|
||||||
]);
|
]);
|
||||||
@ -56,6 +56,7 @@ class UserControllerTest extends ApplicationApiIntegrationTestCase
|
|||||||
'last_name' => $this->getApiUser()->name_last,
|
'last_name' => $this->getApiUser()->name_last,
|
||||||
'language' => $this->getApiUser()->language,
|
'language' => $this->getApiUser()->language,
|
||||||
'root_admin' => $this->getApiUser()->root_admin,
|
'root_admin' => $this->getApiUser()->root_admin,
|
||||||
|
'2fa_enabled' => (bool) $this->getApiUser()->totp_enabled,
|
||||||
'2fa' => (bool) $this->getApiUser()->totp_enabled,
|
'2fa' => (bool) $this->getApiUser()->totp_enabled,
|
||||||
'created_at' => $this->formatTimestamp($this->getApiUser()->created_at),
|
'created_at' => $this->formatTimestamp($this->getApiUser()->created_at),
|
||||||
'updated_at' => $this->formatTimestamp($this->getApiUser()->updated_at),
|
'updated_at' => $this->formatTimestamp($this->getApiUser()->updated_at),
|
||||||
@ -73,6 +74,7 @@ class UserControllerTest extends ApplicationApiIntegrationTestCase
|
|||||||
'last_name' => $user->name_last,
|
'last_name' => $user->name_last,
|
||||||
'language' => $user->language,
|
'language' => $user->language,
|
||||||
'root_admin' => (bool) $user->root_admin,
|
'root_admin' => (bool) $user->root_admin,
|
||||||
|
'2fa_enabled' => (bool) $user->totp_enabled,
|
||||||
'2fa' => (bool) $user->totp_enabled,
|
'2fa' => (bool) $user->totp_enabled,
|
||||||
'created_at' => $this->formatTimestamp($user->created_at),
|
'created_at' => $this->formatTimestamp($user->created_at),
|
||||||
'updated_at' => $this->formatTimestamp($user->updated_at),
|
'updated_at' => $this->formatTimestamp($user->updated_at),
|
||||||
|
@ -22,13 +22,18 @@ class AccountControllerTest extends ClientApiIntegrationTestCase
|
|||||||
$response->assertOk()->assertJson([
|
$response->assertOk()->assertJson([
|
||||||
'object' => 'user',
|
'object' => 'user',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'id' => $user->id,
|
'uuid' => $user->uuid,
|
||||||
'admin' => false,
|
|
||||||
'username' => $user->username,
|
'username' => $user->username,
|
||||||
'email' => $user->email,
|
'email' => $user->email,
|
||||||
'first_name' => $user->name_first,
|
'first_name' => $user->name_first,
|
||||||
'last_name' => $user->name_last,
|
'last_name' => $user->name_last,
|
||||||
'language' => $user->language,
|
'language' => 'en',
|
||||||
|
'image' => 'https://gravatar.com/avatar/' . md5(Str::lower($user->email)),
|
||||||
|
'admin' => false,
|
||||||
|
'root_admin' => false,
|
||||||
|
'2fa_enabled' => false,
|
||||||
|
'created_at' => $this->formatTimestamp($user->created_at),
|
||||||
|
'updated_at' => $this->formatTimestamp($user->updated_at),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ class CreateServerSubuserTest extends ClientApiIntegrationTestCase
|
|||||||
{
|
{
|
||||||
[$user, $server] = $this->generateTestAccount();
|
[$user, $server] = $this->generateTestAccount();
|
||||||
|
|
||||||
$email = str_repeat(Str::random(20), 9) . '1@gmail.com'; // 191 is the hard limit for the column in MySQL.
|
$email = str_repeat(Str::random(35), 7) . '@gmail.com'; // 255 is the hard limit for the column in MySQL.
|
||||||
|
|
||||||
$response = $this->actingAs($user)->postJson($this->link($server) . '/users', [
|
$response = $this->actingAs($user)->postJson($this->link($server) . '/users', [
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
@ -99,7 +99,7 @@ class CreateServerSubuserTest extends ClientApiIntegrationTestCase
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
$response->assertJsonPath('errors.0.detail', 'The email must be between 1 and 191 characters.');
|
$response->assertJsonPath('errors.0.detail', 'The email must be between 1 and 255 characters.');
|
||||||
$response->assertJsonPath('errors.0.meta.source_field', 'email');
|
$response->assertJsonPath('errors.0.meta.source_field', 'email');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user