Refactor subuser permissions (#1961)

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
This commit is contained in:
Boy132 2025-12-11 14:34:27 +01:00 committed by GitHub
parent 1ab4ddb07c
commit 760aaf9bfb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
112 changed files with 610 additions and 668 deletions

View File

@ -2,12 +2,13 @@
namespace App\Contracts\Http;
use App\Enums\SubuserPermission;
interface ClientPermissionsRequest
{
/**
* Returns the permissions string indicating which permission should be used to
* validate that the authenticated user has permission to perform this action against
* the given resource (server).
* Returns the permission used to validate that the authenticated user may perform
* this action against the given resource (server).
*/
public function permission(): string;
public function permission(): SubuserPermission|string;
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\Enums;
enum SubuserPermission: string
{
case WebsocketConnect = 'websocket.connect';
case ControlConsole = 'control.console';
case ControlStart = 'control.start';
case ControlStop = 'control.stop';
case ControlRestart = 'control.restart';
case FileRead = 'file.read';
case FileReadContent = 'file.read-content';
case FileCreate = 'file.create';
case FileUpdate = 'file.update';
case FileDelete = 'file.delete';
case FileArchive = 'file.archive';
case FileSftp = 'file.sftp';
case BackupRead = 'backup.read';
case BackupCreate = 'backup.create';
case BackupDelete = 'backup.delete';
case BackupDownload = 'backup.download';
case BackupRestore = 'backup.restore';
case ScheduleRead = 'schedule.read';
case ScheduleCreate = 'schedule.create';
case ScheduleUpdate = 'schedule.update';
case ScheduleDelete = 'schedule.delete';
case UserRead = 'user.read';
case UserCreate = 'user.create';
case UserUpdate = 'user.update';
case UserDelete = 'user.delete';
case DatabaseRead = 'database.read';
case DatabaseCreate = 'database.create';
case DatabaseUpdate = 'database.update';
case DatabaseDelete = 'database.delete';
case DatabaseViewPassword = 'database.view-password';
case AllocationRead = 'allocation.read';
case AllocationCreate = 'allocation.create';
case AllocationUpdate = 'allocation.update';
case AllocationDelete = 'allocation.delete';
case ActivityRead = 'activity.read';
case StartupRead = 'startup.read';
case StartupUpdate = 'startup.update';
case StartupDockerImage = 'startup.docker-image';
case SettingsRename = 'settings.rename';
case SettingsDescription = 'settings.description';
case SettingsReinstall = 'settings.reinstall';
/** @return string[] */
public function split(): array
{
return explode('.', $this->value, 2);
}
public function isHidden(): bool
{
return $this === self::WebsocketConnect;
}
public function getIcon(): ?string
{
[$group, $permission] = $this->split();
return match ($group) {
'control' => 'tabler-terminal-2',
'user' => 'tabler-users',
'file' => 'tabler-files',
'backup' => 'tabler-file-zip',
'allocation' => 'tabler-network',
'startup' => 'tabler-player-play',
'database' => 'tabler-database',
'schedule' => 'tabler-clock',
'settings' => 'tabler-settings',
'activity' => 'tabler-stack',
default => null,
};
}
}

View File

@ -2,9 +2,9 @@
namespace App\Extensions\Features\Schemas;
use App\Enums\SubuserPermission;
use App\Extensions\Features\FeatureSchemaInterface;
use App\Facades\Activity;
use App\Models\Permission;
use App\Models\Server;
use App\Models\ServerVariable;
use App\Repositories\Daemon\DaemonServerRepository;
@ -54,7 +54,7 @@ class GSLTokenSchema implements FeatureSchemaInterface
->modalHeading('Invalid GSL token')
->modalDescription('It seems like your Gameserver Login Token (GSL token) is invalid or has expired.')
->modalSubmitActionLabel('Update GSL Token')
->disabledSchema(fn () => !user()?->can(Permission::ACTION_STARTUP_UPDATE, $server))
->disabledSchema(fn () => !user()?->can(SubuserPermission::StartupUpdate, $server))
->schema([
TextEntry::make('info')
->label(new HtmlString(Blade::render('You can either <x-filament::link href="https://steamcommunity.com/dev/managegameservers" target="_blank">generate a new one</x-filament::link> and enter it below or leave the field blank to remove it completely.'))),

View File

@ -2,9 +2,9 @@
namespace App\Extensions\Features\Schemas;
use App\Enums\SubuserPermission;
use App\Extensions\Features\FeatureSchemaInterface;
use App\Facades\Activity;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonServerRepository;
use Exception;
@ -44,7 +44,7 @@ class JavaVersionSchema implements FeatureSchemaInterface
->modalHeading('Unsupported Java Version')
->modalDescription('This server is currently running an unsupported version of Java and cannot be started.')
->modalSubmitActionLabel('Update Docker Image')
->disabledSchema(fn () => !user()?->can(Permission::ACTION_STARTUP_DOCKER_IMAGE, $server))
->disabledSchema(fn () => !user()?->can(SubuserPermission::StartupDockerImage, $server))
->schema([
TextEntry::make('java')
->label('Please select a supported version from the list below to continue starting the server.'),

View File

@ -4,11 +4,11 @@ namespace App\Filament\App\Resources\Servers\Pages;
use App\Enums\CustomizationKey;
use App\Enums\ServerResourceType;
use App\Enums\SubuserPermission;
use App\Filament\App\Resources\Servers\ServerResource;
use App\Filament\Components\Tables\Columns\ProgressBarColumn;
use App\Filament\Components\Tables\Columns\ServerEntryColumn;
use App\Filament\Server\Pages\Console;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonServerRepository;
use App\Traits\Filament\CanCustomizeHeaderActions;
@ -244,21 +244,21 @@ class ListServers extends ListRecords
->label(trans('server/console.power_actions.start'))
->color('primary')
->icon('tabler-player-play-filled')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_START, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStart, $server))
->visible(fn (Server $server) => $server->retrieveStatus()->isStartable())
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'start']),
Action::make('restart')
->label(trans('server/console.power_actions.restart'))
->color('gray')
->icon('tabler-reload')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_RESTART, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlRestart, $server))
->visible(fn (Server $server) => $server->retrieveStatus()->isRestartable())
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'restart']),
Action::make('stop')
->label(trans('server/console.power_actions.stop'))
->color('danger')
->icon('tabler-player-stop-filled')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_STOP, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStop, $server))
->visible(fn (Server $server) => $server->retrieveStatus()->isStoppable() && !$server->retrieveStatus()->isKillable())
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'stop']),
Action::make('kill')
@ -266,7 +266,7 @@ class ListServers extends ListRecords
->color('danger')
->icon('tabler-alert-square')
->tooltip(trans('server/console.power_actions.kill_tooltip'))
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_STOP, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStop, $server))
->visible(fn (Server $server) => $server->retrieveStatus()->isKillable())
->dispatch('powerAction', fn (Server $server) => ['server' => $server, 'action' => 'kill']),
])

View File

@ -2,7 +2,7 @@
namespace App\Filament\Components\Actions;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Schedule;
use App\Models\Server;
use App\Services\Schedules\Sharing\ScheduleExporterService;
@ -36,7 +36,7 @@ class ExportScheduleAction extends Action
$this->label(trans('filament-actions::export.modal.actions.export.label'));
$this->authorize(fn () => user()?->can(Permission::ACTION_SCHEDULE_READ, $server));
$this->authorize(fn () => user()?->can(SubuserPermission::ScheduleRead, $server));
$this->action(fn (ScheduleExporterService $service, Schedule $schedule) => response()->streamDownload(function () use ($service, $schedule) {
echo $service->handle($schedule);

View File

@ -2,7 +2,7 @@
namespace App\Filament\Components\Actions;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Server;
use App\Services\Schedules\Sharing\ScheduleImporterService;
use Exception;
@ -33,7 +33,7 @@ class ImportScheduleAction extends Action
$this->label(trans('filament-actions::import.modal.actions.import.label'));
$this->authorize(fn () => user()?->can(Permission::ACTION_SCHEDULE_CREATE, $server));
$this->authorize(fn () => user()?->can(SubuserPermission::ScheduleCreate, $server));
$this->schema([
Tabs::make('Tabs')

View File

@ -4,6 +4,7 @@ namespace App\Filament\Server\Pages;
use App\Enums\ConsoleWidgetPosition;
use App\Enums\ContainerStatus;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\Server\ServerStateConflictException;
use App\Extensions\Features\FeatureService;
use App\Filament\Server\Widgets\ServerConsole;
@ -12,7 +13,6 @@ use App\Filament\Server\Widgets\ServerMemoryChart;
use App\Filament\Server\Widgets\ServerNetworkChart;
use App\Filament\Server\Widgets\ServerOverview;
use App\Livewire\AlertBanner;
use App\Models\Permission;
use App\Models\Server;
use App\Traits\Filament\CanCustomizeHeaderActions;
use Filament\Actions\Action;
@ -164,7 +164,7 @@ class Console extends Page
->label(trans('server/console.power_actions.start'))
->color('primary')
->icon('tabler-player-play-filled')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_START, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStart, $server))
->disabled(fn (Server $server) => $server->isInConflictState() || !$this->status->isStartable())
->action(fn (Server $server) => $this->dispatch('setServerState', uuid: $server->uuid, state: 'start'))
->size(Size::ExtraLarge),
@ -172,7 +172,7 @@ class Console extends Page
->label(trans('server/console.power_actions.restart'))
->color('gray')
->icon('tabler-reload')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_RESTART, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlRestart, $server))
->disabled(fn (Server $server) => $server->isInConflictState() || !$this->status->isRestartable())
->action(fn (Server $server) => $this->dispatch('setServerState', uuid: $server->uuid, state: 'restart'))
->size(Size::ExtraLarge),
@ -180,7 +180,7 @@ class Console extends Page
->label(trans('server/console.power_actions.stop'))
->color('danger')
->icon('tabler-player-stop-filled')
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_STOP, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStop, $server))
->visible(fn () => !$this->status->isKillable())
->disabled(fn (Server $server) => $server->isInConflictState() || !$this->status->isStoppable())
->action(fn (Server $server) => $this->dispatch('setServerState', uuid: $server->uuid, state: 'stop'))
@ -191,7 +191,7 @@ class Console extends Page
->icon('tabler-alert-square')
->tooltip(trans('server/console.power_actions.kill_tooltip'))
->requiresConfirmation()
->authorize(fn (Server $server) => user()?->can(Permission::ACTION_CONTROL_STOP, $server))
->authorize(fn (Server $server) => user()?->can(SubuserPermission::ControlStop, $server))
->visible(fn () => $this->status->isKillable())
->disabled(fn (Server $server) => $server->isInConflictState() || !$this->status->isKillable())
->action(fn (Server $server) => $this->dispatch('setServerState', uuid: $server->uuid, state: 'kill'))

View File

