mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-01 14:06:15 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
9ac5f9ebb3 | |||
ed8965b92b | |||
9473d198e1 | |||
55269dbcde | |||
3d67153912 | |||
11e3b167cc | |||
ad027eb033 | |||
e031bafba5 | |||
b5c8d99ef8 | |||
109d644ad8 | |||
5ccbab74b1 | |||
7d367465ff | |||
eec83f577c | |||
fd77368cf3 | |||
a862a603f2 | |||
3b42f93654 | |||
661292df5e | |||
0cfb938320 | |||
dd4a3d30c0 | |||
2b849c888e | |||
d9a791755e |
@ -22,7 +22,9 @@ public function create(Server $server, array $input): Database
|
|||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
]);
|
]);
|
||||||
$server->database()->handler()->create($database->name);
|
/** @var \App\SSH\Services\Database\Database */
|
||||||
|
$databaseHandler = $server->database()->handler();
|
||||||
|
$databaseHandler->create($database->name);
|
||||||
$database->status = DatabaseStatus::READY;
|
$database->status = DatabaseStatus::READY;
|
||||||
$database->save();
|
$database->save();
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ private function getInterval(array $input): Expression
|
|||||||
)->diffInHours();
|
)->diffInHours();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($periodInHours <= 1) {
|
if (abs($periodInHours) <= 1) {
|
||||||
return DB::raw("strftime('%Y-%m-%d %H:%M:00', created_at) as date_interval");
|
return DB::raw("strftime('%Y-%m-%d %H:%M:00', created_at) as date_interval");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ public function add(User $user, array $input): void
|
|||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
'provider' => $input['provider'],
|
'provider' => $input['provider'],
|
||||||
'label' => $input['label'],
|
'label' => $input['label'],
|
||||||
|
'project_id' => isset($input['global']) && $input['global'] ? null : $user->current_project_id,
|
||||||
]);
|
]);
|
||||||
$this->validateType($channel, $input);
|
$this->validateType($channel, $input);
|
||||||
$channel->data = $channel->provider()->createData($input);
|
$channel->data = $channel->provider()->createData($input);
|
||||||
|
34
app/Actions/NotificationChannels/EditChannel.php
Normal file
34
app/Actions/NotificationChannels/EditChannel.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\NotificationChannels;
|
||||||
|
|
||||||
|
use App\Models\NotificationChannel;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class EditChannel
|
||||||
|
{
|
||||||
|
public function edit(NotificationChannel $notificationChannel, User $user, array $input): void
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$notificationChannel->label = $input['label'];
|
||||||
|
$notificationChannel->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
||||||
|
|
||||||
|
$notificationChannel->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'label' => [
|
||||||
|
'required',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Validator::make($input, $rules)->validate();
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Actions\PHP;
|
namespace App\Actions\PHP;
|
||||||
|
|
||||||
|
use App\Enums\PHPIniType;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\SSH\Services\PHP\PHP;
|
use App\SSH\Services\PHP\PHP;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class GetPHPIni
|
class GetPHPIni
|
||||||
@ -18,7 +21,7 @@ public function getIni(Server $server, array $input): string
|
|||||||
/** @var PHP $handler */
|
/** @var PHP $handler */
|
||||||
$handler = $php->handler();
|
$handler = $php->handler();
|
||||||
|
|
||||||
return $handler->getPHPIni();
|
return $handler->getPHPIni($input['type']);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw ValidationException::withMessages(
|
throw ValidationException::withMessages(
|
||||||
['ini' => $e->getMessage()]
|
['ini' => $e->getMessage()]
|
||||||
@ -28,6 +31,13 @@ public function getIni(Server $server, array $input): string
|
|||||||
|
|
||||||
public function validate(Server $server, array $input): void
|
public function validate(Server $server, array $input): void
|
||||||
{
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'type' => [
|
||||||
|
'required',
|
||||||
|
Rule::in([PHPIniType::CLI, PHPIniType::FPM]),
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
|
||||||
if (! isset($input['version']) || ! in_array($input['version'], $server->installedPHPVersions())) {
|
if (! isset($input['version']) || ! in_array($input['version'], $server->installedPHPVersions())) {
|
||||||
throw ValidationException::withMessages(
|
throw ValidationException::withMessages(
|
||||||
['version' => __('This version is not installed')]
|
['version' => __('This version is not installed')]
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Actions\PHP;
|
namespace App\Actions\PHP;
|
||||||
|
|
||||||
|
use App\Enums\PHPIniType;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@ -22,19 +25,19 @@ public function update(Server $server, array $input): void
|
|||||||
|
|
||||||
$tmpName = Str::random(10).strtotime('now');
|
$tmpName = Str::random(10).strtotime('now');
|
||||||
try {
|
try {
|
||||||
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
/** @var FilesystemAdapter $storageDisk */
|
||||||
$storageDisk = Storage::disk('local');
|
$storageDisk = Storage::disk('local');
|
||||||
|
|
||||||
$storageDisk->put($tmpName, $input['ini']);
|
$storageDisk->put($tmpName, $input['ini']);
|
||||||
$service->server->ssh('root')->upload(
|
$service->server->ssh('root')->upload(
|
||||||
$storageDisk->path($tmpName),
|
$storageDisk->path($tmpName),
|
||||||
"/etc/php/$service->version/cli/php.ini"
|
sprintf('/etc/php/%s/%s/php.ini', $service->version, $input['type'])
|
||||||
);
|
);
|
||||||
$this->deleteTempFile($tmpName);
|
$this->deleteTempFile($tmpName);
|
||||||
} catch (Throwable) {
|
} catch (Throwable) {
|
||||||
$this->deleteTempFile($tmpName);
|
$this->deleteTempFile($tmpName);
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'ini' => __("Couldn't update php.ini file!"),
|
'ini' => __("Couldn't update php.ini (:type) file!", ['type' => $input['type']]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +59,10 @@ public function validate(Server $server, array $input): void
|
|||||||
'string',
|
'string',
|
||||||
],
|
],
|
||||||
'version' => 'required|string',
|
'version' => 'required|string',
|
||||||
|
'type' => [
|
||||||
|
'required',
|
||||||
|
Rule::in([PHPIniType::CLI, PHPIniType::FPM]),
|
||||||
|
],
|
||||||
])->validate();
|
])->validate();
|
||||||
|
|
||||||
if (! in_array($input['version'], $server->installedPHPVersions())) {
|
if (! in_array($input['version'], $server->installedPHPVersions())) {
|
||||||
|
32
app/Actions/Script/CreateScript.php
Normal file
32
app/Actions/Script/CreateScript.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Script;
|
||||||
|
|
||||||
|
use App\Models\Script;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class CreateScript
|
||||||
|
{
|
||||||
|
public function create(User $user, array $input): Script
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$script = new Script([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'name' => $input['name'],
|
||||||
|
'content' => $input['content'],
|
||||||
|
]);
|
||||||
|
$script->save();
|
||||||
|
|
||||||
|
return $script;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'content' => ['required', 'string'],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
28
app/Actions/Script/EditScript.php
Normal file
28
app/Actions/Script/EditScript.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Script;
|
||||||
|
|
||||||
|
use App\Models\Script;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class EditScript
|
||||||
|
{
|
||||||
|
public function edit(Script $script, array $input): Script
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$script->name = $input['name'];
|
||||||
|
$script->content = $input['content'];
|
||||||
|
$script->save();
|
||||||
|
|
||||||
|
return $script;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'content' => ['required', 'string'],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
62
app/Actions/Script/ExecuteScript.php
Normal file
62
app/Actions/Script/ExecuteScript.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Script;
|
||||||
|
|
||||||
|
use App\Enums\ScriptExecutionStatus;
|
||||||
|
use App\Models\Script;
|
||||||
|
use App\Models\ScriptExecution;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\ServerLog;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class ExecuteScript
|
||||||
|
{
|
||||||
|
public function execute(Script $script, Server $server, array $input): ScriptExecution
|
||||||
|
{
|
||||||
|
$this->validate($server, $input);
|
||||||
|
|
||||||
|
$execution = new ScriptExecution([
|
||||||
|
'script_id' => $script->id,
|
||||||
|
'user' => $input['user'],
|
||||||
|
'variables' => $input['variables'] ?? [],
|
||||||
|
'status' => ScriptExecutionStatus::EXECUTING,
|
||||||
|
]);
|
||||||
|
$execution->save();
|
||||||
|
|
||||||
|
dispatch(function () use ($execution, $server, $script) {
|
||||||
|
$content = $execution->getContent();
|
||||||
|
$log = ServerLog::make($server, 'script-'.$script->id.'-'.strtotime('now'));
|
||||||
|
$log->save();
|
||||||
|
$execution->server_log_id = $log->id;
|
||||||
|
$execution->save();
|
||||||
|
$server->os()->runScript('~/', $content, $log, $execution->user);
|
||||||
|
$execution->status = ScriptExecutionStatus::COMPLETED;
|
||||||
|
$execution->save();
|
||||||
|
})->catch(function () use ($execution) {
|
||||||
|
$execution->status = ScriptExecutionStatus::FAILED;
|
||||||
|
$execution->save();
|
||||||
|
})->onConnection('ssh');
|
||||||
|
|
||||||
|
return $execution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(Server $server, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'user' => [
|
||||||
|
'required',
|
||||||
|
Rule::in([
|
||||||
|
'root',
|
||||||
|
$server->ssh_user,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
'variables' => 'array',
|
||||||
|
'variables.*' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ public function create(User $user, array $input): ServerProvider
|
|||||||
$serverProvider->profile = $input['name'];
|
$serverProvider->profile = $input['name'];
|
||||||
$serverProvider->provider = $input['provider'];
|
$serverProvider->provider = $input['provider'];
|
||||||
$serverProvider->credentials = $provider->credentialData($input);
|
$serverProvider->credentials = $provider->credentialData($input);
|
||||||
|
$serverProvider->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
||||||
$serverProvider->save();
|
$serverProvider->save();
|
||||||
|
|
||||||
return $serverProvider;
|
return $serverProvider;
|
||||||
|
34
app/Actions/ServerProvider/EditServerProvider.php
Normal file
34
app/Actions/ServerProvider/EditServerProvider.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\ServerProvider;
|
||||||
|
|
||||||
|
use App\Models\ServerProvider;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class EditServerProvider
|
||||||
|
{
|
||||||
|
public function edit(ServerProvider $serverProvider, User $user, array $input): void
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$serverProvider->profile = $input['name'];
|
||||||
|
$serverProvider->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
||||||
|
|
||||||
|
$serverProvider->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'name' => [
|
||||||
|
'required',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Validator::make($input, $rules)->validate();
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,12 @@ public function run(Site $site): Deployment
|
|||||||
$log->save();
|
$log->save();
|
||||||
$deployment->log_id = $log->id;
|
$deployment->log_id = $log->id;
|
||||||
$deployment->save();
|
$deployment->save();
|
||||||
$site->server->os()->runScript($site->path, $site->deploymentScript->content, $log);
|
$site->server->os()->runScript(
|
||||||
|
path: $site->path,
|
||||||
|
script: $site->deploymentScript->content,
|
||||||
|
serverLog: $log,
|
||||||
|
variables: $site->environmentVariables($deployment)
|
||||||
|
);
|
||||||
$deployment->status = DeploymentStatus::FINISHED;
|
$deployment->status = DeploymentStatus::FINISHED;
|
||||||
$deployment->save();
|
$deployment->save();
|
||||||
})->catch(function () use ($deployment) {
|
})->catch(function () use ($deployment) {
|
||||||
|
@ -2,10 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Actions\Site;
|
namespace App\Actions\Site;
|
||||||
|
|
||||||
|
use App\Exceptions\SSHUploadFailed;
|
||||||
use App\Models\Site;
|
use App\Models\Site;
|
||||||
|
|
||||||
class UpdateEnv
|
class UpdateEnv
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @throws SSHUploadFailed
|
||||||
|
*/
|
||||||
public function update(Site $site, array $input): void
|
public function update(Site $site, array $input): void
|
||||||
{
|
{
|
||||||
$site->server->os()->editFile(
|
$site->server->os()->editFile(
|
||||||
|
@ -14,7 +14,7 @@ public function edit(SourceControl $sourceControl, User $user, array $input): vo
|
|||||||
$this->validate($input);
|
$this->validate($input);
|
||||||
|
|
||||||
$sourceControl->profile = $input['name'];
|
$sourceControl->profile = $input['name'];
|
||||||
$sourceControl->url = isset($input['url']) ? $input['url'] : null;
|
$sourceControl->url = $input['url'] ?? null;
|
||||||
$sourceControl->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
$sourceControl->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
||||||
|
|
||||||
$this->validateProvider($sourceControl, $input);
|
$this->validateProvider($sourceControl, $input);
|
||||||
|
@ -21,6 +21,7 @@ public function create(User $user, array $input): void
|
|||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
'provider' => $input['provider'],
|
'provider' => $input['provider'],
|
||||||
'profile' => $input['name'],
|
'profile' => $input['name'],
|
||||||
|
'project_id' => isset($input['global']) && $input['global'] ? null : $user->current_project_id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->validateProvider($input, $storageProvider->provider()->validationRules());
|
$this->validateProvider($input, $storageProvider->provider()->validationRules());
|
||||||
|
34
app/Actions/StorageProvider/EditStorageProvider.php
Normal file
34
app/Actions/StorageProvider/EditStorageProvider.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\StorageProvider;
|
||||||
|
|
||||||
|
use App\Models\StorageProvider;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class EditStorageProvider
|
||||||
|
{
|
||||||
|
public function edit(StorageProvider $storageProvider, User $user, array $input): void
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$storageProvider->profile = $input['name'];
|
||||||
|
$storageProvider->project_id = isset($input['global']) && $input['global'] ? null : $user->current_project_id;
|
||||||
|
|
||||||
|
$storageProvider->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'name' => [
|
||||||
|
'required',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Validator::make($input, $rules)->validate();
|
||||||
|
}
|
||||||
|
}
|
10
app/Enums/PHPIniType.php
Normal file
10
app/Enums/PHPIniType.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
final class PHPIniType
|
||||||
|
{
|
||||||
|
const CLI = 'cli';
|
||||||
|
|
||||||
|
const FPM = 'fpm';
|
||||||
|
}
|
12
app/Enums/ScriptExecutionStatus.php
Normal file
12
app/Enums/ScriptExecutionStatus.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
final class ScriptExecutionStatus
|
||||||
|
{
|
||||||
|
const EXECUTING = 'executing';
|
||||||
|
|
||||||
|
const COMPLETED = 'completed';
|
||||||
|
|
||||||
|
const FAILED = 'failed';
|
||||||
|
}
|
@ -4,6 +4,4 @@
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class DeploymentScriptIsEmptyException extends Exception
|
class DeploymentScriptIsEmptyException extends Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
8
app/Exceptions/SSHUploadFailed.php
Executable file
8
app/Exceptions/SSHUploadFailed.php
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
class SSHUploadFailed extends SSHError
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
@ -4,6 +4,4 @@
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class SourceControlIsNotConnected extends Exception
|
class SourceControlIsNotConnected extends Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* @method static string exec(string $command, string $log = '', int $siteId = null, ?bool $stream = false)
|
* @method static string exec(string $command, string $log = '', int $siteId = null, ?bool $stream = false)
|
||||||
* @method static string assertExecuted(array|string $commands)
|
* @method static string assertExecuted(array|string $commands)
|
||||||
* @method static string assertExecutedContains(string $command)
|
* @method static string assertExecutedContains(string $command)
|
||||||
|
* @method static string assertFileUploaded(string $toPath, ?string $content = null)
|
||||||
|
* @method static string getUploadedLocalPath()
|
||||||
* @method static disconnect()
|
* @method static disconnect()
|
||||||
*/
|
*/
|
||||||
class SSH extends FacadeAlias
|
class SSH extends FacadeAlias
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
use App\Exceptions\RepositoryNotFound;
|
use App\Exceptions\RepositoryNotFound;
|
||||||
use App\Exceptions\RepositoryPermissionDenied;
|
use App\Exceptions\RepositoryPermissionDenied;
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
|
use App\Exceptions\SSHUploadFailed;
|
||||||
use App\Facades\Toast;
|
use App\Facades\Toast;
|
||||||
use App\Helpers\HtmxResponse;
|
use App\Helpers\HtmxResponse;
|
||||||
use App\Models\Deployment;
|
use App\Models\Deployment;
|
||||||
@ -81,9 +82,12 @@ public function updateEnv(Server $server, Site $site, Request $request): Redirec
|
|||||||
{
|
{
|
||||||
$this->authorize('manage', $server);
|
$this->authorize('manage', $server);
|
||||||
|
|
||||||
|
try {
|
||||||
app(UpdateEnv::class)->update($site, $request->input());
|
app(UpdateEnv::class)->update($site, $request->input());
|
||||||
|
|
||||||
Toast::success('Env updated!');
|
Toast::success('Env updated!');
|
||||||
|
} catch (SSHUploadFailed) {
|
||||||
|
Toast::error('Failed to update .env file!');
|
||||||
|
}
|
||||||
|
|
||||||
return back();
|
return back();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ public function updateIni(Server $server, Request $request): RedirectResponse
|
|||||||
|
|
||||||
app(UpdatePHPIni::class)->update($server, $request->input());
|
app(UpdatePHPIni::class)->update($server, $request->input());
|
||||||
|
|
||||||
Toast::success('PHP ini updated!');
|
Toast::success(__('PHP ini (:type) updated!', ['type' => $request->input('type')]));
|
||||||
|
|
||||||
return back()->with([
|
return back()->with([
|
||||||
'ini' => $request->input('ini'),
|
'ini' => $request->input('ini'),
|
||||||
|
@ -29,7 +29,7 @@ public function store(Server $server, Request $request): HtmxResponse
|
|||||||
{
|
{
|
||||||
$this->authorize('manage', $server);
|
$this->authorize('manage', $server);
|
||||||
|
|
||||||
/** @var \App\Models\SshKey $key */
|
/** @var SshKey $key */
|
||||||
$key = app(CreateSshKey::class)->create(
|
$key = app(CreateSshKey::class)->create(
|
||||||
$request->user(),
|
$request->user(),
|
||||||
$request->input()
|
$request->input()
|
||||||
|
111
app/Http/Controllers/ScriptController.php
Normal file
111
app/Http/Controllers/ScriptController.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Script\CreateScript;
|
||||||
|
use App\Actions\Script\EditScript;
|
||||||
|
use App\Actions\Script\ExecuteScript;
|
||||||
|
use App\Facades\Toast;
|
||||||
|
use App\Helpers\HtmxResponse;
|
||||||
|
use App\Models\Script;
|
||||||
|
use App\Models\ScriptExecution;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ScriptController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): View
|
||||||
|
{
|
||||||
|
$this->authorize('viewAny', Script::class);
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'scripts' => $user->scripts,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($request->has('edit')) {
|
||||||
|
$data['editScript'] = $user->scripts()->findOrFail($request->input('edit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('execute')) {
|
||||||
|
$data['executeScript'] = $user->scripts()->findOrFail($request->input('execute'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('scripts.index', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Script $script): View
|
||||||
|
{
|
||||||
|
$this->authorize('view', $script);
|
||||||
|
|
||||||
|
return view('scripts.show', [
|
||||||
|
'script' => $script,
|
||||||
|
'executions' => $script->executions()->latest()->paginate(20),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
$this->authorize('create', Script::class);
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
app(CreateScript::class)->create($user, $request->input());
|
||||||
|
|
||||||
|
Toast::success('Script created.');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('scripts.index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Request $request, Script $script): HtmxResponse
|
||||||
|
{
|
||||||
|
$this->authorize('update', $script);
|
||||||
|
|
||||||
|
app(EditScript::class)->edit($script, $request->input());
|
||||||
|
|
||||||
|
Toast::success('Script updated.');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('scripts.index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(Script $script, Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'server' => 'required|exists:servers,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$server = Server::findOrFail($request->input('server'));
|
||||||
|
|
||||||
|
$this->authorize('execute', [$script, $server]);
|
||||||
|
|
||||||
|
app(ExecuteScript::class)->execute($script, $server, $request->input());
|
||||||
|
|
||||||
|
Toast::success('Executing the script...');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('scripts.show', $script));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Script $script): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->authorize('delete', $script);
|
||||||
|
|
||||||
|
$script->delete();
|
||||||
|
|
||||||
|
Toast::success('Script deleted.');
|
||||||
|
|
||||||
|
return redirect()->route('scripts.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function log(Script $script, ScriptExecution $execution): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->authorize('view', $script);
|
||||||
|
|
||||||
|
return back()->with('content', $execution->serverLog?->getContent());
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,9 @@ public function create(Request $request): View
|
|||||||
$this->authorize('create', [Server::class, $user->currentProject]);
|
$this->authorize('create', [Server::class, $user->currentProject]);
|
||||||
|
|
||||||
$provider = $request->query('provider', old('provider', \App\Enums\ServerProvider::CUSTOM));
|
$provider = $request->query('provider', old('provider', \App\Enums\ServerProvider::CUSTOM));
|
||||||
$serverProviders = ServerProvider::query()->where('provider', $provider)->get();
|
$serverProviders = ServerProvider::getByProjectId(auth()->user()->current_project_id)
|
||||||
|
->where('provider', $provider)
|
||||||
|
->get();
|
||||||
|
|
||||||
return view('servers.create', [
|
return view('servers.create', [
|
||||||
'serverProviders' => $serverProviders,
|
'serverProviders' => $serverProviders,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Settings;
|
namespace App\Http\Controllers\Settings;
|
||||||
|
|
||||||
use App\Actions\NotificationChannels\AddChannel;
|
use App\Actions\NotificationChannels\AddChannel;
|
||||||
|
use App\Actions\NotificationChannels\EditChannel;
|
||||||
use App\Facades\Toast;
|
use App\Facades\Toast;
|
||||||
use App\Helpers\HtmxResponse;
|
use App\Helpers\HtmxResponse;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@ -13,11 +14,17 @@
|
|||||||
|
|
||||||
class NotificationChannelController extends Controller
|
class NotificationChannelController extends Controller
|
||||||
{
|
{
|
||||||
public function index(): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
return view('settings.notification-channels.index', [
|
$data = [
|
||||||
'channels' => NotificationChannel::query()->latest()->get(),
|
'channels' => NotificationChannel::getByProjectId(auth()->user()->current_project_id)->get(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($request->has('edit')) {
|
||||||
|
$data['editChannel'] = NotificationChannel::find($request->input('edit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('settings.notification-channels.index', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(Request $request): HtmxResponse
|
public function add(Request $request): HtmxResponse
|
||||||
@ -32,6 +39,19 @@ public function add(Request $request): HtmxResponse
|
|||||||
return htmx()->redirect(route('settings.notification-channels'));
|
return htmx()->redirect(route('settings.notification-channels'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function update(NotificationChannel $notificationChannel, Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
app(EditChannel::class)->edit(
|
||||||
|
$notificationChannel,
|
||||||
|
$request->user(),
|
||||||
|
$request->input(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Toast::success('Channel updated.');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('settings.notification-channels'));
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(int $id): RedirectResponse
|
public function delete(int $id): RedirectResponse
|
||||||
{
|
{
|
||||||
$channel = NotificationChannel::query()->findOrFail($id);
|
$channel = NotificationChannel::query()->findOrFail($id);
|
||||||
|
@ -68,7 +68,7 @@ public function delete(Project $project): RedirectResponse
|
|||||||
return back();
|
return back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function switch($projectId): RedirectResponse
|
public function switch(Request $request, $projectId): RedirectResponse
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
@ -81,6 +81,11 @@ public function switch($projectId): RedirectResponse
|
|||||||
$user->current_project_id = $project->id;
|
$user->current_project_id = $project->id;
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
|
// check if the referer is settings/*
|
||||||
|
if (str_contains($request->headers->get('referer'), 'settings')) {
|
||||||
|
return redirect()->to($request->headers->get('referer'));
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route('servers');
|
return redirect()->route('servers');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Actions\ServerProvider\CreateServerProvider;
|
use App\Actions\ServerProvider\CreateServerProvider;
|
||||||
use App\Actions\ServerProvider\DeleteServerProvider;
|
use App\Actions\ServerProvider\DeleteServerProvider;
|
||||||
|
use App\Actions\ServerProvider\EditServerProvider;
|
||||||
use App\Facades\Toast;
|
use App\Facades\Toast;
|
||||||
use App\Helpers\HtmxResponse;
|
use App\Helpers\HtmxResponse;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@ -14,11 +15,17 @@
|
|||||||
|
|
||||||
class ServerProviderController extends Controller
|
class ServerProviderController extends Controller
|
||||||
{
|
{
|
||||||
public function index(): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
return view('settings.server-providers.index', [
|
$data = [
|
||||||
'providers' => auth()->user()->serverProviders,
|
'providers' => ServerProvider::getByProjectId(auth()->user()->current_project_id)->get(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($request->has('edit')) {
|
||||||
|
$data['editProvider'] = ServerProvider::find($request->input('edit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('settings.server-providers.index', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect(Request $request): HtmxResponse
|
public function connect(Request $request): HtmxResponse
|
||||||
@ -33,6 +40,19 @@ public function connect(Request $request): HtmxResponse
|
|||||||
return htmx()->redirect(route('settings.server-providers'));
|
return htmx()->redirect(route('settings.server-providers'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function update(ServerProvider $serverProvider, Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
app(EditServerProvider::class)->edit(
|
||||||
|
$serverProvider,
|
||||||
|
$request->user(),
|
||||||
|
$request->input(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Toast::success('Provider updated.');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('settings.server-providers'));
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(ServerProvider $serverProvider): RedirectResponse
|
public function delete(ServerProvider $serverProvider): RedirectResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -18,7 +18,7 @@ class SourceControlController extends Controller
|
|||||||
public function index(Request $request): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
'sourceControls' => SourceControl::getByCurrentProject(),
|
'sourceControls' => SourceControl::getByProjectId(auth()->user()->current_project_id)->get(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($request->has('edit')) {
|
if ($request->has('edit')) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Actions\StorageProvider\CreateStorageProvider;
|
use App\Actions\StorageProvider\CreateStorageProvider;
|
||||||
use App\Actions\StorageProvider\DeleteStorageProvider;
|
use App\Actions\StorageProvider\DeleteStorageProvider;
|
||||||
|
use App\Actions\StorageProvider\EditStorageProvider;
|
||||||
use App\Facades\Toast;
|
use App\Facades\Toast;
|
||||||
use App\Helpers\HtmxResponse;
|
use App\Helpers\HtmxResponse;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@ -14,11 +15,17 @@
|
|||||||
|
|
||||||
class StorageProviderController extends Controller
|
class StorageProviderController extends Controller
|
||||||
{
|
{
|
||||||
public function index(): View
|
public function index(Request $request): View
|
||||||
{
|
{
|
||||||
return view('settings.storage-providers.index', [
|
$data = [
|
||||||
'providers' => auth()->user()->storageProviders,
|
'providers' => StorageProvider::getByProjectId(auth()->user()->current_project_id)->get(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($request->has('edit')) {
|
||||||
|
$data['editProvider'] = StorageProvider::find($request->input('edit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('settings.storage-providers.index', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect(Request $request): HtmxResponse
|
public function connect(Request $request): HtmxResponse
|
||||||
@ -33,6 +40,19 @@ public function connect(Request $request): HtmxResponse
|
|||||||
return htmx()->redirect(route('settings.storage-providers'));
|
return htmx()->redirect(route('settings.storage-providers'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function update(StorageProvider $storageProvider, Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
app(EditStorageProvider::class)->edit(
|
||||||
|
$storageProvider,
|
||||||
|
$request->user(),
|
||||||
|
$request->input(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Toast::success('Provider updated.');
|
||||||
|
|
||||||
|
return htmx()->redirect(route('settings.storage-providers'));
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(StorageProvider $storageProvider): RedirectResponse
|
public function delete(StorageProvider $storageProvider): RedirectResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Notifications\NotificationInterface;
|
use App\Notifications\NotificationInterface;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,6 +14,7 @@
|
|||||||
* @property array data
|
* @property array data
|
||||||
* @property string label
|
* @property string label
|
||||||
* @property bool connected
|
* @property bool connected
|
||||||
|
* @property int $project_id
|
||||||
*/
|
*/
|
||||||
class NotificationChannel extends AbstractModel
|
class NotificationChannel extends AbstractModel
|
||||||
{
|
{
|
||||||
@ -24,6 +27,7 @@ class NotificationChannel extends AbstractModel
|
|||||||
'data',
|
'data',
|
||||||
'connected',
|
'connected',
|
||||||
'is_default',
|
'is_default',
|
||||||
|
'project_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@ -47,4 +51,16 @@ public static function notifyAll(NotificationInterface $notification): void
|
|||||||
$channel->notify($notification);
|
$channel->notify($notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function project(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Project::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByProjectId(int $projectId): Builder
|
||||||
|
{
|
||||||
|
return self::query()
|
||||||
|
->where('project_id', $projectId)
|
||||||
|
->orWhereNull('project_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
66
app/Models/Script.php
Normal file
66
app/Models/Script.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $content
|
||||||
|
* @property Carbon $created_at
|
||||||
|
* @property Carbon $updated_at
|
||||||
|
* @property Collection<ScriptExecution> $executions
|
||||||
|
* @property ?ScriptExecution $lastExecution
|
||||||
|
*/
|
||||||
|
class Script extends AbstractModel
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'name',
|
||||||
|
'content',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::deleting(function (Script $script) {
|
||||||
|
$script->executions()->delete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVariables(): array
|
||||||
|
{
|
||||||
|
$variables = [];
|
||||||
|
preg_match_all('/\${(.*?)}/', $this->content, $matches);
|
||||||
|
foreach ($matches[1] as $match) {
|
||||||
|
$variables[] = $match;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_unique($variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executions(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(ScriptExecution::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastExecution(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(ScriptExecution::class)->latest();
|
||||||
|
}
|
||||||
|
}
|
61
app/Models/ScriptExecution.php
Normal file
61
app/Models/ScriptExecution.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $script_id
|
||||||
|
* @property int $server_log_id
|
||||||
|
* @property string $user
|
||||||
|
* @property array $variables
|
||||||
|
* @property string $status
|
||||||
|
* @property Carbon $created_at
|
||||||
|
* @property Carbon $updated_at
|
||||||
|
* @property Script $script
|
||||||
|
* @property ?ServerLog $serverLog
|
||||||
|
*/
|
||||||
|
class ScriptExecution extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'script_id',
|
||||||
|
'server_log_id',
|
||||||
|
'user',
|
||||||
|
'variables',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'script_id' => 'integer',
|
||||||
|
'server_log_id' => 'integer',
|
||||||
|
'variables' => 'array',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function script(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Script::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent(): string
|
||||||
|
{
|
||||||
|
$content = $this->script->content;
|
||||||
|
foreach ($this->variables as $variable => $value) {
|
||||||
|
if (is_string($value) && ! empty($value)) {
|
||||||
|
$content = str_replace('${'.$variable.'}', $value, $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serverLog(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ServerLog::class);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@ -13,6 +14,7 @@
|
|||||||
* @property array $credentials
|
* @property array $credentials
|
||||||
* @property bool $connected
|
* @property bool $connected
|
||||||
* @property User $user
|
* @property User $user
|
||||||
|
* @property ?int $project_id
|
||||||
*/
|
*/
|
||||||
class ServerProvider extends AbstractModel
|
class ServerProvider extends AbstractModel
|
||||||
{
|
{
|
||||||
@ -24,12 +26,14 @@ class ServerProvider extends AbstractModel
|
|||||||
'provider',
|
'provider',
|
||||||
'credentials',
|
'credentials',
|
||||||
'connected',
|
'connected',
|
||||||
|
'project_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
'credentials' => 'encrypted:array',
|
'credentials' => 'encrypted:array',
|
||||||
'connected' => 'boolean',
|
'connected' => 'boolean',
|
||||||
|
'project_id' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
@ -46,4 +50,16 @@ public function servers(): HasMany
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Server::class, 'provider_id');
|
return $this->hasMany(Server::class, 'provider_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function project(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Project::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByProjectId(int $projectId): Builder
|
||||||
|
{
|
||||||
|
return self::query()
|
||||||
|
->where('project_id', $projectId)
|
||||||
|
->orWhereNull('project_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,4 +283,17 @@ public function hasSSL(): bool
|
|||||||
{
|
{
|
||||||
return $this->ssls->isNotEmpty();
|
return $this->ssls->isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function environmentVariables(?Deployment $deployment = null): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'SITE_PATH' => $this->path,
|
||||||
|
'DOMAIN' => $this->domain,
|
||||||
|
'BRANCH' => $this->branch ?? '',
|
||||||
|
'REPOSITORY' => $this->repository ?? '',
|
||||||
|
'COMMIT_ID' => $deployment?->commit_id ?? '',
|
||||||
|
'PHP_VERSION' => $this->php_version,
|
||||||
|
'PHP_PATH' => '/usr/bin/php'.$this->php_version,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\SourceControlProviders\SourceControlProvider;
|
use App\SourceControlProviders\SourceControlProvider;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@ -57,10 +57,10 @@ public function project(): BelongsTo
|
|||||||
return $this->belongsTo(Project::class);
|
return $this->belongsTo(Project::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getByCurrentProject(): Collection
|
public static function getByProjectId(int $projectId): Builder
|
||||||
{
|
{
|
||||||
return self::query()
|
return self::query()
|
||||||
->where('project_id', auth()->user()->current_project_id)
|
->where('project_id', $projectId)
|
||||||
->orWhereNull('project_id')->get();
|
->orWhereNull('project_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@ -12,6 +13,7 @@
|
|||||||
* @property string $provider
|
* @property string $provider
|
||||||
* @property array $credentials
|
* @property array $credentials
|
||||||
* @property User $user
|
* @property User $user
|
||||||
|
* @property int $project_id
|
||||||
*/
|
*/
|
||||||
class StorageProvider extends AbstractModel
|
class StorageProvider extends AbstractModel
|
||||||
{
|
{
|
||||||
@ -22,11 +24,13 @@ class StorageProvider extends AbstractModel
|
|||||||
'profile',
|
'profile',
|
||||||
'provider',
|
'provider',
|
||||||
'credentials',
|
'credentials',
|
||||||
|
'project_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
'credentials' => 'encrypted:array',
|
'credentials' => 'encrypted:array',
|
||||||
|
'project_id' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
@ -45,4 +49,16 @@ public function backups(): HasMany
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Backup::class, 'storage_id');
|
return $this->hasMany(Backup::class, 'storage_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function project(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Project::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByProjectId(int $projectId): Builder
|
||||||
|
{
|
||||||
|
return self::query()
|
||||||
|
->where('project_id', $projectId)
|
||||||
|
->orWhereNull('project_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\UserRole;
|
use App\Enums\UserRole;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@ -105,24 +106,6 @@ public function storageProvider(string $provider): HasOne
|
|||||||
return $this->hasOne(StorageProvider::class)->where('provider', $provider);
|
return $this->hasOne(StorageProvider::class)->where('provider', $provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connectedStorageProviders(): HasMany
|
|
||||||
{
|
|
||||||
return $this->storageProviders()->where('connected', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function connectedSourceControls(): array
|
|
||||||
{
|
|
||||||
$connectedSourceControls = [];
|
|
||||||
$sourceControls = $this->sourceControls()
|
|
||||||
->where('connected', 1)
|
|
||||||
->get(['provider']);
|
|
||||||
foreach ($sourceControls as $sourceControl) {
|
|
||||||
$connectedSourceControls[] = $sourceControl->provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $connectedSourceControls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function projects(): BelongsToMany
|
public function projects(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Project::class, 'user_project')->withTimestamps();
|
return $this->belongsToMany(Project::class, 'user_project')->withTimestamps();
|
||||||
@ -133,11 +116,6 @@ public function currentProject(): HasOne
|
|||||||
return $this->HasOne(Project::class, 'id', 'current_project_id');
|
return $this->HasOne(Project::class, 'id', 'current_project_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isMemberOfProject(Project $project): bool
|
|
||||||
{
|
|
||||||
return $project->user_id === $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createDefaultProject(): Project
|
public function createDefaultProject(): Project
|
||||||
{
|
{
|
||||||
$project = $this->projects()->first();
|
$project = $this->projects()->first();
|
||||||
@ -160,4 +138,18 @@ public function isAdmin(): bool
|
|||||||
{
|
{
|
||||||
return $this->role === UserRole::ADMIN;
|
return $this->role === UserRole::ADMIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scripts(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Script::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allServers(): Builder
|
||||||
|
{
|
||||||
|
return Server::query()->whereHas('project', function (Builder $query) {
|
||||||
|
$query->whereHas('users', function ($query) {
|
||||||
|
$query->where('user_id', $this->id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,5 @@
|
|||||||
|
|
||||||
abstract class AbstractNotificationChannel implements NotificationChannelInterface
|
abstract class AbstractNotificationChannel implements NotificationChannelInterface
|
||||||
{
|
{
|
||||||
public function __construct(protected NotificationChannel $notificationChannel)
|
public function __construct(protected NotificationChannel $notificationChannel) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,6 @@ public function toEmail(object $notifiable): MailMessage
|
|||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(__('Server disconnected!'))
|
->subject(__('Server disconnected!'))
|
||||||
->line("We've disconnected from your server [".$this->server->name.'].')
|
->line("We've disconnected from your server [".$this->server->name.'].')
|
||||||
->line('Please check your sever is online and make sure that has our public keys in it');
|
->line('Please check your server is online and make sure that has our public keys in it');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
class SiteInstallationFailed extends AbstractNotification
|
class SiteInstallationFailed extends AbstractNotification
|
||||||
{
|
{
|
||||||
public function __construct(protected Site $site)
|
public function __construct(protected Site $site) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rawText(): string
|
public function rawText(): string
|
||||||
{
|
{
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
class SiteInstallationSucceed extends AbstractNotification
|
class SiteInstallationSucceed extends AbstractNotification
|
||||||
{
|
{
|
||||||
public function __construct(protected Site $site)
|
public function __construct(protected Site $site) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rawText(): string
|
public function rawText(): string
|
||||||
{
|
{
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
class SourceControlDisconnected extends AbstractNotification
|
class SourceControlDisconnected extends AbstractNotification
|
||||||
{
|
{
|
||||||
public function __construct(protected SourceControl $sourceControl)
|
public function __construct(protected SourceControl $sourceControl) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rawText(): string
|
public function rawText(): string
|
||||||
{
|
{
|
||||||
|
43
app/Policies/ScriptPolicy.php
Normal file
43
app/Policies/ScriptPolicy.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Script;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||||
|
|
||||||
|
class ScriptPolicy
|
||||||
|
{
|
||||||
|
use HandlesAuthorization;
|
||||||
|
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(User $user, Script $script): bool
|
||||||
|
{
|
||||||
|
return $user->id === $script->user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, Script $script): bool
|
||||||
|
{
|
||||||
|
return $user->id === $script->user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(User $user, Script $script, Server $server): bool
|
||||||
|
{
|
||||||
|
return $user->id === $script->user_id && $server->project->users->contains($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(User $user, Script $script): bool
|
||||||
|
{
|
||||||
|
return $user->id === $script->user_id;
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ public function installDependencies(Site $site): void
|
|||||||
$site->server->ssh()->exec(
|
$site->server->ssh()->exec(
|
||||||
$this->getScript('composer-install.sh', [
|
$this->getScript('composer-install.sh', [
|
||||||
'path' => $site->path,
|
'path' => $site->path,
|
||||||
|
'php_version' => $site->php_version,
|
||||||
]),
|
]),
|
||||||
'composer-install',
|
'composer-install',
|
||||||
$site->id
|
$site->id
|
||||||
|
@ -2,6 +2,6 @@ if ! cd __path__; then
|
|||||||
echo 'VITO_SSH_ERROR' && exit 1
|
echo 'VITO_SSH_ERROR' && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev; then
|
if ! php__php_version__ /usr/local/bin/composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev; then
|
||||||
echo 'VITO_SSH_ERROR' && exit 1
|
echo 'VITO_SSH_ERROR' && exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
class Cron
|
class Cron
|
||||||
{
|
{
|
||||||
public function __construct(protected Server $server)
|
public function __construct(protected Server $server) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(string $user, string $cron): void
|
public function update(string $user, string $cron): void
|
||||||
{
|
{
|
||||||
|
@ -2,17 +2,20 @@
|
|||||||
|
|
||||||
namespace App\SSH\OS;
|
namespace App\SSH\OS;
|
||||||
|
|
||||||
|
use App\Exceptions\SSHUploadFailed;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
use App\SSH\HasScripts;
|
use App\SSH\HasScripts;
|
||||||
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class OS
|
class OS
|
||||||
{
|
{
|
||||||
use HasScripts;
|
use HasScripts;
|
||||||
|
|
||||||
public function __construct(protected Server $server)
|
public function __construct(protected Server $server) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function installDependencies(): void
|
public function installDependencies(): void
|
||||||
{
|
{
|
||||||
@ -111,14 +114,25 @@ public function reboot(): void
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws SSHUploadFailed
|
||||||
|
*/
|
||||||
public function editFile(string $path, ?string $content = null): void
|
public function editFile(string $path, ?string $content = null): void
|
||||||
{
|
{
|
||||||
$this->server->ssh()->exec(
|
$tmpName = Str::random(10).strtotime('now');
|
||||||
$this->getScript('edit-file.sh', [
|
try {
|
||||||
'path' => $path,
|
/** @var FilesystemAdapter $storageDisk */
|
||||||
'content' => $content ?? '',
|
$storageDisk = Storage::disk('local');
|
||||||
]),
|
$storageDisk->put($tmpName, $content);
|
||||||
|
$this->server->ssh()->upload(
|
||||||
|
$storageDisk->path($tmpName),
|
||||||
|
$path
|
||||||
);
|
);
|
||||||
|
} catch (Throwable) {
|
||||||
|
throw new SSHUploadFailed();
|
||||||
|
} finally {
|
||||||
|
$this->deleteTempFile($tmpName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFile(string $path): string
|
public function readFile(string $path): string
|
||||||
@ -140,19 +154,23 @@ public function tail(string $path, int $lines): string
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runScript(string $path, string $script, ?ServerLog $serverLog): ServerLog
|
public function runScript(string $path, string $script, ?ServerLog $serverLog, ?string $user = null, ?array $variables = []): ServerLog
|
||||||
{
|
{
|
||||||
$ssh = $this->server->ssh();
|
$ssh = $this->server->ssh($user);
|
||||||
if ($serverLog) {
|
if ($serverLog) {
|
||||||
$ssh->setLog($serverLog);
|
$ssh->setLog($serverLog);
|
||||||
}
|
}
|
||||||
$ssh->exec(
|
$command = '';
|
||||||
$this->getScript('run-script.sh', [
|
foreach ($variables as $key => $variable) {
|
||||||
|
$command .= "$key=$variable".PHP_EOL;
|
||||||
|
}
|
||||||
|
$command .= $this->getScript('run-script.sh', [
|
||||||
'path' => $path,
|
'path' => $path,
|
||||||
'script' => $script,
|
'script' => $script,
|
||||||
]),
|
]);
|
||||||
'run-script'
|
$ssh->exec($command, 'run-script');
|
||||||
);
|
|
||||||
|
info($command);
|
||||||
|
|
||||||
return $ssh->log;
|
return $ssh->log;
|
||||||
}
|
}
|
||||||
@ -198,4 +216,11 @@ public function resourceInfo(): array
|
|||||||
'disk_free' => str($info)->after('disk_free:')->before(PHP_EOL)->toString(),
|
'disk_free' => str($info)->after('disk_free:')->before(PHP_EOL)->toString(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function deleteTempFile(string $name): void
|
||||||
|
{
|
||||||
|
if (Storage::disk('local')->exists($name)) {
|
||||||
|
Storage::disk('local')->delete($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
if ! echo "__content__" | tee __path__; then
|
|
||||||
echo 'VITO_SSH_ERROR' && exit 1
|
|
||||||
fi
|
|
@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
abstract class AbstractService implements ServiceInterface
|
abstract class AbstractService implements ServiceInterface
|
||||||
{
|
{
|
||||||
public function __construct(protected Service $service)
|
public function __construct(protected Service $service) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function creationRules(array $input): array
|
public function creationRules(array $input): array
|
||||||
{
|
{
|
||||||
|
14
app/SSH/Services/Database/scripts/mariadb/install-10.11.sh
Executable file
14
app/SSH/Services/Database/scripts/mariadb/install-10.11.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
|
||||||
|
|
||||||
|
chmod +x mariadb_repo_setup
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive ./mariadb_repo_setup \
|
||||||
|
--mariadb-server-version="mariadb-10.11"
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get update
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server mariadb-backup -y
|
||||||
|
|
||||||
|
sudo systemctl unmask mysql.service
|
||||||
|
|
||||||
|
sudo service mysql start
|
14
app/SSH/Services/Database/scripts/mariadb/install-10.6.sh
Executable file
14
app/SSH/Services/Database/scripts/mariadb/install-10.6.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
|
||||||
|
|
||||||
|
chmod +x mariadb_repo_setup
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive ./mariadb_repo_setup \
|
||||||
|
--mariadb-server-version="mariadb-10.6"
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get update
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server mariadb-backup -y
|
||||||
|
|
||||||
|
sudo systemctl unmask mysql.service
|
||||||
|
|
||||||
|
sudo service mysql start
|
14
app/SSH/Services/Database/scripts/mariadb/install-11.4.sh
Executable file
14
app/SSH/Services/Database/scripts/mariadb/install-11.4.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
|
||||||
|
|
||||||
|
chmod +x mariadb_repo_setup
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive ./mariadb_repo_setup \
|
||||||
|
--mariadb-server-version="mariadb-11.4"
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get update
|
||||||
|
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server mariadb-backup -y
|
||||||
|
|
||||||
|
sudo systemctl unmask mysql.service
|
||||||
|
|
||||||
|
sudo service mysql start
|
@ -4,6 +4,4 @@
|
|||||||
|
|
||||||
use App\SSH\Services\AbstractService;
|
use App\SSH\Services\AbstractService;
|
||||||
|
|
||||||
abstract class AbstractFirewall extends AbstractService implements Firewall
|
abstract class AbstractFirewall extends AbstractService implements Firewall {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
@ -102,12 +102,10 @@ public function installComposer(): void
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPHPIni(): string
|
public function getPHPIni(string $type): string
|
||||||
{
|
{
|
||||||
return $this->service->server->ssh()->exec(
|
return $this->service->server->os()->readFile(
|
||||||
$this->getScript('get-php-ini.sh', [
|
sprintf('/etc/php/%s/%s/php.ini', $this->service->version, $type)
|
||||||
'version' => $this->service->version,
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
if ! cat /etc/php/__version__/cli/php.ini; then
|
|
||||||
echo 'VITO_SSH_ERROR' && exit 1
|
|
||||||
fi
|
|
@ -4,6 +4,4 @@
|
|||||||
|
|
||||||
use App\SSH\Services\AbstractService;
|
use App\SSH\Services\AbstractService;
|
||||||
|
|
||||||
abstract class AbstractWebserver extends AbstractService implements Webserver
|
abstract class AbstractWebserver extends AbstractService implements Webserver {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
@ -27,6 +27,7 @@ server {
|
|||||||
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
||||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
fastcgi_hide_header X-Powered-By;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /\.(?!well-known).* {
|
location ~ /\.(?!well-known).* {
|
||||||
|
@ -23,6 +23,7 @@ server {
|
|||||||
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
||||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
|
fastcgi_hide_header X-Powered-By;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /\.(?!well-known).* {
|
location ~ /\.(?!well-known).* {
|
||||||
|
@ -7,7 +7,5 @@
|
|||||||
|
|
||||||
abstract class AbstractStorage implements Storage
|
abstract class AbstractStorage implements Storage
|
||||||
{
|
{
|
||||||
public function __construct(protected Server $server, protected StorageProvider $storageProvider)
|
public function __construct(protected Server $server, protected StorageProvider $storageProvider) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
class Systemd
|
class Systemd
|
||||||
{
|
{
|
||||||
public function __construct(protected Server $server)
|
public function __construct(protected Server $server) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function status(string $unit): string
|
public function status(string $unit): string
|
||||||
{
|
{
|
||||||
|
@ -24,4 +24,4 @@ if ! wp --path=__path__ core install --url='http://__domain__' --title="__title_
|
|||||||
echo 'VITO_SSH_ERROR' && exit 1
|
echo 'VITO_SSH_ERROR' && exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print "Wordpress installed!"
|
echo "Wordpress installed!"
|
||||||
|
@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
namespace App\SiteTypes;
|
namespace App\SiteTypes;
|
||||||
|
|
||||||
class Laravel extends PHPSite
|
class Laravel extends PHPSite {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,12 @@ class SSHFake extends SSH
|
|||||||
|
|
||||||
protected bool $connectionWillFail = false;
|
protected bool $connectionWillFail = false;
|
||||||
|
|
||||||
|
protected string $uploadedLocalPath;
|
||||||
|
|
||||||
|
protected string $uploadedRemotePath;
|
||||||
|
|
||||||
|
protected string $uploadedContent;
|
||||||
|
|
||||||
public function __construct(?string $output = null)
|
public function __construct(?string $output = null)
|
||||||
{
|
{
|
||||||
$this->output = $output;
|
$this->output = $output;
|
||||||
@ -63,6 +69,9 @@ public function exec(string $command, string $log = '', ?int $siteId = null, ?bo
|
|||||||
|
|
||||||
public function upload(string $local, string $remote): void
|
public function upload(string $local, string $remote): void
|
||||||
{
|
{
|
||||||
|
$this->uploadedLocalPath = $local;
|
||||||
|
$this->uploadedRemotePath = $remote;
|
||||||
|
$this->uploadedContent = file_get_contents($local);
|
||||||
$this->log = null;
|
$this->log = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,4 +114,22 @@ public function assertExecutedContains(string $command): void
|
|||||||
}
|
}
|
||||||
Assert::assertTrue(true, $executed);
|
Assert::assertTrue(true, $executed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function assertFileUploaded(string $toPath, ?string $content = null): void
|
||||||
|
{
|
||||||
|
if (! $this->uploadedLocalPath || ! $this->uploadedRemotePath) {
|
||||||
|
Assert::fail('File is not uploaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert::assertEquals($toPath, $this->uploadedRemotePath);
|
||||||
|
|
||||||
|
if ($content) {
|
||||||
|
Assert::assertEquals($content, $this->uploadedContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUploadedLocalPath(): string
|
||||||
|
{
|
||||||
|
return $this->uploadedLocalPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
namespace App\ValidationRules;
|
namespace App\ValidationRules;
|
||||||
|
|
||||||
use Cron\CronExpression;
|
use Cron\CronExpression;
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
class CronRule implements Rule
|
class CronRule implements ValidationRule
|
||||||
{
|
{
|
||||||
private bool $acceptCustom;
|
private bool $acceptCustom;
|
||||||
|
|
||||||
@ -14,13 +14,14 @@ public function __construct(bool $acceptCustom = false)
|
|||||||
$this->acceptCustom = $acceptCustom;
|
$this->acceptCustom = $acceptCustom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function passes($attribute, $value): bool
|
public function validate(string $attribute, mixed $value, \Closure $fail): void
|
||||||
{
|
{
|
||||||
return CronExpression::isValidExpression($value) || ($this->acceptCustom && $value === 'custom');
|
if (CronExpression::isValidExpression($value)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if ($this->acceptCustom && $value === 'custom') {
|
||||||
public function message(): string
|
return;
|
||||||
{
|
}
|
||||||
return __('Invalid frequency');
|
$fail('Invalid frequency')->translate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,19 @@
|
|||||||
|
|
||||||
namespace App\ValidationRules;
|
namespace App\ValidationRules;
|
||||||
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
class DomainRule implements Rule
|
class DomainRule implements ValidationRule
|
||||||
{
|
{
|
||||||
public function passes($attribute, $value): bool
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
{
|
{
|
||||||
if ($value) {
|
if (! $value) {
|
||||||
return preg_match("/^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$/", $value);
|
return;
|
||||||
}
|
}
|
||||||
|
if (preg_match("/^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$/", $value) === 1) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
$fail('Domain is not valid')->translate();
|
||||||
public function message(): string
|
|
||||||
{
|
|
||||||
return __('Domain is not valid');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,16 @@
|
|||||||
|
|
||||||
namespace App\ValidationRules;
|
namespace App\ValidationRules;
|
||||||
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
class RestrictedIPAddressesRule implements Rule
|
class RestrictedIPAddressesRule implements ValidationRule
|
||||||
{
|
{
|
||||||
/**
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
* Determine if the validation rule passes.
|
|
||||||
*
|
|
||||||
* @param string $attribute
|
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value)
|
|
||||||
{
|
{
|
||||||
return ! in_array($value, config('core.restricted_ip_addresses'));
|
if (! in_array($value, config('core.restricted_ip_addresses'))) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
$fail('IP address is restricted')->translate();
|
||||||
/**
|
|
||||||
* @return array|\Illuminate\Contracts\Translation\Translator|string|null
|
|
||||||
*/
|
|
||||||
public function message()
|
|
||||||
{
|
|
||||||
return __('IP address is restricted.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,49 +2,21 @@
|
|||||||
|
|
||||||
namespace App\ValidationRules;
|
namespace App\ValidationRules;
|
||||||
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use phpseclib3\Crypt\PublicKeyLoader;
|
||||||
|
use phpseclib3\Exception\NoKeyLoadedException;
|
||||||
|
|
||||||
class SshKeyRule implements Rule
|
class SshKeyRule implements ValidationRule
|
||||||
{
|
{
|
||||||
/**
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
* Determine if the validation rule passes.
|
|
||||||
*
|
|
||||||
* @param string $attribute
|
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value)
|
|
||||||
{
|
{
|
||||||
$key_parts = explode(' ', $value, 3);
|
try {
|
||||||
if (count($key_parts) < 2) {
|
PublicKeyLoader::load($value);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (count($key_parts) > 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$algorithm = $key_parts[0];
|
|
||||||
$key = $key_parts[1];
|
|
||||||
if (! in_array($algorithm, ['ssh-rsa', 'ssh-dss'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$key_base64_decoded = base64_decode($key, true);
|
|
||||||
if ($key_base64_decoded == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$check = base64_decode(substr($key, 0, 16));
|
|
||||||
$check = preg_replace("/[^\w\-]/", '', $check);
|
|
||||||
if ((string) $check !== (string) $algorithm) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return;
|
||||||
}
|
} catch (NoKeyLoadedException) {
|
||||||
|
$fail('Invalid key')->translate();
|
||||||
/**
|
}
|
||||||
* @return array|\Illuminate\Contracts\Translation\Translator|string|null
|
|
||||||
*/
|
|
||||||
public function message()
|
|
||||||
{
|
|
||||||
return __('Invalid key');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
class ServerLayout extends Component
|
class ServerLayout extends Component
|
||||||
{
|
{
|
||||||
public function __construct(public Server $server)
|
public function __construct(public Server $server) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
class SiteLayout extends Component
|
class SiteLayout extends Component
|
||||||
{
|
{
|
||||||
public function __construct(public Site $site)
|
public function __construct(public Site $site) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"ext-ftp": "*",
|
"ext-ftp": "*",
|
||||||
"aws/aws-sdk-php": "^3.158",
|
"aws/aws-sdk-php": "^3.158",
|
||||||
"laravel/fortify": "^1.17",
|
"laravel/fortify": "^1.17",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^11.0",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"phpseclib/phpseclib": "~3.0"
|
"phpseclib/phpseclib": "~3.0"
|
||||||
},
|
},
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"laravel/pint": "^1.10",
|
"laravel/pint": "^1.10",
|
||||||
"laravel/sail": "^1.18",
|
"laravel/sail": "^1.18",
|
||||||
"mockery/mockery": "^1.4.4",
|
"mockery/mockery": "^1.4.4",
|
||||||
"nunomaduro/collision": "^7.0",
|
"nunomaduro/collision": "^8.1",
|
||||||
"phpunit/phpunit": "^10.0",
|
"phpunit/phpunit": "^10.0",
|
||||||
"spatie/laravel-ignition": "^2.0"
|
"spatie/laravel-ignition": "^2.0"
|
||||||
},
|
},
|
||||||
|
1386
composer.lock
generated
1386
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,9 @@
|
|||||||
'mysql80',
|
'mysql80',
|
||||||
'mariadb103',
|
'mariadb103',
|
||||||
'mariadb104',
|
'mariadb104',
|
||||||
|
'mariadb106',
|
||||||
|
'mariadb1011',
|
||||||
|
'mariadb114',
|
||||||
'postgresql12',
|
'postgresql12',
|
||||||
'postgresql13',
|
'postgresql13',
|
||||||
'postgresql14',
|
'postgresql14',
|
||||||
@ -50,6 +53,9 @@
|
|||||||
'mysql80' => 'mysql',
|
'mysql80' => 'mysql',
|
||||||
'mariadb103' => 'mariadb',
|
'mariadb103' => 'mariadb',
|
||||||
'mariadb104' => 'mariadb',
|
'mariadb104' => 'mariadb',
|
||||||
|
'mariadb106' => 'mariadb',
|
||||||
|
'mariadb1011' => 'mariadb',
|
||||||
|
'mariadb114' => 'mariadb',
|
||||||
'postgresql12' => 'postgresql',
|
'postgresql12' => 'postgresql',
|
||||||
'postgresql13' => 'postgresql',
|
'postgresql13' => 'postgresql',
|
||||||
'postgresql14' => 'postgresql',
|
'postgresql14' => 'postgresql',
|
||||||
@ -63,6 +69,9 @@
|
|||||||
'mariadb' => '10.3',
|
'mariadb' => '10.3',
|
||||||
'mariadb103' => '10.3',
|
'mariadb103' => '10.3',
|
||||||
'mariadb104' => '10.4',
|
'mariadb104' => '10.4',
|
||||||
|
'mariadb106' => '10.6',
|
||||||
|
'mariadb1011' => '10.11',
|
||||||
|
'mariadb114' => '11.4',
|
||||||
'postgresql12' => '12',
|
'postgresql12' => '12',
|
||||||
'postgresql13' => '13',
|
'postgresql13' => '13',
|
||||||
'postgresql14' => '14',
|
'postgresql14' => '14',
|
||||||
@ -193,14 +202,23 @@
|
|||||||
\App\Enums\OperatingSystem::UBUNTU20 => [
|
\App\Enums\OperatingSystem::UBUNTU20 => [
|
||||||
'10.3' => 'mariadb',
|
'10.3' => 'mariadb',
|
||||||
'10.4' => 'mariadb',
|
'10.4' => 'mariadb',
|
||||||
|
'10.6' => 'mariadb',
|
||||||
|
'10.11' => 'mariadb',
|
||||||
|
'11.4' => 'mariadb',
|
||||||
],
|
],
|
||||||
\App\Enums\OperatingSystem::UBUNTU22 => [
|
\App\Enums\OperatingSystem::UBUNTU22 => [
|
||||||
'10.3' => 'mariadb',
|
'10.3' => 'mariadb',
|
||||||
'10.4' => 'mariadb',
|
'10.4' => 'mariadb',
|
||||||
|
'10.6' => 'mariadb',
|
||||||
|
'10.11' => 'mariadb',
|
||||||
|
'11.4' => 'mariadb',
|
||||||
],
|
],
|
||||||
\App\Enums\OperatingSystem::UBUNTU24 => [
|
\App\Enums\OperatingSystem::UBUNTU24 => [
|
||||||
'10.3' => 'mariadb',
|
'10.3' => 'mariadb',
|
||||||
'10.4' => 'mariadb',
|
'10.4' => 'mariadb',
|
||||||
|
'10.6' => 'mariadb',
|
||||||
|
'10.11' => 'mariadb',
|
||||||
|
'11.4' => 'mariadb',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'postgresql' => [
|
'postgresql' => [
|
||||||
|
@ -487,6 +487,7 @@
|
|||||||
'ubuntu_18' => 'linode/ubuntu18.04',
|
'ubuntu_18' => 'linode/ubuntu18.04',
|
||||||
'ubuntu_20' => 'linode/ubuntu20.04',
|
'ubuntu_20' => 'linode/ubuntu20.04',
|
||||||
'ubuntu_22' => 'linode/ubuntu22.04',
|
'ubuntu_22' => 'linode/ubuntu22.04',
|
||||||
|
'ubuntu_24' => 'linode/ubuntu24.04',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'digitalocean' => [
|
'digitalocean' => [
|
||||||
@ -618,6 +619,7 @@
|
|||||||
'ubuntu_18' => '112929540',
|
'ubuntu_18' => '112929540',
|
||||||
'ubuntu_20' => '112929454',
|
'ubuntu_20' => '112929454',
|
||||||
'ubuntu_22' => '129211873',
|
'ubuntu_22' => '129211873',
|
||||||
|
'ubuntu_24' => '155133621',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'vultr' => [
|
'vultr' => [
|
||||||
@ -789,30 +791,69 @@
|
|||||||
'ubuntu_18' => '270',
|
'ubuntu_18' => '270',
|
||||||
'ubuntu_20' => '387',
|
'ubuntu_20' => '387',
|
||||||
'ubuntu_22' => '1743',
|
'ubuntu_22' => '1743',
|
||||||
|
'ubuntu_24' => '2284',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'hetzner' => [
|
'hetzner' => [
|
||||||
'plans' => [
|
'plans' => [
|
||||||
|
|
||||||
|
/* Shared vCPUs x86 */
|
||||||
[
|
[
|
||||||
'title' => 'CX11 - 1 Cores - 2 Memory - 20 Disk',
|
'title' => 'CX11 - 1 Cores (Intel) - 2 Memory - 20 Disk (eu only)',
|
||||||
'value' => 'cx11',
|
'value' => 'cx11',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CX21 - 2 Cores - 4 Memory - 40 Disk',
|
'title' => 'CX22 - 2 Cores (Intel) - 4 Memory - 40 Disk (eu only)',
|
||||||
|
'value' => 'cx22',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CPX11 - 2 Cores (AMD) - 2 Memory - 40 Disk (eu only)',
|
||||||
|
'value' => 'cpx11',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX21 - 2 Cores (Intel) - 4 Memory - 40 Disk (eu only)',
|
||||||
'value' => 'cx21',
|
'value' => 'cx21',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CX31 - 2 Cores - 8 Memory - 80 Disk',
|
'title' => 'CX32 - 4 Cores (Intel) - 8 Memory - 80 Disk (eu only)',
|
||||||
|
'value' => 'cx32',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CPX21 - 3 Cores (AMD) - 4 Memory - 80 Disk',
|
||||||
|
'value' => 'cpx21',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX31 - 2 Cores (Intel) - 8 Memory - 80 Disk (eu only)',
|
||||||
'value' => 'cx31',
|
'value' => 'cx31',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CX41 - 4 Cores - 16 Memory - 160 Disk',
|
'title' => 'CPX31 - 4 Cores (AMD) - 8 Memory - 160 Disk',
|
||||||
|
'value' => 'cpx31',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX42 - 8 Cores (Intel) - 16 Memory - 160 Disk (eu only)',
|
||||||
|
'value' => 'cx42',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX41 - 4 Cores (Intel) - 16 Memory - 160 Disk (eu only)',
|
||||||
'value' => 'cx41',
|
'value' => 'cx41',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CX51 - 8 Cores - 32 Memory - 240 Disk',
|
'title' => 'CPX41 - 8 Cores (AMD) - 16 Memory - 240 Disk',
|
||||||
|
'value' => 'cpx41',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX52 - 16 Cores (Intel) - 32 Memory - 320 Disk (eu only)',
|
||||||
|
'value' => 'cx52',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CX51 - 8 Cores (Intel) - 32 Memory - 240 Disk (eu only)',
|
||||||
'value' => 'cx51',
|
'value' => 'cx51',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CPX51 - 16 Cores (AMD) - 32 Memory - 360 Disk',
|
||||||
|
'value' => 'cpx51',
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CCX11 Dedicated CPU - 2 Cores - 8 Memory - 80 Disk',
|
'title' => 'CCX11 Dedicated CPU - 2 Cores - 8 Memory - 80 Disk',
|
||||||
'value' => 'ccx11',
|
'value' => 'ccx11',
|
||||||
@ -833,66 +874,50 @@
|
|||||||
'title' => 'CCX51 Dedicated CPU - 32 Cores - 128 Memory - 600 Disk',
|
'title' => 'CCX51 Dedicated CPU - 32 Cores - 128 Memory - 600 Disk',
|
||||||
'value' => 'ccx51',
|
'value' => 'ccx51',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
/* Shared vCPUs Arm64 */
|
||||||
[
|
[
|
||||||
'title' => 'CPX 11 - 2 Cores - 2 Memory - 40 Disk',
|
'title' => 'CAX11 - 2 Cores (ARM64) - 4 Memory - 40 Disk',
|
||||||
'value' => 'cpx11',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CPX 21 - 3 Cores - 4 Memory - 80 Disk',
|
|
||||||
'value' => 'cpx21',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CPX 31 - 4 Cores - 8 Memory - 160 Disk',
|
|
||||||
'value' => 'cpx31',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CPX 41 - 8 Cores - 16 Memory - 240 Disk',
|
|
||||||
'value' => 'cpx41',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CPX 51 - 16 Cores - 32 Memory - 360 Disk',
|
|
||||||
'value' => 'cpx51',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX12 Dedicated CPU - 2 Cores - 8 Memory - 80 Disk',
|
|
||||||
'value' => 'ccx12',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX22 Dedicated CPU - 4 Cores - 16 Memory - 160 Disk',
|
|
||||||
'value' => 'ccx22',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX32 Dedicated CPU - 8 Cores - 32 Memory - 240 Disk',
|
|
||||||
'value' => 'ccx32',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX42 Dedicated CPU - 16 Cores - 64 Memory - 360 Disk',
|
|
||||||
'value' => 'ccx42',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX52 Dedicated CPU - 32 Cores - 128 Memory - 600 Disk',
|
|
||||||
'value' => 'ccx52',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CCX62 Dedicated CPU - 48 Cores - 192 Memory - 960 Disk',
|
|
||||||
'value' => 'ccx62',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'CAX11 - 2 Cores - 4 Memory - 40 Disk',
|
|
||||||
'value' => 'cax11',
|
'value' => 'cax11',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CAX21 - 4 Cores - 8 Memory - 80 Disk',
|
'title' => 'CAX21 - 4 Cores (ARM64) - 8 Memory - 80 Disk',
|
||||||
'value' => 'cax21',
|
'value' => 'cax21',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CAX31 - 8 Cores - 16 Memory - 160 Disk',
|
'title' => 'CAX31 - 8 Cores (ARM64) - 16 Memory - 160 Disk',
|
||||||
'value' => 'cax31',
|
'value' => 'cax31',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'CAX41 - 16 Cores - 32 Memory - 320 Disk',
|
'title' => 'CAX41 - 16 Cores (ARM64) - 32 Memory - 320 Disk',
|
||||||
'value' => 'cax41',
|
'value' => 'cax41',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
/* Dedicated vCPUs */
|
||||||
|
[
|
||||||
|
'title' => 'CCX13 Dedicated CPU - 2 Cores (AMD) - 8 Memory - 80 Disk',
|
||||||
|
'value' => 'ccx13',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CCX23 Dedicated CPU - 4 Cores (AMD) - 16 Memory - 160 Disk',
|
||||||
|
'value' => 'ccx23',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CCX33 Dedicated CPU - 8 Cores (AMD) - 32 Memory - 240 Disk',
|
||||||
|
'value' => 'ccx33',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CCX43 Dedicated CPU - 16 Cores (AMD) - 64 Memory - 360 Disk',
|
||||||
|
'value' => 'ccx43',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CCX53 Dedicated CPU - 32 Cores (AMD) - 128 Memory - 600 Disk',
|
||||||
|
'value' => 'ccx53',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'CCX63 Dedicated CPU - 48 Cores (AMD) - 192 Memory - 960 Disk',
|
||||||
|
'value' => 'ccx63',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'regions' => [
|
'regions' => [
|
||||||
[
|
[
|
||||||
@ -917,9 +942,9 @@
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
'images' => [
|
'images' => [
|
||||||
'ubuntu_18' => 'ubuntu-18.04',
|
|
||||||
'ubuntu_20' => 'ubuntu-20.04',
|
'ubuntu_20' => 'ubuntu-20.04',
|
||||||
'ubuntu_22' => 'ubuntu-22.04',
|
'ubuntu_22' => 'ubuntu-22.04',
|
||||||
|
'ubuntu_24' => 'ubuntu-24.04',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
24
database/factories/ScriptExecutionFactory.php
Normal file
24
database/factories/ScriptExecutionFactory.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Enums\ScriptExecutionStatus;
|
||||||
|
use App\Models\ScriptExecution;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class ScriptExecutionFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = ScriptExecution::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'user' => 'root',
|
||||||
|
'variables' => [],
|
||||||
|
'status' => ScriptExecutionStatus::EXECUTING,
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
22
database/factories/ScriptFactory.php
Normal file
22
database/factories/ScriptFactory.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Script;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class ScriptFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = Script::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->faker->name(),
|
||||||
|
'content' => 'ls -la',
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
0
database/migrations/2014_10_12_000000_create_users_table.php
Executable file → Normal file
0
database/migrations/2014_10_12_000000_create_users_table.php
Executable file → Normal file
0
database/migrations/2014_10_12_100000_create_password_resets_table.php
Executable file → Normal file
0
database/migrations/2014_10_12_100000_create_password_resets_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_192743_create_sessions_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_192743_create_sessions_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_211827_create_servers_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_211827_create_servers_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_214143_create_services_table.php
Executable file → Normal file
0
database/migrations/2021_06_23_214143_create_services_table.php
Executable file → Normal file
0
database/migrations/2021_06_25_102220_create_jobs_table.php
Executable file → Normal file
0
database/migrations/2021_06_25_102220_create_jobs_table.php
Executable file → Normal file
0
database/migrations/2021_06_25_124831_create_server_logs_table.php
Executable file → Normal file
0
database/migrations/2021_06_25_124831_create_server_logs_table.php
Executable file → Normal file
0
database/migrations/2021_06_26_211903_create_sites_table.php
Executable file → Normal file
0
database/migrations/2021_06_26_211903_create_sites_table.php
Executable file → Normal file
0
database/migrations/2021_06_28_085814_create_source_controls_table.php
Executable file → Normal file
0
database/migrations/2021_06_28_085814_create_source_controls_table.php
Executable file → Normal file
0
database/migrations/2021_07_02_065815_create_deployments_table.php
Executable file → Normal file
0
database/migrations/2021_07_02_065815_create_deployments_table.php
Executable file → Normal file
0
database/migrations/2021_07_03_133319_create_databases_table.php
Executable file → Normal file
0
database/migrations/2021_07_03_133319_create_databases_table.php
Executable file → Normal file
0
database/migrations/2021_07_03_133327_create_database_users_table.php
Executable file → Normal file
0
database/migrations/2021_07_03_133327_create_database_users_table.php
Executable file → Normal file
0
database/migrations/2021_07_15_090830_create_firewall_rules_table.php
Executable file → Normal file
0
database/migrations/2021_07_15_090830_create_firewall_rules_table.php
Executable file → Normal file
0
database/migrations/2021_07_30_204454_create_cron_jobs_table.php
Executable file → Normal file
0
database/migrations/2021_07_30_204454_create_cron_jobs_table.php
Executable file → Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('script_executions');
|
||||||
|
|
||||||
|
Schema::create('script_executions', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('script_id');
|
||||||
|
$table->unsignedBigInteger('server_log_id')->nullable();
|
||||||
|
$table->string('user');
|
||||||
|
$table->json('variables')->nullable();
|
||||||
|
$table->string('status');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('script_executions');
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('notification_channels', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('project_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('notification_channels', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('project_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('storage_providers', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('project_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('storage_providers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('project_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('server_providers', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('project_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('server_providers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('project_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -5,6 +5,39 @@ NAME=${NAME:-"vito"}
|
|||||||
EMAIL=${EMAIL:-"vito@vitodeploy.com"}
|
EMAIL=${EMAIL:-"vito@vitodeploy.com"}
|
||||||
PASSWORD=${PASSWORD:-"password"}
|
PASSWORD=${PASSWORD:-"password"}
|
||||||
|
|
||||||
|
# Function to check if a string is 32 characters long
|
||||||
|
check_length() {
|
||||||
|
local key=$1
|
||||||
|
if [ ${#key} -ne 32 ]; then
|
||||||
|
echo "Invalid APP_KEY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if APP_KEY is set
|
||||||
|
if [ -z "$APP_KEY" ]; then
|
||||||
|
echo "APP_KEY is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if APP_KEY starts with 'base64:'
|
||||||
|
if [[ $APP_KEY == base64:* ]]; then
|
||||||
|
# Remove 'base64:' prefix and decode the base64 string
|
||||||
|
decoded_key=$(echo "${APP_KEY:7}" | base64 --decode 2>/dev/null)
|
||||||
|
|
||||||
|
# Check if decoding was successful
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Invalid APP_KEY base64 encoding"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check the length of the decoded key
|
||||||
|
check_length "$decoded_key"
|
||||||
|
else
|
||||||
|
# Check the length of the raw APP_KEY
|
||||||
|
check_length "$APP_KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
# check if the flag file does not exist, indicating a first run
|
# check if the flag file does not exist, indicating a first run
|
||||||
if [ ! -f "$INIT_FLAG" ]; then
|
if [ ! -f "$INIT_FLAG" ]; then
|
||||||
echo "Initializing..."
|
echo "Initializing..."
|
||||||
|
15
package-lock.json
generated
15
package-lock.json
generated
@ -4,6 +4,7 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"name": "vito",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.2",
|
"@tailwindcss/forms": "^0.5.2",
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
@ -694,12 +695,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@ -969,9 +970,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
|
1
public/build/assets/app-7f487305.css
Normal file
1
public/build/assets/app-7f487305.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user