mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-01 14:06:15 +00:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
9db310a06b | |||
f70963d6bb | |||
b75df8e1c5 | |||
a22e9cb946 | |||
b2b9bea0b1 | |||
3f4a2bce3a | |||
8bffefabef | |||
3da1f4fe4c | |||
2214a76e09 | |||
55bf8b8ecf | |||
0420babdef | |||
1c3d78a5ed | |||
8665435bc4 | |||
0ec6a9dea2 | |||
bdfda05398 | |||
919cdc6892 | |||
902548e463 | |||
2462b31f3b | |||
e997d0deea | |||
f06b8f7d20 | |||
f120a570e8 | |||
2d7f225ff2 | |||
31bd146239 |
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1025
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1025
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1025
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
To request a feature or suggest an idea please add it to the feedback boards
|
||||
|
||||
https://features.vitodeploy.com/
|
@ -4,6 +4,8 @@ # Vito
|
||||
|
||||

|
||||
|
||||
[[Discord](https://discord.gg/dcUWA5DV)]
|
||||
|
||||
Better Readme will come soon... :)
|
||||
|
||||
## Documentation
|
||||
@ -12,11 +14,11 @@ ## Documentation
|
||||
|
||||
## Feedbacks
|
||||
|
||||
https://features.vitodeploy.com
|
||||
https://vitodeploy.featurebase.app
|
||||
|
||||
## Roadmap
|
||||
|
||||
https://https://features.vitodeploy.com/roadmap
|
||||
https://vitodeploy.featurebase.app/roadmap
|
||||
|
||||
## Contribution
|
||||
|
||||
|
@ -21,16 +21,25 @@ public function add(User $user, array $input): void
|
||||
'label' => $input['label'],
|
||||
]);
|
||||
$this->validateType($channel, $input);
|
||||
$channel->data = $channel->provider()->data($input);
|
||||
$channel->data = $channel->provider()->createData($input);
|
||||
$channel->save();
|
||||
|
||||
if (! $channel->provider()->connect()) {
|
||||
$channel->delete();
|
||||
|
||||
if ($channel->provider === \App\Enums\NotificationChannel::EMAIL) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => __('Could not connect! Make sure you configured `.env` file correctly.'),
|
||||
]);
|
||||
}
|
||||
|
||||
throw ValidationException::withMessages([
|
||||
'provider' => __('Could not connect'),
|
||||
]);
|
||||
}
|
||||
|
||||
$channel->connected = true;
|
||||
$channel->save();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,7 +58,7 @@ protected function validate(array $input): void
|
||||
*/
|
||||
protected function validateType(NotificationChannel $channel, array $input): void
|
||||
{
|
||||
Validator::make($input, $channel->provider()->validationRules())
|
||||
Validator::make($input, $channel->provider()->createRules($input))
|
||||
->validate();
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,12 @@ public function update(Service $service, string $ini): void
|
||||
{
|
||||
$tmpName = Str::random(10).strtotime('now');
|
||||
try {
|
||||
Storage::disk('local')->put($tmpName, $ini);
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk('local');
|
||||
|
||||
$storageDisk->put($tmpName, $ini);
|
||||
$service->server->ssh('root')->upload(
|
||||
Storage::disk('local')->path($tmpName),
|
||||
$storageDisk->path($tmpName),
|
||||
"/etc/php/$service->version/cli/php.ini"
|
||||
);
|
||||
$this->deleteTempFile($tmpName);
|
||||
|
@ -44,9 +44,8 @@ public function create(User $creator, array $input): Server
|
||||
'progress_step' => 'Initializing',
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
if ($server->provider != 'custom') {
|
||||
$server->provider_id = $input['server_provider'];
|
||||
}
|
||||
@ -119,7 +118,6 @@ private function validateInputs(array $input): void
|
||||
if ($input['provider'] == 'custom') {
|
||||
$rules['ip'] = [
|
||||
'required',
|
||||
'ip',
|
||||
new RestrictedIPAddressesRule(),
|
||||
];
|
||||
$rules['port'] = [
|
||||
|
@ -23,9 +23,8 @@ public function create(Server $server, array $input): Site
|
||||
{
|
||||
$this->validateInputs($server, $input);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$site = new Site([
|
||||
'server_id' => $server->id,
|
||||
'type' => $input['type'],
|
||||
|
@ -2,9 +2,17 @@
|
||||
|
||||
namespace App\Contracts;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
interface Notification
|
||||
{
|
||||
public function subject(): string;
|
||||
public function rawText(): string;
|
||||
|
||||
public function message(bool $mail = false): mixed;
|
||||
public function toEmail(object $notifiable): MailMessage;
|
||||
|
||||
public function toSlack(object $notifiable): string;
|
||||
|
||||
public function toDiscord(object $notifiable): string;
|
||||
|
||||
public function toTelegram(object $notifiable): string;
|
||||
}
|
||||
|
@ -4,11 +4,13 @@
|
||||
|
||||
interface NotificationChannel
|
||||
{
|
||||
public function validationRules(): array;
|
||||
public function createRules(array $input): array;
|
||||
|
||||
public function data(array $input): array;
|
||||
public function createData(array $input): array;
|
||||
|
||||
public function data(): array;
|
||||
|
||||
public function connect(): bool;
|
||||
|
||||
public function sendMessage(string $subject, string $text): void;
|
||||
public function send(object $notifiable, Notification $notification): void;
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ interface Webserver
|
||||
{
|
||||
public function createVHost(Site $site): void;
|
||||
|
||||
public function updateVHost(Site $site): void;
|
||||
public function updateVHost(Site $site, bool $noSSL = false, ?string $vhost = null): void;
|
||||
|
||||
public function getVHost(Site $site): string;
|
||||
|
||||
public function deleteSite(Site $site): void;
|
||||
|
||||
|
@ -11,4 +11,6 @@ final class NotificationChannel extends Enum
|
||||
const SLACK = 'slack';
|
||||
|
||||
const DISCORD = 'discord';
|
||||
|
||||
const TELEGRAM = 'telegram';
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ final class SiteType extends Enum
|
||||
{
|
||||
const PHP = 'php';
|
||||
|
||||
const PHP_BLANK = 'php-blank';
|
||||
|
||||
const LARAVEL = 'laravel';
|
||||
|
||||
const WORDPRESS = 'wordpress';
|
||||
|
17
app/Facades/Notifier.php
Normal file
17
app/Facades/Notifier.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Facades;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* @method static void send(object $notifiable, Notification $notification)
|
||||
*/
|
||||
class Notifier extends Facade
|
||||
{
|
||||
protected static function getFacadeAccessor(): string
|
||||
{
|
||||
return 'notifier';
|
||||
}
|
||||
}
|
19
app/Helpers/Notifier.php
Normal file
19
app/Helpers/Notifier.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\NotificationChannel;
|
||||
|
||||
class Notifier
|
||||
{
|
||||
/**
|
||||
* In the future we can send notifications based on the notifiable instance,
|
||||
* For example, If it was a server then we will send the channels specified by that server
|
||||
* For now, we will send all channels.
|
||||
*/
|
||||
public function send(object $notifiable, Notification $notification): void
|
||||
{
|
||||
NotificationChannel::notifyAll($notification);
|
||||
}
|
||||
}
|
@ -64,11 +64,15 @@ public function setLog(string $logType, $siteId = null): void
|
||||
*/
|
||||
public function connect(bool $sftp = false): void
|
||||
{
|
||||
$ip = $this->server->ip;
|
||||
if (str($ip)->contains(':')) {
|
||||
$ip = '['.$ip.']';
|
||||
}
|
||||
try {
|
||||
if ($sftp) {
|
||||
$this->connection = new SFTP($this->server->ip, $this->server->port);
|
||||
$this->connection = new SFTP($ip, $this->server->port);
|
||||
} else {
|
||||
$this->connection = new SSH2($this->server->ip, $this->server->port);
|
||||
$this->connection = new SSH2($ip, $this->server->port);
|
||||
}
|
||||
|
||||
$login = $this->connection->login($this->user, $this->privateKey);
|
||||
|
@ -32,9 +32,6 @@ public function info(string $message): void
|
||||
|
||||
private function toast(string $type, string $message): void
|
||||
{
|
||||
$this->component->dispatchBrowserEvent('toast', [
|
||||
'type' => $type,
|
||||
'message' => $message,
|
||||
]);
|
||||
$this->component->dispatch('toast', type: $type, message: $message);
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,11 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Exceptions\SourceControlIsNotConnected;
|
||||
use App\Facades\Notifier;
|
||||
use App\Models\GitHook;
|
||||
use App\Notifications\SourceControlDisconnected;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Throwable;
|
||||
|
||||
class GitHookController extends Controller
|
||||
@ -25,7 +28,7 @@ public function __invoke(Request $request)
|
||||
try {
|
||||
$gitHook->site->deploy();
|
||||
} catch (SourceControlIsNotConnected) {
|
||||
// TODO: send notification
|
||||
Notifier::send($gitHook->sourceControl, new SourceControlDisconnected($gitHook->sourceControl));
|
||||
} catch (Throwable $e) {
|
||||
Log::error('git-hook-exception', (array) $e);
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ public function deploy(): void
|
||||
|
||||
$this->toast()->success(__('Deployment started!'));
|
||||
|
||||
$this->emitTo(DeploymentsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(DeploymentsList::class);
|
||||
|
||||
$this->emitTo(DeploymentScript::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(DeploymentScript::class);
|
||||
} catch (SourceControlIsNotConnected $e) {
|
||||
session()->flash('toast.type', 'error');
|
||||
session()->flash('toast.message', $e->getMessage());
|
||||
|
@ -27,8 +27,8 @@ public function save(): void
|
||||
|
||||
session()->flash('status', 'script-updated');
|
||||
|
||||
$this->emitTo(Deploy::class, '$refresh');
|
||||
$this->emitTo(AutoDeployment::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(Deploy::class);
|
||||
$this->dispatch('$refresh')->to(AutoDeployment::class);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -22,7 +22,7 @@ public function showLog(int $id): void
|
||||
$deployment = $this->site->deployments()->findOrFail($id);
|
||||
$this->logContent = $deployment->log->content;
|
||||
|
||||
$this->dispatchBrowserEvent('open-modal', 'show-log');
|
||||
$this->dispatch('open-modal', 'show-log');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -27,7 +27,7 @@ public function save(): void
|
||||
|
||||
session()->flash('status', 'updating-env');
|
||||
|
||||
$this->emit(Deploy::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(Deploy::class);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
19
app/Http/Livewire/Application/PhpBlankApp.php
Normal file
19
app/Http/Livewire/Application/PhpBlankApp.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Application;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Traits\RefreshComponentOnBroadcast;
|
||||
use Livewire\Component;
|
||||
|
||||
class PhpBlankApp extends Component
|
||||
{
|
||||
use RefreshComponentOnBroadcast;
|
||||
|
||||
public Site $site;
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.application.php-blank-app');
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public function render(): View
|
||||
$event = Cache::get('broadcast');
|
||||
if ($event) {
|
||||
Cache::forget('broadcast');
|
||||
$this->emit('broadcast', $event);
|
||||
$this->dispatch('broadcast', $event);
|
||||
}
|
||||
|
||||
return view('livewire.broadcast');
|
||||
|
@ -22,9 +22,9 @@ public function create(): void
|
||||
{
|
||||
app(\App\Actions\CronJob\CreateCronJob::class)->create($this->server, $this->all());
|
||||
|
||||
$this->emitTo(CronjobsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(CronjobsList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('created', true);
|
||||
$this->dispatch('created');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -23,7 +23,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -45,7 +45,7 @@ public function restore(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('restored', true);
|
||||
$this->dispatch('restored');
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
@ -55,7 +55,7 @@ public function delete(): void
|
||||
|
||||
$file->delete();
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -40,7 +40,7 @@ public function create(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('backup-created', true);
|
||||
$this->dispatch('backup-created');
|
||||
}
|
||||
|
||||
public function files(int $id): void
|
||||
@ -48,7 +48,7 @@ public function files(int $id): void
|
||||
$backup = Backup::query()->findOrFail($id);
|
||||
$this->backup = $backup;
|
||||
$this->files = $backup->files()->orderByDesc('id')->simplePaginate(1);
|
||||
$this->dispatchBrowserEvent('show-files', true);
|
||||
$this->dispatch('show-files');
|
||||
}
|
||||
|
||||
public function backup(): void
|
||||
@ -57,7 +57,7 @@ public function backup(): void
|
||||
|
||||
$this->files = $this->backup?->files()->orderByDesc('id')->simplePaginate();
|
||||
|
||||
$this->dispatchBrowserEvent('backup-running', true);
|
||||
$this->dispatch('backup-running');
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
@ -67,7 +67,7 @@ public function delete(): void
|
||||
|
||||
$backup->delete();
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -40,7 +40,7 @@ public function create(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('database-created', true);
|
||||
$this->dispatch('database-created');
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
@ -52,9 +52,9 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->emitTo(DatabaseUserList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(DatabaseUserList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -38,7 +38,7 @@ public function create(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('database-user-created', true);
|
||||
$this->dispatch('database-user-created');
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
@ -50,9 +50,9 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->emitTo(DatabaseList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(DatabaseList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function viewPassword(int $id): void
|
||||
@ -62,7 +62,7 @@ public function viewPassword(int $id): void
|
||||
|
||||
$this->viewPassword = $databaseUser->password;
|
||||
|
||||
$this->dispatchBrowserEvent('open-modal', 'database-user-password');
|
||||
$this->dispatch('open-modal', 'database-user-password');
|
||||
}
|
||||
|
||||
public function showLink(int $id): void
|
||||
@ -73,7 +73,7 @@ public function showLink(int $id): void
|
||||
$this->linkId = $id;
|
||||
$this->link = $databaseUser->databases ?? [];
|
||||
|
||||
$this->dispatchBrowserEvent('open-modal', 'link-database-user');
|
||||
$this->dispatch('open-modal', 'link-database-user');
|
||||
}
|
||||
|
||||
public function link(): void
|
||||
@ -85,7 +85,7 @@ public function link(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('linked', true);
|
||||
$this->dispatch('linked');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -28,9 +28,9 @@ public function create(): void
|
||||
{
|
||||
app(CreateRule::class)->create($this->server, $this->all());
|
||||
|
||||
$this->emitTo(FirewallRulesList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(FirewallRulesList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('created', true);
|
||||
$this->dispatch('created');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -15,6 +15,10 @@ class AddChannel extends Component
|
||||
|
||||
public string $email;
|
||||
|
||||
public string $bot_token;
|
||||
|
||||
public string $chat_id;
|
||||
|
||||
public function add(): void
|
||||
{
|
||||
app(\App\Actions\NotificationChannels\AddChannel::class)->add(
|
||||
@ -22,9 +26,9 @@ public function add(): void
|
||||
$this->all()
|
||||
);
|
||||
|
||||
$this->emitTo(ChannelsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ChannelsList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('added', true);
|
||||
$this->dispatch('added');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -56,7 +56,7 @@ public function uninstall(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function loadIni(int $id): void
|
||||
|
@ -33,7 +33,7 @@ public function submit(): void
|
||||
|
||||
session()->flash('status', 'profile-updated');
|
||||
|
||||
$this->emitTo(UserDropdown::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(UserDropdown::class);
|
||||
}
|
||||
|
||||
public function sendVerificationEmail(): void
|
||||
|
@ -21,9 +21,9 @@ public function create(): void
|
||||
app(\App\Actions\Projects\CreateProject::class)
|
||||
->create(auth()->user(), $this->inputs);
|
||||
|
||||
$this->emitTo(ProjectsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ProjectsList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('created', true);
|
||||
$this->dispatch('created');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -24,9 +24,9 @@ public function create(): void
|
||||
{
|
||||
app(\App\Actions\Queue\CreateQueue::class)->create($this->site, $this->all());
|
||||
|
||||
$this->emitTo(QueuesList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(QueuesList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('created', true);
|
||||
$this->dispatch('created');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -24,7 +24,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function start(Queue $queue): void
|
||||
|
@ -27,7 +27,7 @@ public function showLog(int $id): void
|
||||
$log = $this->server->logs()->findOrFail($id);
|
||||
$this->logContent = $log->content;
|
||||
|
||||
$this->dispatchBrowserEvent('open-modal', 'show-log');
|
||||
$this->dispatch('open-modal', 'show-log');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -22,9 +22,9 @@ public function connect(): void
|
||||
{
|
||||
app(CreateServerProvider::class)->create(auth()->user(), $this->all());
|
||||
|
||||
$this->emitTo(ProvidersList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ProvidersList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('connected', true);
|
||||
$this->dispatch('connected');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -19,9 +19,9 @@ public function add(): void
|
||||
|
||||
$key->deployTo($this->server);
|
||||
|
||||
$this->emitTo(ServerKeysList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ServerKeysList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('added', true);
|
||||
$this->dispatch('added');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -24,9 +24,9 @@ public function add(): void
|
||||
|
||||
$key->deployTo($this->server);
|
||||
|
||||
$this->emitTo(ServerKeysList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ServerKeysList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('added', true);
|
||||
$this->dispatch('added');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -28,7 +28,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -21,7 +21,7 @@ public function refreshComponent(array $data): void
|
||||
return;
|
||||
}
|
||||
|
||||
$this->emit('refreshComponent');
|
||||
$this->dispatch('refreshComponent');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -19,9 +19,9 @@ public function install(): void
|
||||
{
|
||||
app(InstallPHPMyAdminAction::class)->install($this->server, $this->all());
|
||||
|
||||
$this->dispatchBrowserEvent('started', true);
|
||||
$this->dispatch('started');
|
||||
|
||||
$this->emitTo(ServicesList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ServicesList::class);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -26,7 +26,7 @@ public function refreshComponent(array $data): void
|
||||
return;
|
||||
}
|
||||
|
||||
$this->emit('refreshComponent');
|
||||
$this->dispatch('refreshComponent');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
41
app/Http/Livewire/Sites/UpdateVHost.php
Normal file
41
app/Http/Livewire/Sites/UpdateVHost.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Sites;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Traits\HasToast;
|
||||
use App\Traits\RefreshComponentOnBroadcast;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Component;
|
||||
use Throwable;
|
||||
|
||||
class UpdateVHost extends Component
|
||||
{
|
||||
use HasToast;
|
||||
use RefreshComponentOnBroadcast;
|
||||
|
||||
public Site $site;
|
||||
|
||||
public string $vHost = 'Loading...';
|
||||
|
||||
public function loadVHost(): void
|
||||
{
|
||||
$this->vHost = $this->site->server->webserver()->handler()->getVHost($this->site);
|
||||
}
|
||||
|
||||
public function update(): void
|
||||
{
|
||||
try {
|
||||
$this->site->server->webserver()->handler()->updateVHost($this->site, false, $this->vHost);
|
||||
|
||||
$this->toast()->success('VHost updated successfully!');
|
||||
} catch (Throwable $e) {
|
||||
$this->toast()->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.sites.update-v-host');
|
||||
}
|
||||
}
|
@ -20,9 +20,9 @@ public function connect(): void
|
||||
{
|
||||
app(ConnectSourceControl::class)->connect($this->all());
|
||||
|
||||
$this->emitTo(SourceControlsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(SourceControlsList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('connected', true);
|
||||
$this->dispatch('connected');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -19,9 +19,9 @@ public function add(): void
|
||||
$this->all()
|
||||
);
|
||||
|
||||
$this->emitTo(KeysList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(KeysList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('added', true);
|
||||
$this->dispatch('added');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -23,9 +23,9 @@ public function create(): void
|
||||
{
|
||||
app(\App\Actions\SSL\CreateSSL::class)->create($this->site, $this->all());
|
||||
|
||||
$this->emitTo(SslsList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(SslsList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('created', true);
|
||||
$this->dispatch('created');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function refreshComponent(array $data): void
|
||||
@ -34,7 +34,7 @@ public function refreshComponent(array $data): void
|
||||
$this->toast()->error(__('SSL creation failed!'));
|
||||
}
|
||||
|
||||
$this->emit('refreshComponent');
|
||||
$this->dispatch('refreshComponent');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -32,9 +32,9 @@ public function connect(): void
|
||||
{
|
||||
app(CreateStorageProvider::class)->create(auth()->user(), $this->all());
|
||||
|
||||
$this->emitTo(ProvidersList::class, '$refresh');
|
||||
$this->dispatch('$refresh')->to(ProvidersList::class);
|
||||
|
||||
$this->dispatchBrowserEvent('connected', true);
|
||||
$this->dispatch('connected');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
||||
|
||||
$this->refreshComponent([]);
|
||||
|
||||
$this->dispatchBrowserEvent('confirmed', true);
|
||||
$this->dispatch('confirmed');
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
@ -3,8 +3,10 @@
|
||||
namespace App\Jobs\Server;
|
||||
|
||||
use App\Events\Broadcast;
|
||||
use App\Facades\Notifier;
|
||||
use App\Jobs\Job;
|
||||
use App\Models\Server;
|
||||
use App\Notifications\ServerDisconnected;
|
||||
use Throwable;
|
||||
|
||||
class CheckConnection extends Job
|
||||
@ -39,7 +41,7 @@ public function failed(): void
|
||||
{
|
||||
$this->server->status = 'disconnected';
|
||||
$this->server->save();
|
||||
/** @todo notify */
|
||||
Notifier::send($this->server, new ServerDisconnected($this->server));
|
||||
event(
|
||||
new Broadcast('server-status-failed', [
|
||||
'server' => $this->server,
|
||||
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NotificationChannelMessage extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $text;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($subject, $text)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
if ($this->text instanceof MailMessage) {
|
||||
return $this->markdown('vendor.notifications.email', $this->text->data());
|
||||
}
|
||||
|
||||
return $this->markdown('emails.notification-channel-message', [
|
||||
'subject' => $this->subject,
|
||||
'text' => $this->text,
|
||||
]);
|
||||
}
|
||||
}
|
25
app/Mail/NotificationMail.php
Normal file
25
app/Mail/NotificationMail.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NotificationMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public string $text;
|
||||
|
||||
public function __construct(string $subject, string $text)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
public function build(): self
|
||||
{
|
||||
return $this->html($this->text);
|
||||
}
|
||||
}
|
@ -69,8 +69,8 @@ public function deployHook(): void
|
||||
*/
|
||||
public function destroyHook(): void
|
||||
{
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$this->sourceControl->provider()->destroyHook($this->site->repository, $this->hook_id);
|
||||
$this->delete();
|
||||
DB::commit();
|
||||
|
@ -2,19 +2,21 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
/**
|
||||
* @property string $provider
|
||||
* @property string $label
|
||||
* @property array $data
|
||||
* @property bool $connected
|
||||
* @property bool $is_default
|
||||
* @property User $user
|
||||
* @property int $id
|
||||
* @property string provider
|
||||
* @property array data
|
||||
* @property string label
|
||||
* @property bool connected
|
||||
*/
|
||||
class NotificationChannel extends AbstractModel
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
protected $fillable = [
|
||||
'provider',
|
||||
@ -25,15 +27,24 @@ class NotificationChannel extends AbstractModel
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'data' => 'json',
|
||||
'project_id' => 'integer',
|
||||
'data' => 'array',
|
||||
'connected' => 'boolean',
|
||||
'is_default' => 'boolean',
|
||||
];
|
||||
|
||||
public function provider(): \App\Contracts\NotificationChannel
|
||||
{
|
||||
$provider = config('core.notification_channels_providers_class')[$this->provider];
|
||||
$class = config('core.notification_channels_providers_class')[$this->provider];
|
||||
|
||||
return new $provider($this);
|
||||
return new $class($this);
|
||||
}
|
||||
|
||||
public static function notifyAll(Notification $notification): void
|
||||
{
|
||||
$channels = self::all();
|
||||
foreach ($channels as $channel) {
|
||||
$channel->notify($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,19 @@
|
||||
|
||||
use App\Contracts\ServerType;
|
||||
use App\Enums\ServerStatus;
|
||||
use App\Enums\ServiceStatus;
|
||||
use App\Facades\Notifier;
|
||||
use App\Facades\SSH;
|
||||
use App\Jobs\Installation\Upgrade;
|
||||
use App\Jobs\Server\CheckConnection;
|
||||
use App\Jobs\Server\RebootServer;
|
||||
use App\Notifications\ServerInstallationStarted;
|
||||
use App\Support\Testing\SSHFake;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
@ -110,7 +114,9 @@ public static function boot(): void
|
||||
$site->delete();
|
||||
});
|
||||
$server->provider()->delete();
|
||||
$server->logs()->delete();
|
||||
$server->logs()->each(function (ServerLog $log) {
|
||||
$log->delete();
|
||||
});
|
||||
$server->services()->delete();
|
||||
$server->databases()->delete();
|
||||
$server->databaseUsers()->delete();
|
||||
@ -222,6 +228,18 @@ public function defaultService($type): ?Service
|
||||
->where('is_default', 1)
|
||||
->first();
|
||||
|
||||
// If no default service found, get the first service with status ready or stopped
|
||||
if (! $service) {
|
||||
$service = $this->services()
|
||||
->where('type', $type)
|
||||
->whereIn('status', [ServiceStatus::READY, ServiceStatus::STOPPED])
|
||||
->first();
|
||||
if ($service) {
|
||||
$service->is_default = 1;
|
||||
$service->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
@ -239,7 +257,7 @@ public function getServiceByUnit($unit): ?Service
|
||||
public function install(): void
|
||||
{
|
||||
$this->type()->install();
|
||||
// $this->team->notify(new ServerInstallationStarted($this));
|
||||
Notifier::send($this, new ServerInstallationStarted($this));
|
||||
}
|
||||
|
||||
public function ssh(?string $user = null): \App\Helpers\SSH|SSHFake
|
||||
@ -343,10 +361,13 @@ public function sshKey(): array
|
||||
];
|
||||
}
|
||||
|
||||
/** @var FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||
|
||||
return [
|
||||
'public_key' => Str::replace("\n", '', Storage::disk(config('core.key_pairs_disk'))->get($this->id.'.pub')),
|
||||
'public_key_path' => Storage::disk(config('core.key_pairs_disk'))->path($this->id.'.pub'),
|
||||
'private_key_path' => Storage::disk(config('core.key_pairs_disk'))->path((string) $this->id),
|
||||
'public_key_path' => $storageDisk->path($this->id.'.pub'),
|
||||
'private_key_path' => $storageDisk->path((string) $this->id),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,17 @@ class ServerLog extends AbstractModel
|
||||
'site_id' => 'integer',
|
||||
];
|
||||
|
||||
public static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (ServerLog $log) {
|
||||
if (Storage::disk($log->disk)->exists($log->name)) {
|
||||
Storage::disk($log->disk)->delete($log->name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function getRouteKey(): string
|
||||
{
|
||||
return 'log';
|
||||
|
@ -8,10 +8,13 @@
|
||||
use App\Enums\SslStatus;
|
||||
use App\Events\Broadcast;
|
||||
use App\Exceptions\SourceControlIsNotConnected;
|
||||
use App\Facades\Notifier;
|
||||
use App\Jobs\Site\ChangePHPVersion;
|
||||
use App\Jobs\Site\Deploy;
|
||||
use App\Jobs\Site\DeployEnv;
|
||||
use App\Jobs\Site\UpdateBranch;
|
||||
use App\Notifications\SiteInstallationFailed;
|
||||
use App\Notifications\SiteInstallationSucceed;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@ -354,8 +357,8 @@ public function enableAutoDeployment(): void
|
||||
throw new SourceControlIsNotConnected($this->source_control);
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$gitHook = new GitHook([
|
||||
'site_id' => $this->id,
|
||||
'source_control_id' => $this->sourceControl()->id,
|
||||
@ -406,7 +409,7 @@ public function installationFinished(): void
|
||||
'site' => $this,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this, new SiteInstallationSucceed($this));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -422,7 +425,7 @@ public function installationFailed(Throwable $e): void
|
||||
'site' => $this,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this, new SiteInstallationFailed($this));
|
||||
Log::error('install-site-error', [
|
||||
'error' => (string) $e,
|
||||
]);
|
||||
|
13
app/NotificationChannels/AbstractNotificationChannel.php
Normal file
13
app/NotificationChannels/AbstractNotificationChannel.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Contracts\NotificationChannel as NotificationChannelInterface;
|
||||
use App\Models\NotificationChannel;
|
||||
|
||||
abstract class AbstractNotificationChannel implements NotificationChannelInterface
|
||||
{
|
||||
public function __construct(protected NotificationChannel $notificationChannel)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Contracts\NotificationChannel as NotificationChannelContract;
|
||||
use App\Models\NotificationChannel;
|
||||
|
||||
abstract class AbstractProvider implements NotificationChannelContract
|
||||
{
|
||||
protected NotificationChannel $notificationChannel;
|
||||
|
||||
public function __construct(NotificationChannel $notificationChannel)
|
||||
{
|
||||
$this->notificationChannel = $notificationChannel;
|
||||
}
|
||||
}
|
@ -2,21 +2,30 @@
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\NotificationChannel;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class Discord extends AbstractProvider
|
||||
class Discord extends AbstractNotificationChannel
|
||||
{
|
||||
public function validationRules(): array
|
||||
public function createRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => 'required|url',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(array $input): array
|
||||
public function createData(array $input): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => $input['webhook_url'],
|
||||
'webhook_url' => $input['webhook_url'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => $this->notificationChannel->data['webhook_url'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
@ -24,35 +33,39 @@ public function connect(): bool
|
||||
{
|
||||
$connect = $this->checkConnection(
|
||||
__('Congratulations! 🎉'),
|
||||
__("You've connected your Discord to Vito")."\n".
|
||||
__("You've connected your Discord to :app", ['app' => config('app.name')])."\n".
|
||||
__('Manage your notification channels')."\n".
|
||||
route('notification-channels')
|
||||
);
|
||||
|
||||
if (! $connect) {
|
||||
$this->notificationChannel->delete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->notificationChannel->connected = true;
|
||||
$this->notificationChannel->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function sendMessage(string $subject, string $text): void
|
||||
{
|
||||
dispatch(function () use ($subject, $text) {
|
||||
$data = $this->notificationChannel->data;
|
||||
Http::post($data['webhook_url'], [
|
||||
'content' => '*'.$subject.'*'."\n".$text,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function checkConnection(string $subject, string $text): bool
|
||||
{
|
||||
$data = $this->notificationChannel->data;
|
||||
$connect = Http::post($data['webhook_url'], [
|
||||
$connect = Http::post($this->data()['webhook_url'], [
|
||||
'content' => '*'.$subject.'*'."\n".$text,
|
||||
]);
|
||||
|
||||
return $connect->ok();
|
||||
}
|
||||
|
||||
public function send(object $notifiable, Notification $notification): void
|
||||
{
|
||||
/** @var NotificationChannel $notifiable */
|
||||
$this->notificationChannel = $notifiable;
|
||||
$data = $this->notificationChannel->data;
|
||||
Http::post($data['webhook_url'], [
|
||||
'content' => $notification->toSlack($notifiable),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -2,36 +2,58 @@
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Mail\NotificationChannelMessage;
|
||||
use App\Contracts\Notification;
|
||||
use App\Mail\NotificationMail;
|
||||
use App\Models\NotificationChannel;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Throwable;
|
||||
|
||||
class Email extends AbstractProvider
|
||||
class Email extends AbstractNotificationChannel
|
||||
{
|
||||
public function validationRules(): array
|
||||
public function createRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(array $input): array
|
||||
public function createData(array $input): array
|
||||
{
|
||||
return [
|
||||
'email' => $input['email'],
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'email' => $this->notificationChannel->data['email'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
public function connect(): bool
|
||||
{
|
||||
$this->notificationChannel->connected = true;
|
||||
$this->notificationChannel->save();
|
||||
try {
|
||||
Mail::to($this->data()['email'])->send(
|
||||
new NotificationMail(
|
||||
'Connected to VitoDeploy',
|
||||
'This email confirms that you have connected your email to VitoDeploy.'
|
||||
)
|
||||
);
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function sendMessage(string $subject, mixed $text): void
|
||||
public function send(object $notifiable, Notification $notification): void
|
||||
{
|
||||
$data = $this->notificationChannel->data;
|
||||
Mail::to($data['email'])->send(new NotificationChannelMessage($subject, $text));
|
||||
/** @var NotificationChannel $notifiable */
|
||||
$this->notificationChannel = $notifiable;
|
||||
$message = $notification->toEmail($notifiable);
|
||||
Mail::to($this->data()['email'])->send(
|
||||
new NotificationMail($message->subject, $message->render())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,30 @@
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\NotificationChannel;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class Slack extends AbstractProvider
|
||||
class Slack extends AbstractNotificationChannel
|
||||
{
|
||||
public function validationRules(): array
|
||||
public function createRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => 'required|url',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(array $input): array
|
||||
public function createData(array $input): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => $input['webhook_url'],
|
||||
'webhook_url' => $input['webhook_url'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'webhook_url' => $this->notificationChannel->data['webhook_url'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
@ -24,35 +33,39 @@ public function connect(): bool
|
||||
{
|
||||
$connect = $this->checkConnection(
|
||||
__('Congratulations! 🎉'),
|
||||
__("You've connected your Slack to Vito")."\n".
|
||||
__("You've connected your Slack to :app", ['app' => config('app.name')])."\n".
|
||||
__('Manage your notification channels')."\n".
|
||||
route('notification-channels')
|
||||
);
|
||||
|
||||
if (! $connect) {
|
||||
$this->notificationChannel->delete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->notificationChannel->connected = true;
|
||||
$this->notificationChannel->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function sendMessage(string $subject, string $text): void
|
||||
{
|
||||
dispatch(function () use ($subject, $text) {
|
||||
$data = $this->notificationChannel->data;
|
||||
Http::post($data['webhook_url'], [
|
||||
'text' => '*'.$subject.'*'."\n".$text,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function checkConnection(string $subject, string $text): bool
|
||||
{
|
||||
$data = $this->notificationChannel->data;
|
||||
$connect = Http::post($data['webhook_url'], [
|
||||
$connect = Http::post($this->data()['webhook_url'], [
|
||||
'text' => '*'.$subject.'*'."\n".$text,
|
||||
]);
|
||||
|
||||
return $connect->ok();
|
||||
}
|
||||
|
||||
public function send(object $notifiable, Notification $notification): void
|
||||
{
|
||||
/** @var NotificationChannel $notifiable */
|
||||
$this->notificationChannel = $notifiable;
|
||||
$data = $this->notificationChannel->data;
|
||||
Http::post($data['webhook_url'], [
|
||||
'text' => $notification->toSlack($notifiable),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
65
app/NotificationChannels/Telegram.php
Normal file
65
app/NotificationChannels/Telegram.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\NotificationChannels;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\NotificationChannel;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Throwable;
|
||||
|
||||
class Telegram extends AbstractNotificationChannel
|
||||
{
|
||||
protected string $apiUrl = 'https://api.telegram.org/bot';
|
||||
|
||||
public function createRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'bot_token' => 'required|string',
|
||||
'chat_id' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function createData(array $input): array
|
||||
{
|
||||
return [
|
||||
'bot_token' => $input['bot_token'],
|
||||
'chat_id' => $input['chat_id'],
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'bot_token' => $this->notificationChannel->data['bot_token'] ?? '',
|
||||
'chat_id' => $this->notificationChannel->data['chat_id'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
public function connect(): bool
|
||||
{
|
||||
try {
|
||||
$this->sendToTelegram(__('Connected!'));
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function send(object $notifiable, Notification $notification): void
|
||||
{
|
||||
/** @var NotificationChannel $notifiable */
|
||||
$this->notificationChannel = $notifiable;
|
||||
$this->sendToTelegram($notification->toTelegram($notifiable));
|
||||
}
|
||||
|
||||
private function sendToTelegram(string $text): void
|
||||
{
|
||||
Http::post($this->apiUrl.$this->data()['bot_token'].'/sendMessage', [
|
||||
'chat_id' => $this->data()['chat_id'],
|
||||
'text' => $text,
|
||||
'parse_mode' => 'markdown',
|
||||
'disable_web_page_preview' => true,
|
||||
]);
|
||||
}
|
||||
}
|
44
app/Notifications/AbstractNotification.php
Normal file
44
app/Notifications/AbstractNotification.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification as NotificationInterface;
|
||||
use App\Models\NotificationChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
abstract class AbstractNotification extends Notification implements NotificationInterface, ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public function via(object $notifiable): string
|
||||
{
|
||||
/** @var NotificationChannel $notifiable */
|
||||
return get_class($notifiable->provider());
|
||||
}
|
||||
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage())
|
||||
->subject('Notification')
|
||||
->line($this->rawText());
|
||||
}
|
||||
|
||||
public function toSlack(object $notifiable): string
|
||||
{
|
||||
return $this->rawText();
|
||||
}
|
||||
|
||||
public function toDiscord(object $notifiable): string
|
||||
{
|
||||
return $this->rawText();
|
||||
}
|
||||
|
||||
public function toTelegram(object $notifiable): string
|
||||
{
|
||||
return $this->rawText();
|
||||
}
|
||||
}
|
@ -2,12 +2,11 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class FailedToDeleteServerFromProvider implements Notification
|
||||
class FailedToDeleteServerFromProvider extends AbstractNotification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
@ -18,26 +17,18 @@ public function __construct(Server $server)
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function subject(): string
|
||||
public function rawText(): string
|
||||
{
|
||||
return __('Failed to delete the server from the provider!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): mixed
|
||||
{
|
||||
if ($mail) {
|
||||
return $this->mail();
|
||||
}
|
||||
|
||||
return __("We couldn't delete [:server] \nfrom :provider \nPlease check your provider and delete it manually", [
|
||||
'server' => $this->server->name,
|
||||
'provider' => $this->server->provider,
|
||||
]);
|
||||
}
|
||||
|
||||
public function mail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Failed to delete the server from the provider!'))
|
||||
->line("We couldn't delete [".$this->server->name.'] from '.$this->server->provider)
|
||||
->line('Please check your provider and delete it manually');
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Ssl;
|
||||
|
||||
class SSLExpirationAlert implements Notification
|
||||
{
|
||||
protected Ssl $ssl;
|
||||
|
||||
public function __construct(Ssl $ssl)
|
||||
{
|
||||
$this->ssl = $ssl;
|
||||
}
|
||||
|
||||
public function subject(): string
|
||||
{
|
||||
return __('SSL expiring soon!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): string
|
||||
{
|
||||
return $this->ssl->site->domain."'s ".__('SSL is expiring on').' '.$this->ssl->expires_at->format('Y-m-d');
|
||||
}
|
||||
}
|
@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class ServerDisconnected implements Notification
|
||||
class ServerDisconnected extends AbstractNotification
|
||||
{
|
||||
protected Server $server;
|
||||
|
||||
@ -15,25 +14,17 @@ public function __construct(Server $server)
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function subject(): string
|
||||
public function rawText(): string
|
||||
{
|
||||
return __('Server disconnected!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): mixed
|
||||
{
|
||||
if ($mail) {
|
||||
return $this->mail();
|
||||
}
|
||||
|
||||
return __("We've disconnected from your server [:server]", [
|
||||
'server' => $this->server->name,
|
||||
]);
|
||||
}
|
||||
|
||||
public function mail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Server disconnected!'))
|
||||
->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');
|
||||
}
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class ServerInstallationFailed implements Notification
|
||||
class ServerInstallationFailed extends AbstractNotification
|
||||
{
|
||||
protected Server $server;
|
||||
|
||||
@ -15,26 +14,18 @@ public function __construct(Server $server)
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function subject(): string
|
||||
public function rawText(): string
|
||||
{
|
||||
return __('Server installation failed!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): mixed
|
||||
{
|
||||
if ($mail) {
|
||||
return $this->mail();
|
||||
}
|
||||
|
||||
return __("Installation failed for server [:server] \nCheck your server's logs \n:logs", [
|
||||
'server' => $this->server->name,
|
||||
'logs' => url('/servers/'.$this->server->id.'/logs'),
|
||||
]);
|
||||
}
|
||||
|
||||
private function mail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Server installation failed!'))
|
||||
->line('Your server ['.$this->server->name.'] installation has been failed.')
|
||||
->line('Check your server logs')
|
||||
->action('View Logs', url('/servers/'.$this->server->id.'/logs'));
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class ServerInstallationStarted implements Notification
|
||||
class ServerInstallationStarted extends AbstractNotification
|
||||
{
|
||||
protected Server $server;
|
||||
|
||||
@ -15,26 +14,18 @@ public function __construct(Server $server)
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
public function subject(): string
|
||||
public function rawText(): string
|
||||
{
|
||||
return __('Server installation started!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): mixed
|
||||
{
|
||||
if ($mail) {
|
||||
return $this->mail();
|
||||
}
|
||||
|
||||
return __("Installation started for server [:server]\nThis may take several minutes depending on many things like your server's internet speed.\nAs soon as it finishes, We will notify you through this channel.\nYou can check the progress live on your dashboard.\n:progress", [
|
||||
'server' => $this->server->name,
|
||||
'progress' => url('/servers/'.$this->server->id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function mail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Server installation started!'))
|
||||
->line('Your server\'s ['.$this->server->name.'] installation has been started.')
|
||||
->line("This may take several minutes depending on many things like your server's internet speed.")
|
||||
->line('As soon as it finishes, We will notify you through this channel.')
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Contracts\Notification;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class ServerInstallationSucceed implements Notification
|
||||
class ServerInstallationSucceed extends AbstractNotification
|
||||
{
|
||||
protected Server $server;
|
||||
|
||||
@ -20,14 +19,10 @@ public function subject(): string
|
||||
return __('Server installation succeed!');
|
||||
}
|
||||
|
||||
public function message(bool $mail = false): mixed
|
||||
public function rawText(): string
|
||||
{
|
||||
$this->server->refresh();
|
||||
|
||||
if ($mail) {
|
||||
return $this->mail();
|
||||
}
|
||||
|
||||
return __("Installation succeed for server [:server] \nServer IP: :ip \nUser: :user\nPassword: :password\n:link", [
|
||||
'server' => $this->server->name,
|
||||
'ip' => $this->server->ip,
|
||||
@ -37,11 +32,12 @@ public function message(bool $mail = false): mixed
|
||||
]);
|
||||
}
|
||||
|
||||
public function mail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
$this->server->refresh();
|
||||
|
||||
return (new MailMessage)
|
||||
->subject(__('Server installation succeed!'))
|
||||
->line('Your server ['.$this->server->name.'] has been installed successfully.')
|
||||
->line('Server IP: '.$this->server->ip)
|
||||
->line('User: '.$this->server->authentication['user'])
|
||||
|
30
app/Notifications/SiteInstallationFailed.php
Normal file
30
app/Notifications/SiteInstallationFailed.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Site;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class SiteInstallationFailed extends AbstractNotification
|
||||
{
|
||||
public function __construct(protected Site $site)
|
||||
{
|
||||
}
|
||||
|
||||
public function rawText(): string
|
||||
{
|
||||
return __("Installation failed for site [:site] \nCheck your server's logs \n:logs", [
|
||||
'site' => $this->site->domain,
|
||||
'logs' => url('/servers/'.$this->site->server_id.'/logs'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Site installation failed!'))
|
||||
->line('Your site\'s ['.$this->site->domain.'] installation has been failed.')
|
||||
->line('Check your server logs')
|
||||
->action('View Logs', url('/servers/'.$this->site->server_id.'/logs'));
|
||||
}
|
||||
}
|
29
app/Notifications/SiteInstallationSucceed.php
Normal file
29
app/Notifications/SiteInstallationSucceed.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Site;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class SiteInstallationSucceed extends AbstractNotification
|
||||
{
|
||||
public function __construct(protected Site $site)
|
||||
{
|
||||
}
|
||||
|
||||
public function rawText(): string
|
||||
{
|
||||
return __('Installation succeed for site [:site]', [
|
||||
'site' => $this->site->domain,
|
||||
]);
|
||||
}
|
||||
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('Site installation succeed!'))
|
||||
->line('Your site\'s ['.$this->site->domain.'] installation has been installed.')
|
||||
->line('Check your site')
|
||||
->action('View Site', url('/servers/'.$this->site->server_id.'/sites/'.$this->site->id));
|
||||
}
|
||||
}
|
@ -2,41 +2,26 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use App\Models\SourceControl;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class SourceControlDisconnected extends Notification implements ShouldQueue
|
||||
class SourceControlDisconnected extends AbstractNotification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
protected string $sourceControl;
|
||||
|
||||
public function __construct(string $sourceControl)
|
||||
public function __construct(protected SourceControl $sourceControl)
|
||||
{
|
||||
$this->sourceControl = $sourceControl;
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
public function rawText(): string
|
||||
{
|
||||
return ['mail'];
|
||||
return __('Source control [:sourceControl] has been disconnected from Vito', [
|
||||
'sourceControl' => $this->sourceControl->profile,
|
||||
]);
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
public function toEmail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Lost connection to your '.$this->sourceControl)
|
||||
->line("We've lost connection to your $this->sourceControl account.")
|
||||
->line("We'll not able to do any deployments until you reconnect.")
|
||||
->line("To reconnect your $this->sourceControl account please click on the bellow button.")
|
||||
->action('Reconnect', url('/source-controls'));
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
->subject(__('Source control disconnected!'))
|
||||
->line($this->rawText());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Helpers\Notifier;
|
||||
use App\Helpers\SSH;
|
||||
use App\Support\SocialiteProviders\DropboxProvider;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
@ -29,6 +30,9 @@ public function boot(): void
|
||||
$this->app->bind('ssh', function () {
|
||||
return new SSH;
|
||||
});
|
||||
$this->app->bind('notifier', function () {
|
||||
return new Notifier;
|
||||
});
|
||||
|
||||
$this->extendSocialite();
|
||||
}
|
||||
|
26
app/SSHCommands/Nginx/GetNginxVHostCommand.php
Executable file
26
app/SSHCommands/Nginx/GetNginxVHostCommand.php
Executable file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\SSHCommands\Nginx;
|
||||
|
||||
use App\SSHCommands\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class GetNginxVHostCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
protected string $domain
|
||||
) {
|
||||
}
|
||||
|
||||
public function file(): string
|
||||
{
|
||||
return File::get(resource_path('commands/webserver/nginx/get-vhost.sh'));
|
||||
}
|
||||
|
||||
public function content(): string
|
||||
{
|
||||
return str($this->file())
|
||||
->replace('__domain__', $this->domain)
|
||||
->toString();
|
||||
}
|
||||
}
|
@ -4,10 +4,14 @@
|
||||
|
||||
use App\Enums\OperatingSystem;
|
||||
use App\Exceptions\CouldNotConnectToProvider;
|
||||
use App\Facades\Notifier;
|
||||
use App\Notifications\FailedToDeleteServerFromProvider;
|
||||
use Aws\Ec2\Ec2Client;
|
||||
use Aws\EC2InstanceConnect\EC2InstanceConnectClient;
|
||||
use Exception;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Throwable;
|
||||
|
||||
class AWS extends AbstractProvider
|
||||
{
|
||||
@ -125,9 +129,8 @@ public function delete(): void
|
||||
$this->ec2Client->terminateInstances([
|
||||
'InstanceIds' => [$this->server->provider_data['instance_id']],
|
||||
]);
|
||||
} catch (Exception) {
|
||||
/** @todo notify */
|
||||
// $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server));
|
||||
} catch (Throwable) {
|
||||
Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,10 +167,12 @@ private function createKeyPair(): void
|
||||
$result = $this->ec2Client->createKeyPair([
|
||||
'KeyName' => $keyName,
|
||||
]);
|
||||
Storage::disk(config('core.key_pairs_disk'))->put((string) $this->server->id, $result['KeyMaterial']);
|
||||
/** @var FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||
$storageDisk->put((string) $this->server->id, $result['KeyMaterial']);
|
||||
generate_public_key(
|
||||
Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id),
|
||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id.'.pub'),
|
||||
$storageDisk->path((string) $this->server->id),
|
||||
$storageDisk->path($this->server->id.'.pub'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ public function __construct(?Server $server = null)
|
||||
|
||||
protected function generateKeyPair(): void
|
||||
{
|
||||
generate_key_pair(Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id));
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||
generate_key_pair($storageDisk->path((string) $this->server->id));
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ public function createValidationRules(array $input): array
|
||||
return [
|
||||
'ip' => [
|
||||
'required',
|
||||
'ip',
|
||||
Rule::unique('servers', 'ip'),
|
||||
new RestrictedIPAddressesRule(),
|
||||
],
|
||||
@ -59,13 +58,15 @@ public function regions(): array
|
||||
|
||||
public function create(): void
|
||||
{
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||
File::copy(
|
||||
storage_path(config('core.ssh_private_key_name')),
|
||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id)
|
||||
$storageDisk->path($this->server->id)
|
||||
);
|
||||
File::copy(
|
||||
storage_path(config('core.ssh_public_key_name')),
|
||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id.'.pub')
|
||||
$storageDisk->path($this->server->id.'.pub')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Exceptions\CouldNotConnectToProvider;
|
||||
use App\Exceptions\ServerProviderError;
|
||||
use App\Facades\Notifier;
|
||||
use App\Notifications\FailedToDeleteServerFromProvider;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -148,10 +150,9 @@ public function delete(): void
|
||||
$delete = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||
->delete($this->apiUrl.'/droplets/'.$this->server->provider_data['droplet_id']);
|
||||
|
||||
/** @todo notify */
|
||||
// if (! $delete->ok()) {
|
||||
// $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server));
|
||||
// }
|
||||
if (! $delete->ok()) {
|
||||
Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Exceptions\CouldNotConnectToProvider;
|
||||
use App\Exceptions\ServerProviderError;
|
||||
use App\Facades\Notifier;
|
||||
use App\Notifications\FailedToDeleteServerFromProvider;
|
||||
use Illuminate\Http\Client\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
@ -122,10 +124,9 @@ public function delete(): void
|
||||
$delete = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||
->delete($this->apiUrl.'/servers/'.$this->server->provider_data['hetzner_id']);
|
||||
|
||||
/** @todo notify */
|
||||
// if (! $delete->ok()) {
|
||||
// $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server));
|
||||
// }
|
||||
if (! $delete->ok()) {
|
||||
Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server));
|
||||
}
|
||||
}
|
||||
|
||||
// delete key
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Exceptions\CouldNotConnectToProvider;
|
||||
use App\Exceptions\ServerProviderError;
|
||||
use App\Facades\Notifier;
|
||||
use App\Notifications\FailedToDeleteServerFromProvider;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@ -131,10 +133,9 @@ public function delete(): void
|
||||
$delete = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||
->delete($this->apiUrl.'/linode/instances/'.$this->server->provider_data['linode_id']);
|
||||
|
||||
/** @todo notify */
|
||||
// if (! $delete->ok()) {
|
||||
// $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server));
|
||||
// }
|
||||
if (! $delete->ok()) {
|
||||
Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Exceptions\CouldNotConnectToProvider;
|
||||
use App\Exceptions\ServerProviderError;
|
||||
use App\Facades\Notifier;
|
||||
use App\Notifications\FailedToDeleteServerFromProvider;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -85,7 +87,9 @@ public function regions(): array
|
||||
public function create(): void
|
||||
{
|
||||
// generate key pair
|
||||
generate_key_pair(Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id));
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||
generate_key_pair($storageDisk->path((string) $this->server->id));
|
||||
|
||||
$createSshKey = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||
->post($this->apiUrl.'/ssh-keys', [
|
||||
@ -142,10 +146,9 @@ public function delete(): void
|
||||
$delete = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||
->delete($this->apiUrl.'/instances/'.$this->server->provider_data['instance_id']);
|
||||
|
||||
/** @todo notify */
|
||||
// if (! $delete->ok()) {
|
||||
// $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server));
|
||||
// }
|
||||
if (! $delete->ok()) {
|
||||
Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,12 @@
|
||||
namespace App\ServerTypes;
|
||||
|
||||
use App\Events\Broadcast;
|
||||
use App\Facades\Notifier;
|
||||
use App\Jobs\Installation\Initialize;
|
||||
use App\Jobs\Installation\InstallRequirements;
|
||||
use App\Jobs\Installation\Upgrade;
|
||||
use App\Notifications\ServerInstallationFailed;
|
||||
use App\Notifications\ServerInstallationSucceed;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Throwable;
|
||||
@ -66,7 +69,7 @@ public function install(): void
|
||||
'server' => $this->server,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this->server, new ServerInstallationSucceed($this->server));
|
||||
};
|
||||
|
||||
Bus::chain($jobs)
|
||||
@ -79,7 +82,7 @@ public function install(): void
|
||||
'server' => $this->server,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this->server, new ServerInstallationFailed($this->server));
|
||||
Log::error('server-installation-error', [
|
||||
'error' => (string) $e,
|
||||
]);
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
use App\Enums\ServerStatus;
|
||||
use App\Events\Broadcast;
|
||||
use App\Facades\Notifier;
|
||||
use App\Jobs\Installation\Initialize;
|
||||
use App\Jobs\Installation\InstallCertbot;
|
||||
use App\Jobs\Installation\InstallComposer;
|
||||
use App\Jobs\Installation\InstallNodejs;
|
||||
use App\Jobs\Installation\InstallRequirements;
|
||||
use App\Jobs\Installation\Upgrade;
|
||||
use App\Notifications\ServerInstallationFailed;
|
||||
use App\Notifications\ServerInstallationSucceed;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Throwable;
|
||||
@ -88,7 +91,7 @@ public function install(): void
|
||||
'server' => $this->server,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this->server, new ServerInstallationSucceed($this->server));
|
||||
};
|
||||
|
||||
Bus::chain($jobs)
|
||||
@ -101,7 +104,7 @@ public function install(): void
|
||||
'server' => $this->server,
|
||||
])
|
||||
);
|
||||
/** @todo notify */
|
||||
Notifier::send($this->server, new ServerInstallationFailed($this->server));
|
||||
Log::error('server-installation-error', [
|
||||
'error' => (string) $e,
|
||||
]);
|
||||
@ -160,7 +163,7 @@ protected function addSupervisor(): void
|
||||
}
|
||||
|
||||
/**
|
||||
* add supervisor
|
||||
* add redis
|
||||
*/
|
||||
protected function addRedis(): void
|
||||
{
|
||||
@ -172,7 +175,7 @@ protected function addRedis(): void
|
||||
}
|
||||
|
||||
/**
|
||||
* add supervisor
|
||||
* add ufw
|
||||
*/
|
||||
protected function addUfw(): void
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
use App\SSHCommands\Nginx\ChangeNginxPHPVersionCommand;
|
||||
use App\SSHCommands\Nginx\CreateNginxVHostCommand;
|
||||
use App\SSHCommands\Nginx\DeleteNginxSiteCommand;
|
||||
use App\SSHCommands\Nginx\GetNginxVHostCommand;
|
||||
use App\SSHCommands\Nginx\UpdateNginxRedirectsCommand;
|
||||
use App\SSHCommands\Nginx\UpdateNginxVHostCommand;
|
||||
use App\SSHCommands\SSL\CreateCustomSSLCommand;
|
||||
@ -39,19 +40,30 @@ public function createVHost(Site $site): void
|
||||
/**
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function updateVHost(Site $site, bool $noSSL = false): void
|
||||
public function updateVHost(Site $site, bool $noSSL = false, ?string $vhost = null): void
|
||||
{
|
||||
$this->service->server->ssh()->exec(
|
||||
new UpdateNginxVHostCommand(
|
||||
$site->domain,
|
||||
$site->path,
|
||||
$this->generateVhost($site, $noSSL)
|
||||
$vhost ?? $this->generateVhost($site, $noSSL)
|
||||
),
|
||||
'update-vhost',
|
||||
$site->id
|
||||
);
|
||||
}
|
||||
|
||||
public function getVHost(Site $site): string
|
||||
{
|
||||
return $this->service->server->ssh()->exec(
|
||||
new GetNginxVHostCommand(
|
||||
$site->domain
|
||||
),
|
||||
'get-vhost',
|
||||
$site->id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Throwable
|
||||
*/
|
||||
|
@ -22,11 +22,6 @@ public function delete(): void
|
||||
dispatch(new DeleteSite($this->site))->onConnection('ssh');
|
||||
}
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
// TODO: Implement install() method.
|
||||
}
|
||||
|
||||
protected function progress(int $percentage): Closure
|
||||
{
|
||||
return function () use ($percentage) {
|
||||
|
67
app/SiteTypes/PHPBlank.php
Executable file
67
app/SiteTypes/PHPBlank.php
Executable file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\SiteTypes;
|
||||
|
||||
use App\Enums\SiteFeature;
|
||||
use App\Jobs\Site\CreateVHost;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Throwable;
|
||||
|
||||
class PHPBlank extends PHPSite
|
||||
{
|
||||
public function supportedFeatures(): array
|
||||
{
|
||||
return [
|
||||
SiteFeature::DEPLOYMENT,
|
||||
SiteFeature::ENV,
|
||||
SiteFeature::SSL,
|
||||
SiteFeature::QUEUES,
|
||||
];
|
||||
}
|
||||
|
||||
public function createValidationRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'php_version' => [
|
||||
'required',
|
||||
Rule::in($this->site->server->installedPHPVersions()),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function createFields(array $input): array
|
||||
{
|
||||
return [
|
||||
'web_directory' => $input['web_directory'] ?? '',
|
||||
'php_version' => $input['php_version'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
public function data(array $input): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
$chain = [
|
||||
new CreateVHost($this->site),
|
||||
$this->progress(65),
|
||||
function () {
|
||||
$this->site->php()?->restart();
|
||||
},
|
||||
];
|
||||
|
||||
$chain[] = function () {
|
||||
$this->site->installationFinished();
|
||||
};
|
||||
|
||||
Bus::chain($chain)
|
||||
->catch(function (Throwable $e) {
|
||||
$this->site->installationFailed($e);
|
||||
})
|
||||
->onConnection('ssh-long')
|
||||
->dispatch();
|
||||
}
|
||||
}
|
@ -55,6 +55,7 @@ public function createFields(array $input): array
|
||||
'source_control_id' => $input['source_control'] ?? '',
|
||||
'repository' => $input['repository'] ?? '',
|
||||
'branch' => $input['branch'] ?? '',
|
||||
'php_version' => $input['php_version'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
@ -62,7 +63,6 @@ public function data(array $input): array
|
||||
{
|
||||
return [
|
||||
'composer' => isset($input['composer']) && $input['composer'],
|
||||
'php_version' => $input['php_version'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Contracts\Database\Query\Expression;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
function random_color(): string
|
||||
@ -63,3 +64,10 @@ function date_with_timezone($date, $timezone): string
|
||||
|
||||
return $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function cast_to_json(array $json): Illuminate\Database\Query\Expression|Expression
|
||||
{
|
||||
$json = addslashes(json_encode($json));
|
||||
|
||||
return DB::raw("CAST('{$json}' AS JSON)");
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ public function getListeners(): array
|
||||
|
||||
public function refreshComponent(array $data): void
|
||||
{
|
||||
$this->emit('refreshComponent');
|
||||
$this->dispatch('refreshComponent');
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user