Migrate to HTMX (#114)

Dropped Livewire
Added HTMX
Added Blade code lint
Drop Mysql and Redis
Migrate to SQLite
This commit is contained in:
Saeed Vaziry 2024-03-06 17:02:59 +01:00 committed by GitHub
parent 5b2c419e91
commit b2083fc6b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
486 changed files with 8609 additions and 8707 deletions

15
.prettierrc Normal file
View File

@ -0,0 +1,15 @@
{
"plugins": ["prettier-plugin-blade", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": ["*.blade.php"],
"options": {
"parser": "blade",
"printWidth": 120,
"htmlWhitespaceSensitivity": "ignore",
"tabWidth": 4,
"quoteProps": "consistent"
}
}
]
}

View File

@ -39,7 +39,6 @@ ## Credits
- Laravel
- Tailwindcss
- Livewire
- Alpinejs
- Vite
- Laravel Enum by BenSampo

View File

@ -5,12 +5,17 @@
use App\Enums\CronjobStatus;
use App\Models\CronJob;
use App\Models\Server;
use App\SSHCommands\CronJob\UpdateCronJobsCommand;
use App\ValidationRules\CronRule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Throwable;
class CreateCronJob
{
/**
* @throws Throwable
*/
public function create(Server $server, array $input): void
{
$this->validate($input);
@ -19,11 +24,17 @@ public function create(Server $server, array $input): void
'server_id' => $server->id,
'user' => $input['user'],
'command' => $input['command'],
'frequency' => $input['frequency'],
'frequency' => $input['frequency'] == 'custom' ? $input['custom'] : $input['frequency'],
'status' => CronjobStatus::CREATING,
]);
$cronJob->save();
$cronJob->addToServer();
$server->ssh()->exec(
new UpdateCronJobsCommand($cronJob->user, CronJob::crontab($server, $cronJob->user)),
'update-crontab'
);
$cronJob->status = CronjobStatus::READY;
$cronJob->save();
}
/**
@ -41,8 +52,17 @@ private function validate(array $input): void
],
'frequency' => [
'required',
new CronRule(),
new CronRule(acceptCustom: true),
],
])->validateWithBag('createCronJob');
])->validate();
if ($input['frequency'] == 'custom') {
Validator::make($input, [
'custom' => [
'required',
new CronRule(),
],
])->validate();
}
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Actions\CronJob;
use App\Models\CronJob;
use App\Models\Server;
use App\SSHCommands\CronJob\UpdateCronJobsCommand;
use Throwable;
class DeleteCronJob
{
/**
* @throws Throwable
*/
public function delete(Server $server, CronJob $cronJob): void
{
$user = $cronJob->user;
$cronJob->delete();
$server->ssh()->exec(
new UpdateCronJobsCommand($user, CronJob::crontab($server, $user)),
'update-crontab'
);
}
}

View File

@ -24,10 +24,10 @@ public function create($type, Server $server, array $input): Backup
$backup = new Backup([
'type' => $type,
'server_id' => $server->id,
'database_id' => $input['database'] ?? null,
'storage_id' => $input['storage'],
'interval' => $input['interval'] == 'custom' ? $input['custom'] : $input['interval'],
'keep_backups' => $input['keep'],
'database_id' => $input['backup_database'] ?? null,
'storage_id' => $input['backup_storage'],
'interval' => $input['backup_interval'] == 'custom' ? $input['backup_custom'] : $input['backup_interval'],
'keep_backups' => $input['backup_keep'],
'status' => BackupStatus::RUNNING,
]);
$backup->save();
@ -43,16 +43,16 @@ public function create($type, Server $server, array $input): Backup
private function validate($type, Server $server, array $input): void
{
$rules = [
'storage' => [
'backup_storage' => [
'required',
Rule::exists('storage_providers', 'id'),
],
'keep' => [
'backup_keep' => [
'required',
'numeric',
'min:1',
],
'interval' => [
'backup_interval' => [
'required',
Rule::in([
'0 * * * *',
@ -63,13 +63,13 @@ private function validate($type, Server $server, array $input): void
]),
],
];
if ($input['interval'] == 'custom') {
$rules['custom'] = [
if ($input['backup_interval'] == 'custom') {
$rules['backup_custom'] = [
'required',
];
}
if ($type === 'database') {
$rules['database'] = [
$rules['backup_database'] = [
'required',
Rule::exists('databases', 'id')
->where('server_id', $server->id)

View File

@ -2,6 +2,7 @@
namespace App\Actions\Database;
use App\Enums\DatabaseStatus;
use App\Models\Database;
use App\Models\Server;
use Illuminate\Support\Facades\Validator;
@ -22,7 +23,10 @@ public function create(Server $server, array $input): Database
'name' => $input['name'],
]);
$database->save();
$database->createOnServer();
$server->database()->handler()->create($database->name);
$database->status = DatabaseStatus::READY;
$database->save();
return $database;
}

View File

@ -2,6 +2,7 @@
namespace App\Actions\Database;
use App\Enums\DatabaseUserStatus;
use App\Models\DatabaseUser;
use App\Models\Server;
use Illuminate\Support\Facades\Validator;
@ -25,7 +26,18 @@ public function create(Server $server, array $input, array $links = []): Databas
'databases' => $links,
]);
$databaseUser->save();
$databaseUser->createOnServer();
$server->database()->handler()->createUser(
$databaseUser->username,
$databaseUser->password,
$databaseUser->host
);
$databaseUser->status = DatabaseUserStatus::READY;
$databaseUser->save();
if (count($databaseUser->databases) > 0) {
app(LinkUser::class)->link($databaseUser, $databaseUser->databases);
}
return $databaseUser;
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Actions\Database;
use App\Models\Database;
use App\Models\Server;
class DeleteDatabase
{
public function delete(Server $server, Database $database): void
{
$server->database()->handler()->delete($database->name);
$database->delete();
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Actions\Database;
use App\Models\DatabaseUser;
use App\Models\Server;
class DeleteDatabaseUser
{
public function delete(Server $server, DatabaseUser $databaseUser): void
{
$server->database()->handler()->deleteUser($databaseUser->username, $databaseUser->host);
$databaseUser->delete();
}
}

View File

@ -4,6 +4,9 @@
use App\Models\Database;
use App\Models\DatabaseUser;
use App\Models\Server;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
class LinkUser
@ -11,20 +14,50 @@ class LinkUser
/**
* @throws ValidationException
*/
public function link(DatabaseUser $databaseUser, array $databases): void
public function link(DatabaseUser $databaseUser, array $input): void
{
if (! isset($input['databases']) || ! is_array($input['databases'])) {
$input['databases'] = [];
}
$this->validate($databaseUser->server, $input);
$dbs = Database::query()
->where('server_id', $databaseUser->server_id)
->whereIn('name', $databases)
->whereIn('name', $input['databases'])
->count();
if (count($databases) !== $dbs) {
if (count($input['databases']) !== $dbs) {
throw ValidationException::withMessages(['databases' => __('Databases not found!')])
->errorBag('linkUser');
}
$databaseUser->databases = $databases;
$databaseUser->unlinkUser();
$databaseUser->linkUser();
$databaseUser->databases = $input['databases'];
// Unlink the user from all databases
$databaseUser->server->database()->handler()->unlink(
$databaseUser->username,
$databaseUser->host
);
// Link the user to the selected databases
$databaseUser->server->database()->handler()->link(
$databaseUser->username,
$databaseUser->host,
$databaseUser->databases
);
$databaseUser->save();
}
private function validate(Server $server, array $input): void
{
$rules = [
'databases.*' => [
'required',
Rule::exists('databases', 'name')->where('server_id', $server->id),
],
];
Validator::make($input, $rules)->validate();
}
}

View File

@ -24,7 +24,19 @@ public function create(Server $server, array $input): FirewallRule
'status' => FirewallRuleStatus::CREATING,
]);
$rule->save();
$rule->addToServer();
$server->firewall()
->handler()
->addRule(
$rule->type,
$rule->real_protocol,
$rule->port,
$rule->source,
$rule->mask
);
$rule->status = FirewallRuleStatus::READY;
$rule->save();
return $rule;
}
@ -56,6 +68,6 @@ private function validate(Server $server, array $input): void
'mask' => [
'numeric',
],
])->validateWithBag('createRule');
])->validate();
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Actions\FirewallRule;
use App\Enums\FirewallRuleStatus;
use App\Models\FirewallRule;
use App\Models\Server;
class DeleteRule
{
public function delete(Server $server, FirewallRule $rule): void
{
$rule->status = FirewallRuleStatus::DELETING;
$rule->save();
$server->firewall()
->handler()
->removeRule(
$rule->type,
$rule->real_protocol,
$rule->port,
$rule->source,
$rule->mask
);
$rule->delete();
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Actions\PHP;
use App\Enums\ServiceStatus;
use App\Models\Server;
use Illuminate\Validation\ValidationException;
class ChangeDefaultCli
{
public function change(Server $server, array $input): void
{
$this->validate($server, $input);
$service = $server->php($input['version']);
$service->handler()->setDefaultCli();
$server->defaultService('php')->update(['is_default' => 0]);
$service->update(['is_default' => 1]);
$service->update(['status' => ServiceStatus::READY]);
}
public function validate(Server $server, array $input): void
{
if (! isset($input['version']) || ! in_array($input['version'], $server->installedPHPVersions())) {
throw ValidationException::withMessages(
['version' => __('This version is not installed')]
);
}
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Actions\PHP;
use App\Models\Server;
use App\SSHCommands\PHP\GetPHPIniCommand;
use Illuminate\Validation\ValidationException;
class GetPHPIni
{
public function getIni(Server $server, array $input): string
{
$this->validate($server, $input);
try {
return $server->ssh()->exec(new GetPHPIniCommand($input['version']));
} catch (\Throwable $e) {
throw ValidationException::withMessages(
['ini' => $e->getMessage()]
);
}
}
public function validate(Server $server, array $input): void
{
if (! isset($input['version']) || ! in_array($input['version'], $server->installedPHPVersions())) {
throw ValidationException::withMessages(
['version' => __('This version is not installed')]
);
}
}
}

View File

@ -41,12 +41,12 @@ private function validate(Server $server, array $input): void
'required',
Rule::in(config('core.php_versions')),
],
])->validateWithBag('installPHP');
])->validate();
if (in_array($input['version'], $server->installedPHPVersions())) {
throw ValidationException::withMessages(
['version' => __('This version is already installed')]
)->errorBag('installPHP');
);
}
}
}

