migrating tests (Application, Console and Cronjob)

This commit is contained in:
Saeed Vaziry
2024-10-08 22:15:50 +02:00
parent 974af959f1
commit 0da21f40bd
39 changed files with 254 additions and 2684 deletions

View File

@ -34,6 +34,15 @@ class CronJob extends AbstractModel
'hidden' => 'boolean',
];
public static array $statusColors = [
CronjobStatus::CREATING => 'warning',
CronjobStatus::READY => 'success',
CronjobStatus::DELETING => 'danger',
CronjobStatus::ENABLING => 'warning',
CronjobStatus::DISABLING => 'warning',
CronjobStatus::DISABLED => 'gray',
];
public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
@ -75,4 +84,14 @@ public function frequencyLabel(): string
return $this->frequency;
}
public function isEnabled(): bool
{
return $this->status === CronjobStatus::READY;
}
public function isDisabled(): bool
{
return $this->status === CronjobStatus::DISABLED;
}
}

View File

@ -4,6 +4,7 @@
use App\Models\NotificationChannel;
use App\Notifications\NotificationInterface;
use App\Web\Pages\Settings\NotificationChannels\Index;
use Illuminate\Support\Facades\Http;
class Discord extends AbstractNotificationChannel
@ -38,7 +39,7 @@ public function connect(): bool
__('Congratulations! 🎉'),
__("You've connected your Discord to :app", ['app' => config('app.name')])."\n".
__('Manage your notification channels')."\n".
route('settings.notification-channels')
Index::getUrl()
);
if (! $connect) {

View File

@ -4,6 +4,7 @@
use App\Models\NotificationChannel;
use App\Notifications\NotificationInterface;
use App\Web\Pages\Settings\NotificationChannels\Index;
use Illuminate\Support\Facades\Http;
class Slack extends AbstractNotificationChannel
@ -38,7 +39,7 @@ public function connect(): bool
__('Congratulations! 🎉'),
__("You've connected your Slack to :app", ['app' => config('app.name')])."\n".
__('Manage your notification channels')."\n".
route('settings.notification-channels')
Index::getUrl()
);
if (! $connect) {

View File

@ -34,6 +34,6 @@ public function delete(User $user, Server $server): bool
public function manage(User $user, Server $server): bool
{
return $user->isAdmin() || $server->project->users->contains($user);
return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady();
}
}

View File

@ -51,7 +51,7 @@ public function boot(): void
]);
FilamentColor::register([
'slate' => Color::Slate,
'gray' => Color::Gray,
'gray' => Color::Zinc,
'red' => Color::Red,
'orange' => Color::Orange,
'amber' => Color::Amber,

View File

@ -1,15 +0,0 @@
<?php
namespace App\Web\Pages;
use Filament\Widgets\AccountWidget;
class Dashboard extends \Filament\Pages\Dashboard
{
public function getWidgets(): array
{
return [
AccountWidget::class,
];
}
}

View File

@ -12,11 +12,11 @@ class Index extends Page
protected static ?string $slug = 'servers/{server}/console';
protected static ?string $title = 'Console';
protected static ?string $title = 'Headless Console';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('update', static::getServerFromRoute()) ?? false;
$this->authorize('manage', $this->server);
}
public function getWidgets(): array

View File

@ -20,9 +20,9 @@ class Index extends Page
protected $listeners = ['$refresh'];
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [CronJob::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [CronJob::class, $this->server]);
}
public function getWidgets(): array

View File

