mirror of
https://github.com/pelican-dev/panel.git
synced 2026-02-24 03:12:01 +03:00
Compare commits
1 Commits
lance/1228
...
lance/2077
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
380d9900e5 |
@@ -58,6 +58,9 @@ enum SubuserPermission: string
|
||||
case SettingsDescription = 'settings.description';
|
||||
case SettingsReinstall = 'settings.reinstall';
|
||||
|
||||
case MountRead = 'mount.read';
|
||||
case MountUpdate = 'mount.update';
|
||||
|
||||
/** @return string[] */
|
||||
public function split(): array
|
||||
{
|
||||
@@ -84,6 +87,7 @@ enum SubuserPermission: string
|
||||
'schedule' => TablerIcon::Clock,
|
||||
'settings' => TablerIcon::Settings,
|
||||
'activity' => TablerIcon::Stack,
|
||||
'mount' => TablerIcon::LayersLinked,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,6 +143,24 @@ class MountResource extends Resource
|
||||
])
|
||||
->inline()
|
||||
->default(false),
|
||||
ToggleButtons::make('user_mountable')
|
||||
->label(trans('admin/mount.user_mountable'))
|
||||
->helperText(trans('admin/mount.user_mountable_help'))
|
||||
->stateCast(new BooleanStateCast(false, true))
|
||||
->options([
|
||||
false => trans('admin/mount.toggles.not_user_mountable'),
|
||||
true => trans('admin/mount.toggles.user_mountable'),
|
||||
])
|
||||
->icons([
|
||||
false => TablerIcon::Users,
|
||||
true => TablerIcon::Users,
|
||||
])
|
||||
->colors([
|
||||
false => 'warning',
|
||||
true => 'success',
|
||||
])
|
||||
->inline()
|
||||
->default(true),
|
||||
TextInput::make('source')
|
||||
->label(trans('admin/mount.source'))
|
||||
->required()
|
||||
|
||||
@@ -42,7 +42,6 @@ class CreateMount extends CreateRecord
|
||||
protected function handleRecordCreation(array $data): Model
|
||||
{
|
||||
$data['uuid'] ??= Str::uuid()->toString();
|
||||
$data['user_mountable'] = 1;
|
||||
|
||||
return parent::handleRecordCreation($data);
|
||||
}
|
||||
|
||||
114
app/Filament/Server/Pages/Mounts.php
Normal file
114
app/Filament/Server/Pages/Mounts.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Server\Pages;
|
||||
|
||||
use App\Enums\SubuserPermission;
|
||||
use App\Enums\TablerIcon;
|
||||
use App\Facades\Activity;
|
||||
use App\Models\Mount;
|
||||
use App\Models\Server;
|
||||
use BackedEnum;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class Mounts extends ServerFormPage
|
||||
{
|
||||
protected static string|BackedEnum|null $navigationIcon = TablerIcon::LayersLinked;
|
||||
|
||||
protected static ?int $navigationSort = 11;
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return parent::canAccess() && user()?->can(SubuserPermission::MountRead, Filament::getTenant());
|
||||
}
|
||||
|
||||
protected function authorizeAccess(): void
|
||||
{
|
||||
abort_unless(user()?->can(SubuserPermission::MountRead, Filament::getTenant()), 403);
|
||||
}
|
||||
|
||||
protected function fillForm(): void
|
||||
{
|
||||
$this->form->fill([
|
||||
'mounts' => $this->getRecord()->mounts->pluck('id')->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
/** @var Server $server */
|
||||
$server = $this->getRecord();
|
||||
|
||||
$allowedMounts = Mount::query()
|
||||
->where('user_mountable', true)
|
||||
->where(function ($query) use ($server) {
|
||||
$query->whereDoesntHave('nodes')
|
||||
->orWhereHas('nodes', fn ($q) => $q->where('nodes.id', $server->node_id));
|
||||
})
|
||||
->where(function ($query) use ($server) {
|
||||
$query->whereDoesntHave('eggs')
|
||||
->orWhereHas('eggs', fn ($q) => $q->where('eggs.id', $server->egg_id));
|
||||
})
|
||||
->get();
|
||||
|
||||
return parent::form($schema)
|
||||
->components([
|
||||
Section::make(trans('server/mount.description'))
|
||||
->schema([
|
||||
CheckboxList::make('mounts')
|
||||
->hiddenLabel()
|
||||
->relationship('mounts')
|
||||
->options(fn () => $allowedMounts->mapWithKeys(fn (Mount $mount) => [$mount->id => $mount->name]))
|
||||
->descriptions(fn () => $allowedMounts->mapWithKeys(fn (Mount $mount) => [$mount->id => "$mount->source -> $mount->target"]))
|
||||
->helperText(fn () => $allowedMounts->isEmpty() ? trans('server/mount.no_mounts') : null)
|
||||
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::MountUpdate, $server))
|
||||
->bulkToggleable()
|
||||
->live()
|
||||
->afterStateUpdated(function ($state) {
|
||||
$this->save();
|
||||
})
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
/** @var Server $server */
|
||||
$server = $this->getRecord();
|
||||
|
||||
abort_unless(user()?->can(SubuserPermission::MountUpdate, $server), 403);
|
||||
|
||||
try {
|
||||
$this->form->getState();
|
||||
$this->form->saveRelationships();
|
||||
|
||||
Activity::event('server:mount.update')
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title(trans('server/mount.notification_updated'))
|
||||
->success()
|
||||
->send();
|
||||
} catch (\Exception $exception) {
|
||||
Notification::make()
|
||||
->title(trans('server/mount.notification_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return trans('server/mount.title');
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('server/mount.title');
|
||||
}
|
||||
}
|
||||
@@ -39,17 +39,13 @@ class CreateSchedule extends CreateRecord
|
||||
$data['server_id'] = $server->id;
|
||||
}
|
||||
|
||||
$timezone = $data['timezone'] ?? user()->timezone ?? 'UTC';
|
||||
unset($data['timezone']);
|
||||
|
||||
if (!isset($data['next_run_at'])) {
|
||||
$data['next_run_at'] = ScheduleResource::getNextRun(
|
||||
$data['cron_minute'],
|
||||
$data['cron_hour'],
|
||||
$data['cron_day_of_month'],
|
||||
$data['cron_month'],
|
||||
$data['cron_day_of_week'],
|
||||
$timezone
|
||||
$data['cron_day_of_week']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,16 +37,12 @@ class EditSchedule extends EditRecord
|
||||
|
||||
protected function mutateFormDataBeforeSave(array $data): array
|
||||
{
|
||||
$timezone = $data['timezone'] ?? user()->timezone ?? 'UTC';
|
||||
unset($data['timezone']);
|
||||
|
||||
$data['next_run_at'] = ScheduleResource::getNextRun(
|
||||
$data['cron_minute'],
|
||||
$data['cron_hour'],
|
||||
$data['cron_day_of_month'],
|
||||
$data['cron_month'],
|
||||
$data['cron_day_of_week'],
|
||||
$timezone
|
||||
$data['cron_day_of_week']
|
||||
);
|
||||
|
||||
return $data;
|
||||
|
||||
@@ -100,15 +100,13 @@ class ScheduleResource extends Resource
|
||||
Section::make('Cron')
|
||||
->label(trans('server/schedule.cron'))
|
||||
->description(function (Get $get) {
|
||||
$timezone = $get('timezone') ?? user()->timezone ?? 'UTC';
|
||||
|
||||
try {
|
||||
$nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'), $timezone)->timezone($timezone);
|
||||
$nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'))->timezone(user()->timezone ?? 'UTC');
|
||||
} catch (Exception) {
|
||||
$nextRun = trans('server/schedule.invalid');
|
||||
}
|
||||
|
||||
return new HtmlString(trans('server/schedule.cron_body', ['timezone' => $timezone]) . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => $timezone, 'next_run' => $nextRun]));
|
||||
return new HtmlString(trans('server/schedule.cron_body') . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => user()->timezone ?? 'UTC', 'next_run' => $nextRun]));
|
||||
})
|
||||
->schema([
|
||||
Actions::make([
|
||||
@@ -297,13 +295,6 @@ class ScheduleResource extends Resource
|
||||
'default' => 4,
|
||||
'lg' => 5,
|
||||
]),
|
||||
Select::make('timezone')
|
||||
->label(trans('server/schedule.timezone'))
|
||||
->options(fn () => array_combine(timezone_identifiers_list(), timezone_identifiers_list()))
|
||||
->default(user()->timezone ?? 'UTC')
|
||||
->searchable()
|
||||
->live()
|
||||
->hiddenOn('view'),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
@@ -388,10 +379,10 @@ class ScheduleResource extends Resource
|
||||
];
|
||||
}
|
||||
|
||||
public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
|
||||
public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
|
||||
{
|
||||
try {
|
||||
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek, $timezone);
|
||||
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek);
|
||||
} catch (Exception) {
|
||||
Notification::make()
|
||||
->title(trans('server/schedule.notification_invalid_cron'))
|
||||
|
||||
@@ -38,11 +38,11 @@ class Utilities
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
|
||||
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
|
||||
{
|
||||
return Carbon::instance((new CronExpression(
|
||||
sprintf('%s %s %s %s %s', $minute, $hour, $dayOfMonth, $month, $dayOfWeek)
|
||||
))->getNextRunDate(now($timezone)))->setTimezone('UTC');
|
||||
))->getNextRunDate(now('UTC')));
|
||||
}
|
||||
|
||||
public static function checked(string $name, mixed $default): string
|
||||
|
||||
@@ -75,7 +75,7 @@ class ScheduleController extends ClientApiController
|
||||
'cron_minute' => $request->input('minute'),
|
||||
'is_active' => (bool) $request->input('is_active'),
|
||||
'only_when_online' => (bool) $request->input('only_when_online'),
|
||||
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
|
||||
'next_run_at' => $this->getNextRunAt($request),
|
||||
]);
|
||||
|
||||
Activity::event('server:schedule.create')
|
||||
@@ -131,7 +131,7 @@ class ScheduleController extends ClientApiController
|
||||
'cron_minute' => $request->input('minute'),
|
||||
'is_active' => $active,
|
||||
'only_when_online' => (bool) $request->input('only_when_online'),
|
||||
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
|
||||
'next_run_at' => $this->getNextRunAt($request),
|
||||
];
|
||||
|
||||
// Toggle the processing state of the scheduled task when it is enabled or disabled so that an
|
||||
@@ -188,7 +188,7 @@ class ScheduleController extends ClientApiController
|
||||
*
|
||||
* @throws DisplayException
|
||||
*/
|
||||
protected function getNextRunAt(Request $request, string $timezone = 'UTC'): Carbon
|
||||
protected function getNextRunAt(Request $request): Carbon
|
||||
{
|
||||
try {
|
||||
return Utilities::getScheduleNextRunDate(
|
||||
@@ -196,8 +196,7 @@ class ScheduleController extends ClientApiController
|
||||
$request->input('hour'),
|
||||
$request->input('day_of_month'),
|
||||
$request->input('month'),
|
||||
$request->input('day_of_week'),
|
||||
$timezone
|
||||
$request->input('day_of_week')
|
||||
);
|
||||
} catch (Exception) {
|
||||
throw new DisplayException('The cron data provided does not evaluate to a valid expression.');
|
||||
|
||||
@@ -17,9 +17,13 @@ return [
|
||||
'no_mounts' => 'No Mounts',
|
||||
'eggs' => 'Eggs',
|
||||
'nodes' => 'Nodes',
|
||||
'user_mountable' => 'User Mountable?',
|
||||
'user_mountable_help' => 'Allow users to toggle this mount on or off for their servers.',
|
||||
'toggles' => [
|
||||
'writable' => 'Writable',
|
||||
'read_only' => 'Read Only',
|
||||
'user_mountable' => 'User Mountable',
|
||||
'not_user_mountable' => 'Admin Only',
|
||||
],
|
||||
'table' => [
|
||||
'name' => 'Name',
|
||||
|
||||
9
lang/en/server/mount.php
Normal file
9
lang/en/server/mount.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'title' => 'Mounts',
|
||||
'description' => 'Manage the mounts attached to your server.',
|
||||
'no_mounts' => 'There are no user-mountable mounts available for this server.',
|
||||
'notification_updated' => 'Mounts updated successfully.',
|
||||
'notification_failed' => 'Failed to update mounts.',
|
||||
];
|
||||
@@ -29,8 +29,7 @@ return [
|
||||
'enabled' => 'Enable Schedule?',
|
||||
'enabled_hint' => 'This schedule will be executed automatically if enabled.',
|
||||
|
||||
'timezone' => 'Timezone',
|
||||
'cron_body' => 'The cron inputs below use your timezone (:timezone).',
|
||||
'cron_body' => 'Please keep in mind that the cron inputs below always assume UTC.',
|
||||
'cron_timezone' => 'Next run in your timezone (:timezone): <b> :next_run </b>',
|
||||
|
||||
'invalid' => 'Invalid',
|
||||
|
||||
@@ -69,5 +69,8 @@ return [
|
||||
'backup_delete' => 'Allows a user to remove backups from the system.',
|
||||
'backup_download' => 'Allows a user to download a backup for the server. Danger: this allows a user to access all files for the server in the backup.',
|
||||
'backup_restore' => 'Allows a user to restore a backup for the server. Danger: this allows the user to delete all of the server files in the process.',
|
||||
'mount_desc' => 'Permissions that control a user\'s ability to manage mounts for this server.',
|
||||
'mount_read' => 'Allows a user to view the mounts page and see available mounts.',
|
||||
'mount_update' => 'Allows a user to toggle mounts on or off for the server.',
|
||||
],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user