View File

@ -2,8 +2,10 @@
namespace App\Actions\PHP;
use App\Models\Server;
use App\Models\Service;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
class InstallPHPExtension
@ -11,16 +13,18 @@ class InstallPHPExtension
/**
* @throws ValidationException
*/
public function handle(Service $service, array $input): Service
public function install(Server $server, array $input): Service
{
$this->validate($server, $input);
/** @var Service $service */
$service = $server->php($input['version']);
$typeData = $service->type_data;
$typeData['extensions'] = $typeData['extensions'] ?? [];
$service->type_data = $typeData;
$service->save();
$this->validate($service, $input);
$service->handler()->installExtension($input['name']);
$service->handler()->installExtension($input['extension']);
return $service;
}
@ -28,18 +32,25 @@ public function handle(Service $service, array $input): Service
/**
* @throws ValidationException
*/
private function validate(Service $service, array $input): void
private function validate(Server $server, array $input): void
{
Validator::make($input, [
'name' => [
'extension' => [
'required',
'in:'.implode(',', config('core.php_extensions')),
],
])->validateWithBag('installPHPExtension');
'version' => [
'required',
Rule::in($server->installedPHPVersions()),
],
])->validate();
if (in_array($input['name'], $service->type_data['extensions'])) {
/** @var Service $service */
$service = $server->php($input['version']);
if (in_array($input['extension'], $service->type_data['extensions'])) {
throw ValidationException::withMessages(
['name' => __('This extension already installed')]
['extension' => __('This extension already installed')]
)->errorBag('installPHPExtension');
}
}

View File