@ -3,6 +3,8 @@
namespace App\Web\Pages\Servers\CronJobs\Widgets;
use App\Actions\CronJob\DeleteCronJob;
use App\Actions\CronJob\DisableCronJob;
use App\Actions\CronJob\EnableCronJob;
use App\Models\CronJob;
use App\Models\Server;
use Filament\Notifications\Notification;
@ -33,6 +35,17 @@ protected function getTableColumns(): array
->tooltip(fn (CronJob $cronJob) => $cronJob->command)
->searchable()
->copyable(),
TextColumn::make('frequency')
->formatStateUsing(fn (CronJob $cronJob) => $cronJob->frequencyLabel())
->searchable()
->sortable()
->copyable(),
TextColumn::make('status')
->label('Status')
->badge()
->color(fn (CronJob $record) => CronJob::$statusColors[$record->status])
->searchable()
->sortable(),
TextColumn::make('created_at')
->formatStateUsing(fn (CronJob $cronJob) => $cronJob->created_at_by_timezone)
->sortable(),
@ -43,6 +56,30 @@ public function getTable(): Table
{
return $this->table
->actions([
Action::make('enable')
->hiddenLabel()
->tooltip('Enable')
->icon('heroicon-o-play')
->requiresConfirmation()
->authorize(fn (CronJob $record) => auth()->user()->can('update', [$record, $this->server]))
->visible(fn (CronJob $record) => $record->isDisabled())
->action(function (CronJob $record) {
run_action($this, function () use ($record) {
app(EnableCronJob::class)->enable($this->server, $record);
});
}),
Action::make('disable')
->hiddenLabel()
->tooltip('Disable')
->icon('heroicon-o-stop')
->requiresConfirmation()
->authorize(fn (CronJob $record) => auth()->user()->can('update', [$record, $this->server]))
->visible(fn (CronJob $record) => $record->isEnabled())
->action(function (CronJob $record) {
run_action($this, function () use ($record) {
app(DisableCronJob::class)->disable($this->server, $record);
});
}),
Action::make('delete')
->icon('heroicon-o-trash')
->tooltip('Delete')

View File

@ -23,9 +23,9 @@ class Backups extends Page implements HasSecondSubNav
protected static ?string $title = 'Backups';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Backup::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Backup::class, $this->server]);
}
protected function getHeaderActions(): array

View File

@ -20,9 +20,9 @@ class Index extends Page implements HasSecondSubNav
protected static ?string $title = 'Databases';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Database::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Database::class, $this->server]);
}
protected function getHeaderActions(): array

View File

@ -2,6 +2,9 @@
namespace App\Web\Pages\Servers\Databases\Traits;
use App\Models\Backup;
use App\Models\Database;
use App\Models\DatabaseUser;
use App\Web\Pages\Servers\Databases\Backups as Backups;
use App\Web\Pages\Servers\Databases\Index as Databases;
use App\Web\Pages\Servers\Databases\Users as Users;
@ -14,21 +17,21 @@ public function getSecondSubNavigation(): array
{
$items = [];
if (Databases::canAccess()) {
if (auth()->user()->can('viewAny', [Database::class, $this->server])) {
$items[] = NavigationItem::make(Databases::getNavigationLabel())
->icon('heroicon-o-circle-stack')
->isActiveWhen(fn () => request()->routeIs(Databases::getRouteName()))
->url(Databases::getUrl(parameters: ['server' => $this->server]));
}
if (Users::canAccess()) {
if (auth()->user()->can('viewAny', [DatabaseUser::class, $this->server])) {
$items[] = NavigationItem::make(Users::getNavigationLabel())
->icon('heroicon-o-users')
->isActiveWhen(fn () => request()->routeIs(Users::getRouteName()))
->url(Users::getUrl(parameters: ['server' => $this->server]));
}
if (Backups::canAccess()) {
if (auth()->user()->can('viewAny', [Backup::class, $this->server])) {
$items[] = NavigationItem::make(Backups::getNavigationLabel())
->icon('heroicon-o-cloud')
->isActiveWhen(fn () => request()->routeIs(Backups::getRouteName()))

View File

@ -22,9 +22,9 @@ class Users extends Page implements HasSecondSubNav
protected static ?string $title = 'Database Users';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [DatabaseUser::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [DatabaseUser::class, $this->server]);
}
protected function getHeaderActions(): array

View File

@ -20,9 +20,9 @@ class Index extends Page
protected $listeners = ['$refresh'];
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [FirewallRule::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [FirewallRule::class, $this->server]);
}
public function getWidgets(): array

View File

@ -32,9 +32,9 @@ public static function getNavigationItemActiveRoutePattern(): string
return static::getRouteName().'*';
}
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', Server::class) ?? false;
$this->authorize('viewAny', Server::class);
}
public function getWidgets(): array

View File

@ -12,9 +12,9 @@ class Index extends Page
protected static ?string $title = 'Logs';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [ServerLog::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [ServerLog::class, $this->server]);
}
public function getWidgets(): array

