Compare commits

...

317 Commits

Author SHA1 Message Date
Charles
4e85180b3d Fix Release Build (#1089) 2025-03-15 16:21:31 -04:00
Charles
9f4a3b1c0d Fix Releases (#1088) 2025-03-15 16:13:55 -04:00
Boy132
45db06a1bd Refactor captcha (#1068)
* refactor captcha

* add default error message

* prevent rule from being called multiple times

* fixes

* use config

* Update this to latest

* Remove this

---------

Co-authored-by: Lance Pioch <git@lance.sh>
2025-03-15 15:52:38 -04:00
Charles
3e26a1cf09 save record, then try to update (#1087) 2025-03-15 20:33:20 +01:00
Lance Pioch
44111696df Laravel 12.2.0 Shift (#1082)
* Bump Laravel version constraint

* composer update

* Fix php8.2

* Pin filament for now

---------

Co-authored-by: Shift <shift@laravelshift.com>
Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-03-15 15:27:06 -04:00
MartinOscar
e04abcbcf9 Replace existing Egg Reserved_Env_Variables with SERVER_ prefix (#1070)
* Add migration that updates egg->variables->env_variable, egg->startup, egg->servers->startup

* Update `EggImporterService` to replace `EggVariable::RESERVED_ENV_NAMES`

* Use `EggImporterService::parseReservedEnvNames`

* Refactor & Remove `Migration`
2025-03-15 14:51:10 -04:00
MartinOscar
ea5914f362 Add url Repeater to ImportEggHeaderAction (#1071)
* Add url `Repeater` to `ImportEggAction`

* Addtranslation

* Requested changes

* Only allow `multiple` when not editing `Egg`

* Only `deletable` & `grid` if `multiple`

* Fix `FileUpload` & Make sure its a json file
2025-03-15 14:46:10 -04:00
MartinOscar
98c36c4cc3 Fix revamp api_keys migration (#987) 2025-03-15 14:42:43 -04:00
MartinOscar
6bc55b1039 Silent file_exists when its not in defaults allowed open_basedir (#1086) 2025-03-15 14:28:59 -04:00
MartinOscar
11b153d23c Fix null Node Stats (#1075)
* Make sure we are talking to the right wings using `getSystemInformation` as a gate keeper

* Re use method

Co-authored-by: Lance Pioch <git@lance.sh>

---------

Co-authored-by: Lance Pioch <git@lance.sh>
2025-03-15 14:28:15 -04:00
Charles
998ad2ee31 Add hint about overhead when using memory limit (#1069)
* Add hint about overhead when using memory limit

* Update lang/en/admin/server.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* escape `'`

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-03-15 13:10:25 -04:00
Thibault Junin
7f0c7da37f Fix FindViableNodeService to actually filter Tags (#1080)
* fix viable node service to take into account tags

* Update app/Services/Deployment/FindViableNodesService.php

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>

---------

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>
2025-03-13 17:04:44 +01:00
MartinOscar
e93d122a27 Server does not use SoftDelete so deleted_at does not exist (#1083) 2025-03-13 01:00:55 +01:00
MartinOscar
9aaf6b3798 Make redirect & callback public instead of private as required by Laravel 12 (#1081) 2025-03-12 19:32:16 +01:00
MartinOscar
fd6e7eb314 Fix missing space in OAuth modal (#1078) 2025-03-10 19:28:39 +01:00
Lance Pioch
4e694b50ca Make sure the app key is always set (#1074)
* Make sure the key is always set
2025-03-08 21:32:28 -05:00
MartinOscar
3a24edfe1d Tests: Make PHPstan run in 8.2, 8.3 & 8.4 (#1072)
* Add PHP [8.2,8.3,8.4] matrices to `phpstan`

* Use a pointer with `unset($this)` to make PHP 8.4 happy
2025-03-09 01:58:50 +01:00
Lance Pioch
0179ade557 Add Laravel Data package, also some small fixes (#1065)
* Simplify

* Update these

* Add Laravel Data

* Remove unused imports

* Quick fix

* Fix double array

* Update app/Console/Commands/Egg/CheckEggUpdatesCommand.php
2025-03-08 19:56:06 -05:00
MartinOscar
05d74232af Fix Build UI Tests running twice (#1067) 2025-03-08 16:13:55 +01:00
Boy132
a2b2e373be Fix subuser activity log (#1063)
* use user for subject

* add permissions to properties

* always add websocket.connect permission (because it's default)

* small cleanup

* also update editing
2025-03-07 17:29:09 +01:00
MartinOscar
0a17e78f33 Force 2fa_required to no one by default (#1058) 2025-03-06 20:53:29 -05:00
Lance Pioch
c3a65aed07 Laravel 12.1.1 Shift (#1057)
* Bump Laravel version constraint

* Bump community package dependencies

* composer update

---------

Co-authored-by: Shift <shift@laravelshift.com>
2025-03-06 18:37:45 -05:00
MartinOscar
d438e29154 Add missing Database address field (#1049)
* Add address field to display `host:port` to enduser on `ListDatabases` & `EditServer`

* Add `CopyAction` to `EditServer`

* Update databaseHost `display_name_help`
2025-03-06 15:55:40 +01:00
MartinOscar
1fdc428f3e Allow sendCommand on Starting or Running Servers (#1061)
* Replace `string` with `enum`

* Add title

* Allow sendCommand on `Starting` or `Running` servers

* refactor: Use Filament interfaces

* Use `getLabel` instead of `str->headline`

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-03-06 15:55:00 +01:00
Charles
a9e4495c91 Add missing activity loggers on client area (#1060)
* Update Subuser

Adds user deleted notification, Adds logger for creating subusers.

* Update Tasks

* ...

* Update Schedule

* Update Files

* Update Database

* Move `reinstall` to proper array

* Add `:action` to deleted task log

* Updates

* Fix CreateSchedule

* Fix Editing/Saving

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-03-06 09:28:45 -05:00
MartinOscar
98ddb65509 Revert Monaco Changes... (#1062)
Reintroduced the ever expanding editor.

Co-authored-by: notCharles <charles@pelican.dev>
2025-03-06 12:50:34 +01:00
MartinOscar
6caa741798 Make restart the default payload when using PowerAction in Schedules (#1059) 2025-03-05 22:10:48 +01:00
MartinOscar
5512c10ee1 Use daemonRepository instead of BuildModificationService (#1053) 2025-03-04 00:48:22 +01:00
MartinOscar
5331c5abfa Use predis as default redis driver (#1054) 2025-03-03 22:47:01 +01:00
Lance Pioch
36a38ab947 Basic two factor auth implementation (#1050)
* Basic two factor auth

* Remove unused import

* Add translation
2025-03-03 15:22:12 -05:00
Lance Pioch
da195fd2fe PHPstan updates (#1047)
* Not found property rule

* Make these “better”

* Day 1

* Day 2

* Day 3

* Dat 4

* Remove disabled check

* Day 4 continued

* Run pint

* Final changes hopefully

* Pint fixes

* Fix again

* Reset these

* Update app/Filament/Admin/Pages/Health.php

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>

* Update app/Traits/CheckMigrationsTrait.php

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>

---------

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>
2025-03-03 14:41:19 -05:00
Lance Pioch
82409f2fba Laravel 12.x Shift (#1045)
* Convert route options to fluent methods

Laravel 8 adopts the tuple syntax for controller actions. Since the old options array is incompatible with this syntax, Shift converted them to use modern, fluent methods.

* Slim `lang` files

* Shift core files

* Validate via object directly within Controllers

* Use `Gate` facade for controller authorization

* Dispatch jobs directly

* Remove base controller inheritance

* Default config files

In an effort to make upgrading the constantly changing config files easier, Shift defaulted them and merged your true customizations - where ENV variables may not be used.

* Set new `ENV` variables

* Add new Laravel `composer run dev` script

* Add `storage/app/private` folder

* Bump Composer dependencies

* Convert `$casts` property to method

* Adopt Laravel type hints

* Shift cleanup

* Apply suggestions from code review

Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>

* Add old key as backup

* Update composer

* Remove extra line

* Update this

---------

Co-authored-by: Shift <shift@laravelshift.com>
Co-authored-by: MartinOscar <40749467+rmartinoscar@users.noreply.github.com>
2025-03-03 14:41:00 -05:00
MartinOscar
839be53231 Use BuildModificationService on EditServer (#1042)
* Use `BuildModificationService` on `EditServer` & make it throw if we can't reach wings

* Use Node name on `EditServer` & `EditNode`
2025-03-03 19:49:42 +01:00
Charles
d79d461e7c Fix total disk storage (#1040) 2025-03-01 07:30:29 -05:00
Boy132
d8e8240756 Fix EditUser (#1046)
* fix unique when editing user

* unset roles when editing
2025-02-28 13:28:18 +01:00
MartinOscar
0b84b0c08c Make sure tests fails on composer error (#1034)
* Remove `--prefer-dist`

* Add missing args `--no-autoloader` `--no-suggest` `--no-progress` `--no-scripts` `--no-dev`
2025-02-28 02:59:51 +01:00
Lance Pioch
e2045e334f This has been replaced with pint (#1044) 2025-02-27 20:18:09 -05:00
Boy132
5e2d106bb9 Call parent constructor in custom oauth provider classes (#1039) 2025-02-27 17:22:32 +01:00
Charles
40c138f086 Update admin resources (#1038) 2025-02-27 09:28:00 -05:00
Boy132
ab543a399b Fix composer.lock (#1036) 2025-02-27 15:10:21 +01:00
Charles
0308045738 Delete mysql-schema (#1037)
Just build the database from migrations... remove  the requirement for mysql-client on installs
2025-02-27 08:17:17 -05:00
Boy132
cd9cbf20ce Downgrade myclabs/deep-copy back to 1.12.1 (#1033) 2025-02-26 16:27:31 +01:00
Boy132
e1308cb04d Small api docs improvements (#1032)
* update scramble

* cleanup application api endpoints

* cleanup client api endpoints

* fix security schema and make docs homepage nicer

* remove duplicate myclabs/deep-copy

* style(api-docs): use Blade template and Tailwind for styling

* Publish scramble view

* Use localStorage theme instead of config

* Update routes/docs.php

Co-authored-by: Lance Pioch <git@lance.sh>

---------

Co-authored-by: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
Co-authored-by: Lance Pioch <git@lance.sh>
2025-02-26 16:12:19 +01:00
Charles
2d937229fb Add Custom StatBlocks, Add Stats (#1027)
* add custom statblock

* add custom datablock

* Use real values, not placeholders

* More Changes

* remove unused var

* Remove old code

* Remove more

* Updates

* Add LineHeight

Changing the font size cut off the j/g and _

* Fix invisible console selection

Closes #874

* Add Missing to `offline` detection

* Use helper

* Update

* Removals

* Move to `SmallStatBlock`
2025-02-26 10:08:42 -05:00
MartinOscar
3d764a89f7 chore: Upgrade Dependencies (#1005)
* chore: yarn upgrade

* chore: composer upgrade

* chore: php artisan filament:upgrade

* chore: update filament-monaco-editor-views

* chore: update filament-monaco-editor-configs

* chore: move turnstile-views to plugins

* fix monaco-editor loader & css
2025-02-25 14:22:07 +01:00
Boy132
2f56ca5ed5 Add deleteAny and replicate to policies (#1030)
* add `deleteAny` to policies

* add `replicate` to policies
2025-02-25 13:50:15 +01:00
Boy132
fe8e6fcfda Fix StoreServerRequest for deployment (#1031) 2025-02-25 13:49:55 +01:00
MartinOscar
1e7a901371 Don't log duplicated OauthProviders during tests (#1015)
* Make sure OauthProviders we only log if not running tests

* Dependency inject
2025-02-24 19:37:41 +01:00
Boy132
d53820bbdc Add view pages for "simple" resources (#963)
* update ApiKeyResource

* update DatabaseHostResource

* update MountResource

* update RoleResource

* update UserResource

* WebhookResource

* fix phpstan

* add back label translations for resources

* add back other labels

* upstream changes
2025-02-24 15:44:47 +01:00
MartinOscar
d03366cf3d Enhance Node health column (#1023)
* Make sure we are talking to a `Pelican Wings` instance

* Enforce matching `token_id`

* Refactor `NodeSystemInformation`
2025-02-22 21:44:49 +01:00
MartinOscar
7d68da41f4 Add HOSTNAME TERM LANG PWD TZ TIMEZONE to Egg RESERVED_ENV_NAMES (#1026) 2025-02-22 21:44:07 +01:00
MartinOscar
599d53b4f2 Fix Node & Server Create/Edit Page (#1019)
* Add missing `dehydrated` on `Node`

* Add missing `dehydrated` on `Server`
2025-02-21 11:55:11 +01:00
Boy132
f0f04fd86a Add backend validation to subuser permissions (#1014)
* add backend validation to subuser permissions

* always allow websocket.connect

* use collection to clean permissions
2025-02-21 11:02:08 +01:00
MartinOscar
324fc4b7d5 Add Egg copy from & ReplicateAction (#1013)
* Add `Egg` `copy from` for Process & Install Script

* Add builtin `ReplicateAction`

* Use `CopyFrom` for less duplicated code

* Hide label & add tooltip to `ReplicateAction`

* use `iconButton()` instead of `hiddenLabel()`

* use `iconButton()` for every Actions

* Use our translation instead

* Copy egg_variables aswell

* remove `get()`

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------
Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-02-19 19:52:10 +01:00
Quinten
5be4e22a0c Merge pull request #1012 from QuintenQVD0/docker-schedule-health
(docker) supercronic: allow overlapping
2025-02-16 19:32:40 +01:00
Quinten
75aae3e45b supercronic: allow overlapping 2025-02-16 18:44:54 +01:00
MartinOscar
c1704eef3b Interpret Server StartupCommand variables (#1009)
* Use `StartupCommandService`

* Simplify variable name

* Add `PreviewStartupAction`
2025-02-15 17:46:25 -05:00
Quinten
09abec6ee6 fix(docker): enable multi-arch builds (#993)
* fix(docker): enable multi-arch builds

* Remove workflow_dispatch and add missing space

* There is no need for a matrix in the job build-and-push

* Update docker-publish.yml

* Only keep the artifacts for 7 days

* Bump dockerfile labs version to 1.13

* Added a comment in the Dockerfile explaining how to self-build it

* build-php-base cache should not be tagged
2025-02-15 23:32:15 +01:00
David Groselj
206cc76a8b Fix deleted users being shown as "System" in activity log (#1010)
* Show deleted users as "Deleted user"

* Update shown icon

* Apply suggestions from code review

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Update app/Models/ActivityLog.php

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-02-15 17:43:32 +01:00
MartinOscar
b355830db4 Fix File Upload (#952)
* Log correct file name

* Remove duplicated throws comment

* Set maxSize

* Add hints

* Fix unit conversion

* Add translations
2025-02-14 11:11:52 +01:00
MartinOscar
09375df8a7 Add missing selectablePlaceholder(false) & native(false) Fix 500 (#1008)
* Add missing `selectablePlaceholder(false)`

* Add missing `native(false)`
2025-02-14 11:11:16 +01:00
Boy132
96ec2eb3c2 Small translation fixes (#1006)
* display_name_help: replace location with node

* cpu_helper: 100% is one thread, not core

* remove unnecessary "create_action" translation

* nobody saw anything
2025-02-13 21:50:23 +01:00
MartinOscar
b464bb4d25 Add ignoreRecord: true to Server ExternalId (#1004) 2025-02-13 00:35:20 +01:00
MartinOscar
c561035c75 Fix incorrect Allocation permission in Node's AllocationsRelationManager (#995) 2025-02-12 20:35:55 +01:00
MartinOscar
48d1ef5d26 Add WordWrap to MonacoEditor (#1001) 2025-02-12 20:35:23 +01:00
MartinOscar
1f6b659546 Fix Translations (#994)
* Fix copy paste AllocationsRelationManager

* We shouldn't let the user know if the user is correct but the password isn't

* Add missing `trans()` `EditServer`

* Add missing `trans()` User `ServersRelationManager`

* Replace every `__()` with `trans()` helper

* Fix `exceptions` `User` Model

* Replace `Translator->get()` with `trans()` helper

* Revert "We shouldn't let the user know if the user is correct but the password isn't"

This reverts commit e156ee4b38.
that's stock laravel, therefore it needs to stay
2025-02-11 22:16:48 +01:00
MartinOscar
8f47ccfbf7 Fix Health ScheduleCheck (#999)
* Use `ScheduleCheck` instead of a blank `Check`
2025-02-11 22:11:07 +01:00
MartinOscar
35d25d216e Cleanup OAuth _noenv & enabled providers (#989) 2025-02-11 22:10:27 +01:00
MartinOscar
a6963ad802 Remove Deprecated PHPDoc comment & AuditLog Model (#997)
* Remove missleading deprecation, you cant use can/cannot on apikeys

* Remove unused `AuditLog` Model
2025-02-11 19:25:36 +01:00
Thibault Junin
d48cf6b722 Add Webhook Event header (#996)
* Add Webhook Event header
2025-02-11 13:43:40 +01:00
MartinOscar
cba4cf11aa Fix Admin Area translations (#991)
* Fix button

* Replace array with index

* Fix Server ToggleInstallService

* FiNodeVersionsCheck

* Fix CreateWebhookConfiguration

* Fixdatabasehost post_help > port_help

* Fix User CreateServer

* Fix Profile language_help

* Fix Role permission UserResource

* Remove debug & Pint
2025-02-10 10:28:14 -05:00
MartinOscar
96c09acc52 Fix translation (#990) 2025-02-10 00:06:11 -05:00
Charles
7f697017a7 Fix flipped translation keys (#988) 2025-02-10 00:58:08 +01:00
Charles
f8ad720f52 Admin Area Translations (#965)
* Init

* Health Page

* Admin API Keys

* Update API Keys

* Database Hosts

* Mounts

* remove `s`

* Users

* Webhooks

* Server

never again...

* Fix Server

* Settings

* Update Mounts

* Update Databasehost

* Update Server

* Oops, Update Server

* Nodes

* Update User

* Dashboard

* Update Server

* Profile

* Egg

* Role & Update Egg

* Add base Laravel lang files

* update apikey

* remove html back to settings, remove comment

* add `:resource` to create_action

* Update Egg

* Update Egg v2

* Update 1

* trans cf info label

* Update charts

* more trans

* Update Webhook

* update Health

* Update Server

* Update Role

* Fixes

* Bulk Update

* AnotherOne

* Fix relation button label

* rename `admin1` to `admin`

Leftover from testing... oops

* More Translations

* Updates

* `pint` + Relation Manager Titles
2025-02-08 23:16:54 -05:00
Boy132
513117cc42 Fix event listeners for notifications (#971)
* fix event listeners for notifications

* fix "visit panel" url
2025-02-08 14:32:56 +01:00
MartinOscar
5797b790fd Fix ServerList Filter query (#977) 2025-02-08 12:45:36 +01:00
MartinOscar
9ec2f6eae1 Fix OAuthProvider & Add ColorPicker for Authentik (#975)
* Fix driver name

* Fix AuthentikProvider config & Add ColorPicker

* Add sqlite-journal to .gitignore
2025-02-07 17:28:06 +01:00
MartinOscar
77bf70b063 Add default Egg import url (#972) 2025-02-07 15:38:25 +01:00
MartinOscar
b8c1b68328 Add back TransientToken check (#968) 2025-02-05 12:58:10 +01:00
MartinOscar
431c1977e3 Filter out wings metadata in ListActivities (#961) 2025-02-02 15:07:03 +01:00
Lance Pioch
f8ad9a1805 Use PestPHP (#962)
* Install Pest

* Don’t use bootstrap file anymore

* Fix comment

* Think this is needed

* Reset this

* Switch dataproviders to attributes

* Fix these

* Support in memory databases

* Fix this migration

* Switch this back for now

* Add missing import

* Truncate and reseed database

* These are replaced now

* Switch ci to use pest
2025-01-30 16:39:17 -05:00
Lance Pioch
635cc6a029 Add PHP 8.4 Support (#858)
* Add php 8.4

* Update ide helper

* Add php 8.4

* Update laravel sanctum

* Update laravel framework

* Hash rounds were increased

* This is always false

* Extend model now

* This does nothing

* Move model validation methods to trait

* Remove base model

* Backup routes were previously referenced by uuids

* Remove commented code

* Upgrade laravel/framework

* Fix migration

* Update ide helper

* Update sanctum

* Add version to composer

* Add this back in, fixed

* Make this protected to be safer
2025-01-30 16:39:00 -05:00
Charles
20125dbc6f Add front end badges (#960)
* Add front end badges

* I identify as a `string`

* Display even if there's no limit

* use `const`'s

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-30 06:21:28 -05:00
Boy132
d5b8a4c501 Fix file download link (#959)
* fix mount of DownloadFiles

* fix path in download url
2025-01-29 08:32:51 +01:00
MartinOscar
dde5305b3f Add validation & missing reserved vars to EggVariables (#954)
* Add validation & Add missing reserved vars

* env_var not env_name 🤦‍

* Custom validationMessages
2025-01-28 14:22:03 +01:00
MartinOscar
e352754e6f Fix CopyAction & Add to Server Settings page (#950)
* Fix & Add to Server Settings page

* Add `request()->isSecure()`

CopyAction only works on SSL, no point in showing it when its not SSL

---------

Co-authored-by: notCharles <charles@pelican.dev>
2025-01-27 19:41:57 +01:00
MartinOscar
7cde90a39a Fix schedules (#949)
* Fix schedules

* Only explode when payload isn't a power action

* Run only on first day of the month

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-01-27 17:57:17 +01:00
Boy132
3202a59b07 Activity log list improvements (#939)
* handle "server:crashed" log

* update activity log list

* add event filter

* add email to user column

* fix phpstan

* only show the email if the actor is the server owner/ a subuser or if the viewing user is an admin

* Apply same logic from ViewAction & make sure user is admi for url

* Add pagination to avoid showing 2000 records at once

* update can check & pagination

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-27 09:46:39 +01:00
Boy132
71f3abe464 File manager improvements (#936)
* add separate button for "save & close"

* make language selection for editor work

* fix download url

* add info banner for .pelicanignore files

* small cleanup

* fix import

* Move File Lang

* add `ctrl+shift+s` for save & close

* fix keybind

* cleanup and fix default value for edit

* remove unnecessary File::get & trait

* More EditorLanguages not matching their names

* mdx has its own highlighter

---------

Co-authored-by: notCharles <charles@pelican.dev>
Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-26 14:29:53 +01:00
Alexander Featherson
401026efa1 [Fix] Websocket Tokens Refresh issue (#944)
* - Temporary fix for token refresh issue.

More testing is needed.

* Update server-console.blade.php

Removal of final old token var (no longer needed as livewire will handle it through piping)
2025-01-25 22:29:01 +01:00
MartinOscar
654143addc Fix ServerList Filter badge count (#946) 2025-01-25 22:24:55 +01:00
Scai
37f9725f27 chore: add codeowners (#941) 2025-01-24 21:00:15 +02:00
dependabot[bot]
98c915490d Bump vite from 6.0.7 to 6.0.9 (#940)
* Bump vite from 6.0.7 to 6.0.9

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.0.7 to 6.0.9.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.0.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Also bump laravel-vite-plugin

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-24 14:06:00 +02:00
Boy132
6fb54e32f1 Use tabs instead of filter for server list (#937)
* use tabs instead of filter for server list

* move "all servers" to end
2025-01-24 08:29:07 +01:00
Boy132
fef19b9fdd files tooltip for activity logs (#938)
* add files tooltip to activity logs

* fix when "files" isn't an array
2025-01-24 08:28:40 +01:00
Josh
6a4963200c Rootless Docker/Optimized build (#932)
* Rootless Dockerfile/Optimized build

Add unneeded files to .dockerignore
Split Dockerfile into more stages to allow Composer/Yarn to run concurrently
Don't log supervisord to a file, as file logging in a Docker container makes no sense
Redirect process output to container output for log processors
Run all processes as non-root
Minimize files with write permission for non-root user
Move docker folder out of .github, as it has nothing to do with GitHub

* Remove install-php-extensions utility after use and name final stage

* Test arm64 runner

* Allow Docker workflow caching multi-arch separately

* Fix Docker publish workflow branches

* Move Caddyfile/crontab config into docker directory, remove redundant supervisord user

* Further restrict permissions

* Supervisord logs
2025-01-23 11:01:14 +02:00
Boy132
37ba62410f Fix translations for activity logs (#907)
* fix translations for activity logs

* add backwards compatibility for old logs

* update lang file

* small cleanup

* fix singular/ plural for "file"

* fix for "rename" + disable bulk move (because it's not working)
2025-01-23 09:05:23 +01:00
MartinOscar
262e2fd09a Add roles to owner selector on Create/Edit Server page (#935)
* Add roles to owner selector on Create/Edit Server page
2025-01-23 02:47:13 +01:00
Boy132
9e8b9cd599 Update node record after updating (#929)
* refresh node model after updating

* update record so form is correctly filled
2025-01-19 01:28:52 +01:00
Boy132
3411e5e65c NodeStorageChart: Format data after math (#931) 2025-01-19 01:09:54 +01:00
Charles
7e6769c96e Match the owner selection on create server (#927) 2025-01-19 00:21:58 +01:00
Boy132
03eaddb126 Fix server access for admins without subuser (#919)
* fix server access for admins without subuser

* add permission checks to power buttons

* add permission check for console command sending

* fix tests

* fix websocket token permissions

* fix sftp access

* fix server api + small cleanup

* it's "update", not "edit"...

* fix tests

* fix permission const for "activity read"

* fix activity subuser permission
2025-01-17 23:04:22 +01:00
Boy132
61bdf0dcd7 Alert banner improvements: auto-refresh, fixes & "closeable" (#924)
* fix websocket error always displaying

* use livewire component with polling for alert banner container

* add id to alert banner

* cleanup blade file and add "closeable" property
2025-01-17 23:03:34 +01:00
Charles
cbacc18e56 get value of suspended (#922) 2025-01-16 21:18:00 -05:00
Lance Pioch
ad1a9cd33f Update phpstan to latest (#804)
* Fix these

* Update phpstan

* Transform these into their identifiers instead

* Fix custom rule

* License is wrong

* Update these

* Pint fixes

* Fix this

* Consolidate these

* Never supported PHP 7

* Better evaluation

* Fixes

* Don’t need ignore

* Replace trait with service

* Subusers are simply the many to many relationship between Servers and Users

* Adjust to remove ignores

* Use new query builder instead!

* wip

* Update composer

* Quick fixes

* Use realtime facade

* Small fixes

* Convert to static to avoid new

* Update to statics

* Don’t modify protected properties directly

* Run pint

* Change to correct method

* Give up and use the facade

* Make sure this route is available

* Filament hasn’t been loaded yet

* This can be readonly

* Typehint

* These are no longer used

* Quick fixes

* Need doc block help

* Always true

* We use caddy with docker

* Pint

* Fix phpstan issues

* Remove unused import

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-16 14:53:50 -05:00
Quinten
02c4eb19f0 ci: move ARM Docker builds to native ARM runner (#920) 2025-01-16 20:26:31 +02:00
MartinOscar
3a25d0f976 Actually use nodeUpdateService not only for keys (#914)
* Actually use nodeUpdateService not only for keys

* Add behind proxy & ignore panel config updates

* Don't Halt

* Prevent double notification

* Revert "Add behind proxy & ignore panel config updates"

This reverts commit 0147888c6c.
2025-01-16 11:50:08 +01:00
Scai
634b8dec55 Merge pull request #918 from QuintenQVD0/speedup-docker
feat(docker): copy PHP extensions from builder stage to speedup the b…
2025-01-16 10:23:33 +02:00
Quinten
43d0b78742 feat(docker): copy PHP extensions from builder stage to speedup the build
- Reuse compiled PHP extensions from composer stage instead of building them twice
2025-01-16 09:20:54 +01:00
Scai
6b77e69e43 Merge pull request #917 from QuintenQVD0/docker
Fix the docker build
2025-01-16 09:45:36 +02:00
Quinten
efbf4df2a2 Fix the docker build 2025-01-16 08:24:58 +01:00
Boy132
4ec9171017 OAuth improvements (#903)
* rework oauth provider creation & lodaing

* add separate setup form

* use wizard for setup

* add provider class for discord

* cleanup and fixes

* don't throw exception when creating duplicate provider

* update profile and login pages

* did not mean to remove the whole else, oops

* use import
2025-01-15 18:29:06 +01:00
Boy132
885e03ee06 Alert banners (#892)
* add alert banner

* replace old server conflict banner with alert banner

* improve color and icon size

* add alert for websocket errors

* update file loading error to alert banner

* remove old events

* add back `console-status` event

* move @php block under @isset

* remove phpstan ignore

so I'm not getting force choked
2025-01-15 18:23:09 +01:00
MartinOscar
7c6b3a03db Fix Suspendall & Server Condition (#913) 2025-01-15 17:46:27 +01:00
MartinOscar
fe43539ea7 Use temp config for mail testing (#912)
* Use temp config

* Change port when changing encryption

* Pint

* Use finally

* Pint please do your job next time

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-01-15 16:07:12 +01:00
Charles
e145fcdc56 Use Filament labels. (#906)
* Use Filament labels.

* use `trans`

* Show more files

No reason for this to be its own pr...
2025-01-13 09:31:37 -05:00
Charles
8078f2ca4e Edit Node Listing, Enable Storage Graph (#905)
* Remove limits in listing

* Enable Storage Graph

* Wings gives us bytes, use helper function

* Use Node Model

* Remove `?? 0`

* Re-Add `?? 0` remove local

* Add Locale on chart

* We should convert these too...

convert_bytes_to_readable follows the prefix config, so we should do it here too.

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-13 09:31:31 -05:00
MartinOscar
d1007ad2fe Make sure variables are unique per egg (#902)
* Add unique validation

* Also make their name unique

* Custom message
2025-01-10 22:22:47 +01:00
Boy132
7f3b1fd758 Fix server reinstall action (#901)
* fix server reinstall action

* use reinstall service
2025-01-09 23:25:36 +01:00
Josh
d088e79e5e Fix deleting database host when it has assigned nodes (#899)
* Cascade delete from database_host_node when the database host is deleted

* Update database/migrations/2025_01_09_143607_database_host_node_foreign_delete_cascade.php

Remove migration rollback

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>

* Update 2025_01_09_143607_database_host_node_foreign_delete_cascade.php

Fix brace position

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-09 20:21:44 +01:00
Boy132
9cfd87090f Update health page with tailwind classes (#893)
* update health page with tailwind classes

* Move php from Blade to Page

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2025-01-09 08:25:10 +01:00
MartinOscar
a7a7c5ba4d Fix Latest version error (#890)
* Retry if it fails

* Pint
2025-01-08 13:48:36 +01:00
Charles
b14e8fd724 Update colors (#891) 2025-01-07 21:11:05 -05:00
Boy132
c93a836ad8 Remove DaemonConnectionException (#885)
* remove DaemonConnectionException

* update tests
2025-01-07 22:58:04 +01:00
Boy132
6fcf4173d3 Strip http/ https from steam oauth allowed_host (#889)
* strip http/ https from steam oauth allowed_host

* fix param order
2025-01-07 22:47:23 +01:00
Boy132
7449b82f41 adjust path for server panel (#884) 2025-01-07 09:34:13 +01:00
Boy132
af4ac1db92 Update admin area navigation (#881) 2025-01-07 08:24:43 +01:00
Scai
6707d1ccf6 Merge pull request #880 from pelican-dev/feature/vite
Remove old client area and switch to vite
2025-01-07 02:06:27 +02:00
Lance Pioch
b197e73173 Use route instead 2025-01-06 17:35:05 -05:00
Scai
e5418491c8 chore: lint files 2025-01-06 20:08:32 +02:00
Scai
98ebc75965 fix: wrong class used on auth 2025-01-06 20:06:17 +02:00
Scai
121ebe6017 refactor: move assets to service provider 2025-01-06 20:03:10 +02:00
Scai
fc27b24783 fix: remove path on panel default 2025-01-06 20:01:41 +02:00
Scai
8049ef462e refactor: revert oauth routes 2025-01-06 20:01:29 +02:00
Scai
17bb23b5b8 refactor: route redirect links 2025-01-06 19:58:32 +02:00
MartinOscar
8926f9712f Add back denylist (#872) 2025-01-06 16:54:19 +01:00
Scai
e4849d89d7 refactor: replace old index with new filament app 2025-01-06 17:33:32 +02:00
Scai
af11888b82 chore: lint files 2025-01-06 17:15:53 +02:00
Scai
1845f2955f fix: job workflows for releasing 2025-01-06 17:15:44 +02:00
Scai
a2b315ba74 fix: build workflows #1 try 2025-01-06 17:13:06 +02:00
Scai
76c3632d14 chore: update git workflows 2025-01-06 17:06:58 +02:00
Scai
4facaecea0 feat: register assets js/css 2025-01-06 17:04:43 +02:00
Scai
a55a2cce6e feat: impl vite tailwindcss 2025-01-06 17:04:33 +02:00
Boy132
448fe41e78 Add role permission for health page (#878) 2025-01-06 15:43:29 +01:00
Boy132
7f37b3b099 Fix namespace for role permission icons (#877) 2025-01-06 15:42:47 +01:00
Scai
ef54d52866 refactor: remove old provider 2025-01-06 15:49:45 +02:00
Scai
7bd66c3d85 refactor: unused files 2025-01-06 15:48:50 +02:00
Scai
74efc6e8c1 refactor: redirect to new login page 2025-01-06 15:47:16 +02:00
Scai
a7b767ae78 chore: delete old assets 2025-01-06 15:46:54 +02:00
Scai
a3ecf3994b feat: set filament main client ui 2025-01-06 15:46:43 +02:00
Scai
158fa24fff feat: add logo to filament 2025-01-06 15:46:26 +02:00
Scai
e5069e754d chore: unused files & code related to old auth 2025-01-06 15:42:49 +02:00
Scai
cdd46de274 chore: clean base routes 2025-01-06 15:38:44 +02:00
Scai
ff5812e87b chore: remove old auth 2025-01-06 15:38:04 +02:00
Scai
20ce0ca8e6 chore: purge old configs 2025-01-06 15:22:41 +02:00
Scai
66ec86694f chore: delete old client ui 2025-01-06 15:20:20 +02:00
Boy132
295134fb6c Add client_id to steam oauth config (#875) 2025-01-06 12:32:35 +01:00
MartinOscar
ae445840f7 Discard ipAddresses cache if wings is offline + Switch to Select (#862)
* Change TextInputColumn to SelectColumn

* Discard cache if wings is offline

* Return 0.0.0.0 instead of an empty array

* Adjustment & remove dns resolve
2025-01-06 03:37:39 +01:00
MartinOscar
77fd54fdc2 Fix/suspend server offline node (#871)
* Use handle instead of toggle & use const isnstead of string

* Avoid rollback if node is unreachable

* Use Enum & remove default action

* Remove useless test
2025-01-06 03:07:06 +01:00
MartinOscar
18fe4f1123 Show suspended servers (#870) 2025-01-06 01:48:04 +01:00
Charles
2525af8f02 Revert "Listen to more framework webhook events (#728)" (#866)
This reverts commit 7a4c4ce02a.
2025-01-05 19:07:01 -05:00
Charles
7cc4358a04 Fix 500 on duplicate ports (#861)
* Fix 500 on duplicate ports

This should also address N+1 issues from the last PR

* Combine into one method

* Pint

* Add missing type

* Add 0.0.0.0

* Add notifications to help the user

* Pint

* Too verbose

* Show notification here

* Simplify code

* Reset the ports if the ip changes

* Don’t limit these anymore

---------

Co-authored-by: Lance Pioch <git@lance.sh>
2025-01-04 22:30:37 -05:00
MartinOscar
168d37b996 Add missing externalId on Server creation (#859)
* Add missing externalId on server creation

* Pint

* Fix mobile layout

* fix layout

---------

Co-authored-by: notCharles <charles@pelican.dev>
2025-01-04 19:58:51 +01:00
MartinOscar
df615f6915 Remove validated override (#860) 2025-01-04 13:36:22 -05:00
Charles
17805f676e Add OAuth Settings to Settings (#839)
* Replace tabler icon package

* Use new filled icons

note: not everything has a filled icon

* Add OAuth Settings to Settings Page

* Fix authentik base url

* replace hard coded oauth
2025-01-04 12:35:07 -05:00
Lance Pioch
23d515c3e5 Convert to bytes beforehand (#857) 2025-01-04 12:34:26 -05:00
Charles
7a5dd87385 Change limits section on front end (#853)
* Edit Front end settings

* Use helpers

---------

Co-authored-by: Lance Pioch <git@lance.sh>
2025-01-04 11:48:26 -05:00
Charles
8f51502c6d Remove First/Last Name for Users (#855)
* Update Tests

* Update Translations

* Add Migration

* Remove First/Last Names
2025-01-03 17:13:44 -05:00
MartinOscar
9d48799c28 Remove required (#852) 2025-01-02 23:36:36 +01:00
Lance Pioch
133c1a511f Replace some guzzle exceptions and fix server creation failures (#848)
* Replace guzzle exceptions

* Pint fixes

* Fix test

* Remove unused imports

* Catch & Notify the user instead of 500

* Update app/Filament/Admin/Resources/ServerResource/Pages/CreateServer.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2025-01-01 15:20:16 -05:00
Lance Pioch
3a7ddfca5e Scope power buttons to current server (#849)
* Scope setServerState to current server

* Use match statement

* Reset this
2025-01-01 15:20:02 -05:00
MartinOscar
00ae3b8b61 Hide Startup + Show Activity on Server panel when in conflictState (#850)
* Hide startup if isInConflictState

* Show ActivityLog regardless of isInConflictState

* Update app/Filament/Server/Pages/Startup.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2024-12-31 14:19:18 +01:00
MartinOscar
b5733715a6 Remove useless rightJoin (#851) 2024-12-31 14:05:14 +01:00
Lance Pioch
9a859cdec3 Move role resource under the advanced settings (#847) 2024-12-29 18:15:25 -05:00
MartinOscar
1571e3cb24 Rework Schedules (#843) 2024-12-28 16:03:21 -05:00
Charles
a8680c7aed Mobile + Layout Changes (#836)
* Update Server Listing

* Update Edit/Create Server Pages

Re-arrange limits, CPU->Memory->Disk

* Remove auto focus

its cancer on mobile...

* Hide Title, Quick yaml fix

* Hide columns on mobile

* Hide backup locked on mobile

* Fix schedules for mobile

* Hide Notes on mobile

* Consolidate and clean these up

* Simplify

* Remove unused imports

* Replace tabler icon package

* Update app/Filament/Server/Resources/FileResource/Pages/EditFiles.php

Co-authored-by: Lance Pioch <git@lance.sh>

* Allow the unit to be changed

* Use existing method

* Update composer and pint

* Update resources/views/tables/columns/server-entry-column.blade.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Simplify html and add small margin

* Unused

* Add enum

---------

Co-authored-by: Lance Pioch <git@lance.sh>
Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2024-12-28 16:02:24 -05:00
Scai
66a17879a0 fix: use options instead relationship (#845) 2024-12-27 16:14:05 -05:00
Scai
f684da997c Fix deleting node with database host
* fix: delete database host when node is deleted

* chore: revert change to file
2024-12-27 16:12:49 -05:00
Boy132
00644c2c60 Health page (#469)
* add spatie health

* change slug for health page

* add check for panel version

* only check for debug mode if env isn't local

* add check for node versions

* improve short summary

* fix outdated check

* run pint

* fix health checks during tests

* add count to ok message

* fix typo

* temp fix for phpstan job

* fix pint...

* improve "outdated" count

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>

* run pint

* skip node versions check if no nodes are created

* auto run health checks if they didn't run before

* small refactor

* update navigation

Co-authored-by: Charles <sir3lit@gmail.com>

* fix errors if tests didn't run yet

* fix disk usage check

* remove plugin and use own page

* use health status indicator from spatie

* fix after merge

* update icon

* update color classes

* fix after merge

* add back imports

oops...

* wrong import

oops²...

* update spatie/laravel-health to latest

* move Health page to correct namespace

* update NodeVersionsCheck

* use style instead of tailwind classes

workaround until we have vite

* cleanup custom checks

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
Co-authored-by: Charles <sir3lit@gmail.com>
2024-12-24 19:09:16 +01:00
Boy132
02a0c5c3eb Fix wrong language formatting in charts (#832) 2024-12-17 13:08:12 +01:00
Boy132
993e2c4244 Add CreateUser page (#825) 2024-12-13 09:21:37 +01:00
pelican-vehikl
7a4c4ce02a Listen to more framework webhook events (#728)
* Add new framework events to listen to

* Add simple test for framework events

* Update app/Models/WebhookConfiguration.php

Co-authored-by: Lance Pioch <git@lance.sh>

* Update app/Models/WebhookConfiguration.php

Co-authored-by: Lance Pioch <git@lance.sh>

* Update app/Models/WebhookConfiguration.php

---------

Co-authored-by: Vehikl <go@vehikl.com>
Co-authored-by: Lance Pioch <git@lance.sh>
2024-12-13 01:03:35 -05:00
Boy132
914f3dcdbd Add own action class for "rotate database password" (#822) 2024-12-12 18:34:52 +01:00
Boy132
d43b99792f (Admin) UI Consistency (#824)
* update phpdocs

* replace deprecated $label and $pluralLabel

* update record title attributes and labels

* update create pages

* run pint
2024-12-12 18:26:37 +01:00
Boy132
771eece01e Properly handle 404 for editing files (#816) 2024-12-12 18:26:01 +01:00
Boy132
026494c353 Catch correct Exceptions when updating/ deleting subusers (#828) 2024-12-12 17:32:39 +01:00
Charles
663b097d22 Add Edit/Delete on Tasks (#826) 2024-12-12 10:31:33 -05:00
Boy132
d09227659e Add database notifications (#817)
* add database notifications to all panels

* add successful param to Installed event

* add listener for Installed event

* create event for subuser creation

* add listener for SubUserAdded event

* always send Installed event

* create event for subuser removal

* add listener for SubUserRemoved event

* add prefix to server name

* remove view action from SubUserRemoved notification
2024-12-12 14:38:45 +01:00
Boy132
eb819032bc Add own action classes for egg actions (+ add empty state) (#823)
* add own action classes for egg actions

* add empty state to ListEggs

* put Import before Create
2024-12-12 14:29:02 +01:00
Boy132
5af507b54b Add own column class for node health (#820) 2024-12-12 14:14:52 +01:00
Boy132
bbee45592f Move custom columns to new namespace (#821) 2024-12-12 14:14:37 +01:00
Boy132
640ff9f5b3 Remove unused DatabaseResource (#819) 2024-12-12 14:03:16 +01:00
Charles
d6f814b7a3 Move schedule buttons (#815)
* Move buttons around

* change to Save
2024-12-10 17:57:06 -05:00
Charles
8a122fa99c Add redirect after save (#813) 2024-12-10 17:43:23 -05:00
Boy132
3ffb54503f Custom error pages (#810)
* add custom error pages

* move icon in front of header text

* show exception message if user is root admin

* add missing page for very important error: 418

* Update resources/views/errors/layout.blade.php

* Update resources/views/errors/layout.blade.php

* add dark mode to error pages

---------

Co-authored-by: Lance Pioch <lancepioch@gmail.com>
2024-12-10 23:42:43 +01:00
Charles
53460b8d1b Update File Manager (#814)
* Make Everything Sortable

* Replace app calls
2024-12-10 17:40:11 -05:00
Boy132
0051d9fefc Allow admins to change server egg (#811)
* add service that handles egg changing

* add "change egg" action to EditServer page

* add toggle for keeping old variables or not
2024-12-10 23:38:40 +01:00
Lance Pioch
ef1ae72d06 Dynamic server status (#803)
* Better readability

* Force refresh the server instance

* Use kebab case for these

* Fix phpstan

* Retry a little longer

* Updates

* Add pint

* Don’t need this

* Pint fix
2024-12-10 17:36:14 -05:00
Boy132
3dfdc70790 Make use of Laravels AboutCommand (#809)
* add pelican info to laravel AboutCommand

* simplify p:info command
2024-12-10 23:07:59 +01:00
Boy132
8460c52534 Add Run now button for schedules & add status field (#806)
* add `Run Now` button to schedules

* add status to schedule view/ edit

* only show status on "view"
2024-12-09 23:31:03 +01:00
Lance Pioch
2bfc788e13 Allow searching for port when associating allocations (#801) 2024-12-08 16:24:00 -05:00
Lance Pioch
839ff96271 Fix power buttons (#799) 2024-12-08 16:19:15 -05:00
Lance Pioch
5d2b892eab Better IP addresses (#800)
* Unique ip addresses

* Only ipv4 addresses for now

* Switch to selects
2024-12-08 16:19:04 -05:00
MartinOscar
c953b97009 Force width (#798) 2024-12-08 20:27:16 +01:00
MartinOscar
9716b1e64d Only allow one * (#797) 2024-12-08 20:23:37 +01:00
Boy132
8358e410dc Move installer to correct namespace (#795) 2024-12-08 19:57:00 +01:00
Boy132
f6c586bf5b Add persistFiltersInSession to server list (#796) 2024-12-08 19:14:56 +01:00
Charles
feadaa2caf Add Kill button to console (#791)
* Add Kill button to console

* Add confirm, and warning
2024-12-08 12:01:44 -05:00
Charles
23246eb134 Fix #784 (#790)
* Remove +1

* Update app/Filament/Server/Pages/Settings.php

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-08 11:47:01 -05:00
Charles
6921c8b350 Fix power actions (#789) 2024-12-08 17:34:47 +01:00
Charles
8cc91b0747 Small updates (#787)
* increase action size on console

* fix layout on create database
2024-12-08 11:19:35 -05:00
Charles
157fa45234 Fix forever expanding code editor (#782)
* Update CSS

* Update Placeholder
2024-12-07 22:44:13 -05:00
Charles
fd5016809a Enable Global Search (#783) 2024-12-07 22:43:44 -05:00
Lance Pioch
a0f5ef13d6 Show login failure message (#781)
* Show login failure message

* Update resources/scripts/components/auth/LoginContainer.tsx

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-07 22:03:56 -05:00
Lance Pioch
67f1e91236 Fix Issue 763 (#780)
* Fix path to moved component

* Fix actual issue #763
2024-12-07 20:44:41 -05:00
Charles
cc3a7a2d0d Update Server Console, Again... (#776)
* More console changes

* Update Console Page

* Edit console input

* oops

* Remove failed attempt of clearing input when server offline

* Update File Editor to match console

* a touch more style

* Show not-allowed on read-only input

* round bottom corners of command input

* Move custom css to file
2024-12-07 19:22:18 -05:00
Charles
d908fb9a9d Remove unsaved changes alert (#778)
* Remove unsaved changes alert

* Remove this also

* Remove this also...
2024-12-07 11:39:00 -05:00
Boy132
6b96c9dbda Fix admin discover (#777) 2024-12-07 17:06:57 +01:00
Boy132
e27f23b1b6 Move admin pages & resources into own namespace (#741)
* move admin pages & resources into own namespace

* fix imports for resource pages
2024-12-07 15:51:27 +01:00
Charles
4ad2997566 Update database creation (#775)
Updates database creation flow to account for new database host to many nodes change.
2024-12-06 22:46:36 -05:00
pelican-vehikl
7e7f0be7df Allow Database Hosts to have multiple Nodes (#767)
* WIP

* Update laravel and migrations

* WIP

* fix tests

* Update composer

* Fix transformer

* Fix filament pages

* WIP

* Update DatabaseHostTransformer

* fix: tests

* pint this files pls

* resolve merge better

* Update migration

* Update Migration, Again

* Update down migration

---------

Co-authored-by: Vehikl <go@vehikl.com>
2024-12-06 20:24:30 -05:00
Boy132
5b3ae995e6 Show full client api key after creation (#771)
* show notification when api key is created

* remove hardcoded redirect url
2024-12-06 16:31:58 -05:00
Charles
2a34795ab1 More console changes (#774) 2024-12-06 16:21:05 -05:00
Charles
d3da1b0a58 Update Server Console, Address Overflows (#764)
* Update Console

Updates console to be more better <3.

Light Mode still needs some love, haven't figured that out with filaments light/dark options yet as it does not use the "bright<color>" colors...

* Add overflow to... Everything?

* Oops, Add Name label back

* Actually handle Transfer Status & remove useless switch

* Use switch case

* Readonly command input if server can't receive one

* lint

* Update app/Filament/Server/Widgets/ServerConsole.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Use filament::icon instead of raw svg

* Update resources/views/filament/components/server-console.blade.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
2024-12-06 09:46:10 -05:00
Boy132
5317f97870 Display roles as badge in user list (#772) 2024-12-06 13:02:37 +01:00
Boy132
b50acfdba2 Add config value for display width to other pages (#770) 2024-12-06 09:45:06 +01:00
Charles
066bdbdf78 Server Listing tweaks. (#760)
* Server Listing tweaks.

* Use filament::icon instead of raw svg & add hover title

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-05 08:34:47 -05:00
MartinOscar
8103ba6338 Remove unique (#765) 2024-12-05 08:55:04 +01:00
Boy132
44b879215f Add filters to server list (#762)
* add server owner filter

* add egg filter

* replace SelectFilter with TernaryFilter
2024-12-05 08:31:34 +01:00
Charles
d2a7d7708c Add Display Width setting (#759)
Allow users to pick how "wide" the panel is.
2024-12-04 09:41:47 -05:00
Boy132
efc37dd45a Hide sidebar on server list (#761) 2024-12-04 09:50:49 +01:00
MartinOscar
09eac71f05 Delete subuser on owner change (#748)
* Delete subuser on owner change

* Move logic to Model
2024-12-03 23:55:02 +01:00
Boy132
6d42a15ec3 Handle token expiring and token expired websocket events (#755)
* handle `token expiring` and `token expired` events

* fix "getToken"

* Move logic to Widget instead of blade & add user check

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-03 23:54:40 +01:00
Boy132
bbfdee356b Fix timezone for file timestamps (#757) 2024-12-03 14:27:06 +01:00
Charles
994852ca00 Tweak EditNode layout for mobile (#752)
* Tweak EditNode layout for mobile

* Replace hidden with toggle
2024-12-03 05:30:04 -05:00
MartinOscar
141baeb035 Empty array if user->oauth is null (#754) 2024-12-03 08:48:47 +01:00
Boy132
bd51191da6 Add role permissions for webhooks (#742) 2024-12-02 23:53:35 +01:00
Boy132
1337767049 Small changes for new client area (#751)
* add placeholder to allocation notes

* add button to open server in admin area

* use new client area for "console" button on EditServer

* hide schedule presets on view

* use arrow functions for auth checks

* add placeholder to schedules last run

* change icon of "open in admin"

* fix parentheses
2024-12-02 22:27:35 +01:00
Boy132
918ba02075 Remove exception methods because of memory bombing (#750)
* remove exception methods

* throw Halt instead of return

* manually throw Halt to make phpstan happy
2024-12-02 22:27:25 +01:00
Charles
c6977e57c8 Fix Subuser issues. (#747)
* Better Error handling

* Remove unique, make email lowercase in request

* Remove 'kill' option, not used.

* Prevent users from editing them selves

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-01 20:17:27 -05:00
MartinOscar
6d1c153d09 Add config panel.editable_server_descriptions check (#734)
* Add config panel.editable_server_descriptions check

* Hide the field rather then disabling it
2024-12-01 23:27:07 +01:00
Boy132
e5433b7aab Auto update resources on server list (#737)
* auto update resources on server list

* use Arr::get helper
2024-12-01 18:12:58 +01:00
Boy132
355810c549 Combine status & uptime, add address on ServerOverview (#739) 2024-12-01 18:12:28 +01:00
Boy132
4fd1937c54 Hide global search button for now (#738) 2024-12-01 18:04:24 +01:00
Lance Pioch
fea1c51337 feat: Client UI translate to Filament (from React) (#416)
* Add new panel

* Add some basic resource pages

* Wip

* Wip terminal

* Wip

* Add new panel

* Add some basic resource pages

* Wip

* [Sub-Users] Add Invite

TODO: The logic with permissions

* [Sub-Users] Fix Creation

* [Cron] Add basics

* Add basic auth and messages

* Add basic buttons

* WIP on issue/353

* WIP on issue/353

* Add Database page

* Update Database Page

* Start of Backup Page

* Composer Update

* Changes

* Send input

* Remove this includes

* Better offline handling

* Consolidate top nav config

* Update Backups Page

* Update Backups

* Change name

* Add Assign All, Layout Fixes.

* conflict

* update schedule pages

* fix phpstan

* update pint.json

* add cron presets to schedule

* fix tests

* fix task creation

* schedules: disable task creation if limit is reached & disable backup action if backup limit is 0

* update activity pages

* update resources

* Update Edit User

TODO: actually save permissions when they're changed.
TODO: Figure out why Control does not update it's state... but the rest do...

* .... Sure it works.

TODO: Update permissions when you save editing a sub user.

* user: update canAccessPanel & canAccessTenant

* add helper to convert bytes into readable format

* very basic file explorer

* files: fix some stuff & remove dummy data

* files: better error handling

* files: basic file editor

* files: add some actions

* File manager updates

* files: fix paths

* Revery Composer Upgrade, Fixes SQLite

* fix: Pint (#517)

feat: MenuItems to and from admin

* Update File Editing

Updated File Editing to its own page,
Added Permission checks for file manager.

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* add enum for editor langs

* files: add upload & pull actions

* fix build

* files: handle images

* Update to Filament v3.2.98

* files: add remaining actions

* use `authorize` instead of `hidden`

* fix canAccessTenant

* update date columns

* files: testing & fixes

* Fix File Names

Co-authored-by: lancepioch <git@lance.sh>

* Combine Pull/Upload

* Fix BulkDelete

* Uncontained tabs

* Hide Lang Selection, Move Actions

* Update Monaco, more custom

* Add livewire config

livewire limits uploads to 12MB... who knows why...
Fixed uploading a single files failing

* files: fix record url

* basic setup for settings & startup page

* make abstract class for simple app pages

* Basic Startup Page

* Update nav sort

* small cleanup

* startup: fix shouldHideComponent & getSelectOptionsFromRules

* startup: fix non editable fields & set default value

* startup: add todo for save button

* Save Variables after update & off click

Variables update when the user clicks off the input.

* Notifications are cool

* Add rule validation

* Sort variables by sortid

* pint

* Settings Page + Startup Changes

* settings: cleanup

* refactor: use server model for ServerFormPage (formerly known as SimplePage)

* Use Repeater for variables

* Add Network, Remove breadcrumbs

* Add paginated to file explorer

* Fix updating variables

* Add link to go to new client area

* fix after merge

* Add graphs to console page

Graphs still need to get the data from the web socket.

* fix pint & phpstan

* fix authorizeAccess for EditFiles and Startup page

* Fix rules on startup page

* Update console size

* Fix node name

* add "global search" to files list

requires https://github.com/pelican-dev/wings/pull/44

* remove debug dummy data

* update view action on ListServers

* enable SPA mode for app panel

* remove colors from app panel

they are defined globally in AppServiceProvider

* update global search ui a bit

(to be replaced with a custom page that is similar to the list files table)

* add own page for global search

untested - and route needs cleanup (if possible)

* fix File getRows

* remove "path" from SearchFiles (for now)

* fix caching for searched files

* add title and breadcrumbs to global search page

* make cpu & memory charts on console page working

* fix phpstan

* add missing import

* cleanup console views & widgets

* add overview stats to console

* don't be so lazy, console!

* make history working

* decode data to get array

* add missing On

* fix json_decode

* change polling to 1 sec

* hide "0" cpu/ memory

* add data to network chart

* Remove data labels

* fix data on network chart

* fix data on network chart (2nd try)

* WIP Network Stats

* Remove test

* Change MaxWidth

* run pint

* fix phpstan

* Fix storeStats cast

* make $data a string

this time for real

* update visible check for "admin" menu item

* remove account widget

* rebrand "Dashboard" to "Server List"

WIP - doesn't look good but is somewhat working

* fix canAccessPanel

* separate server list into own panel

* change path to avoid conflicts with old client area (and remove sidebar width)

* display correct icon and color on server list entries

* show total memory if server is offline

* replace custom server list page with ListRecords page

* fix tests

* fix namespace

* remove "open" button and make whole column clickable

* Update EditProfile

* run pint

* fix access to server list

* add new login page to panels

* fix next_run_at for new schedules

* use new DateTimeColumn

* add own column for file bytes

* return to server list when clicking title

* fix console loading

* handle server with "conflict state"

* add banner if server is in "conflict state"

* fix phpstan

* update docker image select

* fix permission checks on Settings & Startup pages

* fix query for activity log page

* fix activity log not being logged

* adjust ListActivities

* fix phpstan

* fix pint

* fix profile menu item link on server panel

* add ip tooltip to activity logs (and role permission)

* change backup icon

* update navigation sort

* general code cleanup

* more cleanup

* Disable Restart/Stop if server is offline

* Change rename notification

* Remove negation on abort_unless

* Add notification on save

* Single disabled closure & comment unused import

* Add required to Server Name & Nullable to description

* mutateFormDataBeforeSave doesn't work since we use forceFill

* Fix web socket connection not existing.

* Fix some subuser permissions

* add permission checks to resources

* do not allow self-deletion

* Update editing file permissions

* Fix of the previous fix

* add service for subuser updating

* Only allow save if they have file_update

* Remove unused import

* Update backup delete button

* Add Delete, remove bulks

* Update Database page

* Use Allocation Permissions

* add canAccess check to startup

* Add Permission checks to Settings page

* add service for subuser deletion

* Remove Kill permission

* Updates

* fix move files

* add redirects

* fix phpstan

* activity: remove properties from tans for now

* If alias, use that, else ip

---------

Co-authored-by: notCharles <charles@pelican.dev>
Co-authored-by: Boy132 <mail@boy132.de>
Co-authored-by: Senna <62171904+Poseidon281@users.noreply.github.com>
Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-12-01 04:13:45 +01:00
Boy132
e0c6137b92 Installer: Shows errors on submit & move runMigrations (#722)
* catch Halt exception to make sure error notifications are displayed

* run migrations on submit to make sure the correct data is used
2024-12-01 04:04:40 +01:00
Charles
cd448cd9a7 Add Create Database btn on admin side (#721)
* Add Create Database btn on admin side

* Remove unused function

* readd function

* replace refreshform function

* add authorize, remove database limit check

* add random words, use proper name function, catch exceptions on creation

* add validation, match old client area more

* Add more authorize to Database tab

* Add confirmation to delete

* make password hidden / revealable

* better clarification

* Set default and remove placeholder.

* Remove server import, add database model to auth

* Make same changes for the database host page

* Update app/Filament/Resources/ServerResource/Pages/EditServer.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Update app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Update app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>

* Remove each hidden

* Return nothing if user has no perms

* This is the way... Im done messing with it...

* Fix view permission for relationship manager

* Update app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php

* Pint

---------

Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-11-30 22:04:10 -05:00
Boy132
b208835ed4 Add Oauth frontend and backend improvements (#718)
* better oauth provider loading

* add auth frontend

* add configs for all default providers

* add more default providers

* add env variables to enable oauth providers

* small refactor to link/ unlink routes

* add oauth tab to (admin) profile

* use redirects instead of exceptions

* add notification if no oauth user is found

* use import in config

* remove whmcs provider

* replace hardcoded links with `route`

* redirect to account page on unlink

* remove unnecessary controller and handle linking/ unlinking in action

* only show oauth tab if at least one oauth provider is enabled
2024-11-30 17:38:38 +01:00
MartinOscar
951fc73363 Add min length check (#730) 2024-11-27 09:02:41 +01:00
Boy132
ad9447e974 Add back force https (#726) 2024-11-26 23:27:58 +01:00
Boy132
d2d960ecf3 Update egg jsons (#725)
* re-import eggs

* re-import eggs (again)
2024-11-23 23:29:37 +01:00
Boy132
d555c42644 Update all dependencies (#712)
* update composer.lock

* run pint

* fix phpstan

* update migrations (sqlite `dropForeign`)

* fix migrations

* Reset these back for now

* Alphabetize the rules

* run `php artisan filament:upgrade`

---------

Co-authored-by: Lance Pioch <git@lance.sh>
2024-11-22 09:27:57 +01:00
MartinOscar
f33f91698e Add exit admin to Menu (#723) 2024-11-21 17:49:19 +01:00
Boy132
90afae79db Fix permission check if user is subuser and admin (#720) 2024-11-20 08:41:37 +01:00
Boy132
54039e25a4 Make sure UTC is always used internally (#713)
* force app timezone to be UTC

* remove asDateTime overwrite

* add custom column to display dates in user timezone

* use `APP_TIMEZONE` as default timezone for new users

* revert accidental pinting
2024-11-15 20:41:33 +01:00
Boy132
408897cfcf Allow username on filament login page + make case insensitive (#714)
* allow login with username

* make login case insensitive

* fix tests
2024-11-15 20:39:06 +01:00
MartinOscar
24eb52f7d6 Merge pull request #709 from pelican-dev/charles/fixversio
Fix Panel Version Cache
2024-11-14 01:12:09 +01:00
notCharles
d87d3760a1 Fix Panel Version Cache 2024-11-13 19:08:46 -05:00
Boy132
fe4668a517 Update web installer (again) (#705)
* update web installer (again)

* set default values for mysql/ mariadb and redis

* add own step for queue setup

* create admin user in submit

* disable redis for queue if cache isn't redis

* remove separate user step and make session own step

* use `request()->isSecure()`
2024-11-13 18:15:48 -05:00
Lance Pioch
6125b07afa Remove old admin area (#648)
* Remove old admin

* Remove controller test

* Remove unused exceptions

* Remove unused files

* More small tweaks

* Fix doc block

* Remove unused service

* Restore these

* Add back autoDeploy

* Revert "Add back autoDeploy"

This reverts commit 630c1e08ac.

* Add these back

* Add back exception

* Remove ApiController again

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
Co-authored-by: Boy132 <mail@boy132.de>
Co-authored-by: notCharles <charles@pelican.dev>
2024-11-13 17:05:48 -05:00
Boy132
9717aa4b5f Cleanup SoftwareVersionService (#704)
* cleanup SoftwareVersionService

* fix old admin area

* show latest wings version on EditNode page

* even more cleanup
2024-11-13 16:26:10 -05:00
MartinOscar
9491322d8c Merge pull request #708 from pelican-dev/charles/fixbulk
Prevent Select All on Allocations
2024-11-13 22:25:21 +01:00
notCharles
8ed6bb4d8b pint 2024-11-13 16:22:12 -05:00
notCharles
a787af7a06 Prevent Select All
Prevent Select all on allocations, prevent people from trying to delete 30,000 ports at once ....
2024-11-13 16:21:27 -05:00
MartinOscar
d9016702d6 Merge pull request #707 from pelican-dev/charles/fixnode
Change 'exception'
2024-11-13 22:07:45 +01:00
notCharles
d565441b6a Change 'exception'
Remove the exception and just report the whole error.
2024-11-13 15:58:20 -05:00
Michael (Parker) Parker
cb522b24ef Merge pull request #706 from parkervcp/update/egg_version
use correct case for import
2024-11-09 13:59:38 -05:00
Michael (Parker) Parker
b85b17f080 use correct case for import
use lower case `v` instead of upper case `V`
2024-11-09 13:53:50 -05:00
Lance Pioch
47bd7289b1 Clear webhook cache when webhooks are deleted (#695)
* Clear webhook cache when webhooks are deleted

* fix: type casts

---------

Co-authored-by: Vehikl <go@vehikl.com>
2024-11-07 17:26:47 -05:00
Boy132
a9b76a0f51 Improve egg import error handling (#703)
* make sure read & write are successful

* show exception message in notification
2024-11-07 17:15:47 -05:00
MartinOscar
8eebb82eba Fix AutoDeploy & KeyCreationService (#701)
* Fix AutoDeploy & KeyCreationService

* Get rid of 2nd param & unset perm
2024-11-07 17:15:41 -05:00
Boy132
b3501be6ec Refactor api key permissions (#361)
* use RESOURCE_NAME for requests

* use RESOURCE_NAME for transformers

* add permissions field to api key

* add migration for new permissions field

* update tests

* remove debug log

* set column type to "json"

* remove default attribute to fix tests

* fix default value for permissions

* fix after merge

* fix after merge

* allow to "register" custom permissions

* add "role" to default resource names

* fix after merge

* fix phpstan

* fix migrations
2024-11-06 09:09:10 +01:00
Michael (Parker) Parker
ac67656d82 Merge pull request #700 from BlockyBlockling/skip-caddy-fix
Fixing Docker Environment variable only getting checked for existence instead of value
2024-11-04 11:51:05 -05:00
BlockyBlockling
968239beb3 Update entrypoint.sh
Fixed Syntax after last change
2024-11-04 13:07:57 +01:00
BlockyBlockling
7514206186 Update entrypoint.sh
Adding :- Syntax which ensures that, if SKIP_CADDY is unset, it will be treated as an empty string, which will not match "true". This avoids potential issues with unbound variables in some shell configurations where set -u (treating unset variables as an error) is enabled.

(ChatGPT)
2024-11-04 13:07:20 +01:00
BlockyBlockling
1a8321c937 Update entrypoint.sh
Fixing that its only checking for the existence of the environment variable „SKIP_CADDY“ instead of checking for its value
2024-11-04 12:43:40 +01:00
MartinOscar
340ae8099b Fix trusted proxies settings & Move ips to config & Add ipv6 (#692)
* Fix blank proxy & Move hardcoded cloudflare ips

* Add cloudflare's ipv6

* Pull from url innstead of hardcoded

* Remove Service
2024-11-01 18:16:59 -04:00
Boy132
9d02aeb130 Replace reCAPTCHA with Turnstile (#589)
* add laravel turnstile

* add config & settings for turnstile

* publish view to center captcha

* completely replace reCAPTCHA

* update FailedCaptcha event

* add back config for domain verification

* don't set language so browser lang is used
2024-11-01 18:15:04 -04:00
Charles
cf57c28c40 Update Webhooks to match other resources (#686)
* Move these

Move List/Create to their own pages to follow the flow of the other resources.

* Move EditPage aswell

* Move Save

* Labels

* Change Edit/Delete

---------

Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-11-01 18:14:20 -04:00
Boy132
382dcb3868 Fix redis connection check (#698) 2024-11-01 18:10:36 +01:00
Boy132
f793b49a81 Add egg filter to server mounts list (#697) 2024-11-01 18:10:24 +01:00
Lance Pioch
41ddae1ba0 Update ci.yaml (#643) 2024-10-31 05:39:42 -04:00
MartinOscar
e717e20996 Merge pull request #687 from RMartinOscar/fix/HealthVersion
Fix Node Health not refreshing live & Add tooltip
2024-10-30 01:58:37 +01:00
Lance Pioch
b5145b016b Update app/Models/Node.php 2024-10-29 19:53:12 -04:00
Lance Pioch
95a8f72058 Update app/Models/Node.php 2024-10-29 19:52:51 -04:00
Lance Pioch
19548338ee Update app/Models/Node.php 2024-10-29 19:52:32 -04:00
RMartinOscar
a8356fc5d2 Polishing & throw curl error 2024-10-29 20:36:44 +00:00
Boy132
7a447b04d5 Make sure roles always use web guard name (#690) 2024-10-29 18:29:25 +01:00
RMartinOscar
45699e1614 Set refresh rate 10s & Add tooltip for unreachable node 2024-10-29 15:01:30 +00:00
RMartinOscar
cde3546889 Add poll & tooltip 2024-10-29 03:28:51 +00:00
MartinOscar
3f9c1dbc3c Add prune & event blacklist (#682)
* Add prune & event blacklist

* Pinted 3times with --dirty bruh

* Add to Settings

* Fix prune & description

* Prune Logs not Configuration
2024-10-28 18:44:32 -04:00
Charles
bc2df22d78 Add unique (#685)
Usernames have to be unique, trying to make a new user with an existing username results in a 500, this fixes it.
2024-10-28 18:23:29 -04:00
Michael (Parker) Parker
1a3dc5c743 Update Egg Export Version to PLCN_V1 (#676)
* Update Egg Export Version to PLCN_V1

resolves #675

* correct version tag

* remove trailing space
2024-10-27 18:04:21 -04:00
Charles
fdd1b3798c add whereNull (#680)
Add where null to not include allocations already assigned to a server.
2024-10-27 18:01:09 -04:00
Charles
288cbee32f Fix Docker image selection (#674)
* Fix Docker image selection

Should address issue 672

Closes #672

* Fix Docker image selection in CreateServer page

---------

Co-authored-by: MartinOscar <40749467+RMartinOscar@users.noreply.github.com>
2024-10-27 11:22:12 -04:00
MartinOscar
a70a060350 Add Soft Deletes to webhooks config table (#670) 2024-10-27 00:42:08 -04:00
MartinOscar
590569a131 Remove duplicated spa in AdminPanelProvider (#668) 2024-10-26 23:25:21 -04:00
Charles
7acc8782bb Make description required. (#667) 2024-10-26 22:06:34 -04:00
MartinOscar
f3de185508 Add back auto deploy (#627)
* Add Docker, Refactor, Fix Notification

Co-authored-by: notCharles <charles@pelican.dev>

* Pint

* Required adjustments

* Remove deprecated

* Third time's the charm

---------

Co-authored-by: notCharles <charles@pelican.dev>
2024-10-26 20:43:19 -04:00
Charles
291b514e24 Webhook updates (#666) 2024-10-26 20:40:19 -04:00
Colin DeCarlo
86c369d7ce Implement Webhooks (#548)
* feat: First Webhook PoC draft

* feat: Dispatch Webhooks PoC

* fix: typo in webhook configuration scope

* Update 2024_04_21_162552_create_webhooks_table.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update 2024_04_21_162552_create_webhooks_table.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update 2024_04_21_162544_create_webhook_configurations_table.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update 2024_04_21_162544_create_webhook_configurations_table.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhooks.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhooksJob.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhookForConfiguration.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhookForConfiguration.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhookForConfiguration.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhooksJob.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhooksJob.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* Update DispatchWebhooksJob.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* chore: Implement Webhook Event Discovery

* we got a test working for webhooks

* WIP

* Something is working!

* More tests

* clean up the tests now that they are passing

* WIP

* Don't use model specific events

* WIP

* WIP

* WIP

* WIP

* WIP

* Do it sync

* Reset these

* Don't need restored event type

* Deleted some unused jobs

* Find custom Events

* Remove observers

* Add custom event test

* Run Pint

* Add caching

* Don't cache every single event

* Fix tests

* Run Pint

* Phpstan fixes

* Pint fix

* Test fixes

* Middleware unit test fix

* Pint fixes

* Remove index not working for older dbs

* Use facade instead

---------

Co-authored-by: Pascale Beier <mail@pascalebeier.de>
Co-authored-by: Lance Pioch <lancepioch@gmail.com>
Co-authored-by: Vehikl <go@vehikl.com>
2024-10-26 20:35:25 -04:00
Quinten
5f77deb1fd Panel: Fix wings stoplogic (#407)
* Panel: FIx wings stoplogic

* do not make an expetion for `^C` let wings handle this

* remove withspaces
2024-10-26 19:21:14 -04:00
Charles
5f4429e2c3 Remove Bulk Delete from Nodes (#665)
* Remove Bulk Delete from Nodes

Removes bulk delete option from nodes.

* pint
2024-10-26 18:59:06 -04:00
Lance Pioch
1df3e8d5b0 Don't allow NodeStatisticsJob to be in the queue multiple times (#664)
* Make job unique

* Pint fix
2024-10-26 18:53:32 -04:00
Michael (Parker) Parker
ecb195b2c4 Merge pull request #662 from BlockyBlockling/docker-workflow-rework
Adding fix for forks to use a variable for Docker image reference instead of hard String
2024-10-26 18:45:59 -04:00
BlockyBlockling
86e8a6371e Update docker-publish.yml
Adding fix for forks to use a variable for Docker image reference

Source of information: https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-docker-images
2024-10-24 22:05:46 +02:00
Michael (Parker) Parker
d653edb22e Merge pull request #660 from BlockyBlockling/main
Fixing Critical error on Webserver on Pelican Panel Docker Image
2024-10-24 15:21:48 -04:00
BlockyBlockling
741252e395 Update supervisord.conf
Adding username and password dummy to get rid of critical error message
2024-10-24 21:15:03 +02:00
Michael (Parker) Parker
308601e6fe Merge pull request #659 from pelican-dev/issue/629
Make sure the .env can be accessed by the webserver when running Docker
2024-10-24 08:59:34 -04:00
Lance Pioch
3933222d98 Make sure the .env can be accessed 2024-10-23 21:36:48 -04:00
Boy132
c53ef78d89 Make sure schedules run with UTC (#657)
* make sure schedules use UTC for `next_run_at`

* use function from Utilities
2024-10-23 21:59:13 +02:00
Boy132
60792c05c2 Fix required for pinned threads input (#656) 2024-10-23 12:50:09 +02:00
Boy132
94420d06be Add UI for cpu pinning (#652)
* add ui for cpu pinning

* create "advanced" section
2024-10-22 23:34:46 +02:00
Fredrik Falk
6655ccca6e Speed up docker start (#647)
Starting the docker container is hampered due to setting `chown -R www-data:www-data /var/www/html/` on every start, causing it to traverse the entire directory which in our use case is very slow. This PR instead changes it to set permissions as part of the build process.

Sidenote: Is `LE_EMAIL` supposed to be used in addition to `ADMIN_EMAIL`?
2024-10-21 12:46:42 -04:00
Boy132
a193b4f5ab Installer: fix argument types for testConnection & return type for submit (#650)
* fix argument types for `testConnection`

* fix return type of submit
2024-10-21 18:43:16 +02:00
Boy132
3d5c8d14bd Add back trustedproxy config (#651) 2024-10-21 18:43:05 +02:00
Lance Pioch
de002324d7 Deselect all table records when switching primary allocation (#645) 2024-10-21 12:27:23 -04:00
1776 changed files with 25195 additions and 81521 deletions

View File

@@ -1,10 +1,29 @@
**.DS_Store
.env
.devcontainer
.dockerignore
.editorconfig
.git
node_modules
vendor
.github
**.gitignore
.php-cs-fixer.dist.php
.prettierrc.json
.vscode
Dockerfile
bounties.md
compose.yml
contributing.md
contributor_license_agreement.md
database/database.sqlite
docker/README.md
node_modules
phpstan.neon
phpunit.xml
readme.md
storage/debugbar/*.json
storage/logs/*.log
storage/framework/cache/data/*
storage/framework/sessions/*
storage/framework/testing
storage/framework/views/*.php
storage/logs/*.log
vendor

View File

@@ -1,6 +0,0 @@
public
node_modules
resources/views
babel.config.js
tailwind.config.js
webpack.config.js

View File

@@ -1,52 +0,0 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 6,
ecmaFeatures: {
jsx: true,
},
project: './tsconfig.json',
tsconfigRootDir: './',
},
settings: {
react: {
pragma: 'React',
version: 'detect',
},
linkComponents: [
{ name: 'Link', linkAttribute: 'to' },
{ name: 'NavLink', linkAttribute: 'to' },
],
},
env: {
browser: true,
es6: true,
},
plugins: ['react', 'react-hooks', 'prettier', '@typescript-eslint'],
extends: [
// 'standard',
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:jest-dom/recommended',
],
rules: {
eqeqeq: 'error',
'prettier/prettier': ['error', {}, { usePrettierrc: true }],
// TypeScript can infer this significantly better than eslint ever can.
'react/prop-types': 0,
'react/display-name': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-non-null-assertion': 0,
// 'react/no-unknown-property': ['error', { ignore: ['css'] }],
// This setup is required to avoid a spam of errors when running eslint about React being
// used before it is defined.
//
// @see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md#how-to-use
'no-use-before-define': 0,
'@typescript-eslint/no-use-before-define': 'warn',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-expect-error': 'allow-with-description' }],
},
};

15
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,15 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# More details are here: https://help.github.com/articles/about-codeowners/
# The '*' pattern is global owners.
# Order is important. The last matching pattern has the most precedence.
# The folders are ordered as follows:
# In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones.
# Global
* @pelican-dev/panel

View File

@@ -1,75 +0,0 @@
# If using Ubuntu this file should be placed in:
# /etc/nginx/sites-available/
#
# If using CentOS this file should be placed in:
# /etc/nginx/conf.d/
#
# The MIT License (MIT)
#
# Pterodactyl®
# Copyright © Dane Everitt <dane@daneeveritt.com> and contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
server {
listen 80;
server_name _;
root /app/public;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/panel.app-error.log error;
# allow larger file uploads and longer script runtimes
client_max_body_size 100m;
client_body_timeout 120s;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# the fastcgi_pass path needs to be changed accordingly when using CentOS
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
location ~ /\.ht {
deny all;
}
}

View File

@@ -1,70 +0,0 @@
# If using Ubuntu this file should be placed in:
# /etc/nginx/sites-available/
#
server {
listen 80;
server_name <domain>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name <domain>;
root /app/public;
index index.php;
access_log /var/log/nginx/panel.app-access.log;
error_log /var/log/nginx/panel.app-error.log error;
# allow larger file uploads and longer script runtimes
client_max_body_size 100m;
client_body_timeout 120s;
sendfile off;
# strengthen ssl security
ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
# See the link below for more SSL information:
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
#
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
# Add headers to serve security related headers
add_header Strict-Transport-Security "max-age=15768000; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header Content-Security-Policy "frame-ancestors 'self'";
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
include /etc/nginx/fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}

View File

@@ -1,16 +0,0 @@
[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
listen.owner = nginx
listen.group = nginx
listen.mode = 0750
pm = ondemand
pm.max_children = 9
pm.process_idle_timeout = 10s
pm.max_requests = 200
clear_env = no

View File

@@ -3,10 +3,8 @@ name: Build
on:
push:
branches:
- '**'
- main
pull_request:
branches:
- '**'
jobs:
ui:
@@ -20,14 +18,25 @@ jobs:
- name: Code Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Install PHP dependencies
run: composer install --no-interaction --no-suggest --no-progress --no-autoloader --no-scripts --no-dev
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- name: Install dependencies
- name: Install JS dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production
run: yarn build

View File

@@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: [8.2, 8.3]
php: [8.2, 8.3, 8.4]
database: ["mysql:8"]
services:
database:
@@ -66,16 +66,16 @@ jobs:
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-suggest --prefer-dist
run: composer install --no-interaction --no-suggest --no-progress --no-scripts
- name: Unit tests
run: vendor/bin/phpunit tests/Unit
run: vendor/bin/pest tests/Unit
env:
DB_HOST: UNIT_NO_DB
SKIP_MIGRATIONS: true
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
run: vendor/bin/pest tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[3306] }}
DB_USERNAME: root
@@ -86,8 +86,8 @@ jobs:
strategy:
fail-fast: false
matrix:
php: [8.2, 8.3]
database: ["mariadb:10.3", "mariadb:10.11", "mariadb:11.4"]
php: [8.2, 8.3, 8.4]
database: ["mariadb:10.6", "mariadb:10.11", "mariadb:11.4"]
services:
database:
image: ${{ matrix.database }}
@@ -139,16 +139,16 @@ jobs:
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-suggest --prefer-dist
run: composer install --no-interaction --no-suggest --no-progress --no-scripts
- name: Unit tests
run: vendor/bin/phpunit tests/Unit
run: vendor/bin/pest tests/Unit
env:
DB_HOST: UNIT_NO_DB
SKIP_MIGRATIONS: true
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
run: vendor/bin/pest tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[3306] }}
DB_USERNAME: root
@@ -159,7 +159,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: [8.2, 8.3]
php: [8.2, 8.3, 8.4]
env:
APP_ENV: testing
APP_DEBUG: "false"
@@ -200,16 +200,16 @@ jobs:
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-suggest --prefer-dist
run: composer install --no-interaction --no-suggest --no-progress --no-scripts
- name: Create SQLite file
run: touch database/testing.sqlite
- name: Unit tests
run: vendor/bin/phpunit tests/Unit
run: vendor/bin/pest tests/Unit
env:
DB_HOST: UNIT_NO_DB
SKIP_MIGRATIONS: true
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
run: vendor/bin/pest tests/Integration

View File

@@ -1,6 +1,5 @@
name: Docker
on:
push:
branches:
@@ -9,24 +8,83 @@ on:
types:
- published
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
name: Build and Push
runs-on: ubuntu-latest
build-php-base:
name: Build PHP base image on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
arch: amd64
platform: linux/amd64
- os: ubuntu-24.04-arm
arch: arm64
platform: linux/arm64
steps:
- name: Code checkout
uses: actions/checkout@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
- name: Build the base PHP image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.base
push: false
load: true
platforms: ${{ matrix.platform }}
tags: base-php:${{ matrix.arch }}
cache-from: type=gha,scope=base-php${{ matrix.arch }}
cache-to: type=gha,scope=base-php${{ matrix.arch }}
- name: Export image to file
run: docker save -o base-php-${{ matrix.arch }}.tar base-php:${{ matrix.arch }}
- name: Push the docker build to the artifacts
uses: actions/upload-artifact@v4
with:
name: base-php-${{ matrix.arch }}.tar
path: base-php-${{ matrix.arch }}.tar
retention-days: 7
build-and-push:
name: Build and Push ubuntu-24.04
runs-on: ubuntu-24.04
needs: build-php-base
permissions:
contents: read
packages: write
strategy:
fail-fast: false
# Start a temp local registry because workflow can not pull from localy loaded images
services:
registry:
image: registry:2
ports:
- 5000:5000
# Always run against a tag, even if the commit into the tag has [docker skip] within the commit message.
if: "!contains(github.ref, 'main') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))"
steps:
- name: Code checkout
uses: actions/checkout@v4
- name: Docker metadata
id: docker_meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/pelican-dev/panel
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=false
tags: |
@@ -34,11 +92,14 @@ jobs:
type=ref,event=tag
type=ref,event=branch
- name: Setup QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# We Need to start it in host mode else it can't acces the local registry on port 5000
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
@@ -53,30 +114,52 @@ jobs:
echo "version_tag=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_OUTPUT
echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
# Download the base PHP image AMD64
- uses: actions/download-artifact@v4
with:
name: base-php-amd64.tar
# Download the base PHP image ARM64
- uses: actions/download-artifact@v4
with:
name: base-php-arm64.tar
- name: Load base images into local registry
run: |
docker load -i base-php-amd64.tar
docker load -i base-php-arm64.tar
docker tag base-php:amd64 localhost:5000/base-php:amd64
docker tag base-php:arm64 localhost:5000/base-php:arm64
docker push localhost:5000/base-php:amd64
docker push localhost:5000/base-php:arm64
rm base-php-arm64.tar base-php-amd64.tar
- name: Build and Push (tag)
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
if: "github.event_name == 'release' && github.event.action == 'published'"
with:
context: .
file: ./Dockerfile
push: true
platforms: linux/amd64,linux/arm64
platforms: 'linux/amd64,linux/arm64'
build-args: |
VERSION=${{ steps.build_info.outputs.version_tag }}
labels: ${{ steps.docker_meta.outputs.labels }}
tags: ${{ steps.docker_meta.outputs.tags }}
cache-from: type=gha,scope=tagged${{ matrix.os }}
cache-to: type=gha,scope=tagged${{ matrix.os }},mode=max
- name: Build and Push (main)
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
if: "github.event_name == 'push' && contains(github.ref, 'main')"
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
platforms: 'linux/amd64,linux/arm64'
build-args: |
VERSION=dev-${{ steps.build_info.outputs.short_sha }}
labels: ${{ steps.docker_meta.outputs.labels }}
tags: ${{ steps.docker_meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=gha,scope=${{ matrix.os }}
cache-to: type=gha,scope=${{ matrix.os }},mode=max

View File

@@ -25,21 +25,38 @@ jobs:
run: cp .env.example .env
- name: Install dependencies
run: composer install --no-interaction --no-progress --prefer-dist
run: composer install --no-interaction --no-suggest --no-progress --no-autoloader --no-scripts
- name: Pint
run: vendor/bin/pint --test
phpstan:
name: PHPStan
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: [8.2, 8.3, 8.4]
steps:
- name: Code Checkout
uses: actions/checkout@v4
- name: Get cache directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-${{ matrix.php }}-
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
php-version: ${{ matrix.php }}
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
@@ -48,7 +65,7 @@ jobs:
run: cp .env.example .env
- name: Install dependencies
run: composer install --no-interaction --no-progress --prefer-dist
run: composer install --no-interaction --no-suggest --no-progress --no-scripts
- name: PHPStan
run: vendor/bin/phpstan --memory-limit=-1
run: vendor/bin/phpstan --memory-limit=-1

View File

@@ -11,22 +11,33 @@ jobs:
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Code checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Install PHP dependencies
run: composer install --no-interaction --no-suggest --no-progress --no-autoloader --no-scripts --no-dev
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
- name: Install dependencies
- name: Install JS dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production
run: yarn build
- name: Create release branch and bump version
env:
@@ -44,8 +55,8 @@ jobs:
- name: Create release archive
run: |
rm -rf node_modules tests CODE_OF_CONDUCT.md CONTRIBUTING.md flake.lock flake.nix phpunit.xml shell.nix
tar -czf panel.tar.gz * .editorconfig .env.example .eslintignore .eslintrc.js .gitignore .prettierrc.json
rm -rf node_modules vendor tests CODE_OF_CONDUCT.md CONTRIBUTING.md phpunit.xml shell.nix
tar -czf panel.tar.gz * .env.example
- name: Create checksum
run: |

3
.gitignore vendored
View File

@@ -4,6 +4,7 @@
/public/hot
/public/storage
/storage/*.key
/storage/pail
/storage/clockwork/*
/vendor
*.DS_Store*
@@ -19,10 +20,12 @@ npm-debug.log
yarn-error.log
/.fleet
/.idea
/.nova
/.vscode
public/assets/manifest.json
/database/*.sqlite
/database/*.sqlite-journal
filament-monaco-editor/
_ide_helper*
/.phpstorm.meta.php

View File

@@ -1,52 +0,0 @@
<?php
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = (new Finder())
->in(__DIR__)
->exclude([
'vendor',
'node_modules',
'storage',
'bootstrap/cache',
])
->notName(['_ide_helper*']);
return (new Config())
->setRiskyAllowed(true)
->setFinder($finder)
->setRules([
'@Symfony' => true,
'@PSR1' => true,
'@PSR2' => true,
'@PSR12' => true,
'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
'combine_consecutive_unsets' => true,
'concat_space' => ['spacing' => 'one'],
'heredoc_to_nowdoc' => true,
'no_alias_functions' => true,
'no_unreachable_default_argument_value' => true,
'no_useless_return' => true,
'ordered_imports' => [
'sort_algorithm' => 'length',
],
'phpdoc_align' => [
'align' => 'left',
'tags' => [
'param',
'property',
'return',
'throws',
'type',
'var',
],
],
'random_api_migration' => true,
'ternary_to_null_coalescing' => true,
'yoda_style' => [
'equal' => false,
'identical' => false,
'less_and_greater' => false,
],
]);

View File

@@ -1,51 +1,103 @@
# syntax=docker.io/docker/dockerfile:1.13-labs
# Pelican Production Dockerfile
FROM node:20-alpine AS yarn
#FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn
# For those who want to build this Dockerfile themselves, uncomment lines 6-12 and replace "localhost:5000/base-php:$TARGETARCH" on lines 17 and 67 with "base".
# FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine as base
# ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
# RUN install-php-extensions bcmath gd intl zip opcache pcntl posix pdo_mysql
# RUN rm /usr/local/bin/install-php-extensions
# ================================
# Stage 1-1: Composer Install
# ================================
FROM --platform=$TARGETOS/$TARGETARCH localhost:5000/base-php:$TARGETARCH AS composer
WORKDIR /build
COPY . ./
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy bare minimum to install Composer dependencies
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --no-autoloader --no-scripts
# ================================
# Stage 1-2: Yarn Install
# ================================
FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn
WORKDIR /build
# Copy bare minimum to install Yarn dependencies
COPY package.json yarn.lock ./
RUN yarn config set network-timeout 300000 \
&& yarn install --frozen-lockfile \
&& yarn run build:production
&& yarn install --frozen-lockfile
FROM php:8.3-fpm-alpine
# FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
# ================================
# Stage 2-1: Composer Optimize
# ================================
FROM --platform=$TARGETOS/$TARGETARCH composer AS composerbuild
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy full code to optimize autoload
COPY --exclude=Caddyfile --exclude=docker/ . ./
RUN composer dump-autoload --optimize
# ================================
# Stage 2-2: Build Frontend Assets
# ================================
FROM --platform=$TARGETOS/$TARGETARCH yarn AS yarnbuild
WORKDIR /build
# Copy full code
COPY --exclude=Caddyfile --exclude=docker/ . ./
COPY --from=composer /build .
RUN yarn run build
# ================================
# Stage 5: Build Final Application Image
# ================================
FROM --platform=$TARGETOS/$TARGETARCH localhost:5000/base-php:$TARGETARCH AS final
WORKDIR /var/www/html
# Install dependencies
# Install additional required libraries
RUN apk update && apk add --no-cache \
libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \
zip unzip curl \
caddy ca-certificates supervisor \
&& docker-php-ext-install bcmath gd intl zip opcache pcntl posix pdo_mysql
caddy ca-certificates supervisor supercronic
# Copy the Caddyfile to the container
COPY Caddyfile /etc/caddy/Caddyfile
COPY --chown=root:www-data --chmod=640 --from=composerbuild /build .
COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public
# Copy the application code to the container
COPY . .
# Set permissions
# First ensure all files are owned by root and restrict www-data to read access
RUN chown root:www-data ./ \
&& chmod 750 ./ \
# Files should not have execute set, but directories need it
&& find ./ -type d -exec chmod 750 {} \; \
# Symlink to env/database path, as www-data won't be able to write to webroot
&& ln -s /pelican-data/.env ./.env \
&& ln -s /pelican-data/database/database.sqlite ./database/database.sqlite \
# Create necessary directories
&& mkdir -p /pelican-data /var/run/supervisord /etc/supercronic \
# Finally allow www-data write permissions where necessary
&& chown -R www-data:www-data /pelican-data ./storage ./bootstrap/cache /var/run/supervisord \
&& chmod -R u+rwX,g+rwX,o-rwx /pelican-data ./storage ./bootstrap/cache /var/run/supervisord
COPY --from=yarn /build/public/assets ./public/assets
# Configure Supervisor
COPY docker/supervisord.conf /etc/supervisord.conf
COPY docker/Caddyfile /etc/caddy/Caddyfile
# Add Laravel scheduler to crontab
COPY docker/crontab /etc/supercronic/crontab
RUN touch .env
RUN composer install --no-dev --optimize-autoloader
# Set file permissions
RUN chmod -R 755 storage bootstrap/cache
# Add scheduler to cron
RUN echo "* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1" | crontab -u www-data -
## supervisord config and log dir
RUN cp .github/docker/supervisord.conf /etc/supervisord.conf && \
mkdir /var/log/supervisord/
COPY docker/entrypoint.sh ./docker/entrypoint.sh
HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost/up || exit 1
@@ -54,5 +106,7 @@ EXPOSE 80 443
VOLUME /pelican-data
ENTRYPOINT [ "/bin/ash", ".github/docker/entrypoint.sh" ]
USER www-data
ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ]
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]

10
Dockerfile.base Normal file
View File

@@ -0,0 +1,10 @@
# ================================
# Stage 0: Build PHP Base Image
# ================================
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN install-php-extensions bcmath gd intl zip opcache pcntl posix pdo_mysql
RUN rm /usr/local/bin/install-php-extensions

58
app/Checks/CacheCheck.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
namespace App\Checks;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class CacheCheck extends Check
{
protected ?string $driver = null;
public function driver(string $driver): self
{
$this->driver = $driver;
return $this;
}
public function run(): Result
{
$driver = $this->driver ?? $this->defaultDriver();
$result = Result::make()->meta([
'driver' => $driver,
]);
try {
return $this->canWriteValuesToCache($driver)
? $result->ok(trans('admin/health.results.cache.ok'))
: $result->failed(trans('admin/health.results.cache.failed_retrieve'));
} catch (Exception $exception) {
return $result->failed(trans('admin/health.results.cache.failed', ['error' => $exception->getMessage()]));
}
}
protected function defaultDriver(): ?string
{
return config('cache.default', 'file');
}
protected function canWriteValuesToCache(?string $driver): bool
{
$expectedValue = Str::random(5);
$cacheName = "laravel-health:check-{$expectedValue}";
Cache::driver($driver)->put($cacheName, $expectedValue, 10);
$actualValue = Cache::driver($driver)->get($cacheName);
Cache::driver($driver)->forget($cacheName);
return $actualValue === $expectedValue;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Checks;
use Exception;
use Illuminate\Support\Facades\DB;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class DatabaseCheck extends Check
{
protected ?string $connectionName = null;
public function connectionName(string $connectionName): self
{
$this->connectionName = $connectionName;
return $this;
}
public function run(): Result
{
$connectionName = $this->connectionName ?? $this->getDefaultConnectionName();
$result = Result::make()->meta([
'connection_name' => $connectionName,
]);
try {
DB::connection($connectionName)->getPdo();
return $result->ok(trans('admin/health.results.database.ok'));
} catch (Exception $exception) {
return $result->failed(trans('admin/health.results.database.failed', ['error' => $exception->getMessage()]));
}
}
protected function getDefaultConnectionName(): string
{
return config('database.default');
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Checks;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
use function config;
class DebugModeCheck extends Check
{
protected bool $expected = false;
public function expectedToBe(bool $bool): self
{
$this->expected = $bool;
return $this;
}
public function run(): Result
{
$actual = config('app.debug');
$result = Result::make()
->meta([
'actual' => $actual,
'expected' => $this->expected,
])
->shortSummary($this->convertToWord($actual));
return $this->expected === $actual
? $result->ok()
: $result->failed(trans('admin/health.results.debugmode.failed', [
'actual' => $this->convertToWord($actual),
'expected' => $this->convertToWord($this->expected),
]));
}
protected function convertToWord(bool $boolean): string
{
return $boolean ? 'true' : 'false';
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Checks;
use Illuminate\Support\Facades\App;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class EnvironmentCheck extends Check
{
protected string $expectedEnvironment = 'production';
public function expectEnvironment(string $expectedEnvironment): self
{
$this->expectedEnvironment = $expectedEnvironment;
return $this;
}
public function run(): Result
{
$actualEnvironment = (string) App::environment();
$result = Result::make()
->meta([
'actual' => $actualEnvironment,
'expected' => $this->expectedEnvironment,
])
->shortSummary($actualEnvironment);
return $this->expectedEnvironment === $actualEnvironment
? $result->ok(trans('admin/health.results.environment.ok'))
: $result->failed(trans('admin/health.results.environment.failed', [
'actual' => $actualEnvironment,
'expected' => $this->expectedEnvironment,
]));
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Checks;
use App\Models\Node;
use App\Services\Helpers\SoftwareVersionService;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
use Spatie\Health\Enums\Status;
class NodeVersionsCheck extends Check
{
public function __construct(private SoftwareVersionService $versionService) {}
public function run(): Result
{
$all = Node::query()->count();
if ($all === 0) {
$result = Result::make()
->notificationMessage(trans('admin/health.results.nodeversions.no_nodes_created'))
->shortSummary(trans('admin/health.results.nodeversions.no_nodes'));
$result->status = Status::skipped();
return $result;
}
$latestVersion = $this->versionService->latestWingsVersion();
$outdated = Node::query()->get()
->filter(fn (Node $node) => !isset($node->systemInformation()['exception']) && $node->systemInformation()['version'] !== $latestVersion)
->count();
$result = Result::make()
->meta([
'all' => $all,
'outdated' => $outdated,
])
->shortSummary($outdated === 0 ? trans('admin/health.results.nodeversions.all_up_to_date') : trans('admin/health.results.nodeversions.outdated', ['outdated' => $outdated, 'all' => $all]));
return $outdated === 0
? $result->ok(trans('admin/health.results.nodeversions.ok'))
: $result->failed(trans('admin/health.results.nodeversions.failed', ['outdated' => $outdated, 'all' => $all]));
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Checks;
use App\Services\Helpers\SoftwareVersionService;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class PanelVersionCheck extends Check
{
public function __construct(private SoftwareVersionService $versionService) {}
public function run(): Result
{
$isLatest = $this->versionService->isLatestPanel();
$currentVersion = $this->versionService->currentPanelVersion();
$latestVersion = $this->versionService->latestPanelVersion();
$result = Result::make()
->meta([
'isLatest' => $isLatest,
'currentVersion' => $currentVersion,
'latestVersion' => $latestVersion,
])
->shortSummary($isLatest ? trans('admin/health.results.panelversion.up_to_date') : trans('admin/health.results.panelversion.outdated'));
return $isLatest
? $result->ok(trans('admin/health.results.panelversion.ok'))
: $result->failed(trans('admin/health.results.panelversion.failed', [
'currentVersion' => $currentVersion,
'latestVersion' => $latestVersion,
]));
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Checks;
use Carbon\Carbon;
use Composer\InstalledVersions;
use Spatie\Health\Checks\Checks\ScheduleCheck as BaseCheck;
use Spatie\Health\Checks\Result;
class ScheduleCheck extends BaseCheck
{
public function run(): Result
{
$result = Result::make()->ok(trans('admin/health.results.schedule.ok'));
$lastHeartbeatTimestamp = cache()->store($this->cacheStoreName)->get($this->cacheKey);
if (!$lastHeartbeatTimestamp) {
return $result->failed(trans('admin/health.results.schedule.failed_not_ran'));
}
$latestHeartbeatAt = Carbon::createFromTimestamp($lastHeartbeatTimestamp);
$carbonVersion = InstalledVersions::getVersion('nesbot/carbon');
$minutesAgo = $latestHeartbeatAt->diffInMinutes();
if (version_compare($carbonVersion,
'3.0.0', '<')) {
$minutesAgo += 1;
}
if ($minutesAgo > $this->heartbeatMaxAgeInMinutes) {
return $result->failed(trans('admin/health.results.schedule.failed_last_ran', [
'time' => $minutesAgo,
]));
}
return $result;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Checks;
use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck as BaseCheck;
class UsedDiskSpaceCheck extends BaseCheck
{
protected function getDiskUsagePercentage(): int
{
$freeSpace = disk_free_space($this->filesystemName ?? '/');
$totalSpace = disk_total_space($this->filesystemName ?? '/');
return 100 - ($freeSpace * 100 / $totalSpace);
}
}

View File

@@ -16,28 +16,37 @@ class CheckEggUpdatesCommand extends Command
$eggs = Egg::all();
foreach ($eggs as $egg) {
try {
if (is_null($egg->update_url)) {
$this->comment("{$egg->name}: Skipping (no update url set)");
continue;
}
$currentJson = json_decode($exporterService->handle($egg->id));
unset($currentJson->exported_at);
$updatedJson = json_decode(file_get_contents($egg->update_url));
unset($updatedJson->exported_at);
if (md5(json_encode($currentJson)) === md5(json_encode($updatedJson))) {
$this->info("{$egg->name}: Up-to-date");
cache()->put("eggs.{$egg->uuid}.update", false, now()->addHour());
} else {
$this->warn("{$egg->name}: Found update");
cache()->put("eggs.{$egg->uuid}.update", true, now()->addHour());
}
$this->check($egg, $exporterService);
} catch (Exception $exception) {
$this->error("{$egg->name}: Error ({$exception->getMessage()})");
}
}
}
private function check(Egg $egg, EggExporterService $exporterService): void
{
if (is_null($egg->update_url)) {
$this->comment("$egg->name: Skipping (no update url set)");
return;
}
$currentJson = json_decode($exporterService->handle($egg->id));
unset($currentJson->exported_at);
$updatedEgg = file_get_contents($egg->update_url);
assert($updatedEgg !== false);
$updatedJson = json_decode($updatedEgg);
unset($updatedJson->exported_at);
if (md5(json_encode($currentJson, JSON_THROW_ON_ERROR)) === md5(json_encode($updatedJson, JSON_THROW_ON_ERROR))) {
$this->info("$egg->name: Up-to-date");
cache()->put("eggs.$egg->uuid.update", false, now()->addHour());
return;
}
$this->warn("$egg->name: Found update");
cache()->put("eggs.$egg->uuid.update", true, now()->addHour());
}
}

View File

@@ -27,8 +27,6 @@ class CacheSettingsCommand extends Command
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';
protected array $variables = [];
/**
* CacheSettingsCommand constructor.
*/

View File

@@ -27,6 +27,7 @@ class DatabaseSettingsCommand extends Command
{--username= : Username to use when connecting to the MySQL/ MariaDB server.}
{--password= : Password to use for the MySQL/ MariaDB database.}';
/** @var array<array-key, mixed> */
protected array $variables = [];
/**
@@ -57,7 +58,7 @@ class DatabaseSettingsCommand extends Command
);
if ($this->variables['DB_CONNECTION'] === 'mysql') {
$this->output->note(__('commands.database_settings.DB_HOST_note'));
$this->output->note(trans('commands.database_settings.DB_HOST_note'));
$this->variables['DB_HOST'] = $this->option('host') ?? $this->ask(
'Database Host',
config('database.connections.mysql.host', '127.0.0.1')
@@ -73,7 +74,7 @@ class DatabaseSettingsCommand extends Command
config('database.connections.mysql.database', 'panel')
);
$this->output->note(__('commands.database_settings.DB_USERNAME_note'));
$this->output->note(trans('commands.database_settings.DB_USERNAME_note'));
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
'Database Username',
config('database.connections.mysql.username', 'pelican')
@@ -82,7 +83,7 @@ class DatabaseSettingsCommand extends Command
$askForMySQLPassword = true;
if (!empty(config('database.connections.mysql.password')) && $this->input->isInteractive()) {
$this->variables['DB_PASSWORD'] = config('database.connections.mysql.password');
$askForMySQLPassword = $this->confirm(__('commands.database_settings.DB_PASSWORD_note'));
$askForMySQLPassword = $this->confirm(trans('commands.database_settings.DB_PASSWORD_note'));
}
if ($askForMySQLPassword) {
@@ -106,9 +107,9 @@ class DatabaseSettingsCommand extends Command
$this->database->connection('_panel_command_test')->getPdo();
} catch (\PDOException $exception) {
$this->output->error(sprintf('Unable to connect to the MySQL server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
$this->output->error(__('commands.database_settings.DB_error_2'));
$this->output->error(trans('commands.database_settings.DB_error_2'));
if ($this->confirm(__('commands.database_settings.go_back'))) {
if ($this->confirm(trans('commands.database_settings.go_back'))) {
$this->database->disconnect('_panel_command_test');
return $this->handle();
@@ -117,7 +118,7 @@ class DatabaseSettingsCommand extends Command
return 1;
}
} elseif ($this->variables['DB_CONNECTION'] === 'mariadb') {
$this->output->note(__('commands.database_settings.DB_HOST_note'));
$this->output->note(trans('commands.database_settings.DB_HOST_note'));
$this->variables['DB_HOST'] = $this->option('host') ?? $this->ask(
'Database Host',
config('database.connections.mariadb.host', '127.0.0.1')
@@ -133,7 +134,7 @@ class DatabaseSettingsCommand extends Command
config('database.connections.mariadb.database', 'panel')
);
$this->output->note(__('commands.database_settings.DB_USERNAME_note'));
$this->output->note(trans('commands.database_settings.DB_USERNAME_note'));
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
'Database Username',
config('database.connections.mariadb.username', 'pelican')
@@ -142,7 +143,7 @@ class DatabaseSettingsCommand extends Command
$askForMariaDBPassword = true;
if (!empty(config('database.connections.mariadb.password')) && $this->input->isInteractive()) {
$this->variables['DB_PASSWORD'] = config('database.connections.mariadb.password');
$askForMariaDBPassword = $this->confirm(__('commands.database_settings.DB_PASSWORD_note'));
$askForMariaDBPassword = $this->confirm(trans('commands.database_settings.DB_PASSWORD_note'));
}
if ($askForMariaDBPassword) {
@@ -166,9 +167,9 @@ class DatabaseSettingsCommand extends Command
$this->database->connection('_panel_command_test')->getPdo();
} catch (\PDOException $exception) {
$this->output->error(sprintf('Unable to connect to the MariaDB server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
$this->output->error(__('commands.database_settings.DB_error_2'));
$this->output->error(trans('commands.database_settings.DB_error_2'));
if ($this->confirm(__('commands.database_settings.go_back'))) {
if ($this->confirm(trans('commands.database_settings.go_back'))) {
$this->database->disconnect('_panel_command_test');
return $this->handle();
@@ -179,7 +180,7 @@ class DatabaseSettingsCommand extends Command
} elseif ($this->variables['DB_CONNECTION'] === 'sqlite') {
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
'Database Path',
env('DB_DATABASE', 'database.sqlite')
(string) env('DB_DATABASE', 'database.sqlite')
);
}

View File

@@ -22,6 +22,7 @@ class EmailSettingsCommand extends Command
{--username=}
{--password=}';
/** @var array<array-key, mixed> */
protected array $variables = [];
/**
@@ -91,7 +92,7 @@ class EmailSettingsCommand extends Command
trans('command/messages.environment.mail.ask_smtp_password')
);
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
$this->variables['MAIL_SCHEME'] = $this->option('encryption') ?? $this->choice(
trans('command/messages.environment.mail.ask_encryption'),
['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'],
config('mail.mailers.smtp.encryption', 'tls')

View File

@@ -27,8 +27,6 @@ class QueueSettingsCommand extends Command
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';
protected array $variables = [];
/**
* QueueSettingsCommand constructor.
*/

View File

@@ -21,7 +21,7 @@ class QueueWorkerServiceCommand extends Command
$serviceName = $this->option('service-name') ?? $this->ask('Queue worker service name', 'pelican-queue');
$path = '/etc/systemd/system/' . $serviceName . '.service';
$fileExists = file_exists($path);
$fileExists = @file_exists($path);
if ($fileExists && !$this->option('overwrite') && !$this->confirm('The service file already exists. Do you want to overwrite it?')) {
$this->line('Creation of queue worker service file aborted because service file already exists.');

View File

@@ -20,8 +20,6 @@ class RedisSetupCommand extends Command
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';
protected array $variables = [];
/**
* RedisSetupCommand constructor.
*/

View File

@@ -28,8 +28,6 @@ class SessionSettingsCommand extends Command
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}';
protected array $variables = [];
/**
* SessionSettingsCommand constructor.
*/

View File

@@ -3,7 +3,6 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\Helpers\SoftwareVersionService;
class InfoCommand extends Command
{
@@ -11,98 +10,8 @@ class InfoCommand extends Command
protected $signature = 'p:info';
/**
* InfoCommand constructor.
*/
public function __construct(private SoftwareVersionService $versionService)
{
parent::__construct();
}
/**
* Handle execution of command.
*/
public function handle(): void
{
$this->output->title('Version Information');
$this->table([], [
['Panel Version', $this->versionService->versionData()['version']],
['Latest Version', $this->versionService->getPanel()],
['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
], 'compact');
$this->output->title('Application Configuration');
$this->table([], [
['Environment', config('app.env') === 'production' ? config('app.env') : $this->formatText(config('app.env'), 'bg=red')],
['Debug Mode', config('app.debug') ? $this->formatText('Yes', 'bg=red') : 'No'],
['Application Name', config('app.name')],
['Application URL', config('app.url')],
['Installation Directory', base_path()],
['Cache Driver', config('cache.default')],
['Queue Driver', config('queue.default') === 'sync' ? $this->formatText(config('queue.default'), 'bg=red') : config('queue.default')],
['Session Driver', config('session.driver')],
['Filesystem Driver', config('filesystems.default')],
], 'compact');
$this->output->title('Database Configuration');
$driver = config('database.default');
if ($driver === 'sqlite') {
$this->table([], [
['Driver', $driver],
['Database', config("database.connections.$driver.database")],
], 'compact');
} else {
$this->table([], [
['Driver', $driver],
['Host', config("database.connections.$driver.host")],
['Port', config("database.connections.$driver.port")],
['Database', config("database.connections.$driver.database")],
['Username', config("database.connections.$driver.username")],
], 'compact');
}
$this->output->title('Email Configuration');
$driver = config('mail.default');
if ($driver === 'smtp') {
$this->table([], [
['Driver', $driver],
['Host', config("mail.mailers.$driver.host")],
['Port', config("mail.mailers.$driver.port")],
['Username', config("mail.mailers.$driver.username")],
['Encryption', config("mail.mailers.$driver.encryption")],
['From Address', config('mail.from.address')],
['From Name', config('mail.from.name')],
], 'compact');
} else {
$this->table([], [
['Driver', $driver],
['From Address', config('mail.from.address')],
['From Name', config('mail.from.name')],
], 'compact');
}
$this->output->title('Backup Configuration');
$driver = config('backups.default');
if ($driver === 's3') {
$this->table([], [
['Driver', $driver],
['Region', config("backups.disks.$driver.region")],
['Bucket', config("backups.disks.$driver.bucket")],
['Endpoint', config("backups.disks.$driver.endpoint")],
['Use path style endpoint', config("backups.disks.$driver.use_path_style_endpoint") ? 'Yes' : 'No'],
], 'compact');
} else {
$this->table([], [
['Driver', $driver],
], 'compact');
}
}
/**
* Format output in a Name: Value manner.
*/
private function formatText(string $value, string $opts = ''): string
{
return sprintf('<%s>%s</>', $opts, $value);
$this->call('about');
}
}

View File

@@ -45,31 +45,31 @@ class MakeNodeCommand extends Command
*/
public function handle(): void
{
$data['name'] = $this->option('name') ?? $this->ask(__('commands.make_node.name'));
$data['description'] = $this->option('description') ?? $this->ask(__('commands.make_node.description'));
$data['name'] = $this->option('name') ?? $this->ask(trans('commands.make_node.name'));
$data['description'] = $this->option('description') ?? $this->ask(trans('commands.make_node.description'));
$data['scheme'] = $this->option('scheme') ?? $this->anticipate(
__('commands.make_node.scheme'),
trans('commands.make_node.scheme'),
['https', 'http'],
'https'
);
$data['fqdn'] = $this->option('fqdn') ?? $this->ask(__('commands.make_node.fqdn'));
$data['public'] = $this->option('public') ?? $this->confirm(__('commands.make_node.public'), true);
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm(__('commands.make_node.behind_proxy'));
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm(__('commands.make_node.maintenance_mode'));
$data['memory'] = $this->option('maxMemory') ?? $this->ask(__('commands.make_node.memory'), '0');
$data['memory_overallocate'] = $this->option('overallocateMemory') ?? $this->ask(__('commands.make_node.memory_overallocate'), '-1');
$data['disk'] = $this->option('maxDisk') ?? $this->ask(__('commands.make_node.disk'), '0');
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask(__('commands.make_node.disk_overallocate'), '-1');
$data['cpu'] = $this->option('maxCpu') ?? $this->ask(__('commands.make_node.cpu'), '0');
$data['cpu_overallocate'] = $this->option('overallocateCpu') ?? $this->ask(__('commands.make_node.cpu_overallocate'), '-1');
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask(__('commands.make_node.upload_size'), '256');
$data['daemon_listen'] = $this->option('daemonListeningPort') ?? $this->ask(__('commands.make_node.daemonListen'), '8080');
$data['daemon_sftp'] = $this->option('daemonSFTPPort') ?? $this->ask(__('commands.make_node.daemonSFTP'), '2022');
$data['daemon_sftp_alias'] = $this->option('daemonSFTPAlias') ?? $this->ask(__('commands.make_node.daemonSFTPAlias'), '');
$data['daemon_base'] = $this->option('daemonBase') ?? $this->ask(__('commands.make_node.daemonBase'), '/var/lib/pelican/volumes');
$data['fqdn'] = $this->option('fqdn') ?? $this->ask(trans('commands.make_node.fqdn'));
$data['public'] = $this->option('public') ?? $this->confirm(trans('commands.make_node.public'), true);
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm(trans('commands.make_node.behind_proxy'));
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm(trans('commands.make_node.maintenance_mode'));
$data['memory'] = $this->option('maxMemory') ?? $this->ask(trans('commands.make_node.memory'), '0');
$data['memory_overallocate'] = $this->option('overallocateMemory') ?? $this->ask(trans('commands.make_node.memory_overallocate'), '-1');
$data['disk'] = $this->option('maxDisk') ?? $this->ask(trans('commands.make_node.disk'), '0');
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask(trans('commands.make_node.disk_overallocate'), '-1');
$data['cpu'] = $this->option('maxCpu') ?? $this->ask(trans('commands.make_node.cpu'), '0');
$data['cpu_overallocate'] = $this->option('overallocateCpu') ?? $this->ask(trans('commands.make_node.cpu_overallocate'), '-1');
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask(trans('commands.make_node.upload_size'), '256');
$data['daemon_listen'] = $this->option('daemonListeningPort') ?? $this->ask(trans('commands.make_node.daemonListen'), '8080');
$data['daemon_sftp'] = $this->option('daemonSFTPPort') ?? $this->ask(trans('commands.make_node.daemonSFTP'), '2022');
$data['daemon_sftp_alias'] = $this->option('daemonSFTPAlias') ?? $this->ask(trans('commands.make_node.daemonSFTPAlias'), '');
$data['daemon_base'] = $this->option('daemonBase') ?? $this->ask(trans('commands.make_node.daemonBase'), '/var/lib/pelican/volumes');
$node = $this->creationService->handle($data);
$this->line(__('commands.make_node.success', ['name' => $data['name'], 'id' => $node->id]));
$this->line(trans('commands.make_node.success', ['name' => $data['name'], 'id' => $node->id]));
}
}

View File

@@ -19,14 +19,14 @@ class NodeConfigurationCommand extends Command
/** @var \App\Models\Node $node */
$node = Node::query()->where($column, $this->argument('node'))->firstOr(function () {
$this->error(__('commands.node_config.error_not_exist'));
$this->error(trans('commands.node_config.error_not_exist'));
exit(1);
});
$format = $this->option('format');
if (!in_array($format, ['yaml', 'yml', 'json'])) {
$this->error(__('commands.node_config.error_invalid_format'));
$this->error(trans('commands.node_config.error_invalid_format'));
return 1;
}

View File

@@ -13,12 +13,12 @@ class KeyGenerateCommand extends BaseKeyGenerateCommand
public function handle(): void
{
if (!empty(config('app.key')) && $this->input->isInteractive()) {
$this->output->warning(__('commands.key_generate.error_already_exist'));
if (!$this->confirm(__('commands.key_generate.understand'))) {
$this->output->warning(trans('commands.key_generate.error_already_exist'));
if (!$this->confirm(trans('commands.key_generate.understand'))) {
return;
}
if (!$this->confirm(__('commands.key_generate.continue'))) {
if (!$this->confirm(trans('commands.key_generate.continue'))) {
return;
}
}

View File

@@ -6,7 +6,7 @@ use Illuminate\Console\Command;
use App\Models\Schedule;
use Illuminate\Database\Eloquent\Builder;
use App\Services\Schedules\ProcessScheduleService;
use Carbon\Carbon;
use Throwable;
class ProcessRunnableCommand extends Command
{
@@ -14,21 +14,18 @@ class ProcessRunnableCommand extends Command
protected $description = 'Process schedules in the database and determine which are ready to run.';
/**
* Handle command execution.
*/
public function handle(): int
public function handle(ProcessScheduleService $processScheduleService): int
{
$schedules = Schedule::query()
->with('tasks')
->whereRelation('server', fn (Builder $builder) => $builder->whereNull('status'))
->where('is_active', true)
->where('is_processing', false)
->where('next_run_at', '<=', Carbon::now()->toDateTimeString())
->where('next_run_at', '<=', now('UTC')->toDateTimeString())
->get();
if ($schedules->count() < 1) {
$this->line(__('commands.schedule.process.no_tasks'));
$this->line(trans('commands.schedule.process.no_tasks'));
return 0;
}
@@ -36,7 +33,7 @@ class ProcessRunnableCommand extends Command
$bar = $this->output->createProgressBar(count($schedules));
foreach ($schedules as $schedule) {
$bar->clear();
$this->processSchedule($schedule);
$this->processSchedule($processScheduleService, $schedule);
$bar->advance();
$bar->display();
}
@@ -51,23 +48,23 @@ class ProcessRunnableCommand extends Command
* never throw an exception out, otherwise you'll end up killing the entire run group causing
* any other schedules to not process correctly.
*/
protected function processSchedule(Schedule $schedule): void
protected function processSchedule(ProcessScheduleService $processScheduleService, Schedule $schedule): void
{
if ($schedule->tasks->isEmpty()) {
return;
}
try {
$this->getLaravel()->make(ProcessScheduleService::class)->handle($schedule);
$processScheduleService->handle($schedule);
$this->line(trans('command/messages.schedule.output_line', [
'schedule' => $schedule->name,
'id' => $schedule->id,
]));
} catch (\Throwable|\Exception $exception) {
} catch (Throwable $exception) {
logger()->error($exception, ['schedule_id' => $schedule->id]);
$this->error(__('commands.schedule.process.no_tasks') . " #$schedule->id: " . $exception->getMessage());
$this->error(trans('commands.schedule.process.no_tasks') . " #$schedule->id: " . $exception->getMessage());
}
}
}

View File

@@ -8,7 +8,7 @@ use Illuminate\Database\Eloquent\Builder;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Factory as ValidatorFactory;
use App\Repositories\Daemon\DaemonPowerRepository;
use App\Exceptions\Http\Connection\DaemonConnectionException;
use Exception;
class BulkPowerActionCommand extends Command
{
@@ -19,26 +19,13 @@ class BulkPowerActionCommand extends Command
protected $description = 'Perform bulk power management on large groupings of servers or nodes at once.';
/**
* BulkPowerActionCommand constructor.
*/
public function __construct(private DaemonPowerRepository $powerRepository, private ValidatorFactory $validator)
{
parent::__construct();
}
/**
* Handle the bulk power request.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function handle(): void
public function handle(DaemonPowerRepository $powerRepository, ValidatorFactory $validator): void
{
$action = $this->argument('action');
$nodes = empty($this->option('nodes')) ? [] : explode(',', $this->option('nodes'));
$servers = empty($this->option('servers')) ? [] : explode(',', $this->option('servers'));
$validator = $this->validator->make([
$validator = $validator->make([
'action' => $action,
'nodes' => $nodes,
'servers' => $servers,
@@ -64,13 +51,17 @@ class BulkPowerActionCommand extends Command
}
$bar = $this->output->createProgressBar($count);
$powerRepository = $this->powerRepository;
$this->getQueryBuilder($servers, $nodes)->each(function (Server $server) use ($action, $powerRepository, &$bar) {
$this->getQueryBuilder($servers, $nodes)->get()->each(function ($server, int $index) use ($action, $powerRepository, &$bar): mixed {
$bar->clear();
if (!$server instanceof Server) {
return null;
}
try {
$powerRepository->setServer($server)->send($action);
} catch (DaemonConnectionException $exception) {
} catch (Exception $exception) {
$this->output->error(trans('command/messages.server.power.action_failed', [
'name' => $server->name,
'id' => $server->id,
@@ -81,6 +72,8 @@ class BulkPowerActionCommand extends Command
$bar->advance();
$bar->display();
return null;
});
$this->line('');
@@ -88,6 +81,9 @@ class BulkPowerActionCommand extends Command
/**
* Returns the query builder instance that will return the servers that should be affected.
*
* @param string[]|int[] $servers
* @param string[]|int[] $nodes
*/
protected function getQueryBuilder(array $servers, array $nodes): Builder
{

View File

@@ -34,30 +34,26 @@ class UpgradeCommand extends Command
{
$skipDownload = $this->option('skip-download');
if (!$skipDownload) {
$this->output->warning(__('commands.upgrade.integrity'));
$this->output->comment(__('commands.upgrade.source_url'));
$this->output->warning(trans('commands.upgrade.integrity'));
$this->output->comment(trans('commands.upgrade.source_url'));
$this->line($this->getUrl());
}
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
$this->error(__('commands.upgrade.php_version') . ' [' . PHP_VERSION . '].');
}
$user = 'www-data';
$group = 'www-data';
if ($this->input->isInteractive()) {
if (!$skipDownload) {
$skipDownload = !$this->confirm(__('commands.upgrade.skipDownload'), true);
$skipDownload = !$this->confirm(trans('commands.upgrade.skipDownload'), true);
}
if (is_null($this->option('user'))) {
$userDetails = function_exists('posix_getpwuid') ? posix_getpwuid(fileowner('public')) : [];
$user = $userDetails['name'] ?? 'www-data';
$message = __('commands.upgrade.webserver_user', ['user' => $user]);
$message = trans('commands.upgrade.webserver_user', ['user' => $user]);
if (!$this->confirm($message, true)) {
$user = $this->anticipate(
__('commands.upgrade.name_webserver'),
trans('commands.upgrade.name_webserver'),
[
'www-data',
'nginx',
@@ -71,10 +67,10 @@ class UpgradeCommand extends Command
$groupDetails = function_exists('posix_getgrgid') ? posix_getgrgid(filegroup('public')) : [];
$group = $groupDetails['name'] ?? 'www-data';
$message = __('commands.upgrade.group_webserver', ['group' => $user]);
$message = trans('commands.upgrade.group_webserver', ['group' => $user]);
if (!$this->confirm($message, true)) {
$group = $this->anticipate(
__('commands.upgrade.group_webserver_question'),
trans('commands.upgrade.group_webserver_question'),
[
'www-data',
'nginx',
@@ -84,8 +80,8 @@ class UpgradeCommand extends Command
}
}
if (!$this->confirm(__('commands.upgrade.are_your_sure'))) {
$this->warn(__('commands.upgrade.terminated'));
if (!$this->confirm(trans('commands.upgrade.are_your_sure'))) {
$this->warn(trans('commands.upgrade.terminated'));
return;
}
@@ -175,7 +171,7 @@ class UpgradeCommand extends Command
});
$this->newLine(2);
$this->info(__('commands.upgrade.success'));
$this->info(trans('commands.upgrade.success'));
}
protected function withProgress(ProgressBar $bar, \Closure $callback): void

View File

@@ -19,7 +19,7 @@ class DisableTwoFactorCommand extends Command
public function handle(): void
{
if ($this->input->isInteractive()) {
$this->output->warning(trans('command/messages.user.2fa_help_text'));
$this->output->warning(trans('command/messages.user.2fa_help_text.0') . trans('command/messages.user.2fa_help_text.1'));
}
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));

View File

@@ -9,9 +9,12 @@ use App\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
use App\Console\Commands\Schedule\ProcessRunnableCommand;
use App\Jobs\NodeStatistics;
use App\Models\ActivityLog;
use App\Models\Webhook;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Database\Console\PruneCommand;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Spatie\Health\Commands\RunHealthChecksCommand;
use Spatie\Health\Commands\ScheduleCheckHeartbeatCommand;
class Kernel extends ConsoleKernel
{
@@ -48,5 +51,12 @@ class Kernel extends ConsoleKernel
if (config('activity.prune_days')) {
$schedule->command(PruneCommand::class, ['--model' => [ActivityLog::class]])->daily();
}
if (config('panel.webhook.prune_days')) {
$schedule->command(PruneCommand::class, ['--model' => [Webhook::class]])->daily();
}
$schedule->command(ScheduleCheckHeartbeatCommand::class)->everyMinute();
$schedule->command(RunHealthChecksCommand::class)->everyFiveMinutes();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Contracts;
use Illuminate\Validation\Validator;
interface Validatable
{
public function getValidator(): Validator;
/**
* @return array<string, mixed>
*/
public static function getRules(): array;
/**
* @return array<string, array<string, mixed>>
*/
public static function getRulesForField(string $field): array;
public function validate(): void;
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Eloquent;
use Illuminate\Database\Eloquent\Builder;
/**
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @extends Builder<TModel>
*/
class BackupQueryBuilder extends Builder
{
public function nonFailed(): self
{
$this->where(function (Builder $query) {
$query
->whereNull('completed_at')
->orWhere('is_successful', true);
});
return $this;
}
}

View File

@@ -2,7 +2,11 @@
namespace App\Enums;
enum ContainerStatus: string
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Contracts\HasLabel;
enum ContainerStatus: string implements HasColor, HasIcon, HasLabel
{
// Docker Based
case Created = 'created';
@@ -19,7 +23,7 @@ enum ContainerStatus: string
// HTTP Based
case Missing = 'missing';
public function icon(): string
public function getIcon(): string
{
return match ($this) {
@@ -36,8 +40,17 @@ enum ContainerStatus: string
};
}
public function color(): string
public function getColor(bool $hex = false): string
{
if ($hex) {
return match ($this) {
self::Created, self::Restarting => '#2563EB',
self::Starting, self::Paused, self::Removing, self::Stopping => '#D97706',
self::Running => '#22C55E',
self::Exited, self::Missing, self::Dead, self::Offline => '#EF4444',
};
}
return match ($this) {
self::Created => 'primary',
self::Starting => 'warning',
@@ -52,4 +65,50 @@ enum ContainerStatus: string
self::Offline => 'gray',
};
}
public function getLabel(): string
{
return str($this->value)->title();
}
public function isOffline(): bool
{
return in_array($this, [ContainerStatus::Offline, ContainerStatus::Missing]);
}
public function isStartingOrRunning(): bool
{
return in_array($this, [ContainerStatus::Starting, ContainerStatus::Running]);
}
public function isStartingOrStopping(): bool
{
return in_array($this, [ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting]);
}
public function isStartable(): bool
{
return !in_array($this, [ContainerStatus::Running, ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting]);
}
public function isRestartable(): bool
{
if ($this->isStartable()) {
return true;
}
return !in_array($this, [ContainerStatus::Offline]);
}
public function isStoppable(): bool
{
return !in_array($this, [ContainerStatus::Starting, ContainerStatus::Stopping, ContainerStatus::Restarting, ContainerStatus::Exited, ContainerStatus::Offline]);
}
public function isKillable(): bool
{
// [ContainerStatus::Restarting, ContainerStatus::Removing, ContainerStatus::Dead, ContainerStatus::Created]
return !in_array($this, [ContainerStatus::Offline, ContainerStatus::Running, ContainerStatus::Exited]);
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace App\Enums;
use Filament\Support\Contracts\HasLabel;
enum EditorLanguages: string implements HasLabel
{
case plaintext = 'plaintext';
case abap = 'abap';
case apex = 'apex';
case azcali = 'azcali';
case bat = 'bat';
case bicep = 'bicep';
case cameligo = 'cameligo';
case coljure = 'coljure';
case coffeescript = 'coffeescript';
case c = 'c';
case cpp = 'cpp';
case csharp = 'csharp';
case csp = 'csp';
case css = 'css';
case cypher = 'cypher';
case dart = 'dart';
case dockerfile = 'dockerfile';
case ecl = 'ecl';
case elixir = 'elixir';
case flow9 = 'flow9';
case fsharp = 'fsharp';
case go = 'go';
case graphql = 'graphql';
case handlebars = 'handlebars';
case hcl = 'hcl';
case html = 'html';
case ini = 'ini';
case java = 'java';
case javascript = 'javascript';
case julia = 'julia';
case json = 'json';
case kotlin = 'kotlin';
case less = 'less';
case lexon = 'lexon';
case lua = 'lua';
case liquid = 'liquid';
case m3 = 'm3';
case markdown = 'markdown';
case mdx = 'mdx';
case mips = 'mips';
case msdax = 'msdax';
case mysql = 'mysql';
case objectivec = 'objective-c';
case pascal = 'pascal';
case pascaligo = 'pascaligo';
case perl = 'perl';
case pgsql = 'pgsql';
case php = 'php';
case pla = 'pla';
case postiats = 'postiats';
case powerquery = 'powerquery';
case powershell = 'powershell';
case proto = 'proto';
case pug = 'pug';
case python = 'python';
case qsharp = 'qsharp';
case r = 'r';
case razor = 'razor';
case redis = 'redis';
case redshift = 'redshift';
case restructuredtext = 'restructuredtext';
case ruby = 'ruby';
case rust = 'rust';
case sb = 'sb';
case scala = 'scala';
case scheme = 'scheme';
case scss = 'scss';
case shell = 'shell';
case sol = 'sol';
case aes = 'aes';
case sparql = 'sparql';
case sql = 'sql';
case st = 'st';
case swift = 'swift';
case systemverilog = 'systemverilog';
case verilog = 'verilog';
case tcl = 'tcl';
case twig = 'twig';
case typescript = 'typescript';
case typespec = 'typespec';
case vb = 'vb';
case wgsl = 'wgsl';
case xml = 'xml';
case yaml = 'yaml';
public static function fromWithAlias(string $match): self
{
return match ($match) {
'h' => self::c,
'cc', 'hpp' => self::cpp,
'cs' => self::csharp,
'class' => self::java,
'htm' => self::html,
'js', 'mjs', 'cjs' => self::javascript,
'kt', 'kts' => self::kotlin,
'md' => self::markdown,
'm' => self::objectivec,
'pl', 'pm' => self::perl,
'php3', 'php4', 'php5', 'phtml' => self::php,
'py', 'pyc', 'pyo', 'pyi' => self::python,
'rdata', 'rds' => self::r,
'rb', 'erb' => self::ruby,
'sc' => self::scala,
'sh', 'zsh' => self::shell,
'ts', 'tsx' => self::typescript,
'yml' => self::yaml,
default => self::tryFrom($match) ?? self::plaintext,
};
}
public function getLabel(): string
{
return $this->name;
}
}

View File

@@ -13,4 +13,5 @@ enum RolePermissionModels: string
case Role = 'role';
case Server = 'server';
case User = 'user';
case Webhook = 'webhook';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Enums;
enum ServerResourceType
{
case Unit;
case Percentage;
case Time;
}

View File

@@ -2,7 +2,11 @@
namespace App\Enums;
enum ServerState: string
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Contracts\HasLabel;
enum ServerState: string implements HasColor, HasIcon, HasLabel
{
case Normal = 'normal';
case Installing = 'installing';
@@ -11,7 +15,7 @@ enum ServerState: string
case Suspended = 'suspended';
case RestoringBackup = 'restoring_backup';
public function icon(): string
public function getIcon(): string
{
return match ($this) {
self::Normal => 'tabler-heart',
@@ -23,7 +27,7 @@ enum ServerState: string
};
}
public function color(): string
public function getColor(): string
{
return match ($this) {
self::Normal => 'primary',
@@ -34,4 +38,9 @@ enum ServerState: string
self::RestoringBackup => 'primary',
};
}
public function getLabel(): string
{
return str($this->value)->headline();
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace App\Enums;
enum SuspendAction: string
{
case Suspend = 'suspend';
case Unsuspend = 'unsuspend';
}

View File

@@ -8,9 +8,7 @@ use Illuminate\Database\Eloquent\Model;
class ActivityLogged extends Event
{
public function __construct(public ActivityLog $model)
{
}
public function __construct(public ActivityLog $model) {}
public function is(string $event): bool
{

View File

@@ -7,7 +7,5 @@ use App\Events\Event;
class DirectLogin extends Event
{
public function __construct(public User $user, public bool $remember)
{
}
public function __construct(public User $user, public bool $remember) {}
}

View File

@@ -12,7 +12,5 @@ class FailedCaptcha extends Event
/**
* Create a new event instance.
*/
public function __construct(public string $ip, public string $domain)
{
}
public function __construct(public string $ip, public ?string $message) {}
}

View File

@@ -12,7 +12,5 @@ class FailedPasswordReset extends Event
/**
* Create a new event instance.
*/
public function __construct(public string $ip, public string $email)
{
}
public function __construct(public string $ip, public string $email) {}
}

View File

@@ -7,7 +7,5 @@ use App\Events\Event;
class ProvidedAuthenticationToken extends Event
{
public function __construct(public User $user, public bool $recovery = false)
{
}
public function __construct(public User $user, public bool $recovery = false) {}
}

View File

@@ -2,6 +2,4 @@
namespace App\Events;
abstract class Event
{
}
abstract class Event {}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Created extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Creating extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Deleted extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -13,7 +13,5 @@ class Installed extends Event
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
public function __construct(public Server $server, public bool $successful, public bool $initialInstall) {}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Saving extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -3,17 +3,15 @@
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use App\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Saved extends Event
class SubUserAdded extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
public function __construct(public Subuser $subuser) {}
}

View File

@@ -4,16 +4,15 @@ namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use App\Models\User;
use Illuminate\Queue\SerializesModels;
class Deleting extends Event
class SubUserRemoved extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
public function __construct(public Server $server, public User $user) {}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Updated extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Illuminate\Queue\SerializesModels;
class Updating extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Server $server)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Created extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Subuser $subuser)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Creating extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Subuser $subuser)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Deleted extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Subuser $subuser)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Deleting extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Subuser $subuser)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\User;
use App\Models\User;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class Created extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public User $user)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\User;
use App\Models\User;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class Creating extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public User $user)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\User;
use App\Models\User;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class Deleted extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public User $user)
{
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Events\User;
use App\Models\User;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class Deleting extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public User $user)
{
}
}

View File

@@ -1,7 +0,0 @@
<?php
namespace App\Exceptions;
class AccountNotFoundException extends \Exception
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace App\Exceptions;
class AutoDeploymentException extends \Exception
{
}

View File

@@ -10,9 +10,11 @@ use Illuminate\Http\Request;
use Psr\Log\LoggerInterface;
use Illuminate\Http\Response;
use Illuminate\Container\Container;
use Prologue\Alerts\AlertsMessageBag;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
/**
* @deprecated
*/
class DisplayException extends PanelException implements HttpExceptionInterface
{
public const LEVEL_DEBUG = 'debug';
@@ -41,6 +43,9 @@ class DisplayException extends PanelException implements HttpExceptionInterface
return Response::HTTP_BAD_REQUEST;
}
/**
* @return array<string, string>
*/
public function getHeaders(): array
{
return [];
@@ -67,9 +72,6 @@ class DisplayException extends PanelException implements HttpExceptionInterface
return response()->json(Handler::toArray($this), $this->getStatusCode(), $this->getHeaders());
}
// @phpstan-ignore-next-line
app(AlertsMessageBag::class)->danger($this->getMessage())->flash();
return redirect()->back()->withInput();
}

View File

@@ -20,6 +20,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Mailer\Exception\TransportException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Throwable;
class Handler extends ExceptionHandler
{
@@ -45,6 +46,8 @@ class Handler extends ExceptionHandler
/**
* Maps exceptions to a specific response code. This handles special exception
* types that don't have a defined response code.
*
* @var array<class-string, int>
*/
protected static array $exceptionResponseCodes = [
AuthenticationException::class => 401,
@@ -180,9 +183,16 @@ class Handler extends ExceptionHandler
}
/**
* Return the exception as a JSONAPI representation for use on API requests.
* @param array<string, mixed> $override
* @return array{errors: array{
* code: string,
* status: string,
* detail: string,
* source?: array{line: int, file: string},
* meta?: array{trace: string[], previous: string[]}
* }}|array{errors: array{non-empty-array<string, mixed>}}
*/
protected function convertExceptionToArray(\Throwable $e, array $override = []): array
public static function exceptionToArray(Throwable $e, array $override = []): array
{
$match = self::$exceptionResponseCodes[get_class($e)] ?? null;
@@ -214,7 +224,7 @@ class Handler extends ExceptionHandler
'trace' => Collection::make($e->getTrace())
->map(fn ($trace) => Arr::except($trace, ['args']))
->all(),
'previous' => Collection::make($this->extractPrevious($e))
'previous' => Collection::make(self::extractPrevious($e))
->map(fn ($exception) => $exception->getTrace())
->map(fn ($trace) => Arr::except($trace, ['args']))
->all(),
@@ -225,6 +235,17 @@ class Handler extends ExceptionHandler
return ['errors' => [array_merge($error, $override)]];
}
/**
* Return the exception as a JSONAPI representation for use on API requests.
*
* @param array{detail?: mixed, source?: mixed, meta?: mixed} $override
* @return array{errors?: array<mixed>}
*/
protected function convertExceptionToArray(Throwable $e, array $override = []): array
{
return self::exceptionToArray($e, $override);
}
/**
* Return an array of exceptions that should not be reported.
*/
@@ -244,22 +265,19 @@ class Handler extends ExceptionHandler
return new JsonResponse($this->convertExceptionToArray($exception), JsonResponse::HTTP_UNAUTHORIZED);
}
return redirect()->guest('/auth/login');
return redirect()->guest(route('filament.app.auth.login'));
}
/**
* Extracts all the previous exceptions that lead to the one passed into this
* function being thrown.
*
* @return \Throwable[]
* @return Throwable[]
*/
protected function extractPrevious(\Throwable $e): array
public static function extractPrevious(Throwable $e): array
{
$previous = [];
while ($value = $e->getPrevious()) {
if (!$value instanceof \Throwable) {
break;
}
$previous[] = $value;
$e = $value;
}
@@ -270,10 +288,11 @@ class Handler extends ExceptionHandler
/**
* Helper method to allow reaching into the handler to convert an exception
* into the expected array response type.
*
* @return array<mixed>
*/
public static function toArray(\Throwable $e): array
{
// @phpstan-ignore-next-line
return (new self(app()))->convertExceptionToArray($e);
return self::exceptionToArray($e);
}
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Http\Base;
use App\Exceptions\DisplayException;
class InvalidPasswordProvidedException extends DisplayException
{
}
class InvalidPasswordProvidedException extends DisplayException {}

View File

@@ -1,76 +0,0 @@
<?php
namespace App\Exceptions\Http\Connection;
use Illuminate\Http\Response;
use GuzzleHttp\Exception\GuzzleException;
use App\Exceptions\DisplayException;
use Illuminate\Support\Facades\Context;
/**
* @method \GuzzleHttp\Exception\GuzzleException getPrevious()
*/
class DaemonConnectionException extends DisplayException
{
private int $statusCode = Response::HTTP_GATEWAY_TIMEOUT;
/**
* Every request to the daemon instance will return a unique X-Request-Id header
* which allows for all errors to be efficiently tied to a specific request that
* triggered them, and gives users a more direct method of informing hosts when
* something goes wrong.
*/
private ?string $requestId;
/**
* Throw a displayable exception caused by a daemon connection error.
*/
public function __construct(GuzzleException $previous, bool $useStatusCode = true)
{
/** @var \GuzzleHttp\Psr7\Response|null $response */
$response = method_exists($previous, 'getResponse') ? $previous->getResponse() : null;
$this->requestId = $response?->getHeaderLine('X-Request-Id');
Context::add('request_id', $this->requestId);
if ($useStatusCode) {
$this->statusCode = is_null($response) ? $this->statusCode : $response->getStatusCode();
// There are rare conditions where daemon encounters a panic condition and crashes the
// request being made after content has already been sent over the wire. In these cases
// you can end up with a "successful" response code that is actual an error.
//
// Handle those better here since we shouldn't ever end up in this exception state and
// be returning a 2XX level response.
if ($this->statusCode < 400) {
$this->statusCode = Response::HTTP_BAD_GATEWAY;
}
}
if (is_null($response)) {
$message = 'Could not establish a connection to the machine running this server. Please try again.';
} else {
$message = sprintf('There was an error while communicating with the machine running this server. This error has been logged, please try again. (code: %s) (request_id: %s)', $response->getStatusCode(), $this->requestId ?? '<nil>');
}
// Attempt to pull the actual error message off the response and return that if it is not
// a 500 level error.
if ($this->statusCode < 500 && !is_null($response)) {
$body = json_decode($response->getBody()->__toString(), true);
$message = sprintf('An error occurred on the remote host: %s. (request id: %s)', $body['error'] ?? $message, $this->requestId ?? '<nil>');
}
$level = $this->statusCode >= 500 && $this->statusCode !== 504
? DisplayException::LEVEL_ERROR
: DisplayException::LEVEL_WARNING;
parent::__construct($message, $previous, $level);
}
/**
* Return the HTTP status code for this exception.
*/
public function getStatusCode(): int
{
return $this->statusCode;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Http\Server;
use App\Exceptions\DisplayException;
class FileTypeNotEditableException extends DisplayException
{
}

View File

@@ -42,6 +42,9 @@ class DataValidationException extends PanelException implements HttpExceptionInt
return 500;
}
/**
* @return array<string, string>
*/
public function getHeaders(): array
{
return [];

View File

@@ -2,6 +2,4 @@
namespace App\Exceptions;
class PanelException extends \Exception
{
}
class PanelException extends \Exception {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Repository\Daemon;
use App\Exceptions\Repository\RepositoryException;
class InvalidPowerSignalException extends RepositoryException
{
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Repository;
use App\Exceptions\DisplayException;
class DuplicateDatabaseNameException extends DisplayException
{
}
class DuplicateDatabaseNameException extends DisplayException {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Repository;
use App\Exceptions\PanelException;
class RepositoryException extends PanelException
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Service\Allocation;
use App\Exceptions\PanelException;
class AllocationDoesNotBelongToServerException extends PanelException
{
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Allocation;
use App\Exceptions\DisplayException;
class ServerUsingAllocationException extends DisplayException
{
}
class ServerUsingAllocationException extends DisplayException {}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Deployment;
use App\Exceptions\DisplayException;
class NoViableAllocationException extends DisplayException
{
}
class NoViableAllocationException extends DisplayException {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Service\Egg;
use App\Exceptions\DisplayException;
class BadJsonFormatException extends DisplayException
{
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Egg;
use App\Exceptions\DisplayException;
class HasChildrenException extends DisplayException
{
}
class HasChildrenException extends DisplayException {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Service\Egg;
use App\Exceptions\DisplayException;
class NoParentConfigurationFoundException extends DisplayException
{
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Egg\Variable;
use App\Exceptions\DisplayException;
class BadValidationRuleException extends DisplayException
{
}
class BadValidationRuleException extends DisplayException {}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Egg\Variable;
use App\Exceptions\DisplayException;
class ReservedVariableNameException extends DisplayException
{
}
class ReservedVariableNameException extends DisplayException {}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service;
use App\Exceptions\DisplayException;
class InvalidFileUploadException extends DisplayException
{
}
class InvalidFileUploadException extends DisplayException {}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Node;
use App\Exceptions\DisplayException;
class ConfigurationNotPersistedException extends DisplayException
{
}
class ConfigurationNotPersistedException extends DisplayException {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Service\Schedule\Task;
use App\Exceptions\DisplayException;
class TaskIntervalTooLongException extends DisplayException
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Service\Server;
use App\Exceptions\PanelException;
class RequiredVariableMissingException extends PanelException
{
}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Subuser;
use App\Exceptions\DisplayException;
class ServerSubuserExistsException extends DisplayException
{
}
class ServerSubuserExistsException extends DisplayException {}

View File

@@ -4,6 +4,4 @@ namespace App\Exceptions\Service\Subuser;
use App\Exceptions\DisplayException;
class UserIsServerOwnerException extends DisplayException
{
}
class UserIsServerOwnerException extends DisplayException {}

View File

@@ -1,9 +0,0 @@
<?php
namespace App\Exceptions\Transformer;
use App\Exceptions\PanelException;
class InvalidTransformerLevelException extends PanelException
{
}

View File

@@ -16,20 +16,19 @@ class BackupManager
{
/**
* The array of resolved backup drivers.
*
* @var array<string, FilesystemAdapter>
*/
protected array $adapters = [];
/**
* The registered custom driver creators.
*
* @var array<string, callable>
*/
protected array $customCreators;
/**
* BackupManager constructor.
*/
public function __construct(protected Application $app)
{
}
public function __construct(protected Application $app) {}
/**
* Returns a backup adapter instance.
@@ -88,6 +87,8 @@ class BackupManager
/**
* Calls a custom creator for a given adapter type.
*
* @param array{adapter: string} $config
*/
protected function callCustomCreator(array $config): mixed
{
@@ -96,6 +97,8 @@ class BackupManager
/**
* Creates a new daemon adapter.
*
* @param array<string, string> $config
*/
public function createWingsAdapter(array $config): FilesystemAdapter
{
@@ -104,6 +107,8 @@ class BackupManager
/**
* Creates a new S3 adapter.
*
* @param array<string, string> $config
*/
public function createS3Adapter(array $config): FilesystemAdapter
{
@@ -120,6 +125,8 @@ class BackupManager
/**
* Returns the configuration associated with a given backup type.
*
* @return array<mixed>
*/
protected function getConfig(string $name): array
{
@@ -149,8 +156,9 @@ class BackupManager
*/
public function forget(array|string $adapter): self
{
$adapters = &$this->adapters;
foreach ((array) $adapter as $adapterName) {
unset($this->adapters[$adapterName]);
unset($adapters[$adapterName]);
}
return $this;

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