@ -4,16 +4,17 @@
use App\Models\Server;
use App\Models\Service;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class UninstallPHP
{
public function uninstall(Server $server, string $version): void
public function uninstall(Server $server, array $input): void
{
$this->validate($server, $version);
$this->validate($server, $input);
/** @var Service $php */
$php = $server->services()->where('type', 'php')->where('version', $version)->first();
$php = $server->php($input['version']);
$php->uninstall();
}
@ -21,17 +22,19 @@ public function uninstall(Server $server, string $version): void
/**
* @throws ValidationException
*/
private function validate(Server $server, string $version): void
private function validate(Server $server, array $input): void
{
$php = $server->services()->where('type', 'php')->where('version', $version)->first();
Validator::make($input, [
'version' => 'required|string',
])->validate();
if (! $php) {
if (! in_array($input['version'], $server->installedPHPVersions())) {
throw ValidationException::withMessages(
['version' => __('This version has not been installed yet!')]
['version' => __('This version is not installed')]
);
}
$hasSite = $server->sites()->where('php_version', $version)->first();
$hasSite = $server->sites()->where('php_version', $input['version'])->first();
if ($hasSite) {
throw ValidationException::withMessages(
['version' => __('Cannot uninstall this version because some sites are using it!')]

View File

@ -2,8 +2,9 @@
namespace App\Actions\PHP;
use App\Models\Service;
use App\Models\Server;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Throwable;
@ -13,14 +14,18 @@ class UpdatePHPIni
/**
* @throws ValidationException
*/
public function update(Service $service, string $ini): void
public function update(Server $server, array $input): void
{
$this->validate($server, $input);
$service = $server->php($input['version']);
$tmpName = Str::random(10).strtotime('now');
try {
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
$storageDisk = Storage::disk('local');
$storageDisk->put($tmpName, $ini);
$storageDisk->put($tmpName, $input['ini']);
$service->server->ssh('root')->upload(
$storageDisk->path($tmpName),
"/etc/php/$service->version/cli/php.ini"
@ -42,4 +47,21 @@ private function deleteTempFile(string $name): void
Storage::disk('local')->delete($name);
}
}
public function validate(Server $server, array $input): void
{
Validator::make($input, [
'ini' => [
'required',
'string',
],
'version' => 'required|string',
])->validate();
if (! in_array($input['version'], $server->installedPHPVersions())) {
throw ValidationException::withMessages(
['version' => __('This version is not installed')]
);
}
}
}

View File

@ -8,11 +8,8 @@
class DeleteProject
{
public function delete(User $user, int $projectId): void
public function delete(User $user, Project $project): void
{
/** @var Project $project */
$project = $user->projects()->findOrFail($projectId);
if ($user->projects()->count() === 1) {
throw ValidationException::withMessages([
'project' => __('Cannot delete the last project.'),

View File

@ -26,7 +26,7 @@ private function validate(Project $project, array $input): void
'required',
'string',
'max:255',
Rule::unique('projects')->ignore($project->id),
Rule::unique('projects')->where('user_id', $project->user_id)->ignore($project->id),
],
])->validate();
}

View File

@ -60,6 +60,6 @@ protected function validate(array $input): void
],
];
Validator::make($input, $rules)->validateWithBag('createQueue');
Validator::make($input, $rules)->validate();
}
}

View File

@ -42,6 +42,6 @@ protected function validate(array $input): void
$rules['private'] = 'required';
}
Validator::make($input, $rules)->validateWithBag('createSSL');
Validator::make($input, $rules)->validate();
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Actions\Server;
use App\Facades\Notifier;
use App\Models\Server;
use App\Notifications\ServerDisconnected;
use Throwable;
class CheckConnection
{
public function check(Server $server): Server
{
$status = $server->status;
try {
$server->ssh()->connect();
$server->refresh();
if ($status == 'disconnected') {
$server->status = 'ready';
$server->save();
}
} catch (Throwable) {
$server->status = 'disconnected';
$server->save();
Notifier::send($server, new ServerDisconnected($server));
}
return $server;
}
}

View File

@ -30,7 +30,7 @@ public function create(User $creator, array $input): Server
'user_id' => $creator->id,
'name' => $input['name'],
'ssh_user' => config('core.server_providers_default_user')[$input['provider']][$input['os']],
'ip' => $input['ip'],
'ip' => $input['ip'] ?? '',
'port' => $input['port'] ?? 22,
'os' => $input['os'],
'type' => $input['type'],

View File

@ -35,7 +35,7 @@ public function edit(Server $server, array $input): Server
$server->save();
if ($checkConnection) {
$server->checkConnection();
return $server->checkConnection();
}
return $server;

View File

@ -0,0 +1,24 @@
<?php
namespace App\Actions\Server;
use App\Enums\ServerStatus;
use App\Models\Server;
use App\SSHCommands\System\RebootCommand;
use Throwable;
class RebootServer
{
public function reboot(Server $server): Server
{
try {
$server->ssh()->exec(new RebootCommand(), 'reboot');
$server->status = ServerStatus::DISCONNECTED;
$server->save();
} catch (Throwable) {
$server = $server->checkConnection();
}
return $server;
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace App\Actions\Site;
use App\Models\Site;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class ChangePHPVersion
{
/**
* @throws ValidationException
*/
public function handle(Site $site, array $input): void
{
$this->validate($site, $input);
$site->changePHPVersion($input['php_version']);
}
/**
* @throws ValidationException
*/
protected function validate(Site $site, array $input): void
{
Validator::make($input, [
'php_version' => 'required|in:'.implode(',', $site->server->installedPHPVersions()),
])->validateWithBag('changePHPVersion');
}
}

View File

@ -3,6 +3,7 @@
namespace App\Actions\Site;
use App\Models\Site;
use App\SSHCommands\System\EditFileCommand;
class UpdateEnv
{
@ -13,6 +14,11 @@ public function update(Site $site, array $input): void
$site->type_data = $typeData;
$site->save();
$site->deployEnv();
$site->server->ssh()->exec(
new EditFileCommand(
$site->path.'/.env',
$site->env
)
);
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Actions\Site;
use App\Models\Site;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
class UpdateSourceControl
{
/**
* @throws ValidationException
*/
public function update(Site $site, array $input): void
{
$this->validate($input);
$site->source_control_id = $input['source_control'];
$site->save();
}
/**
* @throws ValidationException
*/
protected function validate(array $input): void
{
Validator::make($input, [
'source_control' => [
'required',
Rule::exists('source_controls', 'id'),
],
])->validate();
}
}

View File

@ -27,11 +27,18 @@ public function create(User $user, array $input): void
$storageProvider->credentials = $storageProvider->provider()->credentialData($input);
if (! $storageProvider->provider()->connect()) {
try {
if (! $storageProvider->provider()->connect()) {
throw ValidationException::withMessages([
'provider' => __("Couldn't connect to the provider"),
]);
}
} catch (\Throwable $e) {
throw ValidationException::withMessages([
'provider' => __("Couldn't connect to the provider"),
'provider' => $e->getMessage(),
]);
}
$storageProvider->save();
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Exceptions;
use Exception;
class SSHCommandError extends Exception
{
//
}

19
app/Facades/Toast.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
/**
* @method static void success(string $message)
* @method static void error(string $message)
* @method static void warning(string $message)
* @method static void info(string $message)
*/
class Toast extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'toast';
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Helpers;
use Illuminate\Http\Response;
class HtmxResponse extends Response
{
public function redirect(string $redirect): self
{
$this->header('HX-Redirect', $redirect);
return $this;
}
public function back(): self
{
return $this->redirect(back()->getTargetUrl());
}
public function refresh(): self
{
$this->header('HX-Refresh', true);
return $this;
}
public function location(string $location): self
{
$this->header('HX-Location', $location);
return $this;
}
}

View File

@ -4,6 +4,8 @@
use App\Contracts\SSHCommand;
use App\Exceptions\SSHAuthenticationError;
use App\Exceptions\SSHCommandError;
use App\Exceptions\SSHConnectionError;
use App\Models\Server;
use App\Models\ServerLog;
use Exception;
@ -99,20 +101,28 @@ public function exec(string|array|SSHCommand $commands, string $log = '', ?int $
$this->log = null;
}
if (! $this->connection) {
$this->connect();
try {
if (! $this->connection) {
$this->connect();
}
} catch (Throwable $e) {
throw new SSHConnectionError($e->getMessage());
}
if (! is_array($commands)) {
$commands = [$commands];
}
$result = '';
foreach ($commands as $command) {
$result .= $this->executeCommand($command);
}
try {
$result = '';
foreach ($commands as $command) {
$result .= $this->executeCommand($command);
}
return $result;
return $result;
} catch (Throwable $e) {
throw new SSHCommandError($e->getMessage());
}
}
/**

View File

@ -2,14 +2,8 @@
namespace App\Helpers;
use Livewire\Component;
class Toast
{
public function __construct(public Component $component)
{
}
public function success(string $message): void
{
$this->toast('success', $message);
@ -32,6 +26,7 @@ public function info(string $message): void
private function toast(string $type, string $message): void
{
$this->component->dispatch('toast', type: $type, message: $message);
session()->flash('toast.type', $type);
session()->flash('toast.message', $message);
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Site\UpdateBranch;
use App\Actions\Site\UpdateDeploymentScript;
use App\Actions\Site\UpdateEnv;
use App\Exceptions\SourceControlIsNotConnected;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Deployment;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ApplicationController extends Controller
{
public function deploy(Server $server, Site $site): HtmxResponse
{
try {
$site->deploy();
Toast::success('Deployment started!');
} catch (SourceControlIsNotConnected $e) {
Toast::error($e->getMessage());
return htmx()->redirect(route('source-controls'));
}
return htmx()->back();
}
public function showDeploymentLog(Server $server, Site $site, Deployment $deployment): RedirectResponse
{
return back()->with('content', $deployment->log->content);
}
public function updateDeploymentScript(Server $server, Site $site, Request $request): RedirectResponse
{
app(UpdateDeploymentScript::class)->update($site, $request->input());
Toast::success('Deployment script updated!');
return back();
}
public function updateBranch(Server $server, Site $site, Request $request): RedirectResponse
{
app(UpdateBranch::class)->update($site, $request->input());
Toast::success('Branch updated!');
return back();
}
public function getEnv(Server $server, Site $site): RedirectResponse
{
return back()->with('env', $site->getEnv());
}
public function updateEnv(Server $server, Site $site, Request $request): RedirectResponse
{
app(UpdateEnv::class)->update($site, $request->input());
Toast::success('Env updated!');
return back();
}
public function enableAutoDeployment(Server $server, Site $site): RedirectResponse
{
if (! $site->auto_deployment) {
try {
$site->enableAutoDeployment();
$site->refresh();
Toast::success('Auto deployment has been enabled.');
} catch (SourceControlIsNotConnected) {
Toast::error('Source control is not connected. Check site\'s settings.');
}
}
return back();
}
public function disableAutoDeployment(Server $server, Site $site): RedirectResponse
{
if ($site->auto_deployment) {
try {
$site->disableAutoDeployment();
$site->refresh();
Toast::success('Auto deployment has been disabled.');
} catch (SourceControlIsNotConnected) {
Toast::error('Source control is not connected. Check site\'s settings.');
}
}
return back();
}
}

View File

@ -2,14 +2,41 @@
namespace App\Http\Controllers;
use App\Actions\CronJob\CreateCronJob;
use App\Actions\CronJob\DeleteCronJob;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\CronJob;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class CronjobController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('cronjobs.index', [
'server' => $server,
'cronjobs' => $server->cronJobs,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
app(CreateCronJob::class)->create($server, $request->input());
Toast::success('Cronjob created successfully.');
return htmx()->back();
}
public function destroy(Server $server, CronJob $cronJob): RedirectResponse
{
app(DeleteCronJob::class)->delete($server, $cronJob);
Toast::success('Cronjob deleted successfully.');
return back();
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Database\CreateBackup;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Backup;
use App\Models\BackupFile;
use App\Models\Database;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseBackupController extends Controller
{
public function show(Server $server, Backup $backup): View
{
return view('databases.backups', [
'server' => $server,
'databases' => $server->databases,
'backup' => $backup,
'files' => $backup->files()->orderByDesc('id')->simplePaginate(10),
]);
}
public function run(Server $server, Backup $backup): RedirectResponse
{
$backup->run();
Toast::success('Backup is running.');
return back();
}
public function store(Server $server, Request $request): HtmxResponse
{
app(CreateBackup::class)->create('database', $server, $request->input());
Toast::success('Backup created successfully.');
return htmx()->back();
}
public function destroy(Server $server, Backup $backup): RedirectResponse
{
$backup->delete();
Toast::success('Backup deleted successfully.');
return back();
}
public function restore(Server $server, Backup $backup, BackupFile $backupFile, Request $request): HtmxResponse
{
$this->validate($request, [
'database' => 'required|exists:databases,id',
]);
/** @var Database $database */
$database = Database::query()->findOrFail($request->input('database'));
$backupFile->restore($database);
Toast::success('Backup restored successfully.');
return htmx()->back();
}
public function destroyFile(Server $server, Backup $backup, BackupFile $backupFile): RedirectResponse
{
$backupFile->delete();
Toast::success('Backup file deleted successfully.');
return back();
}
}

View File

@ -2,9 +2,16 @@
namespace App\Http\Controllers;
use App\Models\Backup;
use App\Actions\Database\CreateDatabase;
use App\Actions\Database\CreateDatabaseUser;
use App\Actions\Database\DeleteDatabase;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Database;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseController extends Controller
{
@ -12,14 +19,31 @@ public function index(Server $server): View
{
return view('databases.index', [
'server' => $server,
'databases' => $server->databases,
'databaseUsers' => $server->databaseUsers,
'backups' => $server->backups,
]);
}
public function backups(Server $server, Backup $backup): View
public function store(Server $server, Request $request): HtmxResponse
{
return view('databases.backups', [
'server' => $server,
'backup' => $backup,
]);
$database = app(CreateDatabase::class)->create($server, $request->input());
if ($request->input('user')) {
app(CreateDatabaseUser::class)->create($server, $request->input(), [$database->name]);
}
Toast::success('Database created successfully.');
return htmx()->back();
}
public function destroy(Server $server, Database $database): RedirectResponse
{
app(DeleteDatabase::class)->delete($server, $database);
Toast::success('Database deleted successfully.');
return back();
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Database\CreateDatabaseUser;
use App\Actions\Database\DeleteDatabaseUser;
use App\Actions\Database\LinkUser;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\DatabaseUser;
use App\Models\Server;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class DatabaseUserController extends Controller
{
public function store(Server $server, Request $request): HtmxResponse
{
$database = app(CreateDatabaseUser::class)->create($server, $request->input());
if ($request->input('user')) {
app(CreateDatabaseUser::class)->create($server, $request->input(), [$database->name]);
}
Toast::success('User created successfully.');
return htmx()->back();
}
public function destroy(Server $server, DatabaseUser $databaseUser): RedirectResponse
{
app(DeleteDatabaseUser::class)->delete($server, $databaseUser);
Toast::success('User deleted successfully.');
return back();
}
public function password(Server $server, DatabaseUser $databaseUser): RedirectResponse
{
return back()->with([
'password' => $databaseUser->password,
]);
}
public function link(Server $server, DatabaseUser $databaseUser, Request $request): HtmxResponse
{
app(LinkUser::class)->link($databaseUser, $request->input());
Toast::success('Database linked successfully.');
return htmx()->back();
}
}

View File

@ -2,14 +2,41 @@
namespace App\Http\Controllers;
use App\Actions\FirewallRule\CreateRule;
use App\Actions\FirewallRule\DeleteRule;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\FirewallRule;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class FirewallController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('firewall.index', [
'server' => $server,
'rules' => $server->firewallRules,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
app(CreateRule::class)->create($server, $request->input());
Toast::success('Firewall rule created!');
return htmx()->back();
}
public function destroy(Server $server, FirewallRule $firewallRule): RedirectResponse
{
app(DeleteRule::class)->delete($server, $firewallRule);
Toast::success('Firewall rule deleted!');
return back();
}
}

View File

@ -2,14 +2,84 @@
namespace App\Http\Controllers;
use App\Actions\PHP\ChangeDefaultCli;
use App\Actions\PHP\GetPHPIni;
use App\Actions\PHP\InstallNewPHP;
use App\Actions\PHP\InstallPHPExtension;
use App\Actions\PHP\UninstallPHP;
use App\Actions\PHP\UpdatePHPIni;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class PHPController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('php.index', [
'server' => $server,
'phps' => $server->services()->where('type', 'php')->get(),
'defaultPHP' => $server->defaultService('php'),
]);
}
public function install(Server $server, Request $request): HtmxResponse
{
try {
app(InstallNewPHP::class)->install($server, $request->input());
Toast::success('PHP is being installed!');
} catch (ValidationException $e) {
Toast::error($e->getMessage());
}
return htmx()->back();
}
public function installExtension(Server $server, Request $request): HtmxResponse
{
app(InstallPHPExtension::class)->install($server, $request->input());
Toast::success('PHP extension is being installed! Check the logs');
return htmx()->back();
}
public function defaultCli(Server $server, Request $request): HtmxResponse
{
app(ChangeDefaultCli::class)->change($server, $request->input());
Toast::success('Default PHP CLI is being changed!');
return htmx()->back();
}
public function getIni(Server $server, Request $request): RedirectResponse
{
$ini = app(GetPHPIni::class)->getIni($server, $request->input());
return back()->with('ini', $ini);
}
public function updateIni(Server $server, Request $request): RedirectResponse
{
app(UpdatePHPIni::class)->update($server, $request->input());
Toast::success('PHP ini updated!');
return back();
}
public function uninstall(Server $server, Request $request): RedirectResponse
{
app(UninstallPHP::class)->uninstall($server, $request->input());
Toast::success('PHP is being uninstalled!');
return back();
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Project;
use App\Models\User;
use Illuminate\Contracts\View\View;
class ProjectController extends Controller
{
public function index(): View
{
return view('projects.index');
}
public function switch($projectId)
{
/** @var User $user */
$user = auth()->user();
/** @var Project $project */
$project = $user->projects()->findOrFail($projectId);
$user->current_project_id = $project->id;
$user->save();
return redirect()->route('servers');
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Http\Controllers;
use App\Actions\Queue\CreateQueue;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Queue;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class QueueController extends Controller
{
public function index(Server $server, Site $site): View
{
return view('queues.index', [
'server' => $server,
'site' => $site,
'queues' => $site->queues,
]);
}
public function store(Server $server, Site $site, Request $request): HtmxResponse
{
app(CreateQueue::class)->create($site, $request->input());
Toast::success('Queue is being created.');
return htmx()->back();
}
public function action(Server $server, Site $site, Queue $queue, string $action): HtmxResponse
{
$queue->{$action}();
Toast::success('Queue is about to '.$action);
return htmx()->back();
}
public function destroy(Server $server, Site $site, Queue $queue): RedirectResponse
{
$queue->remove();
Toast::success('Queue is being deleted.');
return back();
}
}

View File

@ -2,14 +2,62 @@
namespace App\Http\Controllers;
use App\Actions\SshKey\CreateSshKey;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\SshKey;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSHKeyController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('server-ssh-keys.index', [
'server' => $server,
'keys' => $server->sshKeys,
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
/** @var \App\Models\SshKey $key */
$key = app(CreateSshKey::class)->create(
$request->user(),
$request->input()
);
$key->deployTo($server);
Toast::success('SSH Key added and being deployed to the server.');
return htmx()->back();
}
public function destroy(Server $server, SshKey $sshKey): RedirectResponse
{
$sshKey->deleteFrom($server);
Toast::success('SSH Key is being deleted.');
return back();
}
public function deploy(Server $server, Request $request): HtmxResponse
{
$this->validate($request, [
'key_id' => 'required|exists:ssh_keys,id',
]);
/** @var SshKey $sshKey */
$sshKey = SshKey::query()->findOrFail($request->input('key_id'));
$sshKey->deployTo($server);
Toast::success('SSH Key is being deployed to the server.');
return htmx()->back();
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers;
use App\Actions\SSL\CreateSSL;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Site;
use App\Models\Ssl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSLController extends Controller
{
public function index(Server $server, Site $site): View
{
return view('ssls.index', [
'server' => $server,
'site' => $site,
'ssls' => $site->ssls,
]);
}
public function store(Server $server, Site $site, Request $request): HtmxResponse
{
app(CreateSSL::class)->create($site, $request->input());
Toast::success('SSL certificate is being created.');
return htmx()->back();
}
public function destroy(Server $server, Site $site, Ssl $ssl): RedirectResponse
{
$ssl->remove();
Toast::success('SSL certificate is being deleted.');
return back();
}
}

View File

@ -2,27 +2,68 @@
namespace App\Http\Controllers;
use App\Actions\Server\CreateServer;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\ServerProvider;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Throwable;
class ServerController extends Controller
{
public function index()
public function index(): View
{
return view('servers.index');
/** @var User $user */
$user = auth()->user();
$servers = $user->currentProject->servers()->orderByDesc('created_at')->get();
return view('servers.index', compact('servers'));
}
public function create()
public function create(Request $request): View
{
return view('servers.create');
$provider = $request->query('provider', old('provider', \App\Enums\ServerProvider::CUSTOM));
$serverProviders = ServerProvider::query()->where('provider', $provider)->get();
return view('servers.create', [
'serverProviders' => $serverProviders,
'provider' => $provider,
]);
}
public function show(Server $server)
/**
* @throws Throwable
*/
public function store(Request $request): HtmxResponse
{
return view('servers.show', compact('server'));
$server = app(CreateServer::class)->create(
$request->user(),
$request->input()
);
Toast::success('Server created successfully.');
return htmx()->redirect(route('servers.show', ['server' => $server]));
}
public function logs(Server $server)
public function show(Server $server): View
{
return view('servers.logs', compact('server'));
return view('servers.show', [
'server' => $server,
'logs' => $server->logs()->latest()->limit(10)->get(),
]);
}
public function delete(Server $server): RedirectResponse
{
$server->delete();
Toast::success('Server deleted successfully.');
return redirect()->route('servers');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers;
use App\Models\Server;
use App\Models\ServerLog;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
class ServerLogController extends Controller
{
public function index(Server $server): View
{
return view('server-logs.index', [
'server' => $server,
]);
}
public function show(Server $server, ServerLog $serverLog): RedirectResponse
{
if ($server->id != $serverLog->server_id) {
abort(404);
}
return back()->with([
'content' => $serverLog->content,
]);
}
}

View File

@ -2,12 +2,55 @@
namespace App\Http\Controllers;
use App\Actions\Server\EditServer;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServerSettingController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('server-settings.index', compact('server'));
}
public function checkConnection(Server $server): RedirectResponse|HtmxResponse
{
$oldStatus = $server->status;
$server = $server->checkConnection();
if ($server->status == 'disconnected') {
Toast::error('Server is disconnected.');
}
if ($server->status == 'ready') {
Toast::success('Server is ready.');
}
if ($oldStatus != $server->status) {
return htmx()->redirect(back()->getTargetUrl());
}
return back();
}
public function reboot(Server $server): HtmxResponse
{
$server->reboot();
return htmx()->redirect(back()->getTargetUrl());
}
public function edit(Request $request, Server $server): RedirectResponse
{
app(EditServer::class)->edit($server, $request->input());
Toast::success('Server updated.');
return back();
}
}

View File

@ -2,14 +2,46 @@
namespace App\Http\Controllers;
use App\Facades\Toast;
use App\Models\Server;
use App\Models\Service;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
class ServiceController extends Controller
{
public function index(Server $server)
public function index(Server $server): View
{
return view('services.index', [
'server' => $server,
'services' => $server->services,
]);
}
public function start(Server $server, Service $service): RedirectResponse
{
$service->start();
Toast::success('Service is being started!');
return back();
}
public function stop(Server $server, Service $service): RedirectResponse
{
$service->stop();
Toast::success('Service is being stopped!');
return back();
}
public function restart(Server $server, Service $service): RedirectResponse
{
$service->restart();
Toast::success('Service is being restarted!');
return back();
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\NotificationChannels\AddChannel;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\NotificationChannel;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class NotificationChannelController extends Controller
{
public function index(): View
{
return view('settings.notification-channels.index', [
'channels' => NotificationChannel::query()->latest()->get(),
]);
}
public function add(Request $request): HtmxResponse
{
app(AddChannel::class)->add(
$request->user(),
$request->input()
);
Toast::success('Channel added successfully');
return htmx()->redirect(route('notification-channels'));
}
public function delete(int $id): RedirectResponse
{
$channel = NotificationChannel::query()->findOrFail($id);
$channel->delete();
Toast::success('Channel deleted successfully');
return redirect()->route('notification-channels');
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\User\UpdateUserPassword;
use App\Actions\User\UpdateUserProfileInformation;
use App\Facades\Toast;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function index(): View
{
return view('settings.profile.index');
}
public function info(Request $request): RedirectResponse
{
app(UpdateUserProfileInformation::class)->update(
$request->user(),
$request->input()
);
Toast::success('Profile information updated.');
return back();
}
public function password(Request $request): RedirectResponse
{
app(UpdateUserPassword::class)->update(
$request->user(),
$request->input()
);
Toast::success('Password updated.');
return back();
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\Projects\CreateProject;
use App\Actions\Projects\DeleteProject;
use App\Actions\Projects\UpdateProject;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\Project;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class ProjectController extends Controller
{
public function index(): View
{
return view('settings.projects.index', [
'projects' => auth()->user()->projects,
]);
}
public function create(Request $request): HtmxResponse
{
app(CreateProject::class)->create($request->user(), $request->input());
Toast::success('Project created.');
return htmx()->redirect(route('projects'));
}
public function update(Request $request, Project $project): HtmxResponse
{
/** @var Project $project */
$project = $request->user()->projects()->findOrFail($project->id);
app(UpdateProject::class)->update($project, $request->input());
Toast::success('Project updated.');
return htmx()->redirect(route('projects'));
}
public function delete(Project $project): RedirectResponse
{
/** @var Project $project */
$project = auth()->user()->projects()->findOrFail($project->id);
try {
app(DeleteProject::class)->delete(auth()->user(), $project);
} catch (ValidationException $e) {
Toast::error($e->getMessage());
return back();
}
Toast::success('Project deleted.');
return back();
}
public function switch($projectId): RedirectResponse
{
/** @var User $user */
$user = auth()->user();
/** @var Project $project */
$project = $user->projects()->findOrFail($projectId);
$user->current_project_id = $project->id;
$user->save();
return redirect()->route('servers');
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\SshKey\CreateSshKey;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\SshKey;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SSHKeyController extends Controller
{
public function index(): View
{
return view('settings.ssh-keys.index', [
'keys' => SshKey::query()->latest()->get(),
]);
}
public function add(Request $request): HtmxResponse
{
app(CreateSshKey::class)->create(
$request->user(),
$request->input()
);
Toast::success('SSH Key added');
return htmx()->redirect(route('ssh-keys'));
}
public function delete(int $id): RedirectResponse
{
$key = SshKey::query()->findOrFail($id);
$key->delete();
Toast::success('SSH Key deleted');
return redirect()->route('ssh-keys');
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\ServerProvider\CreateServerProvider;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\ServerProvider;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ServerProviderController extends Controller
{
public function index(): View
{
return view('settings.server-providers.index', [
'providers' => auth()->user()->serverProviders,
]);
}
public function connect(Request $request): HtmxResponse
{
app(CreateServerProvider::class)->create(
$request->user(),
$request->input()
);
Toast::success('Server provider connected.');
return htmx()->redirect(route('server-providers'));
}
/**
* @TODO Update servers using this provider
*/
public function delete(int $id): RedirectResponse
{
$serverProvider = ServerProvider::query()->findOrFail($id);
$serverProvider->delete();
Toast::success('Server provider deleted.');
return back();
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\SourceControl\ConnectSourceControl;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\SourceControl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
/**
* @TODO Assign user to source control
*/
class SourceControlController extends Controller
{
public function index(): View
{
return view('settings.source-controls.index', [
'sourceControls' => SourceControl::query()->orderByDesc('id')->get(),
]);
}
public function connect(Request $request): HtmxResponse
{
app(ConnectSourceControl::class)->connect(
$request->input(),
);
Toast::success('Source control connected.');
return htmx()->redirect(route('source-controls'));
}
public function delete(int $id): RedirectResponse
{
$sourceControl = SourceControl::query()->findOrFail($id);
$sourceControl->delete();
Toast::success('Source control deleted.');
return redirect()->route('source-controls');
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Http\Controllers\Settings;
use App\Actions\StorageProvider\CreateStorageProvider;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Http\Controllers\Controller;
use App\Models\StorageProvider;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class StorageProviderController extends Controller
{
public function index(): View
{
return view('settings.storage-providers.index', [
'providers' => auth()->user()->storageProviders,
]);
}
public function connect(Request $request): HtmxResponse
{
app(CreateStorageProvider::class)->create(
$request->user(),
$request->input()
);
Toast::success('Storage provider connected.');
return htmx()->redirect(route('storage-providers'));
}
/**
* @TODO Update servers using this provider
*/
public function delete(int $id): RedirectResponse
{
$storageProvider = StorageProvider::query()->findOrFail($id);
$storageProvider->delete();
Toast::success('Storage provider deleted.');
return back();
}
}

View File

@ -2,9 +2,16 @@
namespace App\Http\Controllers;
use App\Actions\Site\CreateSite;
use App\Enums\SiteType;
use App\Facades\Toast;
use App\Helpers\HtmxResponse;
use App\Models\Server;
use App\Models\Site;
use App\Models\SourceControl;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class SiteController extends Controller
{
@ -12,13 +19,25 @@ public function index(Server $server): View
{
return view('sites.index', [
'server' => $server,
'sites' => $server->sites()->orderByDesc('id')->get(),
]);
}
public function store(Server $server, Request $request): HtmxResponse
{
$site = app(CreateSite::class)->create($server, $request->input());
Toast::success('Site created');
return htmx()->redirect(route('servers.sites.show', [$server, $site]));
}
public function create(Server $server): View
{
return view('sites.create', [
'server' => $server,
'type' => old('type', request()->query('type', SiteType::LARAVEL)),
'sourceControls' => SourceControl::all(),
]);
}
@ -30,43 +49,12 @@ public function show(Server $server, Site $site): View
]);
}
public function application(Server $server, Site $site): View
public function destroy(Server $server, Site $site): RedirectResponse
{
return view('sites.application', [
'server' => $server,
'site' => $site,
]);
}
$site->remove();
public function ssl(Server $server, Site $site): View
{
return view('sites.ssl', [
'server' => $server,
'site' => $site,
]);
}
Toast::success('Site is being deleted');
public function queues(Server $server, Site $site): View
{
return view('sites.queues', [
'server' => $server,
'site' => $site,
]);
}
public function settings(Server $server, Site $site): View
{
return view('sites.settings', [
'server' => $server,
'site' => $site,
]);
}
public function logs(Server $server, Site $site): View
{
return view('sites.logs', [
'server' => $server,
'site' => $site,
]);
return redirect()->route('servers.sites', $server);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Contracts\View\View;
class SiteLogController extends Controller
{
public function index(Server $server, Site $site): View
{
return view('site-logs.index', [
'server' => $server,
'site' => $site,
]);
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers;
use App\Facades\Toast;
use App\Models\Server;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Throwable;
class SiteSettingController extends Controller
{
public function index(Server $server, Site $site): View
{
return view('site-settings.index', [
'server' => $server,
'site' => $site,
]);
}
public function getVhost(Server $server, Site $site): RedirectResponse
{
return back()->with('vhost', $server->webserver()->handler()->getVHost($site));
}
public function updateVhost(Server $server, Site $site, Request $request): RedirectResponse
{
$this->validate($request, [
'vhost' => 'required|string',
]);
try {
$server->webserver()->handler()->updateVHost($site, false, $request->input('vhost'));
Toast::success('VHost updated successfully!');
} catch (Throwable $e) {
Toast::error($e->getMessage());
}
return back();
}
public function updatePHPVersion(Server $server, Site $site, Request $request): RedirectResponse
{
$this->validate($request, [
'version' => [
'required',
Rule::exists('services', 'version')->where('type', 'php'),
],
]);
try {
$site->changePHPVersion($request->input('version'));
Toast::success('PHP version updated successfully!');
} catch (Throwable $e) {
Toast::error($e->getMessage());
}
return back();
}
}

View File

@ -2,6 +2,7 @@
namespace App\Http;
use App\Http\Middleware\HandleSSHErrors;
use App\Http\Middleware\ServerIsReadyMiddleware;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
@ -65,5 +66,6 @@ class Kernel extends HttpKernel
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'server-is-ready' => ServerIsReadyMiddleware::class,
'handle-ssh-errors' => HandleSSHErrors::class,
];
}

View File

@ -1,60 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Exceptions\SourceControlIsNotConnected;
use App\Models\Site;
use App\Traits\HasToast;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Throwable;
class AutoDeployment extends Component
{
use HasToast;
use RefreshComponentOnBroadcast;
public Site $site;
/**
* @throws Throwable
*/
public function enable(): void
{
if (! $this->site->auto_deployment) {
try {
$this->site->enableAutoDeployment();
$this->site->refresh();
$this->toast()->success(__('Auto deployment has been enabled.'));
} catch (SourceControlIsNotConnected) {
$this->toast()->error(__('Source control is not connected. Check site\'s settings.'));
}
}
}
/**
* @throws Throwable
*/
public function disable(): void
{
if ($this->site->auto_deployment) {
try {
$this->site->disableAutoDeployment();
$this->site->refresh();
$this->toast()->success(__('Auto deployment has been disabled.'));
} catch (SourceControlIsNotConnected) {
$this->toast()->error(__('Source control is not connected. Check site\'s settings.'));
}
}
}
public function render(): View
{
return view('livewire.application.auto-deployment');
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Actions\Site\UpdateBranch;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ChangeBranch extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public string $branch;
public function mount(): void
{
$this->branch = $this->site->branch;
}
public function change(): void
{
app(UpdateBranch::class)->update($this->site, $this->all());
session()->flash('status', 'updating-branch');
}
public function render(): View
{
return view('livewire.application.change-branch');
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Exceptions\SourceControlIsNotConnected;
use App\Models\Site;
use App\Traits\HasToast;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class Deploy extends Component
{
use HasToast;
use RefreshComponentOnBroadcast;
public Site $site;
public function deploy(): void
{
try {
$this->site->deploy();
$this->toast()->success(__('Deployment started!'));
$this->dispatch('$refresh')->to(DeploymentsList::class);
$this->dispatch('$refresh')->to(DeploymentScript::class);
} catch (SourceControlIsNotConnected $e) {
session()->flash('toast.type', 'error');
session()->flash('toast.message', $e->getMessage());
$this->redirect(route('source-controls'));
}
}
public function render(): View
{
return view('livewire.application.deploy');
}
}

View File

@ -1,38 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Actions\Site\UpdateDeploymentScript;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DeploymentScript extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public string $script;
public function mount(): void
{
$this->script = $this->site->deploymentScript->content;
}
public function save(): void
{
app(UpdateDeploymentScript::class)->update($this->site, $this->all());
session()->flash('status', 'script-updated');
$this->dispatch('$refresh')->to(Deploy::class);
$this->dispatch('$refresh')->to(AutoDeployment::class);
}
public function render(): View
{
return view('livewire.application.deployment-script');
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Models\Site;
use App\Traits\HasCustomPaginationView;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DeploymentsList extends Component
{
use HasCustomPaginationView;
use RefreshComponentOnBroadcast;
public Site $site;
public string $logContent;
public function showLog(int $id): void
{
$deployment = $this->site->deployments()->findOrFail($id);
$this->logContent = $deployment->log->content;
$this->dispatch('open-modal', 'show-log');
}
public function render(): View
{
return view('livewire.application.deployments-list', [
'deployments' => $this->site->deployments()->latest()->simplePaginate(10),
]);
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Actions\Site\UpdateEnv;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class Env extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public string $env = 'Loading...';
public function loadEnv(): void
{
$this->env = $this->site->getEnv();
}
public function save(): void
{
app(UpdateEnv::class)->update($this->site, $this->all());
session()->flash('status', 'updating-env');
$this->dispatch('$refresh')->to(Deploy::class);
}
public function render(): View
{
return view('livewire.application.env');
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class LaravelApp extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public function render(): View
{
return view('livewire.application.laravel-app');
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class PhpApp extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public function render(): View
{
return view('livewire.application.php-app');
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Livewire\Component;
class PhpBlankApp extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public function render()
{
return view('livewire.application.php-blank-app');
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Http\Livewire\Application;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class WordpressApp extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public function render(): View
{
return view('livewire.application.wordpress-app');
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace App\Http\Livewire;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
class Broadcast extends Component
{
public function render(): View
{
$event = Cache::get('broadcast');
if ($event) {
Cache::forget('broadcast');
$this->dispatch('broadcast', $event);
}
return view('livewire.broadcast');
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace App\Http\Livewire\Cronjobs;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CreateCronjob extends Component
{
public Server $server;
public string $user = '';
public string $command;
public string $frequency = '';
public string $custom;
public function create(): void
{
app(\App\Actions\CronJob\CreateCronJob::class)->create($this->server, $this->all());
$this->dispatch('$refresh')->to(CronjobsList::class);
$this->dispatch('created');
}
public function render(): View
{
return view('livewire.cronjobs.create-cronjob');
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Http\Livewire\Cronjobs;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CronjobsList extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public int $deleteId;
public function delete(): void
{
$cronjob = $this->server->cronJobs()->where('id', $this->deleteId)->firstOrFail();
$cronjob->removeFromServer();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.cronjobs.cronjobs-list', [
'cronjobs' => $this->server->cronJobs,
]);
}
}

View File

@ -1,67 +0,0 @@
<?php
namespace App\Http\Livewire\Databases;
use App\Models\Backup;
use App\Models\BackupFile;
use App\Models\Database;
use App\Models\Server;
use App\Traits\HasCustomPaginationView;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DatabaseBackupFiles extends Component
{
use HasCustomPaginationView;
use RefreshComponentOnBroadcast;
public Server $server;
public Backup $backup;
public string $restoreId = '';
public string $restoreDatabaseId = '';
public int $deleteId;
public function backup(): void
{
$this->backup->run();
$this->refreshComponent([]);
}
public function restore(): void
{
/** @var BackupFile $file */
$file = BackupFile::query()->findOrFail($this->restoreId);
/** @var Database $database */
$database = Database::query()->findOrFail($this->restoreDatabaseId);
$file->restore($database);
$this->refreshComponent([]);
$this->dispatch('restored');
}
public function delete(): void
{
/** @var BackupFile $file */
$file = BackupFile::query()->findOrFail($this->deleteId);
$file->delete();
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.databases.database-backup-files', [
'files' => $this->backup->files()->orderByDesc('id')->simplePaginate(10),
]);
}
}

View File

@ -1,81 +0,0 @@
<?php
namespace App\Http\Livewire\Databases;
use App\Actions\Database\CreateBackup;
use App\Models\Backup;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Livewire\WithPagination;
class DatabaseBackups extends Component
{
use RefreshComponentOnBroadcast;
use WithPagination;
public Server $server;
public int $deleteId;
public string $database = '';
public string $storage = '';
public string $interval = '';
public string $custom = '';
public int $keep = 10;
public ?Backup $backup = null;
protected ?Paginator $files = null;
public function create(): void
{
app(CreateBackup::class)->create('database', $this->server, $this->all());
$this->refreshComponent([]);
$this->dispatch('backup-created');
}
public function files(int $id): void
{
$backup = Backup::query()->findOrFail($id);
$this->backup = $backup;
$this->files = $backup->files()->orderByDesc('id')->simplePaginate(1);
$this->dispatch('show-files');
}
public function backup(): void
{
$this->backup?->run();
$this->files = $this->backup?->files()->orderByDesc('id')->simplePaginate();
$this->dispatch('backup-running');
}
public function delete(): void
{
/** @var Backup $backup */
$backup = Backup::query()->findOrFail($this->deleteId);
$backup->delete();
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.databases.database-backups', [
'backups' => $this->server->backups,
'databases' => $this->server->databases,
'files' => $this->files,
]);
}
}

View File

@ -1,66 +0,0 @@
<?php
namespace App\Http\Livewire\Databases;
use App\Actions\Database\CreateDatabase;
use App\Actions\Database\CreateDatabaseUser;
use App\Models\Database;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DatabaseList extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public int $deleteId;
public string $name;
public bool $user;
public string $username;
public string $password;
public bool $remote = false;
public string $host = '%';
public function create(): void
{
$database = app(CreateDatabase::class)->create($this->server, $this->all());
if ($this->all()['user']) {
app(CreateDatabaseUser::class)->create($this->server, $this->all(), [$database->name]);
}
$this->refreshComponent([]);
$this->dispatch('database-created');
}
public function delete(): void
{
/** @var Database $database */
$database = Database::query()->findOrFail($this->deleteId);
$database->deleteFromServer();
$this->refreshComponent([]);
$this->dispatch('$refresh')->to(DatabaseUserList::class);
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.databases.database-list', [
'databases' => $this->server->databases,
]);
}
}

View File

@ -1,98 +0,0 @@
<?php
namespace App\Http\Livewire\Databases;
use App\Actions\Database\CreateDatabaseUser;
use App\Actions\Database\LinkUser;
use App\Models\DatabaseUser;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DatabaseUserList extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public int $deleteId;
public string $username;
public string $password;
public bool $remote;
public string $host = '%';
public int $linkId;
public array $link = [];
public string $viewPassword = '';
public function create(): void
{
app(CreateDatabaseUser::class)->create($this->server, $this->all());
$this->refreshComponent([]);
$this->dispatch('database-user-created');
}
public function delete(): void
{
/** @var DatabaseUser $databaseUser */
$databaseUser = DatabaseUser::query()->findOrFail($this->deleteId);
$databaseUser->deleteFromServer();
$this->refreshComponent([]);
$this->dispatch('$refresh')->to(DatabaseList::class);
$this->dispatch('confirmed');
}
public function viewPassword(int $id): void
{
/** @var DatabaseUser $databaseUser */
$databaseUser = DatabaseUser::query()->findOrFail($id);
$this->viewPassword = $databaseUser->password;
$this->dispatch('open-modal', 'database-user-password');
}
public function showLink(int $id): void
{
/** @var DatabaseUser $databaseUser */
$databaseUser = DatabaseUser::query()->findOrFail($id);
$this->linkId = $id;
$this->link = $databaseUser->databases ?? [];
$this->dispatch('open-modal', 'link-database-user');
}
public function link(): void
{
/** @var DatabaseUser $databaseUser */
$databaseUser = DatabaseUser::query()->findOrFail($this->linkId);
app(LinkUser::class)->link($databaseUser, $this->link);
$this->refreshComponent([]);
$this->dispatch('linked');
}
public function render(): View
{
return view('livewire.databases.database-user-list', [
'databases' => $this->server->databases,
'databaseUsers' => $this->server->databaseUsers,
]);
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\Firewall;
use App\Actions\FirewallRule\CreateRule;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CreateFirewallRule extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public string $type = 'allow';
public string $protocol = 'tcp';
public string $port;
public string $source = '0.0.0.0';
public string $mask = '';
public function create(): void
{
app(CreateRule::class)->create($this->server, $this->all());
$this->dispatch('$refresh')->to(FirewallRulesList::class);
$this->dispatch('created');
}
public function render(): View
{
return view('livewire.firewall.create-firewall-rule');
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Firewall;
use App\Models\FirewallRule;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class FirewallRulesList extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public int $deleteId;
public function delete(): void
{
/** @var FirewallRule $rule */
$rule = FirewallRule::query()->findOrFail($this->deleteId);
$rule->removeFromServer();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.firewall.firewall-rules-list', [
'rules' => $this->server->firewallRules,
]);
}
}

View File

@ -1,38 +0,0 @@
<?php
namespace App\Http\Livewire\NotificationChannels;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class AddChannel extends Component
{
public string $provider = '';
public string $label;
public string $webhook_url;
public string $email;
public string $bot_token;
public string $chat_id;
public function add(): void
{
app(\App\Actions\NotificationChannels\AddChannel::class)->add(
auth()->user(),
$this->all()
);
$this->dispatch('$refresh')->to(ChannelsList::class);
$this->dispatch('added');
}
public function render(): View
{
return view('livewire.notification-channels.add-channel');
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\NotificationChannels;
use App\Models\NotificationChannel;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ChannelsList extends Component
{
use RefreshComponentOnBroadcast;
public int $deleteId;
protected $listeners = [
'$refresh',
];
public function delete(): void
{
$channel = NotificationChannel::query()->findOrFail($this->deleteId);
$channel->delete();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.notification-channels.channels-list', [
'channels' => NotificationChannel::query()->latest()->get(),
]);
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace App\Http\Livewire\Php;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class DefaultCli extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public function change(string $version): void
{
$this->server->php($version)->handler()->setDefaultCli();
$this->refreshComponent([]);
}
public function render(): View
{
return view('livewire.php.default-cli', [
'defaultPHP' => $this->server->defaultService('php'),
'phps' => $this->server->services()->where('type', 'php')->get(), //
]);
}
}

View File

@ -1,117 +0,0 @@
<?php
namespace App\Http\Livewire\Php;
use App\Actions\PHP\InstallNewPHP;
use App\Actions\PHP\InstallPHPExtension;
use App\Actions\PHP\UpdatePHPIni;
use App\Models\Server;
use App\Models\Service;
use App\SSHCommands\PHP\GetPHPIniCommand;
use App\Traits\RefreshComponentOnBroadcast;
use Exception;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Throwable;
class InstalledVersions extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public int $uninstallId;
public int $iniId;
public string $ini = 'Loading php.ini';
public ?int $extensionId = null;
public string $extension = '';
public function install(string $version): void
{
app(InstallNewPHP::class)->install($this->server, [
'version' => $version,
]);
$this->refreshComponent([]);
}
public function restart(int $id): void
{
/** @var Service $service */
$service = Service::query()->findOrFail($id);
$service->restart();
$this->refreshComponent([]);
}
public function uninstall(): void
{
/** @var Service $service */
$service = Service::query()->findOrFail($this->uninstallId);
$service->uninstall();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function loadIni(int $id): void
{
$this->iniId = $id;
$this->ini = 'Loading php.ini';
/** @var Service $service */
$service = Service::query()->findOrFail($this->iniId);
try {
$this->ini = $service->server->ssh()->exec(new GetPHPIniCommand($service->version));
} catch (Throwable) {
//
}
}
public function saveIni(): void
{
/** @var Service $service */
$service = Service::query()->findOrFail($this->iniId);
app(UpdatePHPIni::class)->update($service, $this->all()['ini']);
$this->refreshComponent([]);
session()->flash('status', 'ini-updated');
}
/**
* @throws Exception
*/
public function installExtension(): void
{
/** @var Service $service */
$service = Service::query()->findOrFail($this->extensionId);
app(InstallPHPExtension::class)->handle($service, [
'name' => $this->extension,
]);
session()->flash('status', 'started-installation');
}
public function render(): View
{
if ($this->extensionId) {
/** @var Service $php */
$php = Service::query()->findOrFail($this->extensionId);
$installedExtensions = $php->type_data['extensions'] ?? [];
}
return view('livewire.php.installed-versions', [
'phps' => $this->server->services()->where('type', 'php')->get(),
'installedExtensions' => $installedExtensions ?? [],
]);
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class TwoFactorAuthentication extends Component
{
public function render(): View
{
return view('livewire.profile.two-factor-authentication');
}
}

View File

@ -1,32 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Actions\User\UpdateUserPassword;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class UpdatePassword extends Component
{
public string $current_password;
public string $password;
public string $password_confirmation;
public function update(): void
{
app(UpdateUserPassword::class)->update(auth()->user(), $this->all());
$this->current_password = '';
$this->password = '';
$this->password_confirmation = '';
session()->flash('status', 'password-updated');
}
public function render(): View
{
return view('livewire.profile.update-password');
}
}

View File

@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Actions\User\UpdateUserProfileInformation;
use App\Http\Livewire\UserDropdown;
use App\Models\User;
use Exception;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class UpdateProfileInformation extends Component
{
public string $name;
public string $email;
public string $timezone;
public function mount(): void
{
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
$this->timezone = auth()->user()->timezone;
}
/**
* @throws Exception
*/
public function submit(): void
{
app(UpdateUserProfileInformation::class)->update(auth()->user(), $this->all());
session()->flash('status', 'profile-updated');
$this->dispatch('$refresh')->to(UserDropdown::class);
}
public function sendVerificationEmail(): void
{
/** @var User $user */
$user = auth()->user();
if (! $user->hasVerifiedEmail()) {
$user->sendEmailVerificationNotification();
session()->flash('status', 'verification-link-sent');
}
}
public function render(): View
{
return view('livewire.profile.update-profile-information');
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Projects;
use App\Traits\HasToast;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CreateProject extends Component
{
use HasToast;
use RefreshComponentOnBroadcast;
public bool $open = false;
public array $inputs = [];
public function create(): void
{
app(\App\Actions\Projects\CreateProject::class)
->create(auth()->user(), $this->inputs);
$this->dispatch('$refresh')->to(ProjectsList::class);
$this->dispatch('created');
}
public function render(): View
{
if (request()->query('create')) {
$this->open = true;
}
return view('livewire.projects.create-project');
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Projects;
use App\Actions\Projects\UpdateProject;
use App\Models\Project;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class EditProject extends Component
{
use RefreshComponentOnBroadcast;
public Project $project;
public array $inputs = [];
public function save(): void
{
app(UpdateProject::class)->update($this->project, $this->inputs);
$this->redirect(route('projects'));
}
public function mount(): void
{
$this->inputs = [
'name' => $this->project->name,
];
}
public function render(): View
{
return view('livewire.projects.edit-project');
}
}

View File

@ -1,42 +0,0 @@
<?php
namespace App\Http\Livewire\Projects;
use App\Actions\Projects\DeleteProject;
use App\Traits\HasToast;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Illuminate\Validation\ValidationException;
use Livewire\Component;
class ProjectsList extends Component
{
use HasToast;
use RefreshComponentOnBroadcast;
protected $listeners = [
'$refresh',
];
public int $deleteId;
public function delete(): void
{
try {
app(DeleteProject::class)->delete(auth()->user(), $this->deleteId);
$this->redirect(route('projects'));
return;
} catch (ValidationException $e) {
$this->toast()->error($e->getMessage());
}
}
public function render(): View
{
return view('livewire.projects.projects-list', [
'projects' => auth()->user()->projects()->orderByDesc('id')->get(),
]);
}
}

View File

@ -1,36 +0,0 @@
<?php
namespace App\Http\Livewire\Queues;
use App\Models\Site;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CreateQueue extends Component
{
public Site $site;
public string $command;
public string $user = '';
public int $auto_start = 1;
public int $auto_restart = 1;
public int $numprocs;
public function create(): void
{
app(\App\Actions\Queue\CreateQueue::class)->create($this->site, $this->all());
$this->dispatch('$refresh')->to(QueuesList::class);
$this->dispatch('created');
}
public function render(): View
{
return view('livewire.queues.create-queue');
}
}

View File

@ -1,57 +0,0 @@
<?php
namespace App\Http\Livewire\Queues;
use App\Models\Queue;
use App\Models\Site;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class QueuesList extends Component
{
use RefreshComponentOnBroadcast;
public Site $site;
public int $deleteId;
public function delete(): void
{
$queue = $this->site->queues()->findOrFail($this->deleteId);
$queue->remove();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function start(Queue $queue): void
{
$queue->start();
$this->refreshComponent([]);
}
public function restart(Queue $queue): void
{
$queue->restart();
$this->refreshComponent([]);
}
public function stop(Queue $queue): void
{
$queue->stop();
$this->refreshComponent([]);
}
public function render(): View
{
return view('livewire.queues.queues-list', [
'queues' => $this->site->queues,
]);
}
}

View File

@ -1,58 +0,0 @@
<?php
namespace App\Http\Livewire\ServerLogs;
use App\Models\Server;
use App\Models\Site;
use App\Traits\HasCustomPaginationView;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class LogsList extends Component
{
use HasCustomPaginationView;
use RefreshComponentOnBroadcast;
public ?int $count = null;
public Server $server;
public ?Site $site = null;
public string $logContent;
public function showLog(int $id): void
{
$log = $this->server->logs()->findOrFail($id);
$this->logContent = $log->content;
$this->dispatch('open-modal', 'show-log');
}
public function render(): View
{
if ($this->site) {
return $this->renderSite();
}
if ($this->count) {
$logs = $this->server->logs()->latest()->take(10)->get();
} else {
$logs = $this->server->logs()->latest()->simplePaginate(10);
}
return view('livewire.server-logs.logs-list', compact('logs'));
}
private function renderSite(): View
{
if ($this->count) {
$logs = $this->site->logs()->latest()->take(10)->get();
} else {
$logs = $this->site->logs()->latest()->simplePaginate(10);
}
return view('livewire.server-logs.logs-list', compact('logs'));
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\ServerProviders;
use App\Actions\ServerProvider\CreateServerProvider;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ConnectProvider extends Component
{
public string $provider = '';
public string $name;
public string $token;
public string $key;
public string $secret;
public function connect(): void
{
app(CreateServerProvider::class)->create(auth()->user(), $this->all());
$this->dispatch('$refresh')->to(ProvidersList::class);
$this->dispatch('connected');
}
public function render(): View
{
if (request()->query('provider')) {
$this->provider = request()->query('provider');
}
return view('livewire.server-providers.connect-provider', [
'open' => ! is_null(request()->query('provider')),
]);
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\ServerProviders;
use App\Models\ServerProvider;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ProvidersList extends Component
{
use RefreshComponentOnBroadcast;
public int $deleteId;
protected $listeners = [
'$refresh',
];
public function delete(): void
{
$provider = ServerProvider::query()->findOrFail($this->deleteId);
$provider->delete();
$this->refreshComponent([]);
$this->dispatch('confirmed');
}
public function render(): View
{
return view('livewire.server-providers.providers-list', [
'providers' => ServerProvider::query()->latest()->get(),
]);
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace App\Http\Livewire\ServerSettings;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class CheckConnection extends Component
{
public Server $server;
public function check(): void
{
$this->server->checkConnection();
session()->flash('status', 'checking-connection');
}
public function render(): View
{
return view('livewire.server-settings.check-connection');
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace App\Http\Livewire\ServerSettings;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class EditServer extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public string $name;
public string $ip;
public string $port;
public function mount(): void
{
$this->name = $this->server->name;
$this->ip = $this->server->ip;
$this->port = $this->server->port;
}
public function update(): void
{
app(\App\Actions\Server\EditServer::class)->edit($this->server, $this->all());
session()->flash('status', 'server-updated');
}
public function render(): View
{
return view('livewire.server-settings.edit-server');
}
}

View File

@ -1,24 +0,0 @@
<?php
namespace App\Http\Livewire\ServerSettings;
use App\Models\Server;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class RebootServer extends Component
{
public Server $server;
public function reboot(): void
{
$this->server->reboot();
session()->flash('status', 'rebooting-server');
}
public function render(): View
{
return view('livewire.server-settings.reboot-server');
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Http\Livewire\ServerSettings;
use App\Models\Server;
use App\Traits\RefreshComponentOnBroadcast;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class ServerDetails extends Component
{
use RefreshComponentOnBroadcast;
public Server $server;
public function render(): View
{
return view('livewire.server-settings.server-details');
}
}

View File

@ -1,33 +0,0 @@
<?php
namespace App\Http\Livewire\ServerSshKeys;
use App\Models\Server;
use App\Models\SshKey;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class AddExistingKey extends Component
{
public Server $server;
public string $key_id = '';
public function add(): void
{
$key = SshKey::query()->findOrFail($this->all()['key_id']);
$key->deployTo($this->server);
$this->dispatch('$refresh')->to(ServerKeysList::class);
$this->dispatch('added');
}
public function render(): View
{
return view('livewire.server-ssh-keys.add-existing-key', [
'keys' => SshKey::all(),
]);
}
}

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