View File

@ -11,9 +11,9 @@ class Index extends Page
protected static ?string $title = 'Metrics';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Metric::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Metric::class, $this->server]);
}
public function getWidgets(): array

View File

@ -16,9 +16,9 @@ class Index extends Page
protected static ?string $title = 'PHP';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Service::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Service::class, $this->server]);
}
public function getWidgets(): array

View File

@ -2,7 +2,15 @@
namespace App\Web\Pages\Servers;
use App\Models\CronJob;
use App\Models\Database;
use App\Models\FirewallRule;
use App\Models\Metric;
use App\Models\Server;
use App\Models\ServerLog;
use App\Models\Service;
use App\Models\Site;
use App\Models\SshKey;
use App\Web\Components\Page as BasePage;
use App\Web\Pages\Servers\Console\Index as ConsoleIndex;
use App\Web\Pages\Servers\CronJobs\Index as CronJobsIndex;
@ -18,8 +26,6 @@
use App\Web\Pages\Servers\View as ServerView;
use App\Web\Pages\Servers\Widgets\ServerSummary;
use Filament\Navigation\NavigationItem;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Route;
abstract class Page extends BasePage
{
@ -31,84 +37,84 @@ public function getSubNavigation(): array
{
$items = [];
if (ServerView::canAccess()) {
if (auth()->user()->can('view', $this->server)) {
$items[] = NavigationItem::make(ServerView::getNavigationLabel())
->icon('heroicon-o-chart-pie')
->isActiveWhen(fn () => request()->routeIs(ServerView::getRouteName()))
->url(ServerView::getUrl(parameters: ['server' => $this->server]));
}
if (SitesIndex::canAccess()) {
if (auth()->user()->can('viewAny', [Site::class, $this->server])) {
$items[] = NavigationItem::make(SitesIndex::getNavigationLabel())
->icon('heroicon-o-cursor-arrow-ripple')
->isActiveWhen(fn () => request()->routeIs(SitesIndex::getRouteName().'*'))
->url(SitesIndex::getUrl(parameters: ['server' => $this->server]));
}
if (DatabasesIndex::canAccess()) {
if (auth()->user()->can('viewAny', [Database::class, $this->server])) {
$items[] = NavigationItem::make(DatabasesIndex::getNavigationLabel())
->icon('heroicon-o-circle-stack')
->isActiveWhen(fn () => request()->routeIs(DatabasesIndex::getRouteName().'*'))
->url(DatabasesIndex::getUrl(parameters: ['server' => $this->server]));
}
if (PHPIndex::canAccess()) {
if (auth()->user()->can('viewAny', [Service::class, $this->server])) {
$items[] = NavigationItem::make(PHPIndex::getNavigationLabel())
->icon('heroicon-o-code-bracket')
->isActiveWhen(fn () => request()->routeIs(PHPIndex::getRouteName().'*'))
->url(PHPIndex::getUrl(parameters: ['server' => $this->server]));
}
if (FirewallIndex::canAccess()) {
if (auth()->user()->can('viewAny', [FirewallRule::class, $this->server])) {
$items[] = NavigationItem::make(FirewallIndex::getNavigationLabel())
->icon('heroicon-o-fire')
->isActiveWhen(fn () => request()->routeIs(FirewallIndex::getRouteName().'*'))
->url(FirewallIndex::getUrl(parameters: ['server' => $this->server]));
}
if (CronJobsIndex::canAccess()) {
if (auth()->user()->can('viewAny', [CronJob::class, $this->server])) {
$items[] = NavigationItem::make(CronJobsIndex::getNavigationLabel())
->icon('heroicon-o-clock')
->isActiveWhen(fn () => request()->routeIs(CronJobsIndex::getRouteName().'*'))
->url(CronJobsIndex::getUrl(parameters: ['server' => $this->server]));
}
if (SshKeysIndex::canAccess()) {
if (auth()->user()->can('viewAnyServer', [SshKey::class, $this->server])) {
$items[] = NavigationItem::make(SshKeysIndex::getNavigationLabel())
->icon('heroicon-o-key')
->isActiveWhen(fn () => request()->routeIs(SshKeysIndex::getRouteName().'*'))
->url(SshKeysIndex::getUrl(parameters: ['server' => $this->server]));
}
if (ServicesIndex::canAccess()) {
if (auth()->user()->can('viewAny', [Service::class, $this->server])) {
$items[] = NavigationItem::make(ServicesIndex::getNavigationLabel())
->icon('heroicon-o-cog-6-tooth')
->isActiveWhen(fn () => request()->routeIs(ServicesIndex::getRouteName().'*'))
->url(ServicesIndex::getUrl(parameters: ['server' => $this->server]));
}
if (MetricsIndex::canAccess()) {
if (auth()->user()->can('viewAny', [Metric::class, $this->server])) {
$items[] = NavigationItem::make(MetricsIndex::getNavigationLabel())
->icon('heroicon-o-chart-bar')
->isActiveWhen(fn () => request()->routeIs(MetricsIndex::getRouteName().'*'))
->url(MetricsIndex::getUrl(parameters: ['server' => $this->server]));
}
if (ConsoleIndex::canAccess()) {
if (auth()->user()->can('manage', $this->server)) {
$items[] = NavigationItem::make(ConsoleIndex::getNavigationLabel())
->icon('heroicon-o-command-line')
->isActiveWhen(fn () => request()->routeIs(ConsoleIndex::getRouteName().'*'))
->url(ConsoleIndex::getUrl(parameters: ['server' => $this->server]));
}
if (LogsIndex::canAccess()) {
if (auth()->user()->can('viewAny', [ServerLog::class, $this->server])) {
$items[] = NavigationItem::make(LogsIndex::getNavigationLabel())
->icon('heroicon-o-square-3-stack-3d')
->isActiveWhen(fn () => request()->routeIs(LogsIndex::getRouteName().'*'))
->url(LogsIndex::getUrl(parameters: ['server' => $this->server]));
}
if (ServerSettings::canAccess()) {
if (auth()->user()->can('update', $this->server)) {
$items[] = NavigationItem::make(ServerSettings::getNavigationLabel())
->icon('heroicon-o-wrench-screwdriver')
->isActiveWhen(fn () => request()->routeIs(ServerSettings::getRouteName().'*'))
@ -127,25 +133,6 @@ protected function getHeaderWidgets(): array
];
}
protected static function getServerFromRoute(): ?Server
{
$server = request()->route('server');
if (! $server) {
$server = Route::getRoutes()->match(Request::create(url()->previous()))->parameter('server');
}
if ($server instanceof Server) {
return $server;
}
if ($server) {
return Server::query()->find($server);
}
return null;
}
public function getHeaderWidgetsColumns(): int|string|array
{
return 1;

View File

@ -20,9 +20,9 @@ class Index extends Page
protected static ?string $title = 'SSH Keys';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAnyServer', [SshKey::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [SshKey::class, $this->server]);
}
public function getWidgets(): array

View File

@ -17,9 +17,9 @@ class Index extends Page
protected static ?string $title = 'Services';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Service::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Service::class, $this->server]);
}
public function getWidgets(): array

View File

@ -20,9 +20,9 @@ class Settings extends Page
protected $listeners = ['$refresh'];
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('update', static::getServerFromRoute()) ?? false;
$this->authorize('update', $this->server);
}
public function getWidgets(): array

View File

@ -24,9 +24,9 @@ class Index extends \App\Web\Pages\Servers\Page
protected static ?string $title = 'Sites';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Site::class, static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Site::class, $this->server]);
}
public function getWidgets(): array

View File

@ -2,7 +2,9 @@
namespace App\Web\Pages\Servers\Sites;
use App\Models\Queue;
use App\Models\Site;
use App\Models\Ssl;
use App\Web\Contracts\HasSecondSubNav;
use App\Web\Pages\Servers\Page as BasePage;
use App\Web\Pages\Servers\Sites\Widgets\SiteSummary;
@ -17,9 +19,10 @@ abstract class Page extends BasePage implements HasSecondSubNav
public function getSecondSubNavigation(): array
{
$user = auth()->user();
$items = [];
if (View::canAccess()) {
if ($user->can('view', [$this->site, $this->server])) {
$items[] = NavigationItem::make(View::getNavigationLabel())
->icon('heroicon-o-globe-alt')
->isActiveWhen(fn () => request()->routeIs(View::getRouteName()))
@ -29,7 +32,7 @@ public function getSecondSubNavigation(): array
]));
}
if (Pages\SSL\Index::canAccess()) {
if ($user->can('viewAny', [Ssl::class, $this->site, $this->server])) {
$items[] = NavigationItem::make(Pages\SSL\Index::getNavigationLabel())
->icon('heroicon-o-lock-closed')
->isActiveWhen(fn () => request()->routeIs(Pages\SSL\Index::getRouteName()))
@ -39,7 +42,7 @@ public function getSecondSubNavigation(): array
]));
}
if (Pages\Queues\Index::canAccess()) {
if ($user->can('viewAny', [Queue::class, $this->site, $this->server])) {
$items[] = NavigationItem::make(Pages\Queues\Index::getNavigationLabel())
->icon('heroicon-o-queue-list')
->isActiveWhen(fn () => request()->routeIs(Pages\Queues\Index::getRouteName()))
@ -49,7 +52,7 @@ public function getSecondSubNavigation(): array
]));
}
if (Settings::canAccess()) {
if ($user->can('update', [$this->site, $this->server])) {
$items[] = NavigationItem::make(Settings::getNavigationLabel())
->icon('heroicon-o-wrench-screwdriver')
->isActiveWhen(fn () => request()->routeIs(Settings::getRouteName()))

View File

@ -3,6 +3,7 @@
namespace App\Web\Pages\Servers\Sites\Pages\Queues;
use App\Actions\Queue\CreateQueue;
use App\Models\Queue;
use App\Web\Pages\Servers\Sites\Page;
use Filament\Actions\Action;
use Filament\Actions\CreateAction;
@ -18,9 +19,9 @@ class Index extends Page
protected static ?string $title = 'Queues';
public static function canAccess(): bool
public function mount(): void
{
return true;
$this->authorize('viewAny', [Queue::class, $this->site, $this->server]);
}
public function getWidgets(): array

View File

@ -20,9 +20,9 @@ class Index extends Page
protected static ?string $title = 'SSL';
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('viewAny', [Ssl::class, static::getSiteFromRoute(), static::getServerFromRoute()]) ?? false;
$this->authorize('viewAny', [Ssl::class, $this->site, $this->server]);
}
public function getWidgets(): array

View File

@ -17,9 +17,9 @@ class Settings extends Page
protected $listeners = ['$refresh'];
public static function canAccess(): bool
public function mount(): void
{
return auth()->user()?->can('update', [static::getSiteFromRoute(), static::getServerFromRoute()]) ?? false;
$this->authorize('update', [$this->site, $this->server]);
}
public function getWidgets(): array

View File

@ -28,12 +28,9 @@ class View extends Page
public function mount(): void
{
$this->previousStatus = $this->site->status;
}
$this->authorize('view', [$this->site, $this->server]);
public static function canAccess(): bool
{
return auth()->user()?->can('view', [static::getSiteFromRoute(), static::getServerFromRoute()]) ?? false;
$this->previousStatus = $this->site->status;
}
#[On('$refresh')]

View File

@ -18,14 +18,10 @@ class View extends Page
public function mount(): void
{
$this->authorize('view', $this->server);
$this->previousStatus = $this->server->status;
}
public static function canAccess(): bool
{
return auth()->user()?->can('view', static::getServerFromRoute()) ?? false;
}
#[On('$refresh')]
public function refresh(): void
{

View File

@ -21,13 +21,13 @@ class Settings extends Page
protected static bool $shouldRegisterNavigation = false;
public static function canAccess(): bool
{
return auth()->user()?->can('update', get_from_route(Project::class, 'project')) ?? false;
}
public Project $project;
public function mount(): void
{
$this->authorize('update', $this->project);
}
public function getWidgets(): array
{
return [