Plugins base (#613)

* wip

* wip

* cleanup

* notification channels

* phpstan

* services

* remove server types

* refactoring

* refactoring
This commit is contained in:
Saeed Vaziry
2025-06-14 14:35:18 +02:00
committed by GitHub
parent adc0653d15
commit 131b828807
311 changed files with 3976 additions and 2660 deletions

View File

@ -4,7 +4,10 @@
use App\Actions\Database\ManageBackupFile;
use App\Enums\BackupFileStatus;
use App\Enums\StorageProvider as StorageProviderAlias;
use App\StorageProviders\Dropbox;
use App\StorageProviders\FTP;
use App\StorageProviders\Local;
use App\StorageProviders\S3;
use Carbon\Carbon;
use Database\Factories\BackupFileFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -81,7 +84,7 @@ public function isAvailable(): bool
public function isLocal(): bool
{
return $this->backup->storage->provider === StorageProviderAlias::LOCAL;
return $this->backup->storage->provider === Local::id();
}
/**
@ -103,8 +106,8 @@ public function path(): string
$databaseName = $this->backup->database->name;
return match ($storage->provider) {
StorageProviderAlias::DROPBOX => '/'.$databaseName.'/'.$this->name.'.zip',
StorageProviderAlias::S3, StorageProviderAlias::FTP, StorageProviderAlias::LOCAL => implode('/', [
Dropbox::id() => '/'.$databaseName.'/'.$this->name.'.zip',
S3::id(), FTP::id(), Local::id() => implode('/', [
rtrim((string) $storage->credentials['path'], '/'),
$databaseName,
$this->name.'.zip',

View File

@ -3,6 +3,7 @@
namespace App\Models;
use App\Enums\CronjobStatus;
use Database\Factories\CronJobFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -18,7 +19,7 @@
*/
class CronJob extends AbstractModel
{
/** @use HasFactory<\Database\Factories\CronJobFactory> */
/** @use HasFactory<CronJobFactory> */
use HasFactory;
protected $fillable = [

View File

@ -3,6 +3,7 @@
namespace App\Models;
use App\Enums\DatabaseUserStatus;
use Database\Factories\DatabaseUserFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -17,7 +18,7 @@
*/
class DatabaseUser extends AbstractModel
{
/** @use HasFactory<\Database\Factories\DatabaseUserFactory> */
/** @use HasFactory<DatabaseUserFactory> */
use HasFactory;
protected $fillable = [

View File

@ -2,6 +2,7 @@
namespace App\Models;
use Database\Factories\FileFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -23,7 +24,7 @@
*/
class File extends AbstractModel
{
/** @use HasFactory<\Database\Factories\FileFactory> */
/** @use HasFactory<FileFactory> */
use HasFactory;
protected $fillable = [

View File

@ -3,6 +3,7 @@
namespace App\Models;
use App\Exceptions\FailedToDestroyGitHook;
use Database\Factories\GitHookFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -19,7 +20,7 @@
*/
class GitHook extends AbstractModel
{
/** @use HasFactory<\Database\Factories\GitHookFactory> */
/** @use HasFactory<GitHookFactory> */
use HasFactory;
protected $fillable = [

View File

@ -42,7 +42,7 @@ class NotificationChannel extends AbstractModel
public function provider(): \App\NotificationChannels\NotificationChannel
{
$class = config('core.notification_channels_providers_class')[$this->provider];
$class = config('notification-channel.providers.'.$this->provider.'.handler');
/** @var \App\NotificationChannels\NotificationChannel $provider */
$provider = new $class($this);

View File

@ -3,6 +3,7 @@
namespace App\Models;
use Carbon\Carbon;
use Database\Factories\ScriptFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -25,7 +26,7 @@
*/
class Script extends AbstractModel
{
/** @use HasFactory<\Database\Factories\ScriptFactory> */
/** @use HasFactory<ScriptFactory> */
use HasFactory;
protected $fillable = [

View File

@ -4,6 +4,7 @@
use App\Enums\ScriptExecutionStatus;
use Carbon\Carbon;
use Database\Factories\ScriptExecutionFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -23,7 +24,7 @@
*/
class ScriptExecution extends AbstractModel
{
/** @use HasFactory<\Database\Factories\ScriptExecutionFactory> */
/** @use HasFactory<ScriptExecutionFactory> */
use HasFactory;
protected $fillable = [

View File

@ -7,10 +7,9 @@
use App\Enums\ServiceStatus;
use App\Exceptions\SSHError;
use App\Facades\SSH;
use App\ServerTypes\ServerType;
use App\SSH\Cron\Cron;
use App\SSH\OS\Cron;
use App\SSH\OS\OS;
use App\SSH\Systemd\Systemd;
use App\SSH\OS\Systemd;
use App\Support\Testing\SSHFake;
use Carbon\Carbon;
use Database\Factories\ServerFactory;
@ -81,8 +80,6 @@ class Server extends AbstractModel
'local_ip',
'port',
'os',
'type',
'type_data',
'provider',
'provider_id',
'provider_data',
@ -101,7 +98,6 @@ class Server extends AbstractModel
protected $casts = [
'project_id' => 'integer',
'user_id' => 'integer',
'type_data' => 'json',
'port' => 'integer',
'provider_data' => 'json',
'authentication' => 'encrypted:json',
@ -410,19 +406,9 @@ public function installedNodejsVersions(): array
return $versions;
}
public function type(): ServerType
{
$typeClass = config('core.server_types_class')[$this->type];
/** @var ServerType $type */
$type = new $typeClass($this);
return $type;
}
public function provider(): \App\ServerProviders\ServerProvider
{
$providerClass = config('core.server_providers_class')[$this->provider];
$providerClass = config('server-provider.providers.'.$this->provider.'.handler');
/** @var \App\ServerProviders\ServerProvider $provider */
$provider = new $providerClass($this->serverProvider ?? new ServerProvider, $this);

View File

@ -67,7 +67,7 @@ public function servers(): HasMany
public function provider(): \App\ServerProviders\ServerProvider
{
$providerClass = config('core.server_providers_class')[$this->provider];
$providerClass = config('server-provider.providers.'.$this->provider.'.handler');
/** @var \App\ServerProviders\ServerProvider $provider */
$provider = new $providerClass($this, new Server);

View File

@ -5,15 +5,16 @@
use App\Actions\Service\Manage;
use App\Enums\ServiceStatus;
use App\Exceptions\ServiceInstallationFailed;
use App\SSH\Services\Firewall\Firewall;
use App\SSH\Services\PHP\PHP;
use App\SSH\Services\ProcessManager\ProcessManager;
use App\SSH\Services\ServiceInterface;
use App\SSH\Services\Webserver\Webserver;
use App\Services\Firewall\Firewall;
use App\Services\PHP\PHP;
use App\Services\ProcessManager\ProcessManager;
use App\Services\ServiceInterface;
use App\Services\Webserver\Webserver;
use Database\Factories\ServiceFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
use InvalidArgumentException;
/**
* @property int $server_id
@ -50,17 +51,6 @@ class Service extends AbstractModel
'is_default' => 'boolean',
];
public static function boot(): void
{
parent::boot();
static::creating(function (Service $service): void {
if (array_key_exists($service->name, config('core.service_units'))) {
$service->unit = config('core.service_units')[$service->name][$service->server->os][$service->version];
}
});
}
/**
* @var array<string, string>
*/
@ -87,9 +77,14 @@ public function server(): BelongsTo
return $this->belongsTo(Server::class);
}
public function handler(): ServiceInterface|Webserver|PHP|Firewall|\App\SSH\Services\Database\Database|ProcessManager
public function handler(): ServiceInterface|Webserver|PHP|Firewall|\App\Services\Database\Database|ProcessManager
{
$handler = config('core.service_handlers')[$this->name];
$name = $this->name;
$handler = config("service.services.$name.handler");
if (! $handler) {
throw new InvalidArgumentException("Service handler for $name is not defined.");
}
/** @var ServiceInterface $service */
$service = new $handler($this);
@ -109,26 +104,26 @@ public function validateInstall(string $result): void
public function start(): void
{
$this->unit && app(Manage::class)->start($this);
$this->handler()->unit() && app(Manage::class)->start($this);
}
public function stop(): void
{
$this->unit && app(Manage::class)->stop($this);
$this->handler()->unit() && app(Manage::class)->stop($this);
}
public function restart(): void
{
$this->unit && app(Manage::class)->restart($this);
$this->handler()->unit() && app(Manage::class)->restart($this);
}
public function enable(): void
{
$this->unit && app(Manage::class)->enable($this);
$this->handler()->unit() && app(Manage::class)->enable($this);
}
public function disable(): void
{
$this->unit && app(Manage::class)->disable($this);
$this->handler()->unit() && app(Manage::class)->disable($this);
}
}

View File

@ -8,9 +8,10 @@
use App\Exceptions\FailedToDestroyGitHook;
use App\Exceptions\SourceControlIsNotConnected;
use App\Exceptions\SSHError;
use App\Services\PHP\PHP;
use App\Services\Webserver\Webserver;
use App\SiteFeatures\ActionInterface;
use App\SiteTypes\SiteType;
use App\SSH\Services\PHP\PHP;
use App\SSH\Services\Webserver\Webserver;
use App\Traits\HasProjectThroughServer;
use Database\Factories\SiteFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -20,6 +21,7 @@
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use RuntimeException;
/**
* @property int $server_id
@ -237,12 +239,15 @@ public function getAliasesString(): string
public function type(): SiteType
{
$typeClass = config('core.site_types_class.'.$this->type);
$handlerClass = config('site.types.'.$this->type.'.handler');
if (! class_exists($handlerClass)) {
throw new RuntimeException("Site type handler class {$handlerClass} does not exist.");
}
/** @var SiteType $type */
$type = new $typeClass($this);
/** @var SiteType $handler */
$handler = new $handlerClass($this);
return $type;
return $handler;
}
public function php(): ?Service
@ -352,11 +357,6 @@ public function getSshKeyName(): string
return str('site_'.$this->id)->toString();
}
public function hasFeature(string $feature): bool
{
return in_array($feature, $this->type()->supportedFeatures());
}
public function getEnv(): string
{
try {
@ -438,4 +438,25 @@ public function activeRedirects(): HasMany
{
return $this->redirects()->whereIn('status', [RedirectStatus::CREATING, RedirectStatus::READY]);
}
/**
* @return array<string, mixed>
*/
public function features(): array
{
$features = config('site.types.'.$this->type.'.features', []);
foreach ($features as $featureKey => $feature) {
foreach ($feature['actions'] ?? [] as $actionKey => $action) {
$handlerClass = $action['handler'] ?? null;
if ($handlerClass && class_exists($handlerClass)) {
/** @var ActionInterface $handler */
$handler = new $handlerClass($this);
$action['active'] = $handler->active();
}
$features[$featureKey]['actions'][$actionKey] = $action;
}
}
return $features;
}
}

View File

@ -3,6 +3,7 @@
namespace App\Models;
use App\SourceControlProviders\SourceControlProvider;
use Database\Factories\SourceControlFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -19,7 +20,7 @@
*/
class SourceControl extends AbstractModel
{
/** @use HasFactory<\Database\Factories\SourceControlFactory> */
/** @use HasFactory<SourceControlFactory> */
use HasFactory;
use SoftDeletes;
@ -41,7 +42,7 @@ class SourceControl extends AbstractModel
public function provider(): SourceControlProvider
{
$providerClass = config('core.source_control_providers_class')[$this->provider];
$providerClass = config('source-control.providers.'.$this->provider.'.handler');
/** @var SourceControlProvider $provider */
$provider = new $providerClass($this);

View File

@ -45,10 +45,10 @@ public function user(): BelongsTo
public function provider(): \App\StorageProviders\StorageProvider
{
$providerClass = config('core.storage_providers_class')[$this->provider];
$providerClass = config('storage-provider.providers.'.$this->provider.'.handler');
/** @var \App\StorageProviders\StorageProvider $provider */
$provider = new $providerClass($this);
$provider = new $providerClass($this, new Server);
return $provider;
}

View File

@ -3,7 +3,7 @@
namespace App\Models;
use App\Enums\WorkerStatus;
use App\SSH\Services\ProcessManager\ProcessManager;
use App\Services\ProcessManager\ProcessManager;
use Database\Factories\WorkerFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -21,6 +21,7 @@
* @property int $redirect_stderr
* @property string $stdout_logfile
* @property string $status
* @property string $name
* @property Server $server
* @property Site $site
*/
@ -40,6 +41,7 @@ class Worker extends AbstractModel
'redirect_stderr',
'stdout_logfile',
'status',
'name',
];
protected $casts = [