@ -2,8 +2,8 @@
namespace App\Filament\Server\Pages;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Servers\ReinstallServerService;
use Exception;
@ -60,7 +60,7 @@ class Settings extends ServerFormPage
->columnStart(1)
->columnSpanFull()
->label(trans('server/setting.server_info.name'))
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_SETTINGS_RENAME, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::SettingsRename, $server))
->required()
->live(onBlur: true)
->afterStateUpdated(fn ($state, Server $server) => $this->updateName($state, $server)),
@ -69,7 +69,7 @@ class Settings extends ServerFormPage
->columnSpanFull()
->label(trans('server/setting.server_info.description'))
->hidden(!config('panel.editable_server_descriptions'))
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_SETTINGS_DESCRIPTION, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::SettingsDescription, $server))
->autosize()
->live(onBlur: true)
->afterStateUpdated(fn ($state, Server $server) => $this->updateDescription($state ?? '', $server)),
@ -319,7 +319,7 @@ class Settings extends ServerFormPage
]),
Fieldset::make(trans('server/setting.server_info.sftp.title'))
->columnSpanFull()
->hidden(fn (Server $server) => !user()?->can(Permission::ACTION_FILE_SFTP, $server))
->hidden(fn (Server $server) => !user()?->can(SubuserPermission::FileSftp, $server))
->columns([
'default' => 1,
'sm' => 1,
@ -361,19 +361,19 @@ class Settings extends ServerFormPage
]),
]),
Section::make(trans('server/setting.reinstall.title'))
->hidden(fn (Server $server) => !user()?->can(Permission::ACTION_SETTINGS_REINSTALL, $server))
->hidden(fn (Server $server) => !user()?->can(SubuserPermission::SettingsReinstall, $server))
->columnSpanFull()
->footerActions([
Action::make('reinstall')
->label(trans('server/setting.reinstall.action'))
->color('danger')
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_SETTINGS_REINSTALL, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::SettingsReinstall, $server))
->requiresConfirmation()
->modalHeading(trans('server/setting.reinstall.modal'))
->modalDescription(trans('server/setting.reinstall.modal_description'))
->modalSubmitActionLabel(trans('server/setting.reinstall.yes'))
->action(function (Server $server, ReinstallServerService $reinstallService) {
abort_unless(user()?->can(Permission::ACTION_SETTINGS_REINSTALL, $server), 403);
abort_unless(user()?->can(SubuserPermission::SettingsReinstall, $server), 403);
try {
$reinstallService->handle($server);
@ -412,7 +412,7 @@ class Settings extends ServerFormPage
public function updateName(string $name, Server $server): void
{
abort_unless(user()?->can(Permission::ACTION_SETTINGS_RENAME, $server), 403);
abort_unless(user()?->can(SubuserPermission::SettingsRename, $server), 403);
$original = $server->name;
@ -443,7 +443,7 @@ class Settings extends ServerFormPage
public function updateDescription(string $description, Server $server): void
{
abort_unless(user()?->can(Permission::ACTION_SETTINGS_DESCRIPTION, $server) && config('panel.editable_server_descriptions'), 403);
abort_unless(user()?->can(SubuserPermission::SettingsDescription, $server) && config('panel.editable_server_descriptions'), 403);
$original = $server->description;

View File

@ -2,10 +2,10 @@
namespace App\Filament\Server\Pages;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Components\Actions\PreviewStartupAction;
use App\Filament\Components\Forms\Fields\StartupVariable;
use App\Models\Permission;
use App\Models\Server;
use App\Models\ServerVariable;
use Exception;
@ -51,7 +51,7 @@ class Startup extends ServerFormPage
->label(trans('server/startup.command'))
->live()
->visible(fn (Server $server) => in_array($server->startup, $server->egg->startup_commands))
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_STARTUP_UPDATE, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::StartupUpdate, $server))
->formatStateUsing(fn (Server $server) => $server->startup)
->afterStateUpdated(function ($state, Server $server, Set $set) {
$original = $server->startup;
@ -85,7 +85,7 @@ class Startup extends ServerFormPage
->label(trans('server/startup.docker_image'))
->live()
->visible(fn (Server $server) => in_array($server->image, $server->egg->docker_images))
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_STARTUP_DOCKER_IMAGE, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::StartupDockerImage, $server))
->afterStateUpdated(function ($state, Server $server) {
$original = $server->image;
$server->forceFill(['image' => $state])->saveOrFail();
@ -123,7 +123,7 @@ class Startup extends ServerFormPage
return $query->where('egg_variables.user_viewable', true)->orderByPowerJoins('variable.sort');
})
->grid()
->disabled(fn (Server $server) => !user()?->can(Permission::ACTION_STARTUP_UPDATE, $server))
->disabled(fn (Server $server) => !user()?->can(SubuserPermission::StartupUpdate, $server))
->reorderable(false)->addable(false)->deletable(false)
->schema([
StartupVariable::make('variable_value')
@ -139,12 +139,12 @@ class Startup extends ServerFormPage
protected function authorizeAccess(): void
{
abort_unless(user()?->can(Permission::ACTION_STARTUP_READ, Filament::getTenant()), 403);
abort_unless(user()?->can(SubuserPermission::StartupRead, Filament::getTenant()), 403);
}
public static function canAccess(): bool
{
return parent::canAccess() && user()?->can(Permission::ACTION_STARTUP_READ, Filament::getTenant());
return parent::canAccess() && user()?->can(SubuserPermission::StartupRead, Filament::getTenant());
}
public function update(?string $state, ServerVariable $serverVariable): null

View File

@ -2,10 +2,10 @@
namespace App\Filament\Server\Resources\Allocations;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Server\Resources\Allocations\Pages\ListAllocations;
use App\Models\Allocation;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Allocations\FindAssignableAllocationService;
use App\Traits\Filament\BlockAccessInConflict;
@ -57,7 +57,7 @@ class AllocationResource extends Resource
TextInputColumn::make('notes')
->label(trans('server/network.notes'))
->visibleFrom('sm')
->disabled(fn () => !user()?->can(Permission::ACTION_ALLOCATION_UPDATE, $server))
->disabled(fn () => !user()?->can(SubuserPermission::AllocationUpdate, $server))
->placeholder(trans('server/network.no_notes')),
IconColumn::make('primary')
->icon(fn ($state) => match ($state) {
@ -69,7 +69,7 @@ class AllocationResource extends Resource
default => 'gray',
})
->tooltip(fn (Allocation $allocation) => $allocation->id === $server->allocation_id ? trans('server/network.primary') : trans('server/network.make_primary'))
->action(fn (Allocation $allocation) => user()?->can(PERMISSION::ACTION_ALLOCATION_UPDATE, $server) && $server->update(['allocation_id' => $allocation->id]))
->action(fn (Allocation $allocation) => user()?->can(SubuserPermission::AllocationUpdate, $server) && $server->update(['allocation_id' => $allocation->id]))
->default(fn (Allocation $allocation) => $allocation->id === $server->allocation_id)
->label(trans('server/network.primary')),
IconColumn::make('is_locked')
@ -81,7 +81,7 @@ class AllocationResource extends Resource
->recordActions([
DetachAction::make()
->visible(fn (Allocation $allocation) => !$allocation->is_locked || user()?->can('update', $allocation->node))
->authorize(fn () => user()?->can(Permission::ACTION_ALLOCATION_DELETE, $server))
->authorize(fn () => user()?->can(SubuserPermission::AllocationDelete, $server))
->label(trans('server/network.delete'))
->action(function (Allocation $allocation) {
Allocation::where('id', $allocation->id)->update([
@ -101,7 +101,7 @@ class AllocationResource extends Resource
Action::make('add_allocation')
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon(fn () => $server->allocations()->count() >= $server->allocation_limit ? 'tabler-network-off' : 'tabler-network')
->authorize(fn () => user()?->can(Permission::ACTION_ALLOCATION_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::AllocationCreate, $server))
->tooltip(fn () => $server->allocations()->count() >= $server->allocation_limit ? trans('server/network.limit') : trans('server/network.add'))
->hidden(fn () => !config('panel.client_features.allocations.enabled') || $server->allocation === null)
->disabled(fn () => $server->allocations()->count() >= $server->allocation_limit)

View File

@ -4,13 +4,13 @@ namespace App\Filament\Server\Resources\Backups;
use App\Enums\BackupStatus;
use App\Enums\ServerState;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Components\Tables\Columns\BytesColumn;
use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Filament\Server\Resources\Backups\Pages\ListBackups;
use App\Http\Controllers\Api\Client\Servers\BackupController;
use App\Models\Backup;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonBackupRepository;
use App\Services\Backups\DeleteBackupService;
@ -128,7 +128,7 @@ class BackupResource extends Resource
ActionGroup::make([
Action::make('rename')
->icon('tabler-pencil')
->authorize(fn () => user()?->can(Permission::ACTION_BACKUP_DELETE, $server))
->authorize(fn () => user()?->can(SubuserPermission::BackupDelete, $server))
->label(trans('server/backup.actions.rename.title'))
->schema([
TextInput::make('name')
@ -159,7 +159,7 @@ class BackupResource extends Resource
Action::make('lock')
->iconSize(IconSize::Large)
->icon(fn (Backup $backup) => !$backup->is_locked ? 'tabler-lock' : 'tabler-lock-open')
->authorize(fn () => user()?->can(Permission::ACTION_BACKUP_DELETE, $server))
->authorize(fn () => user()?->can(SubuserPermission::BackupDelete, $server))
->label(fn (Backup $backup) => !$backup->is_locked ? trans('server/backup.actions.lock.lock') : trans('server/backup.actions.lock.unlock'))
->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->toggleLock($request, $server, $backup))
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
@ -168,7 +168,7 @@ class BackupResource extends Resource
->iconSize(IconSize::Large)
->color('primary')
->icon('tabler-download')
->authorize(fn () => user()?->can(Permission::ACTION_BACKUP_DOWNLOAD, $server))
->authorize(fn () => user()?->can(SubuserPermission::BackupDownload, $server))
->url(fn (DownloadLinkService $downloadLinkService, Backup $backup, Request $request) => $downloadLinkService->handle($backup, $request->user()), true)
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
Action::make('restore')
@ -176,7 +176,7 @@ class BackupResource extends Resource
->iconSize(IconSize::Large)
->color('success')
->icon('tabler-folder-up')
->authorize(fn () => user()?->can(Permission::ACTION_BACKUP_RESTORE, $server))
->authorize(fn () => user()?->can(SubuserPermission::BackupRestore, $server))
->schema([
TextEntry::make('stop_info')
->hiddenLabel()
@ -258,7 +258,7 @@ class BackupResource extends Resource
])
->toolbarActions([
CreateAction::make()
->authorize(fn () => user()?->can(Permission::ACTION_BACKUP_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::BackupCreate, $server))
->icon('tabler-file-zip')
->tooltip(fn () => $server->backups()->count() >= $server->backup_limit ? trans('server/backup.actions.create.limit') : trans('server/backup.actions.create.title'))
->disabled(fn () => $server->backups()->count() >= $server->backup_limit)
@ -269,7 +269,7 @@ class BackupResource extends Resource
->action(function (InitiateBackupService $initiateBackupService, $data) use ($server) {
$action = $initiateBackupService->setIgnoredFiles(explode(PHP_EOL, $data['ignored'] ?? ''));
if (user()?->can(Permission::ACTION_BACKUP_DELETE, $server)) {
if (user()?->can(SubuserPermission::BackupDelete, $server)) {
$action->setIsLocked((bool) $data['is_locked']);
}

View File

@ -2,12 +2,12 @@
namespace App\Filament\Server\Resources\Databases;
use App\Enums\SubuserPermission;
use App\Filament\Components\Actions\RotateDatabasePasswordAction;
use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Filament\Server\Resources\Databases\Pages\ListDatabases;
use App\Models\Database;
use App\Models\DatabaseHost;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Databases\DatabaseManagementService;
use App\Traits\Filament\BlockAccessInConflict;
@ -87,10 +87,10 @@ class DatabaseResource extends Resource
TextInput::make('password')
->label(trans('server/database.password'))
->password()->revealable()
->hidden(fn () => !user()?->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
->hidden(fn () => !user()?->can(SubuserPermission::DatabaseViewPassword, $server))
->hintAction(
RotateDatabasePasswordAction::make()
->authorize(fn () => user()?->can(Permission::ACTION_DATABASE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::DatabaseUpdate, $server))
)
->copyable()
->formatStateUsing(fn (Database $database) => $database->password),
@ -102,7 +102,7 @@ class DatabaseResource extends Resource
TextInput::make('jdbc')
->label(trans('server/database.jdbc'))
->password()->revealable()
->hidden(!user()?->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
->hidden(!user()?->can(SubuserPermission::DatabaseViewPassword, $server))
->copyable()
->columnSpanFull()
->formatStateUsing(fn (Database $database) => $database->jdbc),

View File

@ -2,9 +2,9 @@
namespace App\Filament\Server\Resources\Files\Pages;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Server\Resources\Files\FileResource;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Nodes\NodeJWTService;
use Carbon\CarbonImmutable;
@ -55,7 +55,7 @@ class DownloadFiles extends Page
protected function authorizeAccess(): void
{
abort_unless(user()?->can(Permission::ACTION_FILE_READ_CONTENT, Filament::getTenant()), 403);
abort_unless(user()?->can(SubuserPermission::FileReadContent, Filament::getTenant()), 403);
}
public static function route(string $path): PageRegistration

View File

@ -2,13 +2,13 @@
namespace App\Filament\Server\Resources\Files\Pages;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\Server\FileSizeTooLargeException;
use App\Exceptions\Repository\FileNotEditableException;
use App\Facades\Activity;
use App\Filament\Server\Resources\Files\FileResource;
use App\Livewire\AlertBanner;
use App\Models\File;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonFileRepository;
use App\Traits\Filament\CanCustomizeHeaderActions;
@ -83,7 +83,7 @@ class EditFiles extends Page
->footerActions([
Action::make('save_and_close')
->label(trans('server/file.actions.edit.save_close'))
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->icon('tabler-device-floppy')
->keyBindings('mod+shift+s')
->action(function () {
@ -103,7 +103,7 @@ class EditFiles extends Page
}),
Action::make('save')
->label(trans('server/file.actions.edit.save'))
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->icon('tabler-device-floppy')
->keyBindings('mod+s')
->action(function () {
@ -233,7 +233,7 @@ class EditFiles extends Page
protected function authorizeAccess(): void
{
abort_unless(user()?->can(Permission::ACTION_FILE_READ_CONTENT, Filament::getTenant()), 403);
abort_unless(user()?->can(SubuserPermission::FileReadContent, Filament::getTenant()), 403);
}
/**

View File

@ -2,6 +2,7 @@
namespace App\Filament\Server\Resources\Files\Pages;
use App\Enums\SubuserPermission;
use App\Exceptions\Repository\FileExistsException;
use App\Facades\Activity;
use App\Filament\Components\Tables\Columns\BytesColumn;
@ -9,7 +10,6 @@ use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Filament\Server\Resources\Files\FileResource;
use App\Livewire\AlertBanner;
use App\Models\File;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonFileRepository;
use App\Services\Nodes\NodeJWTService;
@ -122,7 +122,7 @@ class ListFiles extends ListRecords
return self::getUrl(['path' => encode_path(join_paths($this->path, $file->name))]);
}
if (!user()?->can(Permission::ACTION_FILE_READ_CONTENT, $server)) {
if (!user()?->can(SubuserPermission::FileReadContent, $server)) {
return null;
}
@ -130,18 +130,18 @@ class ListFiles extends ListRecords
})
->recordActions([
Action::make('view')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_READ, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileRead, $server))
->label(trans('server/file.actions.open'))
->icon('tabler-eye')->iconSize(IconSize::Large)
->visible(fn (File $file) => $file->is_directory)
->url(fn (File $file) => self::getUrl(['path' => encode_path(join_paths($this->path, $file->name))])),
EditAction::make('edit')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_READ_CONTENT, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileReadContent, $server))
->visible(fn (File $file) => $file->canEdit())
->url(fn (File $file) => EditFiles::getUrl(['path' => encode_path(join_paths($this->path, $file->name))])),
ActionGroup::make([
Action::make('rename')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->label(trans('server/file.actions.rename.title'))
->icon('tabler-forms')->iconSize(IconSize::Large)
->schema([
@ -171,7 +171,7 @@ class ListFiles extends ListRecords
$this->refreshPage();
}),
Action::make('copy')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))
->label(trans('server/file.actions.copy.title'))
->icon('tabler-copy')->iconSize(IconSize::Large)
->visible(fn (File $file) => $file->is_file)
@ -190,13 +190,13 @@ class ListFiles extends ListRecords
$this->refreshPage();
}),
Action::make('download')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_READ_CONTENT, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileReadContent, $server))
->label(trans('server/file.actions.download'))
->icon('tabler-download')->iconSize(IconSize::Large)
->visible(fn (File $file) => $file->is_file)
->url(fn (File $file) => DownloadFiles::getUrl(['path' => encode_path(join_paths($this->path, $file->name))]), true),
Action::make('move')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->label(trans('server/file.actions.move.title'))
->icon('tabler-replace')->iconSize(IconSize::Large)
->schema([
@ -233,7 +233,7 @@ class ListFiles extends ListRecords
$this->refreshPage();
}),
Action::make('permissions')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->label(trans('server/file.actions.permissions.title'))
->icon('tabler-license')->iconSize(IconSize::Large)
->schema([
@ -295,7 +295,7 @@ class ListFiles extends ListRecords
->send();
}),
Action::make('archive')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_ARCHIVE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileArchive, $server))
->label(trans('server/file.actions.archive.title'))
->icon('tabler-archive')->iconSize(IconSize::Large)
->schema([
@ -335,7 +335,7 @@ class ListFiles extends ListRecords
$this->refreshPage();
}),
Action::make('unarchive')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_ARCHIVE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileArchive, $server))
->label(trans('server/file.actions.unarchive.title'))
->icon('tabler-archive')->iconSize(IconSize::Large)
->visible(fn (File $file) => $file->isArchive())
@ -356,7 +356,7 @@ class ListFiles extends ListRecords
}),
])->iconSize(IconSize::Large),
DeleteAction::make()
->authorize(fn () => user()?->can(Permission::ACTION_FILE_DELETE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileDelete, $server))
->hiddenLabel()
->iconSize(IconSize::Large)
->requiresConfirmation()
@ -376,7 +376,7 @@ class ListFiles extends ListRecords
->toolbarActions([
BulkActionGroup::make([
BulkAction::make('move')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileUpdate, $server))
->schema([
TextInput::make('location')
->label(trans('server/file.actions.move.directory'))
@ -405,7 +405,7 @@ class ListFiles extends ListRecords
$this->refreshPage();
}),
BulkAction::make('archive')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_ARCHIVE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileArchive, $server))
->schema([
Grid::make(3)
->schema([
@ -446,7 +446,7 @@ class ListFiles extends ListRecords
}),
DeleteBulkAction::make()
->successNotificationTitle(null)
->authorize(fn () => user()?->can(Permission::ACTION_FILE_DELETE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileDelete, $server))
->action(function (Collection $files) {
$files = $files->map(fn ($file) => $file['name'])->toArray();
$this->getDaemonFileRepository()->deleteFiles($this->path, $files);
@ -466,7 +466,7 @@ class ListFiles extends ListRecords
]),
Action::make('new_file')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))
->tooltip(trans('server/file.actions.new_file.title'))
->hiddenLabel()->icon('tabler-file-plus')->iconButton()->iconSize(IconSize::ExtraLarge)
->color('primary')
@ -499,7 +499,7 @@ class ListFiles extends ListRecords
->hiddenLabel(),
]),
Action::make('new_folder')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))
->hiddenLabel()->icon('tabler-folder-plus')->iconButton()->iconSize(IconSize::ExtraLarge)
->tooltip(trans('server/file.actions.new_folder.title'))
->color('primary')
@ -530,10 +530,10 @@ class ListFiles extends ListRecords
->required(),
]),
Action::make('uploadFile')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))
->view('filament.server.pages.file-upload'),
Action::make('uploadURL')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))
->hiddenLabel()->icon('tabler-download')->iconButton()->iconSize(IconSize::ExtraLarge)
->tooltip(trans('server/file.actions.upload.from_url'))
->modalHeading(trans('server/file.actions.upload.from_url'))
@ -555,7 +555,7 @@ class ListFiles extends ListRecords
->url(),
]),
Action::make('search')
->authorize(fn () => user()?->can(Permission::ACTION_FILE_READ, $server))
->authorize(fn () => user()?->can(SubuserPermission::FileRead, $server))
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->tooltip(trans('server/file.actions.nested_search.title'))
->color('primary')
@ -605,7 +605,7 @@ class ListFiles extends ListRecords
/** @var Server $server */
$server = Filament::getTenant();
if (!user()?->can(Permission::ACTION_FILE_CREATE, $server)) {
if (!user()?->can(SubuserPermission::FileCreate, $server)) {
abort(403, 'You do not have permission to upload files.');
}
@ -640,7 +640,7 @@ class ListFiles extends ListRecords
/** @var Server $server */
$server = Filament::getTenant();
if (!user()?->can(Permission::ACTION_FILE_CREATE, $server)) {
if (!user()?->can(SubuserPermission::FileCreate, $server)) {
abort(403, 'You do not have permission to create folders.');
}

View File

@ -3,9 +3,9 @@
namespace App\Filament\Server\Resources\Schedules\Pages;
use App\Enums\ScheduleStatus;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Server\Resources\Schedules\ScheduleResource;
use App\Models\Permission;
use App\Models\Schedule;
use App\Services\Schedules\ProcessScheduleService;
use App\Traits\Filament\CanCustomizeHeaderActions;
@ -29,7 +29,7 @@ class ViewSchedule extends ViewRecord
{
return [
Action::make('run_now')
->authorize(fn () => user()?->can(Permission::ACTION_SCHEDULE_UPDATE, Filament::getTenant()))
->authorize(fn () => user()?->can(SubuserPermission::ScheduleUpdate, Filament::getTenant()))
->label(fn (Schedule $schedule) => $schedule->tasks->count() === 0 ? trans('server/schedule.no_tasks') : ($schedule->status === ScheduleStatus::Processing ? ScheduleStatus::Processing->getLabel() : trans('server/schedule.run_now')))
->color(fn (Schedule $schedule) => $schedule->tasks->count() === 0 || $schedule->status === ScheduleStatus::Processing ? 'warning' : 'primary')
->disabled(fn (Schedule $schedule) => $schedule->tasks->count() === 0 || $schedule->status === ScheduleStatus::Processing)

View File

@ -2,9 +2,9 @@
namespace App\Filament\Server\Resources\Subusers;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Filament\Server\Resources\Subusers\Pages\ListSubusers;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Services\Subusers\SubuserCreationService;
@ -68,7 +68,11 @@ class SubuserResource extends Resource
$tabs = [];
$permissionsArray = [];
foreach (Permission::permissionData() as $data) {
foreach (Subuser::allPermissionData() as $data) {
if ($data['hidden']) {
continue;
}
$options = [];
$descriptions = [];
@ -84,6 +88,7 @@ class SubuserResource extends Resource
Section::make()
->description(trans('server/user.permissions.' . $data['name'] . '_desc'))
->icon($data['icon'])
->contained(false)
->schema([
CheckboxList::make($data['name'])
->hiddenLabel()
@ -109,9 +114,12 @@ class SubuserResource extends Resource
TextColumn::make('user.email')
->label(trans('server/user.email'))
->searchable(),
TextColumn::make('permissions')
TextColumn::make('permissions_count')
->label(trans('server/user.permissions.title'))
->state(fn (Subuser $subuser) => count($subuser->permissions) - 1),
->state(fn (Subuser $subuser) => collect($subuser->permissions)
->reject(fn (string $permission) => SubuserPermission::tryFrom($permission)?->isHidden() ?? false)
->count()
),
])
->recordActions([
DeleteAction::make()
@ -129,14 +137,14 @@ class SubuserResource extends Resource
EditAction::make()
->label(trans('server/user.edit'))
->hidden(fn (Subuser $subuser) => user()?->id === $subuser->user->id)
->authorize(fn () => user()?->can(Permission::ACTION_USER_UPDATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::UserUpdate, $server))
->modalHeading(fn (Subuser $subuser) => trans('server/user.editing', ['user' => $subuser->user->email]))
->successNotificationTitle(null)
->action(function (array $data, SubuserUpdateService $subuserUpdateService, Subuser $subuser) use ($server) {
$permissions = collect($data)
->forget('email')
->flatMap(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))
->push(Permission::ACTION_WEBSOCKET_CONNECT)
->push(SubuserPermission::WebsocketConnect->value)
->unique()
->all();
@ -212,7 +220,7 @@ class SubuserResource extends Resource
->icon('tabler-user-plus')
->tooltip(trans('server/user.invite_user'))
->createAnother(false)
->authorize(fn () => user()?->can(Permission::ACTION_USER_CREATE, $server))
->authorize(fn () => user()?->can(SubuserPermission::UserCreate, $server))
->schema([
Grid::make()
->columnSpanFull()
@ -266,7 +274,7 @@ class SubuserResource extends Resource
$permissions = collect($data)
->forget('email')
->flatMap(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))
->push(Permission::ACTION_WEBSOCKET_CONNECT)
->push(SubuserPermission::WebsocketConnect->value)
->unique()
->all();

View File

@ -2,9 +2,9 @@
namespace App\Filament\Server\Widgets;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\HttpForbiddenException;
use App\Livewire\AlertBanner;
use App\Models\Permission;
use App\Models\Server;
use App\Models\User;
use App\Services\Nodes\NodeJWTService;
@ -46,7 +46,7 @@ class ServerConsole extends Widget
protected function getToken(): string
{
if (!$this->user || !$this->server || $this->user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $this->server)) {
if (!$this->user || !$this->server || $this->user->cannot(SubuserPermission::WebsocketConnect, $this->server)) {
throw new HttpForbiddenException('You do not have permission to connect to this server\'s websocket.');
}
@ -72,7 +72,7 @@ class ServerConsole extends Widget
protected function authorizeSendCommand(): bool
{
return $this->user->can(Permission::ACTION_CONTROL_CONSOLE, $this->server);
return $this->user->can(SubuserPermission::ControlConsole, $this->server);
}
protected function canSendCommand(): bool

View File

@ -4,13 +4,12 @@ namespace App\Http\Controllers\Api\Client;
use App\Http\Requests\Api\Client\GetServersRequest;
use App\Models\Filters\MultiFieldServerFilter;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Transformers\Api\Client\ServerTransformer;
use Dedoc\Scramble\Attributes\Group;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\QueryBuilder;
@ -81,14 +80,14 @@ class ClientController extends ClientApiController
*
* Returns all the subuser permissions available on the system.
*
* @return array{object: string, attributes: array{permissions: Collection}}
* @return array{object: string, attributes: array{permissions: string[]}}
*/
public function permissions(): array
{
return [
'object' => 'system_permissions',
'attributes' => [
'permissions' => Permission::permissions(),
'permissions' => Subuser::allPermissionKeys(),
],
];
}

View File

@ -2,10 +2,10 @@
namespace App\Http\Controllers\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Http\Controllers\Api\Client\ClientApiController;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\ActivityLog;
use App\Models\Permission;
use App\Models\Role;
use App\Models\Server;
use App\Models\User;
@ -29,7 +29,7 @@ class ActivityLogController extends ClientApiController
*/
public function __invoke(ClientApiRequest $request, Server $server): array
{
Gate::authorize(Permission::ACTION_ACTIVITY_READ, $server);
Gate::authorize(SubuserPermission::ActivityRead, $server);
$activity = QueryBuilder::for($server->activity())
->allowedSorts(['timestamp'])

View File

@ -3,13 +3,13 @@
namespace App\Http\Controllers\Api\Client\Servers;
use App\Enums\ServerState;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Http\Controllers\Api\Client\ClientApiController;
use App\Http\Requests\Api\Client\Servers\Backups\RenameBackupRequest;
use App\Http\Requests\Api\Client\Servers\Backups\RestoreBackupRequest;
use App\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest;
use App\Models\Backup;
use App\Models\Permission;
use App\Models\Server;
use App\Repositories\Daemon\DaemonBackupRepository;
use App\Services\Backups\DeleteBackupService;
@ -48,7 +48,7 @@ class BackupController extends ClientApiController
*/
public function index(Request $request, Server $server): array
{
if (!$request->user()->can(Permission::ACTION_BACKUP_READ, $server)) {
if (!$request->user()->can(SubuserPermission::BackupRead, $server)) {
throw new AuthorizationException();
}
@ -82,7 +82,7 @@ class BackupController extends ClientApiController
// otherwise ignore this status. This gets a little funky since it isn't clear
// how best to allow a user to create a backup that is locked without also preventing
// them from just filling up a server with backups that can never be deleted?
if ($request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
if ($request->user()->can(SubuserPermission::BackupDelete, $server)) {
$action->setIsLocked((bool) $request->input('is_locked'));
}
@ -110,7 +110,7 @@ class BackupController extends ClientApiController
*/
public function toggleLock(Request $request, Server $server, Backup $backup): array
{
if (!$request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
if (!$request->user()->can(SubuserPermission::BackupDelete, $server)) {
throw new AuthorizationException();
}
@ -136,7 +136,7 @@ class BackupController extends ClientApiController
*/
public function view(Request $request, Server $server, Backup $backup): array
{
if (!$request->user()->can(Permission::ACTION_BACKUP_READ, $server)) {
if (!$request->user()->can(SubuserPermission::BackupRead, $server)) {
throw new AuthorizationException();
}
@ -155,7 +155,7 @@ class BackupController extends ClientApiController
*/
public function delete(Request $request, Server $server, Backup $backup): JsonResponse
{
if (!$request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
if (!$request->user()->can(SubuserPermission::BackupDelete, $server)) {
throw new AuthorizationException();
}
@ -181,7 +181,7 @@ class BackupController extends ClientApiController
*/
public function download(Request $request, Server $server, Backup $backup): JsonResponse
{
if (!$request->user()->can(Permission::ACTION_BACKUP_DOWNLOAD, $server)) {
if (!$request->user()->can(SubuserPermission::BackupDownload, $server)) {
throw new AuthorizationException();
}

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\HttpForbiddenException;
use App\Exceptions\Model\DataValidationException;
use App\Exceptions\Service\ServiceLimitExceededException;
@ -9,7 +10,6 @@ use App\Facades\Activity;
use App\Http\Controllers\Api\Client\ClientApiController;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Http\Requests\Api\Client\Servers\Schedules\StoreTaskRequest;
use App\Models\Permission;
use App\Models\Schedule;
use App\Models\Server;
use App\Models\Task;
@ -170,7 +170,7 @@ class ScheduleTaskController extends ClientApiController
throw new NotFoundHttpException();
}
if (!$request->user()->can(Permission::ACTION_SCHEDULE_DELETE, $server)) {
if (!$request->user()->can(SubuserPermission::ScheduleDelete, $server)) {
throw new HttpForbiddenException('You do not have permission to perform this action.');
}

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Exceptions\Model\DataValidationException;
use App\Exceptions\Service\Subuser\ServerSubuserExistsException;
use App\Exceptions\Service\Subuser\UserIsServerOwnerException;
@ -11,7 +12,6 @@ use App\Http\Requests\Api\Client\Servers\Subusers\DeleteSubuserRequest;
use App\Http\Requests\Api\Client\Servers\Subusers\GetSubuserRequest;
use App\Http\Requests\Api\Client\Servers\Subusers\StoreSubuserRequest;
use App\Http\Requests\Api\Client\Servers\Subusers\UpdateSubuserRequest;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Models\User;
@ -82,18 +82,17 @@ class SubuserController extends ClientApiController
*/
public function store(StoreSubuserRequest $request, Server $server): array
{
$response = $this->creationService->handle(
$server,
$request->input('email'),
$this->getDefaultPermissions($request)
);
$email = $request->input('email');
$permissions = $this->getCleanedPermissions($request);
$subuser = $this->creationService->handle($server, $email, $permissions);
Activity::event('server:subuser.create')
->subject($response->user)
->property(['email' => $request->input('email'), 'permissions' => $this->getDefaultPermissions($request)])
->subject($subuser->user)
->property(['email' => $email, 'permissions' => $subuser->permissions])
->log();
return $this->fractal->item($response)
return $this->fractal->item($subuser)
->transformWith($this->getTransformer(SubuserTransformer::class))
->toArray();
}
@ -112,7 +111,7 @@ class SubuserController extends ClientApiController
/** @var Subuser $subuser */
$subuser = $request->attributes->get('subuser');
$this->updateService->handle($subuser, $server, $this->getDefaultPermissions($request));
$this->updateService->handle($subuser, $server, $this->getCleanedPermissions($request));
return $this->fractal->item($subuser->refresh())
->transformWith($this->getTransformer(SubuserTransformer::class))
@ -135,17 +134,19 @@ class SubuserController extends ClientApiController
}
/**
* Returns the default permissions for subusers and parses out any permissions
* Returns the "cleaned" permissions for subusers and parses out any permissions
* that were passed that do not also exist in the internally tracked list of
* permissions.
*
* @return array<array-key, mixed>
* @return string[]
*/
protected function getDefaultPermissions(Request $request): array
protected function getCleanedPermissions(Request $request): array
{
$allowed = Permission::permissionKeys()->all();
$cleaned = array_intersect($request->input('permissions') ?? [], $allowed);
return array_unique(array_merge($cleaned, [Permission::ACTION_WEBSOCKET_CONNECT]));
return collect($request->input('permissions') ?? [])
->intersect(Subuser::allPermissionKeys())
->push(SubuserPermission::WebsocketConnect->value)
->unique()
->values()
->toArray();
}
}

View File

@ -2,10 +2,10 @@
namespace App\Http\Controllers\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\HttpForbiddenException;
use App\Http\Controllers\Api\Client\ClientApiController;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Nodes\NodeJWTService;
use App\Services\Servers\GetUserPermissionsService;
@ -37,7 +37,7 @@ class WebsocketController extends ClientApiController
public function __invoke(ClientApiRequest $request, Server $server): JsonResponse
{
$user = $request->user();
if ($user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $server)) {
if ($user->cannot(SubuserPermission::WebsocketConnect, $server)) {
throw new HttpForbiddenException('You do not have permission to connect to this server\'s websocket.');
}

View File

@ -2,11 +2,11 @@
namespace App\Http\Controllers\Api\Remote;
use App\Enums\SubuserPermission;
use App\Exceptions\Http\HttpForbiddenException;
use App\Facades\Activity;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Remote\SftpAuthenticationFormRequest;
use App\Models\Permission;
use App\Models\Server;
use App\Models\User;
use App\Services\Servers\GetUserPermissionsService;
@ -141,7 +141,7 @@ class SftpAuthenticationController extends Controller
if ($user->cannot('update server', $server) && $server->owner_id !== $user->id) {
$permissions = $this->permissions->handle($server, $user);
if (!in_array(Permission::ACTION_FILE_SFTP, $permissions)) {
if (!in_array(SubuserPermission::FileSftp->value, $permissions)) {
Activity::event('server:sftp.denied')->actor($user)->subject($server)->log();
throw new HttpForbiddenException('You do not have permission to access SFTP for this server.');

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Backups;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class RenameBackupRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_BACKUP_DELETE;
return SubuserPermission::BackupDelete;
}
public function rules(): array

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Backups;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class RestoreBackupRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_BACKUP_RESTORE;
return SubuserPermission::BackupRestore;
}
public function rules(): array

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Backups;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class StoreBackupRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_BACKUP_CREATE;
return SubuserPermission::BackupCreate;
}
public function rules(): array

View File

@ -3,13 +3,13 @@
namespace App\Http\Requests\Api\Client\Servers\Databases;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class DeleteDatabaseRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_DATABASE_DELETE;
return SubuserPermission::DatabaseDelete;
}
}

View File

@ -3,13 +3,13 @@
namespace App\Http\Requests\Api\Client\Servers\Databases;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class GetDatabasesRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_DATABASE_READ;
return SubuserPermission::DatabaseRead;
}
}

View File

@ -2,16 +2,16 @@
namespace App\Http\Requests\Api\Client\Servers\Databases;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class RotatePasswordRequest extends ClientApiRequest
{
/**
* Check that the user has permission to rotate the password.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_DATABASE_UPDATE;
return SubuserPermission::DatabaseUpdate;
}
}

View File

@ -3,9 +3,9 @@
namespace App\Http\Requests\Api\Client\Servers\Databases;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Database;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Databases\DatabaseManagementService;
use Illuminate\Database\Query\Builder;
@ -14,9 +14,9 @@ use Webmozart\Assert\Assert;
class StoreDatabaseRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_DATABASE_CREATE;
return SubuserPermission::DatabaseCreate;
}
public function rules(): array

View File

@ -3,14 +3,14 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class ChmodFilesRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_UPDATE;
return SubuserPermission::FileUpdate;
}
public function rules(): array

View File

@ -2,17 +2,17 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class CompressFilesRequest extends ClientApiRequest
{
/**
* Checks that the authenticated user is allowed to create archives for this server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_ARCHIVE;
return SubuserPermission::FileArchive;
}
public function rules(): array

View File

@ -3,14 +3,14 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class CopyFileRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
public function rules(): array

View File

@ -2,17 +2,17 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class CreateFolderRequest extends ClientApiRequest
{
/**
* Checks that the authenticated user is allowed to create files on the server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
public function rules(): array

View File

@ -2,8 +2,8 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class DecompressFilesRequest extends ClientApiRequest
{
@ -12,9 +12,9 @@ class DecompressFilesRequest extends ClientApiRequest
* rely on the archive permission here as it makes more sense to make sure the user can create
* additional files rather than make an archive.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
public function rules(): array

View File

@ -3,14 +3,14 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class DeleteFileRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_DELETE;
return SubuserPermission::FileDelete;
}
/**

View File

@ -3,8 +3,8 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class GetFileContentsRequest extends ClientApiRequest implements ClientPermissionsRequest
{
@ -13,9 +13,9 @@ class GetFileContentsRequest extends ClientApiRequest implements ClientPermissio
* validate that the authenticated user has permission to perform this action aganist
* the given resource (server).
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_READ_CONTENT;
return SubuserPermission::FileReadContent;
}
public function rules(): array

View File

@ -2,8 +2,8 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class ListFilesRequest extends ClientApiRequest
{
@ -11,9 +11,9 @@ class ListFilesRequest extends ClientApiRequest
* Check that the user making this request to the API is authorized to list all
* the files that exist for a given server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_READ;
return SubuserPermission::FileRead;
}
public function rules(): array

View File

@ -3,14 +3,14 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class PullFileRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
public function rules(): array

View File

@ -3,8 +3,8 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class RenameFileRequest extends ClientApiRequest implements ClientPermissionsRequest
{
@ -12,9 +12,9 @@ class RenameFileRequest extends ClientApiRequest implements ClientPermissionsReq
* The permission the user is required to have in order to perform this
* request action.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_UPDATE;
return SubuserPermission::FileUpdate;
}
public function rules(): array

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class UploadFileRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
}

View File

@ -3,8 +3,8 @@
namespace App\Http\Requests\Api\Client\Servers\Files;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class WriteFileContentRequest extends ClientApiRequest implements ClientPermissionsRequest
{
@ -13,9 +13,9 @@ class WriteFileContentRequest extends ClientApiRequest implements ClientPermissi
* validate that the authenticated user has permission to perform this action aganist
* the given resource (server).
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_FILE_CREATE;
return SubuserPermission::FileCreate;
}
/**

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Network;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class DeleteAllocationRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_ALLOCATION_DELETE;
return SubuserPermission::AllocationDelete;
}
}

View File

@ -2,8 +2,8 @@
namespace App\Http\Requests\Api\Client\Servers\Network;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class GetNetworkRequest extends ClientApiRequest
{
@ -11,8 +11,8 @@ class GetNetworkRequest extends ClientApiRequest
* Check that the user has permission to view the allocations for
* this server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_ALLOCATION_READ;
return SubuserPermission::AllocationRead;
}
}

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Network;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class NewAllocationRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_ALLOCATION_CREATE;
return SubuserPermission::AllocationCreate;
}
}

View File

@ -2,15 +2,15 @@
namespace App\Http\Requests\Api\Client\Servers\Network;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Allocation;
use App\Models\Permission;
class UpdateAllocationRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_ALLOCATION_UPDATE;
return SubuserPermission::AllocationUpdate;
}
public function rules(): array

View File

@ -2,12 +2,12 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class DeleteScheduleRequest extends ViewScheduleRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_DELETE;
return SubuserPermission::ScheduleDelete;
}
}

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Schedule;
class StoreScheduleRequest extends ViewScheduleRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_CREATE;
return SubuserPermission::ScheduleCreate;
}
public function rules(): array

View File

@ -2,7 +2,7 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class StoreTaskRequest extends ViewScheduleRequest
{
@ -11,9 +11,9 @@ class StoreTaskRequest extends ViewScheduleRequest
* check if they can modify a schedule to determine if they're able to do this. There
* are no task specific permissions.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_UPDATE;
return SubuserPermission::ScheduleUpdate;
}
public function rules(): array

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class TriggerScheduleRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_UPDATE;
return SubuserPermission::ScheduleUpdate;
}
public function rules(): array

View File

@ -2,12 +2,12 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class UpdateScheduleRequest extends StoreScheduleRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_UPDATE;
return SubuserPermission::ScheduleUpdate;
}
}

View File

@ -2,8 +2,8 @@
namespace App\Http\Requests\Api\Client\Servers\Schedules;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
use App\Models\Schedule;
use App\Models\Server;
use App\Models\Task;
@ -36,8 +36,8 @@ class ViewScheduleRequest extends ClientApiRequest
return true;
}
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SCHEDULE_READ;
return SubuserPermission::ScheduleRead;
}
}

View File

@ -2,17 +2,17 @@
namespace App\Http\Requests\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class SendCommandRequest extends ClientApiRequest
{
/**
* Determine if the API user has permission to perform this action.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_CONTROL_CONSOLE;
return SubuserPermission::ControlConsole;
}
/**

View File

@ -2,28 +2,28 @@
namespace App\Http\Requests\Api\Client\Servers;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class SendPowerRequest extends ClientApiRequest
{
/**
* Determine if the user has permission to send a power command to a server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
switch ($this->input('signal')) {
case 'start':
return Permission::ACTION_CONTROL_START;
return SubuserPermission::ControlStart;
case 'stop':
case 'kill':
return Permission::ACTION_CONTROL_STOP;
return SubuserPermission::ControlStop;
case 'restart':
return Permission::ACTION_CONTROL_RESTART;
return SubuserPermission::ControlRestart;
}
// Fallback for invalid signals
return Permission::ACTION_WEBSOCKET_CONNECT;
return SubuserPermission::WebsocketConnect;
}
/**

View File

@ -3,8 +3,8 @@
namespace App\Http\Requests\Api\Client\Servers\Settings;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class DescriptionServerRequest extends ClientApiRequest implements ClientPermissionsRequest
{
@ -13,9 +13,9 @@ class DescriptionServerRequest extends ClientApiRequest implements ClientPermiss
* validate that the authenticated user has permission to perform this action against
* the given resource (server).
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SETTINGS_DESCRIPTION;
return SubuserPermission::SettingsDescription;
}
/**

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Settings;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class ReinstallServerRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SETTINGS_REINSTALL;
return SubuserPermission::SettingsReinstall;
}
}

View File

@ -3,8 +3,8 @@
namespace App\Http\Requests\Api\Client\Servers\Settings;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
use App\Models\Server;
class RenameServerRequest extends ClientApiRequest implements ClientPermissionsRequest
@ -14,9 +14,9 @@ class RenameServerRequest extends ClientApiRequest implements ClientPermissionsR
* validate that the authenticated user has permission to perform this action against
* the given resource (server).
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_SETTINGS_RENAME;
return SubuserPermission::SettingsRename;
}
/**

View File

@ -3,17 +3,17 @@
namespace App\Http\Requests\Api\Client\Servers\Settings;
use App\Contracts\Http\ClientPermissionsRequest;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
use App\Models\Server;
use Illuminate\Validation\Rule;
use Webmozart\Assert\Assert;
class SetDockerImageRequest extends ClientApiRequest implements ClientPermissionsRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_STARTUP_DOCKER_IMAGE;
return SubuserPermission::StartupDockerImage;
}
public function rules(): array

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Startup;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class GetStartupRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_STARTUP_READ;
return SubuserPermission::StartupRead;
}
}

View File

@ -2,14 +2,14 @@
namespace App\Http\Requests\Api\Client\Servers\Startup;
use App\Enums\SubuserPermission;
use App\Http\Requests\Api\Client\ClientApiRequest;
use App\Models\Permission;
class UpdateStartupVariableRequest extends ClientApiRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_STARTUP_UPDATE;
return SubuserPermission::StartupUpdate;
}
/**

View File

@ -2,12 +2,12 @@
namespace App\Http\Requests\Api\Client\Servers\Subusers;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class DeleteSubuserRequest extends SubuserRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_USER_DELETE;
return SubuserPermission::UserDelete;
}
}

View File

@ -2,15 +2,15 @@
namespace App\Http\Requests\Api\Client\Servers\Subusers;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class GetSubuserRequest extends SubuserRequest
{
/**
* Confirm that a user is able to view subusers for the specified server.
*/
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_USER_READ;
return SubuserPermission::UserRead;
}
}

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Subusers;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class StoreSubuserRequest extends SubuserRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_USER_CREATE;
return SubuserPermission::UserCreate;
}
public function rules(): array

View File

@ -2,13 +2,13 @@
namespace App\Http\Requests\Api\Client\Servers\Subusers;
use App\Models\Permission;
use App\Enums\SubuserPermission;
class UpdateSubuserRequest extends SubuserRequest
{
public function permission(): string
public function permission(): SubuserPermission
{
return Permission::ACTION_USER_UPDATE;
return SubuserPermission::UserUpdate;
}
public function rules(): array

View File

@ -1,221 +0,0 @@
<?php
namespace App\Models;
use App\Contracts\Validatable;
use App\Traits\HasValidation;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class Permission extends Model implements Validatable
{
use HasFactory, HasValidation;
/**
* The resource name for this model when it is transformed into an
* API representation using fractal.
*/
public const RESOURCE_NAME = 'subuser_permission';
/**
* Constants defining different permissions available.
*/
public const ACTION_WEBSOCKET_CONNECT = 'websocket.connect';
public const ACTION_CONTROL_CONSOLE = 'control.console';
public const ACTION_CONTROL_START = 'control.start';
public const ACTION_CONTROL_STOP = 'control.stop';
public const ACTION_CONTROL_RESTART = 'control.restart';
public const ACTION_DATABASE_READ = 'database.read';
public const ACTION_DATABASE_CREATE = 'database.create';
public const ACTION_DATABASE_UPDATE = 'database.update';
public const ACTION_DATABASE_DELETE = 'database.delete';
public const ACTION_DATABASE_VIEW_PASSWORD = 'database.view-password';
public const ACTION_SCHEDULE_READ = 'schedule.read';
public const ACTION_SCHEDULE_CREATE = 'schedule.create';
public const ACTION_SCHEDULE_UPDATE = 'schedule.update';
public const ACTION_SCHEDULE_DELETE = 'schedule.delete';
public const ACTION_USER_READ = 'user.read';
public const ACTION_USER_CREATE = 'user.create';
public const ACTION_USER_UPDATE = 'user.update';
public const ACTION_USER_DELETE = 'user.delete';
public const ACTION_BACKUP_READ = 'backup.read';
public const ACTION_BACKUP_CREATE = 'backup.create';
public const ACTION_BACKUP_DELETE = 'backup.delete';
public const ACTION_BACKUP_DOWNLOAD = 'backup.download';
public const ACTION_BACKUP_RESTORE = 'backup.restore';
public const ACTION_ALLOCATION_READ = 'allocation.read';
public const ACTION_ALLOCATION_CREATE = 'allocation.create';
public const ACTION_ALLOCATION_UPDATE = 'allocation.update';
public const ACTION_ALLOCATION_DELETE = 'allocation.delete';
public const ACTION_FILE_READ = 'file.read';
public const ACTION_FILE_READ_CONTENT = 'file.read-content';
public const ACTION_FILE_CREATE = 'file.create';
public const ACTION_FILE_UPDATE = 'file.update';
public const ACTION_FILE_DELETE = 'file.delete';
public const ACTION_FILE_ARCHIVE = 'file.archive';
public const ACTION_FILE_SFTP = 'file.sftp';
public const ACTION_STARTUP_READ = 'startup.read';
public const ACTION_STARTUP_UPDATE = 'startup.update';
public const ACTION_STARTUP_DOCKER_IMAGE = 'startup.docker-image';
public const ACTION_SETTINGS_RENAME = 'settings.rename';
public const ACTION_SETTINGS_DESCRIPTION = 'settings.description';
public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall';
public const ACTION_ACTIVITY_READ = 'activity.read';
public $timestamps = false;
/**
* Fields that are not mass assignable.
*/
protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<array-key, string[]> */
public static array $validationRules = [
'subuser_id' => ['required', 'numeric', 'min:1'],
'permission' => ['required', 'string'],
];
protected function casts(): array
{
return [
'subuser_id' => 'integer',
];
}
/**
* All the permissions available on the system.
*
* @return array<int, array{
* name: string,
* icon: string,
* permissions: string[]
* }>
*/
public static function permissionData(): array
{
return [
[
'name' => 'control',
'icon' => 'tabler-terminal-2',
'permissions' => ['console', 'start', 'stop', 'restart'],
],
[
'name' => 'user',
'icon' => 'tabler-users',
'permissions' => ['read', 'create', 'update', 'delete'],
],
[
'name' => 'file',
'icon' => 'tabler-files',
'permissions' => ['read', 'read-content', 'create', 'update', 'delete', 'archive', 'sftp'],
],
[
'name' => 'backup',
'icon' => 'tabler-file-zip',
'permissions' => ['read', 'create', 'delete', 'download', 'restore'],
],
[
'name' => 'allocation',
'icon' => 'tabler-network',
'permissions' => ['read', 'create', 'update', 'delete'],
],
[
'name' => 'startup',
'icon' => 'tabler-player-play',
'permissions' => ['read', 'update', 'docker-image'],
],
[
'name' => 'database',
'icon' => 'tabler-database',
'permissions' => ['read', 'create', 'update', 'delete', 'view-password'],
],
[
'name' => 'schedule',
'icon' => 'tabler-clock',
'permissions' => ['read', 'create', 'update', 'delete'],
],
[
'name' => 'settings',
'icon' => 'tabler-settings',
'permissions' => ['rename', 'description', 'reinstall'],
],
[
'name' => 'activity',
'icon' => 'tabler-stack',
'permissions' => ['read'],
],
];
}
/**
* Returns all the permissions available on the system for a user to have when controlling a server.
*/
public static function permissions(): Collection
{
$permissions = [
'websocket' => [
'description' => 'Allows the user to connect to the server websocket, giving them access to view console output and realtime server stats.',
'keys' => [
'connect' => 'Allows a user to connect to the websocket instance for a server to stream the console.',
],
],
];
foreach (static::permissionData() as $data) {
$permissions[$data['name']] = [
'description' => trans('server/users.permissions.' . $data['name'] . '_desc'),
'keys' => collect($data['permissions'])->mapWithKeys(fn ($key) => [$key => trans('server/users.permissions.' . $data['name'] . '_' . str($key)->replace('-', '_'))])->toArray(),
];
}
return collect($permissions);
}
public static function permissionKeys(): Collection
{
return static::permissions()
->map(fn ($value, $prefix) => array_map(fn ($value) => "$prefix.$value", array_keys($value['keys'])))
->flatten();
}
}

View File

@ -3,12 +3,12 @@
namespace App\Models;
use App\Contracts\Validatable;
use App\Enums\SubuserPermission;
use App\Traits\HasValidation;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Notifications\Notifiable;
/**
@ -33,6 +33,28 @@ class Subuser extends Model implements Validatable
*/
public const RESOURCE_NAME = 'server_subuser';
/** @var array<string, array{name: string, hidden: ?bool, icon: ?string, permissions: string[]}> */
protected static array $customPermissions = [];
/** @param string[] $permissions */
public static function registerCustomPermissions(string $name, array $permissions, ?string $icon = null, ?bool $hidden = null): void
{
$customPermission = static::$customPermissions[$name] ?? [];
$customPermission['name'] = $name;
$customPermission['permissions'] = array_merge($customPermission['permissions'] ?? [], $permissions);
if (!is_null($icon)) {
$customPermission['icon'] = $icon;
}
if (!is_null($hidden)) {
$customPermission['hidden'] = $hidden;
}
static::$customPermissions[$name] = $customPermission;
}
/**
* Fields that are not mass assignable.
*/
@ -71,11 +93,56 @@ class Subuser extends Model implements Validatable
return $this->belongsTo(User::class);
}
/**
* Gets the permissions associated with a subuser.
*/
public function permissions(): HasMany
/** @return array<array{name: string, hidden: bool, icon: string, permissions: string[]}> */
public static function allPermissionData(): array
{
return $this->hasMany(Permission::class);
$allPermissions = [];
foreach (SubuserPermission::cases() as $subuserPermission) {
[$group, $permission] = $subuserPermission->split();
$allPermissions[$group] = [
'name' => $group,
'hidden' => $subuserPermission->isHidden(),
'icon' => $subuserPermission->getIcon(),
'permissions' => array_merge($allPermissions[$group]['permissions'] ?? [], [$permission]),
];
}
foreach (static::$customPermissions as $customPermission) {
$name = $customPermission['name'];
$groupData = $allPermissions[$name] ?? [];
$groupData = [
'name' => $name,
'hidden' => $customPermission['hidden'] ?? $groupData['hidden'] ?? false,
'icon' => $customPermission['icon'] ?? $groupData['icon'],
'permissions' => array_unique(array_merge($groupData['permissions'] ?? [], $customPermission['permissions'])),
];
$allPermissions[$name] = $groupData;
}
return array_values($allPermissions);
}
/** @return string[] */
public static function allPermissionKeys(): array
{
return collect(static::allPermissionData())
->map(fn ($data) => array_map(fn ($permission) => $data['name'] . '.' . $permission, $data['permissions']))
->flatten()
->unique()
->toArray();
}
public static function doesPermissionExist(string|SubuserPermission $permission): bool
{
if ($permission instanceof SubuserPermission) {
$permission = $permission->value;
}
return str_contains($permission, '.') && in_array($permission, static::allPermissionKeys());
}
}

View File

@ -4,6 +4,7 @@ namespace App\Models;
use App\Contracts\Validatable;
use App\Enums\CustomizationKey;
use App\Enums\SubuserPermission;
use App\Exceptions\DisplayException;
use App\Extensions\Avatar\AvatarService;
use App\Models\Traits\HasAccessTokens;
@ -327,14 +328,18 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
return !$key ? $customization : $customization[$key->value];
}
protected function checkPermission(Server $server, string $permission = ''): bool
protected function checkPermission(Server $server, string|SubuserPermission $permission = ''): bool
{
if ($permission instanceof SubuserPermission) {
$permission = $permission->value;
}
if ($this->canned('update', $server) || $server->owner_id === $this->id) {
return true;
}
// If the user only has "view" permissions allow viewing the console
if ($permission === Permission::ACTION_WEBSOCKET_CONNECT && $this->canned('view', $server)) {
if ($permission === SubuserPermission::WebsocketConnect->value && $this->canned('view', $server)) {
return true;
}
@ -356,13 +361,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
*/
public function can($abilities, mixed $arguments = []): bool
{
if (is_string($abilities) && str_contains($abilities, '.')) {
[$permission, $key] = str($abilities)->explode('.', 2);
if (isset(Permission::permissions()[$permission]['keys'][$key])) {
if ($arguments instanceof Server) {
return $this->checkPermission($arguments, $abilities);
}
if ($arguments instanceof Server) {
if ($abilities instanceof SubuserPermission || Subuser::doesPermissionExist($abilities)) {
return $this->checkPermission($arguments, $abilities);
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,11 +11,11 @@ class ActivityLogPolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_ACTIVITY_READ, Filament::getTenant());
return $user->can(SubuserPermission::ActivityRead, Filament::getTenant());
}
public function view(User $user, Model $model): bool
{
return $user->can(Permission::ACTION_ACTIVITY_READ, Filament::getTenant());
return $user->can(SubuserPermission::ActivityRead, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,26 +11,26 @@ class AllocationPolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_ALLOCATION_READ, Filament::getTenant());
return $user->can(SubuserPermission::AllocationRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_ALLOCATION_READ, Filament::getTenant());
return $user->can(SubuserPermission::AllocationRead, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_ALLOCATION_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::AllocationCreate, Filament::getTenant());
}
public function edit(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_ALLOCATION_UPDATE, Filament::getTenant());
return $user->can(SubuserPermission::AllocationUpdate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_ALLOCATION_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::AllocationDelete, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,21 +11,21 @@ class BackupPolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_BACKUP_READ, Filament::getTenant());
return $user->can(SubuserPermission::BackupRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_BACKUP_READ, Filament::getTenant());
return $user->can(SubuserPermission::BackupRead, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_BACKUP_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::BackupCreate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_BACKUP_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::BackupDelete, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,26 +11,26 @@ class DatabasePolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_DATABASE_READ, Filament::getTenant());
return $user->can(SubuserPermission::DatabaseRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_DATABASE_READ, Filament::getTenant());
return $user->can(SubuserPermission::DatabaseRead, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_DATABASE_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::DatabaseCreate, Filament::getTenant());
}
public function edit(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_DATABASE_UPDATE, Filament::getTenant());
return $user->can(SubuserPermission::DatabaseUpdate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_DATABASE_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::DatabaseDelete, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,26 +11,26 @@ class FilePolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_FILE_READ, Filament::getTenant());
return $user->can(SubuserPermission::FileRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_FILE_READ_CONTENT, Filament::getTenant());
return $user->can(SubuserPermission::FileReadContent, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_FILE_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::FileCreate, Filament::getTenant());
}
public function edit(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_FILE_UPDATE, Filament::getTenant());
return $user->can(SubuserPermission::FileUpdate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_FILE_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::FileDelete, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,26 +11,26 @@ class SchedulePolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_SCHEDULE_READ, Filament::getTenant());
return $user->can(SubuserPermission::ScheduleRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_SCHEDULE_READ, Filament::getTenant());
return $user->can(SubuserPermission::ScheduleRead, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_SCHEDULE_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::ScheduleCreate, Filament::getTenant());
}
public function edit(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_SCHEDULE_UPDATE, Filament::getTenant());
return $user->can(SubuserPermission::ScheduleUpdate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_SCHEDULE_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::ScheduleDelete, Filament::getTenant());
}
}

View File

@ -2,8 +2,8 @@
namespace App\Policies;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Models\User;
class ServerPolicy
@ -22,7 +22,7 @@ class ServerPolicy
return null;
}
if (Permission::permissionKeys()->contains($ability)) {
if (Subuser::doesPermissionExist($ability)) {
// Owner has full server permissions
if ($server->owner_id === $user->id) {
return true;

View File

@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
@ -11,26 +11,26 @@ class SubuserPolicy
{
public function viewAny(User $user): bool
{
return $user->can(Permission::ACTION_USER_READ, Filament::getTenant());
return $user->can(SubuserPermission::UserRead, Filament::getTenant());
}
public function view(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_USER_READ, Filament::getTenant());
return $user->can(SubuserPermission::UserRead, Filament::getTenant());
}
public function create(User $user): bool
{
return $user->can(Permission::ACTION_USER_CREATE, Filament::getTenant());
return $user->can(SubuserPermission::UserCreate, Filament::getTenant());
}
public function edit(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_USER_UPDATE, Filament::getTenant());
return $user->can(SubuserPermission::UserUpdate, Filament::getTenant());
}
public function delete(User $user, Model $record): bool
{
return $user->can(Permission::ACTION_USER_DELETE, Filament::getTenant());
return $user->can(SubuserPermission::UserDelete, Filament::getTenant());
}
}

View File

@ -2,7 +2,7 @@
namespace App\Services\Servers;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Server;
use App\Models\Subuser;
use App\Models\User;
@ -32,7 +32,7 @@ class GetUserPermissionsService
];
if ($isAdmin) {
return $isOwner || $user->can('update', $server) ? array_merge(['*'], $adminPermissions) : array_merge([Permission::ACTION_WEBSOCKET_CONNECT], $adminPermissions);
return $isOwner || $user->can('update', $server) ? array_merge(['*'], $adminPermissions) : array_merge([SubuserPermission::WebsocketConnect->value], $adminPermissions);
}
/** @var Subuser|null $subuser */

View File

@ -2,11 +2,11 @@
namespace App\Services\Subusers;
use App\Enums\SubuserPermission;
use App\Events\Server\SubUserAdded;
use App\Exceptions\Model\DataValidationException;
use App\Exceptions\Service\Subuser\ServerSubuserExistsException;
use App\Exceptions\Service\Subuser\UserIsServerOwnerException;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Models\User;
@ -58,7 +58,7 @@ class SubuserCreationService
$cleanedPermissions = collect($permissions)
->unique()
->filter(fn ($permission) => $permission === Permission::ACTION_WEBSOCKET_CONNECT || user()?->can($permission, $server))
->filter(fn ($permission) => $permission === SubuserPermission::WebsocketConnect->value || user()?->can($permission, $server))
->sort()
->values()
->all();

View File

@ -2,8 +2,8 @@
namespace App\Services\Subusers;
use App\Enums\SubuserPermission;
use App\Facades\Activity;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Repositories\Daemon\DaemonServerRepository;
@ -22,7 +22,7 @@ class SubuserUpdateService
{
$cleanedPermissions = collect($permissions)
->unique()
->filter(fn ($permission) => $permission === Permission::ACTION_WEBSOCKET_CONNECT || user()?->can($permission, $server))
->filter(fn ($permission) => $permission === SubuserPermission::WebsocketConnect->value || user()?->can($permission, $server))
->sort()
->values()
->all();

View File

@ -2,8 +2,8 @@
namespace App\Transformers\Api\Client;
use App\Enums\SubuserPermission;
use App\Models\Database;
use App\Models\Permission;
use League\Fractal\Resource\Item;
use League\Fractal\Resource\NullResource;
@ -41,7 +41,7 @@ class DatabaseTransformer extends BaseClientTransformer
*/
public function includePassword(Database $database): Item|NullResource
{
if (!$this->request->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $database->server)) {
if (!$this->request->user()->can(SubuserPermission::DatabaseViewPassword, $database->server)) {
return $this->null();
}

View File

@ -2,10 +2,10 @@
namespace App\Transformers\Api\Client;
use App\Enums\SubuserPermission;
use App\Models\Allocation;
use App\Models\Egg;
use App\Models\EggVariable;
use App\Models\Permission;
use App\Models\Server;
use App\Models\Subuser;
use App\Services\Servers\StartupCommandService;
@ -60,7 +60,7 @@ class ServerTransformer extends BaseClientTransformer
'oom_disabled' => !$server->oom_killer,
'oom_killer' => $server->oom_killer,
],
'invocation' => $service->handle($server, hideAllValues: !$user->can(Permission::ACTION_STARTUP_READ, $server)),
'invocation' => $service->handle($server, hideAllValues: !$user->can(SubuserPermission::StartupRead, $server)),
'docker_image' => $server->image,
'egg_features' => $server->egg->inherit_features,
'feature_limits' => [
@ -98,7 +98,7 @@ class ServerTransformer extends BaseClientTransformer
//
// This allows us to avoid too much permission regression, without also hiding information that
// is generally needed for the frontend to make sense when browsing or searching results.
if (!$user->can(Permission::ACTION_ALLOCATION_READ, $server)) {
if (!$user->can(SubuserPermission::AllocationRead, $server)) {
$primary = clone $server->allocation;
$primary->notes = null;
@ -110,7 +110,7 @@ class ServerTransformer extends BaseClientTransformer
public function includeVariables(Server $server): Collection|NullResource
{
if (!$this->request->user()->can(Permission::ACTION_STARTUP_READ, $server)) {
if (!$this->request->user()->can(SubuserPermission::StartupRead, $server)) {
return $this->null();
}
@ -134,7 +134,7 @@ class ServerTransformer extends BaseClientTransformer
*/
public function includeSubusers(Server $server): Collection|NullResource
{
if (!$this->request->user()->can(Permission::ACTION_USER_READ, $server)) {
if (!$this->request->user()->can(SubuserPermission::UserRead, $server)) {
return $this->null();
}

View File

@ -2,7 +2,6 @@
namespace Database\Factories;
use App\Models\Permission;
use Illuminate\Database\Eloquent\Factories\Factory;
class PermissionFactory extends Factory

View File

@ -2,7 +2,7 @@
namespace Database\Factories;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Subuser;
use Illuminate\Database\Eloquent\Factories\Factory;
@ -22,7 +22,7 @@ class SubuserFactory extends Factory
{
return [
'permissions' => [
Permission::ACTION_WEBSOCKET_CONNECT,
SubuserPermission::WebsocketConnect->value,
],
];
}

View File

@ -1,8 +1,8 @@
<?php
use App\Enums\ServerState;
use App\Enums\SubuserPermission;
use App\Http\Controllers\Api\Client\Servers\SettingsController;
use App\Models\Permission;
use App\Repositories\Daemon\DaemonServerRepository;
use Symfony\Component\HttpFoundation\Response;
@ -11,7 +11,7 @@ pest()->group('API');
covers(SettingsController::class);
it('server name cannot be changed', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = generateTestAccount([SubuserPermission::WebsocketConnect]);
$originalName = $server->name;
$this->actingAs($user)
@ -26,7 +26,7 @@ it('server name cannot be changed', function () {
});
it('server description can be changed', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_SETTINGS_DESCRIPTION]);
[$user, $server] = generateTestAccount([SubuserPermission::SettingsDescription]);
$originalDescription = $server->description;
$newDescription = 'Test Server Description';
@ -45,7 +45,7 @@ it('server description can be changed', function () {
});
it('server description cannot be changed', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_SETTINGS_DESCRIPTION]);
[$user, $server] = generateTestAccount([SubuserPermission::SettingsDescription]);
Config::set('panel.editable_server_descriptions', false);
$originalDescription = $server->description;
@ -61,7 +61,7 @@ it('server description cannot be changed', function () {
});
it('server name can be changed', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT, Permission::ACTION_SETTINGS_RENAME]);
[$user, $server] = generateTestAccount([SubuserPermission::WebsocketConnect, SubuserPermission::SettingsRename]);
$originalName = $server->name;
$this->actingAs($user)
@ -76,7 +76,7 @@ it('server name can be changed', function () {
});
test('unauthorized user cannot change docker image in use by server', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = generateTestAccount([SubuserPermission::WebsocketConnect]);
$originalImage = $server->image;
$this->actingAs($user)
@ -92,7 +92,7 @@ test('unauthorized user cannot change docker image in use by server', function (
test('cannot change docker image to image not allowed by egg', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_STARTUP_DOCKER_IMAGE]);
[$user, $server] = generateTestAccount([SubuserPermission::StartupDockerImage]);
$server->image = 'ghcr.io/pelican-eggs/yolks:java_17';
$server->save();
@ -112,7 +112,7 @@ test('cannot change docker image to image not allowed by egg', function () {
});
test('can change docker image in use by server', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_STARTUP_DOCKER_IMAGE]);
[$user, $server] = generateTestAccount([SubuserPermission::StartupDockerImage]);
$oldImage = 'ghcr.io/pelican-eggs/yolks:java_17';
$server->image = $oldImage;
$server->save();
@ -135,7 +135,7 @@ test('can change docker image in use by server', function () {
});
test('unable to change the docker image set by administrator', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_STARTUP_DOCKER_IMAGE]);
[$user, $server] = generateTestAccount([SubuserPermission::StartupDockerImage]);
$oldImage = 'ghcr.io/pelican-eggs/yolks:java_custom';
$server->image = $oldImage;
$server->save();
@ -155,7 +155,7 @@ test('unable to change the docker image set by administrator', function () {
});
test('can be reinstalled', function () {
[$user, $server] = generateTestAccount([Permission::ACTION_SETTINGS_REINSTALL]);
[$user, $server] = generateTestAccount([SubuserPermission::SettingsReinstall]);
expect($server->isInstalled())->toBeTrue();
$service = \Mockery::mock(DaemonServerRepository::class);

View File

@ -3,7 +3,6 @@
use App\Enums\RolePermissionModels;
use App\Filament\Admin\Resources\Eggs\Pages\ListEggs;
use App\Models\Egg;
use App\Models\Permission;
use App\Models\Role;
use function Pest\Livewire\livewire;

View File

@ -3,7 +3,6 @@
use App\Enums\RolePermissionModels;
use App\Filament\Admin\Resources\Nodes\Pages\ListNodes;
use App\Models\Node;
use App\Models\Permission;
use App\Models\Role;
use App\Models\Server;
use Filament\Actions\CreateAction;

View File

@ -2,8 +2,8 @@
namespace App\Tests\Integration\Api\Client;
use App\Enums\SubuserPermission;
use App\Models\Allocation;
use App\Models\Permission;
use App\Models\Role;
use App\Models\Server;
use App\Models\Subuser;
@ -158,7 +158,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
Subuser::query()->create([
'user_id' => $users[0]->id,
'server_id' => $servers[1]->id,
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
'permissions' => [SubuserPermission::WebsocketConnect->value],
]);
$response = $this->actingAs($users[0])->getJson('/api/client');
@ -189,7 +189,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
Subuser::query()->create([
'user_id' => $users[0]->id,
'server_id' => $servers[1]->id,
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
'permissions' => [SubuserPermission::WebsocketConnect],
]);
$response = $this->actingAs($users[0])->getJson('/api/client?type=owner');
@ -214,7 +214,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
->assertJson([
'object' => 'system_permissions',
'attributes' => [
'permissions' => Permission::permissions()->toArray(),
'permissions' => Subuser::allPermissionKeys(),
],
]);
}
@ -239,7 +239,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
Subuser::query()->create([
'user_id' => $users[0]->id,
'server_id' => $servers[1]->id,
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
'permissions' => [SubuserPermission::WebsocketConnect->value],
]);
// Only servers 2 & 3 (0 indexed) should be returned by the API at this point. The user making
@ -274,7 +274,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
Subuser::query()->create([
'user_id' => $users[0]->id,
'server_id' => $servers[1]->id,
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
'permissions' => [SubuserPermission::WebsocketConnect->value],
]);
// All servers should be returned.
@ -311,7 +311,7 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
public function test_only_primary_allocation_is_returned_to_subuser(): void
{
/** @var \App\Models\Server $server */
[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::WebsocketConnect]);
$server->allocation->notes = 'Test notes';
$server->allocation->save();

View File

@ -2,8 +2,8 @@
namespace App\Tests\Integration\Api\Client\Server\Allocation;
use App\Enums\SubuserPermission;
use App\Models\Allocation;
use App\Models\Permission;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
use PHPUnit\Framework\Attributes\DataProvider;
@ -48,7 +48,7 @@ class CreateNewAllocationTest extends ClientApiIntegrationTestCase
public function test_allocation_cannot_be_created_if_user_does_not_have_permission(): void
{
/** @var \App\Models\Server $server */
[$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_UPDATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationUpdate]);
$server->update(['allocation_limit' => 2]);
$this->actingAs($user)->postJson($this->link($server, '/network/allocations'))->assertForbidden();
@ -88,6 +88,6 @@ class CreateNewAllocationTest extends ClientApiIntegrationTestCase
public static function permissionDataProvider(): array
{
return [[[Permission::ACTION_ALLOCATION_CREATE]], [[]]];
return [[[SubuserPermission::AllocationCreate]], [[]]];
}
}

View File

@ -2,8 +2,8 @@
namespace App\Tests\Integration\Api\Client\Server\Allocation;
use App\Enums\SubuserPermission;
use App\Models\Allocation;
use App\Models\Permission;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
use PHPUnit\Framework\Attributes\DataProvider;
@ -56,7 +56,7 @@ class DeleteAllocationTest extends ClientApiIntegrationTestCase
public function test_error_is_returned_if_user_does_not_have_permission(): void
{
/** @var \App\Models\Server $server */
[$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationCreate]);
/** @var \App\Models\Allocation $allocation */
$allocation = Allocation::factory()->create([
@ -101,6 +101,6 @@ class DeleteAllocationTest extends ClientApiIntegrationTestCase
public static function permissionDataProvider(): array
{
return [[[Permission::ACTION_ALLOCATION_DELETE]], [[]]];
return [[[SubuserPermission::AllocationDelete]], [[]]];
}
}

View File

@ -2,9 +2,9 @@
namespace App\Tests\Integration\Api\Client\Server\Backup;
use App\Enums\SubuserPermission;
use App\Events\ActivityLogged;
use App\Models\Backup;
use App\Models\Permission;
use App\Repositories\Daemon\DaemonBackupRepository;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
@ -24,7 +24,7 @@ class DeleteBackupTest extends ClientApiIntegrationTestCase
public function test_user_without_permission_cannot_delete_backup(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_BACKUP_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::BackupCreate]);
$backup = Backup::factory()->create(['server_id' => $server->id]);
@ -41,7 +41,7 @@ class DeleteBackupTest extends ClientApiIntegrationTestCase
{
Event::fake([ActivityLogged::class]);
[$user, $server] = $this->generateTestAccount([Permission::ACTION_BACKUP_DELETE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::BackupDelete]);
/** @var \App\Models\Backup $backup */
$backup = Backup::factory()->create(['server_id' => $server->id]);

View File

@ -2,9 +2,9 @@
namespace App\Tests\Integration\Api\Client\Server;
use App\Enums\SubuserPermission;
use App\Http\Controllers\Api\Client\Servers\CommandController;
use App\Http\Requests\Api\Client\Servers\SendCommandRequest;
use App\Models\Permission;
use App\Models\Server;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use GuzzleHttp\Exception\BadResponseException;
@ -38,7 +38,7 @@ class CommandControllerTest extends ClientApiIntegrationTestCase
*/
public function test_subuser_without_permission_receives_error(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::WebsocketConnect]);
$response = $this->actingAs($user)->postJson("/api/client/servers/$server->uuid/command", [
'command' => 'say Test',
@ -52,7 +52,7 @@ class CommandControllerTest extends ClientApiIntegrationTestCase
*/
public function test_command_can_send_to_server(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_CONTROL_CONSOLE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::ControlConsole]);
$server = \Mockery::mock($server)->makePartial();

View File

@ -2,8 +2,8 @@
namespace App\Tests\Integration\Api\Client\Server;
use App\Enums\SubuserPermission;
use App\Models\Allocation;
use App\Models\Permission;
use App\Models\User;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
@ -41,7 +41,7 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
$this->actingAs($user)->getJson($this->link($server, '/network/allocations'))
->assertNotFound();
[$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationCreate]);
$this->actingAs($user)->getJson($this->link($server, '/network/allocations'))
->assertForbidden();
@ -91,7 +91,7 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
$this->actingAs($user)->postJson($this->link($server->allocation))->assertNotFound();
[$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationCreate]);
$this->actingAs($user)->postJson($this->link($server->allocation))->assertForbidden();
}
@ -125,7 +125,7 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
$this->actingAs($user)->postJson($this->link($server->allocation, '/primary'))
->assertNotFound();
[$user, $server] = $this->generateTestAccount([Permission::ACTION_ALLOCATION_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationCreate]);
$this->actingAs($user)->postJson($this->link($server->allocation, '/primary'))
->assertForbidden();
@ -133,6 +133,6 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
public static function updatePermissionsDataProvider(): array
{
return [[[]], [[Permission::ACTION_ALLOCATION_UPDATE]]];
return [[[]], [[SubuserPermission::AllocationUpdate]]];
}
}

View File

@ -2,7 +2,7 @@
namespace App\Tests\Integration\Api\Client\Server;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Repositories\Daemon\DaemonServerRepository;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
@ -15,7 +15,7 @@ class PowerControllerTest extends ClientApiIntegrationTestCase
* an error in response. This checks against the specific permission needed to send
* the command to the server.
*
* @param string[] $permissions
* @param array<string|SubuserPermission> $permissions
*/
#[DataProvider('invalidPermissionDataProvider')]
public function test_subuser_without_permissions_receives_error(string $action, array $permissions): void
@ -47,7 +47,7 @@ class PowerControllerTest extends ClientApiIntegrationTestCase
* Test that sending a valid power actions works.
*/
#[DataProvider('validPowerActionDataProvider')]
public function test_action_can_be_sent_to_server(string $action, string $permission): void
public function test_action_can_be_sent_to_server(string $action, string|SubuserPermission $permission): void
{
$service = \Mockery::mock(DaemonServerRepository::class);
$this->app->instance(DaemonServerRepository::class, $service);
@ -74,25 +74,25 @@ class PowerControllerTest extends ClientApiIntegrationTestCase
public static function invalidPermissionDataProvider(): array
{
return [
['start', [Permission::ACTION_CONTROL_STOP, Permission::ACTION_CONTROL_RESTART]],
['stop', [Permission::ACTION_CONTROL_START]],
['kill', [Permission::ACTION_CONTROL_START, Permission::ACTION_CONTROL_RESTART]],
['restart', [Permission::ACTION_CONTROL_STOP, Permission::ACTION_CONTROL_START]],
['random', [Permission::ACTION_CONTROL_START]],
['start', [SubuserPermission::ControlStop, SubuserPermission::ControlRestart]],
['stop', [SubuserPermission::ControlStart]],
['kill', [SubuserPermission::ControlStart, SubuserPermission::ControlRestart]],
['restart', [SubuserPermission::ControlStop, SubuserPermission::ControlStart]],
['random', [SubuserPermission::ControlStart]],
];
}
public static function validPowerActionDataProvider(): array
{
return [
['start', Permission::ACTION_CONTROL_START],
['stop', Permission::ACTION_CONTROL_STOP],
['restart', Permission::ACTION_CONTROL_RESTART],
['kill', Permission::ACTION_CONTROL_STOP],
['start', SubuserPermission::ControlStart],
['stop', SubuserPermission::ControlStop],
['restart', SubuserPermission::ControlRestart],
['kill', SubuserPermission::ControlStop],
// Yes, these spaces are intentional. You should be able to send values with or without
// a space on the start/end since we should be trimming the values.
[' restart', Permission::ACTION_CONTROL_RESTART],
['kill ', Permission::ACTION_CONTROL_STOP],
[' restart', SubuserPermission::ControlRestart],
['kill ', SubuserPermission::ControlStop],
];
}
}

View File

@ -2,7 +2,7 @@
namespace App\Tests\Integration\Api\Client\Server;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Repositories\Daemon\DaemonServerRepository;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
@ -16,7 +16,7 @@ class ResourceUtilizationControllerTest extends ClientApiIntegrationTestCase
$service = \Mockery::mock(DaemonServerRepository::class);
$this->app->instance(DaemonServerRepository::class, $service);
[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::WebsocketConnect]);
$service->expects('setServer')->with(\Mockery::on(function ($value) use ($server) {
return $server->uuid === $value->uuid;

View File

@ -2,7 +2,7 @@
namespace App\Tests\Integration\Api\Client\Server\Schedule;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Schedule;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
use Illuminate\Http\Response;
@ -83,7 +83,7 @@ class CreateServerScheduleTest extends ClientApiIntegrationTestCase
*/
public function test_subuser_cannot_create_schedule_without_permissions(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_SCHEDULE_UPDATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::ScheduleUpdate]);
$this->actingAs($user)
->postJson("/api/client/servers/$server->uuid/schedules", [])
@ -92,6 +92,6 @@ class CreateServerScheduleTest extends ClientApiIntegrationTestCase
public static function permissionsDataProvider(): array
{
return [[[]], [[Permission::ACTION_SCHEDULE_CREATE]]];
return [[[]], [[SubuserPermission::ScheduleCreate]]];
}
}

View File

@ -2,7 +2,7 @@
namespace App\Tests\Integration\Api\Client\Server\Schedule;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Schedule;
use App\Models\Task;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
@ -66,7 +66,7 @@ class DeleteServerScheduleTest extends ClientApiIntegrationTestCase
*/
public function test_error_is_returned_if_subuser_does_not_have_required_permissions(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_SCHEDULE_UPDATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::ScheduleUpdate]);
$schedule = Schedule::factory()->create(['server_id' => $server->id]);
@ -79,6 +79,6 @@ class DeleteServerScheduleTest extends ClientApiIntegrationTestCase
public static function permissionsDataProvider(): array
{
return [[[]], [[Permission::ACTION_SCHEDULE_DELETE]]];
return [[[]], [[SubuserPermission::ScheduleDelete]]];
}
}

View File

@ -2,8 +2,8 @@
namespace App\Tests\Integration\Api\Client\Server\Schedule;
use App\Enums\SubuserPermission;
use App\Jobs\Schedule\RunTaskJob;
use App\Models\Permission;
use App\Models\Schedule;
use App\Models\Task;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
@ -56,7 +56,7 @@ class ExecuteScheduleTest extends ClientApiIntegrationTestCase
*/
public function test_user_without_schedule_update_permission_cannot_execute(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_SCHEDULE_CREATE]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::ScheduleCreate]);
/** @var \App\Models\Schedule $schedule */
$schedule = Schedule::factory()->create(['server_id' => $server->id]);
@ -66,6 +66,6 @@ class ExecuteScheduleTest extends ClientApiIntegrationTestCase
public static function permissionsDataProvider(): array
{
return [[[]], [[Permission::ACTION_SCHEDULE_UPDATE]]];
return [[[]], [[SubuserPermission::ScheduleUpdate]]];
}
}

View File

@ -2,7 +2,7 @@
namespace App\Tests\Integration\Api\Client\Server\Schedule;
use App\Models\Permission;
use App\Enums\SubuserPermission;
use App\Models\Schedule;
use App\Models\Task;
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
@ -76,7 +76,7 @@ class GetServerSchedulesTest extends ClientApiIntegrationTestCase
*/
public function test_user_without_permission_cannot_view_schedules(): void
{
[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
[$user, $server] = $this->generateTestAccount([SubuserPermission::WebsocketConnect]);
$this->actingAs($user)
->getJson("/api/client/servers/$server->uuid/schedules")
@ -94,8 +94,8 @@ class GetServerSchedulesTest extends ClientApiIntegrationTestCase
return [
[[], false],
[[], true],
[[Permission::ACTION_SCHEDULE_READ], false],
[[Permission::ACTION_SCHEDULE_READ], true],
[[SubuserPermission::ScheduleRead], false],
[[SubuserPermission::ScheduleRead], true],
];
}
}

Some files were not shown because too many files have changed in this diff Show More