mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-01 14:06:15 +00:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
debcd002f1 | |||
59e8c82e5c | |||
682da0d6d5 | |||
9db310a06b | |||
f70963d6bb | |||
b75df8e1c5 | |||
a22e9cb946 | |||
b2b9bea0b1 | |||
3f4a2bce3a | |||
8bffefabef | |||
3da1f4fe4c | |||
2214a76e09 | |||
55bf8b8ecf | |||
0420babdef | |||
1c3d78a5ed | |||
8665435bc4 | |||
0ec6a9dea2 | |||
bdfda05398 | |||
919cdc6892 | |||
902548e463 | |||
2462b31f3b | |||
e997d0deea | |||
f06b8f7d20 | |||
f120a570e8 | |||
2d7f225ff2 | |||
31bd146239 | |||
10a6bb57a8 | |||
fd2244d382 | |||
551f1ce40e | |||
1ce92d9361 | |||
ec6e55e30c |
38
.env.docker
Executable file
38
.env.docker
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
APP_NAME=Vito
|
||||||
|
APP_ENV=production
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=vito
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=password
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=null
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
FILESYSTEM_DRIVER=local
|
||||||
|
QUEUE_CONNECTION=default
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=
|
||||||
|
MAIL_PORT=
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS=null
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
SSH_PUBLIC_KEY_NAME=ssh-public.key
|
||||||
|
SSH_PRIVATE_KEY_NAME=ssh-private.pem
|
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
|||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
|
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
|||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
|
@ -26,8 +26,8 @@ REDIS_PASSWORD=null
|
|||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=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/
|
65
Dockerfile
Normal file
65
Dockerfile
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
|
||||||
|
RUN echo "mysql-server mysql-server/root_password password password" | debconf-set-selections
|
||||||
|
RUN echo "mysql-server mysql-server/root_password_again password password" | debconf-set-selections
|
||||||
|
|
||||||
|
# upgrade
|
||||||
|
RUN apt clean && apt update && apt update && apt upgrade -y && apt autoremove -y
|
||||||
|
|
||||||
|
# requirements
|
||||||
|
RUN apt install -y software-properties-common curl zip unzip git gcc
|
||||||
|
|
||||||
|
# nginx
|
||||||
|
RUN apt install -y nginx
|
||||||
|
|
||||||
|
# php
|
||||||
|
RUN apt update \
|
||||||
|
&& apt install -y gnupg gosu curl ca-certificates zip unzip git supervisor libcap2-bin libpng-dev \
|
||||||
|
python2 dnsutils librsvg2-bin fswatch wget \
|
||||||
|
&& add-apt-repository ppa:ondrej/php -y \
|
||||||
|
&& apt update \
|
||||||
|
&& apt install -y php8.1 php8.1-fpm php8.1-mbstring php8.1-mysql php8.1-mcrypt php8.1-gd php8.1-xml \
|
||||||
|
php8.1-curl php8.1-gettext php8.1-zip php8.1-bcmath php8.1-soap php8.1-redis
|
||||||
|
COPY docker/standalone/php.ini /etc/php/8.1/cli/conf.d/99-vito.ini
|
||||||
|
|
||||||
|
# composer
|
||||||
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||||
|
|
||||||
|
# mysql
|
||||||
|
RUN wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.22-1_all.deb \
|
||||||
|
&& mkdir -p /etc/apt/keyrings \
|
||||||
|
&& apt clean \
|
||||||
|
&& apt update \
|
||||||
|
&& dpkg -i mysql-apt-config_0.8.22-1_all.deb \
|
||||||
|
&& apt install mysql-server -y
|
||||||
|
|
||||||
|
RUN service mysql stop
|
||||||
|
|
||||||
|
# app
|
||||||
|
COPY . /var/www/html
|
||||||
|
RUN rm -rf /var/www/html/vendor
|
||||||
|
RUN rm -rf /var/www/html/.env
|
||||||
|
RUN composer install --no-dev --prefer-dist
|
||||||
|
RUN chown -R www-data:www-data /var/www/html \
|
||||||
|
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||||
|
|
||||||
|
# webserver
|
||||||
|
RUN rm /etc/nginx/sites-available/default
|
||||||
|
RUN rm /etc/nginx/sites-enabled/default
|
||||||
|
COPY docker/standalone/nginx.conf /etc/nginx/sites-available/default
|
||||||
|
RUN ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
|
||||||
|
|
||||||
|
# supervisord
|
||||||
|
COPY docker/standalone/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# start
|
||||||
|
COPY docker/standalone/start.sh /start.sh
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
|
||||||
|
EXPOSE 80 3306
|
||||||
|
|
||||||
|
CMD ["/start.sh"]
|
47
README.md
47
README.md
@ -1,28 +1,49 @@
|
|||||||
# Vito
|
|
||||||
|
|
||||||

|
<p align="center">
|
||||||
|
<img alt="srcshot 2024-02-23 at 16 26 21@2x" src="https://github.com/vitodeploy/vito/assets/61919774/c22842ff-b458-443c-90b7-a98148b0d49e" alt="VitoDeploy>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/vitodeploy/vito/actions"><img alt="GitHub Workflow Status" src="https://github.com/vitodeploy/vito/workflows/tests/badge.svg"></a>
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
|
||||||

|
------
|
||||||
|
## About Vito
|
||||||
|
|
||||||
Better Readme will come soon... :)
|
Vito is a self-hosted web application that helps you manage your servers and deploy your PHP applications into production servers without a hassle.
|
||||||
|
|
||||||
## Documentation
|
## Features
|
||||||
|
|
||||||
https://vitodeploy.com
|
- Provisions and Manages the server
|
||||||
|
- Easy database management, Supports Mysql and MariaDB
|
||||||
|
- Deploy your PHP applications such as Laravel
|
||||||
|
- Manage your server's firewall
|
||||||
|
- Supports Custom and Letsencrypt SSL
|
||||||
|
- Uses supervisor to handle queues
|
||||||
|
- Manages server's services
|
||||||
|
- Deploy your SSH Keys to the server
|
||||||
|
- Create and Manage cron jobs on the server
|
||||||
|
|
||||||
## Contribution
|
## Useful Links
|
||||||
|
|
||||||
Please read the contribution guide [Here](/CONTRIBUTING.md)
|
- [Documentation](https://vitodeploy.com)
|
||||||
|
- [Feedbacks](https://vitodeploy.featurebase.app)
|
||||||
## Security
|
- [Roadmap](https://vitodeploy.featurebase.app/roadmap)
|
||||||
|
- [Discord](https://discord.gg/dcUWA5DV)
|
||||||
Please read the security policy [Here](/SECURITY.md)
|
- [Contribution](/CONTRIBUTING.md)
|
||||||
|
- [Security](/SECURITY.md)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- Laravel
|
- Laravel
|
||||||
- Tailwind
|
- Tailwindcss
|
||||||
- Livewire
|
- Livewire
|
||||||
- Alpinejs
|
- Alpinejs
|
||||||
- Vite
|
- Vite
|
||||||
- Laravel Enum by BenSampo
|
- Laravel Enum by BenSampo
|
||||||
|
- Log Viewer by Arunas Skirius
|
||||||
|
- PHPSecLib
|
||||||
|
- Laravel Blade Icons
|
||||||
|
- Guzzlehttp
|
||||||
|
- Owenvoke for `owenvoke/blade-fontawesome`
|
||||||
|
- Axios
|
||||||
|
- Toastr by CodeSeven
|
||||||
|
@ -21,16 +21,25 @@ public function add(User $user, array $input): void
|
|||||||
'label' => $input['label'],
|
'label' => $input['label'],
|
||||||
]);
|
]);
|
||||||
$this->validateType($channel, $input);
|
$this->validateType($channel, $input);
|
||||||
$channel->data = $channel->provider()->data($input);
|
$channel->data = $channel->provider()->createData($input);
|
||||||
$channel->save();
|
$channel->save();
|
||||||
|
|
||||||
if (! $channel->provider()->connect()) {
|
if (! $channel->provider()->connect()) {
|
||||||
$channel->delete();
|
$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([
|
throw ValidationException::withMessages([
|
||||||
'provider' => __('Could not connect'),
|
'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
|
protected function validateType(NotificationChannel $channel, array $input): void
|
||||||
{
|
{
|
||||||
Validator::make($input, $channel->provider()->validationRules())
|
Validator::make($input, $channel->provider()->createRules($input))
|
||||||
->validate();
|
->validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@ public function update(Service $service, string $ini): void
|
|||||||
{
|
{
|
||||||
$tmpName = Str::random(10).strtotime('now');
|
$tmpName = Str::random(10).strtotime('now');
|
||||||
try {
|
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(
|
$service->server->ssh('root')->upload(
|
||||||
Storage::disk('local')->path($tmpName),
|
$storageDisk->path($tmpName),
|
||||||
"/etc/php/$service->version/cli/php.ini"
|
"/etc/php/$service->version/cli/php.ini"
|
||||||
);
|
);
|
||||||
$this->deleteTempFile($tmpName);
|
$this->deleteTempFile($tmpName);
|
||||||
|
36
app/Actions/Projects/CreateProject.php
Normal file
36
app/Actions/Projects/CreateProject.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Projects;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class CreateProject
|
||||||
|
{
|
||||||
|
public function create(User $user, array $input): Project
|
||||||
|
{
|
||||||
|
$this->validate($user, $input);
|
||||||
|
|
||||||
|
$project = new Project([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'name' => $input['name'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$project->save();
|
||||||
|
|
||||||
|
return $project;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(User $user, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
|
'unique:projects,name,NULL,id,user_id,'.$user->id,
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
31
app/Actions/Projects/DeleteProject.php
Normal file
31
app/Actions/Projects/DeleteProject.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Projects;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class DeleteProject
|
||||||
|
{
|
||||||
|
public function delete(User $user, int $projectId): void
|
||||||
|
{
|
||||||
|
/** @var Project $project */
|
||||||
|
$project = $user->projects()->findOrFail($projectId);
|
||||||
|
|
||||||
|
if ($user->projects()->count() === 1) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'project' => __('Cannot delete the last project.'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->current_project_id == $project->id) {
|
||||||
|
/** @var Project $randomProject */
|
||||||
|
$randomProject = $user->projects()->where('id', '!=', $project->id)->first();
|
||||||
|
$user->current_project_id = $randomProject->id;
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$project->delete();
|
||||||
|
}
|
||||||
|
}
|
33
app/Actions/Projects/UpdateProject.php
Normal file
33
app/Actions/Projects/UpdateProject.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Projects;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UpdateProject
|
||||||
|
{
|
||||||
|
public function update(Project $project, array $input): Project
|
||||||
|
{
|
||||||
|
$this->validate($project, $input);
|
||||||
|
|
||||||
|
$project->name = $input['name'];
|
||||||
|
|
||||||
|
$project->save();
|
||||||
|
|
||||||
|
return $project;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(Project $project, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('projects')->ignore($project->id),
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ public function create(User $creator, array $input): Server
|
|||||||
$this->validateInputs($input);
|
$this->validateInputs($input);
|
||||||
|
|
||||||
$server = new Server([
|
$server = new Server([
|
||||||
|
'project_id' => $creator->currentProject->id,
|
||||||
'user_id' => $creator->id,
|
'user_id' => $creator->id,
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'ssh_user' => config('core.server_providers_default_user')[$input['provider']][$input['os']],
|
'ssh_user' => config('core.server_providers_default_user')[$input['provider']][$input['os']],
|
||||||
@ -43,9 +44,8 @@ public function create(User $creator, array $input): Server
|
|||||||
'progress_step' => 'Initializing',
|
'progress_step' => 'Initializing',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
|
||||||
|
|
||||||
if ($server->provider != 'custom') {
|
if ($server->provider != 'custom') {
|
||||||
$server->provider_id = $input['server_provider'];
|
$server->provider_id = $input['server_provider'];
|
||||||
}
|
}
|
||||||
@ -118,7 +118,6 @@ private function validateInputs(array $input): void
|
|||||||
if ($input['provider'] == 'custom') {
|
if ($input['provider'] == 'custom') {
|
||||||
$rules['ip'] = [
|
$rules['ip'] = [
|
||||||
'required',
|
'required',
|
||||||
'ip',
|
|
||||||
new RestrictedIPAddressesRule(),
|
new RestrictedIPAddressesRule(),
|
||||||
];
|
];
|
||||||
$rules['port'] = [
|
$rules['port'] = [
|
||||||
|
@ -23,9 +23,8 @@ public function create(Server $server, array $input): Site
|
|||||||
{
|
{
|
||||||
$this->validateInputs($server, $input);
|
$this->validateInputs($server, $input);
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
|
||||||
|
|
||||||
$site = new Site([
|
$site = new Site([
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
'type' => $input['type'],
|
'type' => $input['type'],
|
||||||
|
0
app/Actions/Site/UpdateEnv.php
Executable file → Normal file
0
app/Actions/Site/UpdateEnv.php
Executable file → Normal file
@ -2,9 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Contracts;
|
namespace App\Contracts;
|
||||||
|
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
interface Notification
|
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
|
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 connect(): bool;
|
||||||
|
|
||||||
public function sendMessage(string $subject, string $text): void;
|
public function send(object $notifiable, Notification $notification): void;
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ public function create(
|
|||||||
?int $siteId = null
|
?int $siteId = null
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
public function delete(int $id, int $siteId = null): void;
|
public function delete(int $id, ?int $siteId = null): void;
|
||||||
|
|
||||||
public function restart(int $id, int $siteId = null): void;
|
public function restart(int $id, ?int $siteId = null): void;
|
||||||
|
|
||||||
public function stop(int $id, int $siteId = null): void;
|
public function stop(int $id, ?int $siteId = null): void;
|
||||||
|
|
||||||
public function start(int $id, int $siteId = null): void;
|
public function start(int $id, ?int $siteId = null): void;
|
||||||
|
|
||||||
public function getLogs(string $logPath): string;
|
public function getLogs(string $logPath): string;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ public function credentialData(array $input): array;
|
|||||||
|
|
||||||
public function data(array $input): array;
|
public function data(array $input): array;
|
||||||
|
|
||||||
public function connect(array $credentials = null): bool;
|
public function connect(?array $credentials = null): bool;
|
||||||
|
|
||||||
public function plans(): array;
|
public function plans(): array;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ interface SourceControlProvider
|
|||||||
{
|
{
|
||||||
public function connect(): bool;
|
public function connect(): bool;
|
||||||
|
|
||||||
public function getRepo(string $repo = null): mixed;
|
public function getRepo(?string $repo = null): mixed;
|
||||||
|
|
||||||
public function fullRepoUrl(string $repo, string $key): string;
|
public function fullRepoUrl(string $repo, string $key): string;
|
||||||
|
|
||||||
|
@ -9,7 +9,9 @@ interface Webserver
|
|||||||
{
|
{
|
||||||
public function createVHost(Site $site): void;
|
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;
|
public function deleteSite(Site $site): void;
|
||||||
|
|
||||||
|
@ -11,4 +11,6 @@ final class NotificationChannel extends Enum
|
|||||||
const SLACK = 'slack';
|
const SLACK = 'slack';
|
||||||
|
|
||||||
const DISCORD = 'discord';
|
const DISCORD = 'discord';
|
||||||
|
|
||||||
|
const TELEGRAM = 'telegram';
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ final class SiteType extends Enum
|
|||||||
{
|
{
|
||||||
const PHP = 'php';
|
const PHP = 'php';
|
||||||
|
|
||||||
|
const PHP_BLANK = 'php-blank';
|
||||||
|
|
||||||
const LARAVEL = 'laravel';
|
const LARAVEL = 'laravel';
|
||||||
|
|
||||||
const WORDPRESS = 'wordpress';
|
const WORDPRESS = 'wordpress';
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class SourceControlIsNotConnected extends Exception
|
class SourceControlIsNotConnected extends Exception
|
||||||
{
|
{
|
||||||
public function __construct(protected SourceControl|string|null $sourceControl, string $message = null)
|
public function __construct(protected SourceControl|string|null $sourceControl, ?string $message = null)
|
||||||
{
|
{
|
||||||
parent::__construct($message ?? 'Source control is not connected');
|
parent::__construct($message ?? 'Source control is not connected');
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,7 @@ class SSH
|
|||||||
|
|
||||||
protected PrivateKey $privateKey;
|
protected PrivateKey $privateKey;
|
||||||
|
|
||||||
public function init(Server $server, string $asUser = null): self
|
public function init(Server $server, ?string $asUser = null): self
|
||||||
{
|
{
|
||||||
$this->connection = null;
|
$this->connection = null;
|
||||||
$this->log = null;
|
$this->log = null;
|
||||||
@ -64,11 +64,15 @@ public function setLog(string $logType, $siteId = null): void
|
|||||||
*/
|
*/
|
||||||
public function connect(bool $sftp = false): void
|
public function connect(bool $sftp = false): void
|
||||||
{
|
{
|
||||||
|
$ip = $this->server->ip;
|
||||||
|
if (str($ip)->contains(':')) {
|
||||||
|
$ip = '['.$ip.']';
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if ($sftp) {
|
if ($sftp) {
|
||||||
$this->connection = new SFTP($this->server->ip, $this->server->port);
|
$this->connection = new SFTP($ip, $this->server->port);
|
||||||
} else {
|
} 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);
|
$login = $this->connection->login($this->user, $this->privateKey);
|
||||||
@ -87,7 +91,7 @@ public function connect(bool $sftp = false): void
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function exec(string|array|SSHCommand $commands, string $log = '', int $siteId = null): string
|
public function exec(string|array|SSHCommand $commands, string $log = '', ?int $siteId = null): string
|
||||||
{
|
{
|
||||||
if ($log) {
|
if ($log) {
|
||||||
$this->setLog($log, $siteId);
|
$this->setLog($log, $siteId);
|
||||||
|
@ -32,9 +32,6 @@ public function info(string $message): void
|
|||||||
|
|
||||||
private function toast(string $type, string $message): void
|
private function toast(string $type, string $message): void
|
||||||
{
|
{
|
||||||
$this->component->dispatchBrowserEvent('toast', [
|
$this->component->dispatch('toast', type: $type, message: $message);
|
||||||
'type' => $type,
|
|
||||||
'message' => $message,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
|
use App\Facades\Notifier;
|
||||||
use App\Models\GitHook;
|
use App\Models\GitHook;
|
||||||
|
use App\Notifications\SourceControlDisconnected;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class GitHookController extends Controller
|
class GitHookController extends Controller
|
||||||
@ -25,7 +28,7 @@ public function __invoke(Request $request)
|
|||||||
try {
|
try {
|
||||||
$gitHook->site->deploy();
|
$gitHook->site->deploy();
|
||||||
} catch (SourceControlIsNotConnected) {
|
} catch (SourceControlIsNotConnected) {
|
||||||
// TODO: send notification
|
Notifier::send($gitHook->sourceControl, new SourceControlDisconnected($gitHook->sourceControl));
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
Log::error('git-hook-exception', (array) $e);
|
Log::error('git-hook-exception', (array) $e);
|
||||||
}
|
}
|
||||||
|
29
app/Http/Controllers/ProjectController.php
Normal file
29
app/Http/Controllers/ProjectController.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
|
class ProjectController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
return view('projects.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function switch($projectId)
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
/** @var Project $project */
|
||||||
|
$project = $user->projects()->findOrFail($projectId);
|
||||||
|
|
||||||
|
$user->current_project_id = $project->id;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return redirect()->route('servers');
|
||||||
|
}
|
||||||
|
}
|
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
class AutoDeployment extends Component
|
class AutoDeployment extends Component
|
||||||
{
|
{
|
||||||
use RefreshComponentOnBroadcast;
|
|
||||||
use HasToast;
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
public Site $site;
|
public Site $site;
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
class Deploy extends Component
|
class Deploy extends Component
|
||||||
{
|
{
|
||||||
use RefreshComponentOnBroadcast;
|
|
||||||
use HasToast;
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
public Site $site;
|
public Site $site;
|
||||||
|
|
||||||
@ -23,9 +23,9 @@ public function deploy(): void
|
|||||||
|
|
||||||
$this->toast()->success(__('Deployment started!'));
|
$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) {
|
} catch (SourceControlIsNotConnected $e) {
|
||||||
session()->flash('toast.type', 'error');
|
session()->flash('toast.type', 'error');
|
||||||
session()->flash('toast.message', $e->getMessage());
|
session()->flash('toast.message', $e->getMessage());
|
||||||
|
@ -27,8 +27,8 @@ public function save(): void
|
|||||||
|
|
||||||
session()->flash('status', 'script-updated');
|
session()->flash('status', 'script-updated');
|
||||||
|
|
||||||
$this->emitTo(Deploy::class, '$refresh');
|
$this->dispatch('$refresh')->to(Deploy::class);
|
||||||
$this->emitTo(AutoDeployment::class, '$refresh');
|
$this->dispatch('$refresh')->to(AutoDeployment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
class DeploymentsList extends Component
|
class DeploymentsList extends Component
|
||||||
{
|
{
|
||||||
use RefreshComponentOnBroadcast;
|
|
||||||
use HasCustomPaginationView;
|
use HasCustomPaginationView;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
public Site $site;
|
public Site $site;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ public function showLog(int $id): void
|
|||||||
$deployment = $this->site->deployments()->findOrFail($id);
|
$deployment = $this->site->deployments()->findOrFail($id);
|
||||||
$this->logContent = $deployment->log->content;
|
$this->logContent = $deployment->log->content;
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('open-modal', 'show-log');
|
$this->dispatch('open-modal', 'show-log');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -14,11 +14,11 @@ class Env extends Component
|
|||||||
|
|
||||||
public Site $site;
|
public Site $site;
|
||||||
|
|
||||||
public string $env;
|
public string $env = 'Loading...';
|
||||||
|
|
||||||
public function mount(): void
|
public function loadEnv(): void
|
||||||
{
|
{
|
||||||
$this->env = $this->site->env;
|
$this->env = $this->site->getEnv();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(): void
|
public function save(): void
|
||||||
@ -27,7 +27,7 @@ public function save(): void
|
|||||||
|
|
||||||
session()->flash('status', 'updating-env');
|
session()->flash('status', 'updating-env');
|
||||||
|
|
||||||
$this->emit(Deploy::class, '$refresh');
|
$this->dispatch('$refresh')->to(Deploy::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
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');
|
$event = Cache::get('broadcast');
|
||||||
if ($event) {
|
if ($event) {
|
||||||
Cache::forget('broadcast');
|
Cache::forget('broadcast');
|
||||||
$this->emit('broadcast', $event);
|
$this->dispatch('broadcast', $event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('livewire.broadcast');
|
return view('livewire.broadcast');
|
||||||
|
@ -22,9 +22,9 @@ public function create(): void
|
|||||||
{
|
{
|
||||||
app(\App\Actions\CronJob\CreateCronJob::class)->create($this->server, $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -23,7 +23,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -45,7 +45,7 @@ public function restore(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('restored', true);
|
$this->dispatch('restored');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
@ -55,7 +55,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$file->delete();
|
$file->delete();
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -40,7 +40,7 @@ public function create(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('backup-created', true);
|
$this->dispatch('backup-created');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function files(int $id): void
|
public function files(int $id): void
|
||||||
@ -48,7 +48,7 @@ public function files(int $id): void
|
|||||||
$backup = Backup::query()->findOrFail($id);
|
$backup = Backup::query()->findOrFail($id);
|
||||||
$this->backup = $backup;
|
$this->backup = $backup;
|
||||||
$this->files = $backup->files()->orderByDesc('id')->simplePaginate(1);
|
$this->files = $backup->files()->orderByDesc('id')->simplePaginate(1);
|
||||||
$this->dispatchBrowserEvent('show-files', true);
|
$this->dispatch('show-files');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function backup(): void
|
public function backup(): void
|
||||||
@ -57,7 +57,7 @@ public function backup(): void
|
|||||||
|
|
||||||
$this->files = $this->backup?->files()->orderByDesc('id')->simplePaginate();
|
$this->files = $this->backup?->files()->orderByDesc('id')->simplePaginate();
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('backup-running', true);
|
$this->dispatch('backup-running');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
@ -67,7 +67,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$backup->delete();
|
$backup->delete();
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -40,7 +40,7 @@ public function create(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('database-created', true);
|
$this->dispatch('database-created');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
@ -52,9 +52,9 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->emitTo(DatabaseUserList::class, '$refresh');
|
$this->dispatch('$refresh')->to(DatabaseUserList::class);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -38,7 +38,7 @@ public function create(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('database-user-created', true);
|
$this->dispatch('database-user-created');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
@ -50,9 +50,9 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$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
|
public function viewPassword(int $id): void
|
||||||
@ -62,7 +62,7 @@ public function viewPassword(int $id): void
|
|||||||
|
|
||||||
$this->viewPassword = $databaseUser->password;
|
$this->viewPassword = $databaseUser->password;
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('open-modal', 'database-user-password');
|
$this->dispatch('open-modal', 'database-user-password');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showLink(int $id): void
|
public function showLink(int $id): void
|
||||||
@ -73,7 +73,7 @@ public function showLink(int $id): void
|
|||||||
$this->linkId = $id;
|
$this->linkId = $id;
|
||||||
$this->link = $databaseUser->databases ?? [];
|
$this->link = $databaseUser->databases ?? [];
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('open-modal', 'link-database-user');
|
$this->dispatch('open-modal', 'link-database-user');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function link(): void
|
public function link(): void
|
||||||
@ -85,7 +85,7 @@ public function link(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('linked', true);
|
$this->dispatch('linked');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -28,9 +28,9 @@ public function create(): void
|
|||||||
{
|
{
|
||||||
app(CreateRule::class)->create($this->server, $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -15,6 +15,10 @@ class AddChannel extends Component
|
|||||||
|
|
||||||
public string $email;
|
public string $email;
|
||||||
|
|
||||||
|
public string $bot_token;
|
||||||
|
|
||||||
|
public string $chat_id;
|
||||||
|
|
||||||
public function add(): void
|
public function add(): void
|
||||||
{
|
{
|
||||||
app(\App\Actions\NotificationChannels\AddChannel::class)->add(
|
app(\App\Actions\NotificationChannels\AddChannel::class)->add(
|
||||||
@ -22,9 +26,9 @@ public function add(): void
|
|||||||
$this->all()
|
$this->all()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->emitTo(ChannelsList::class, '$refresh');
|
$this->dispatch('$refresh')->to(ChannelsList::class);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('added', true);
|
$this->dispatch('added');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -56,7 +56,7 @@ public function uninstall(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadIni(int $id): void
|
public function loadIni(int $id): void
|
||||||
|
@ -33,7 +33,7 @@ public function submit(): void
|
|||||||
|
|
||||||
session()->flash('status', 'profile-updated');
|
session()->flash('status', 'profile-updated');
|
||||||
|
|
||||||
$this->emitTo(UserDropdown::class, '$refresh');
|
$this->dispatch('$refresh')->to(UserDropdown::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendVerificationEmail(): void
|
public function sendVerificationEmail(): void
|
||||||
|
37
app/Http/Livewire/Projects/CreateProject.php
Normal file
37
app/Http/Livewire/Projects/CreateProject.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Projects;
|
||||||
|
|
||||||
|
use App\Traits\HasToast;
|
||||||
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class CreateProject extends Component
|
||||||
|
{
|
||||||
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
|
public bool $open = false;
|
||||||
|
|
||||||
|
public array $inputs = [];
|
||||||
|
|
||||||
|
public function create(): void
|
||||||
|
{
|
||||||
|
app(\App\Actions\Projects\CreateProject::class)
|
||||||
|
->create(auth()->user(), $this->inputs);
|
||||||
|
|
||||||
|
$this->dispatch('$refresh')->to(ProjectsList::class);
|
||||||
|
|
||||||
|
$this->dispatch('created');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
if (request()->query('create')) {
|
||||||
|
$this->open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('livewire.projects.create-project');
|
||||||
|
}
|
||||||
|
}
|
37
app/Http/Livewire/Projects/EditProject.php
Normal file
37
app/Http/Livewire/Projects/EditProject.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Projects;
|
||||||
|
|
||||||
|
use App\Actions\Projects\UpdateProject;
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class EditProject extends Component
|
||||||
|
{
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
|
public Project $project;
|
||||||
|
|
||||||
|
public array $inputs = [];
|
||||||
|
|
||||||
|
public function save(): void
|
||||||
|
{
|
||||||
|
app(UpdateProject::class)->update($this->project, $this->inputs);
|
||||||
|
|
||||||
|
$this->redirect(route('projects'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->inputs = [
|
||||||
|
'name' => $this->project->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('livewire.projects.edit-project');
|
||||||
|
}
|
||||||
|
}
|
42
app/Http/Livewire/Projects/ProjectsList.php
Normal file
42
app/Http/Livewire/Projects/ProjectsList.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Projects;
|
||||||
|
|
||||||
|
use App\Actions\Projects\DeleteProject;
|
||||||
|
use App\Traits\HasToast;
|
||||||
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class ProjectsList extends Component
|
||||||
|
{
|
||||||
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
|
protected $listeners = [
|
||||||
|
'$refresh',
|
||||||
|
];
|
||||||
|
|
||||||
|
public int $deleteId;
|
||||||
|
|
||||||
|
public function delete(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
app(DeleteProject::class)->delete(auth()->user(), $this->deleteId);
|
||||||
|
|
||||||
|
$this->redirect(route('projects'));
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$this->toast()->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('livewire.projects.projects-list', [
|
||||||
|
'projects' => auth()->user()->projects()->orderByDesc('id')->get(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -24,9 +24,9 @@ public function create(): void
|
|||||||
{
|
{
|
||||||
app(\App\Actions\Queue\CreateQueue::class)->create($this->site, $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -24,7 +24,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(Queue $queue): void
|
public function start(Queue $queue): void
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
class LogsList extends Component
|
class LogsList extends Component
|
||||||
{
|
{
|
||||||
use RefreshComponentOnBroadcast;
|
|
||||||
use HasCustomPaginationView;
|
use HasCustomPaginationView;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
public ?int $count = null;
|
public ?int $count = null;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ public function showLog(int $id): void
|
|||||||
$log = $this->server->logs()->findOrFail($id);
|
$log = $this->server->logs()->findOrFail($id);
|
||||||
$this->logContent = $log->content;
|
$this->logContent = $log->content;
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('open-modal', 'show-log');
|
$this->dispatch('open-modal', 'show-log');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -22,9 +22,9 @@ public function connect(): void
|
|||||||
{
|
{
|
||||||
app(CreateServerProvider::class)->create(auth()->user(), $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -19,9 +19,9 @@ public function add(): void
|
|||||||
|
|
||||||
$key->deployTo($this->server);
|
$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
|
public function render(): View
|
||||||
|
@ -24,9 +24,9 @@ public function add(): void
|
|||||||
|
|
||||||
$key->deployTo($this->server);
|
$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
|
public function render(): View
|
||||||
|
@ -28,7 +28,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Servers;
|
namespace App\Http\Livewire\Servers;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\User;
|
||||||
use App\Traits\RefreshComponentOnBroadcast;
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -13,8 +13,12 @@ class ServersList extends Component
|
|||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
$servers = $user->currentProject->servers()->orderByDesc('created_at')->get();
|
||||||
|
|
||||||
return view('livewire.servers.servers-list', [
|
return view('livewire.servers.servers-list', [
|
||||||
'servers' => Server::all(),
|
'servers' => $servers,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public function refreshComponent(array $data): void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->emit('refreshComponent');
|
$this->dispatch('refreshComponent');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -19,9 +19,9 @@ public function install(): void
|
|||||||
{
|
{
|
||||||
app(InstallPHPMyAdminAction::class)->install($this->server, $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -26,7 +26,7 @@ public function refreshComponent(array $data): void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->emit('refreshComponent');
|
$this->dispatch('refreshComponent');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
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());
|
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
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -19,9 +19,9 @@ public function add(): void
|
|||||||
$this->all()
|
$this->all()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->emitTo(KeysList::class, '$refresh');
|
$this->dispatch('$refresh')->to(KeysList::class);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('added', true);
|
$this->dispatch('added');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -23,9 +23,9 @@ public function create(): void
|
|||||||
{
|
{
|
||||||
app(\App\Actions\SSL\CreateSSL::class)->create($this->site, $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
class SslsList extends Component
|
class SslsList extends Component
|
||||||
{
|
{
|
||||||
use RefreshComponentOnBroadcast;
|
|
||||||
use HasToast;
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
public Site $site;
|
public Site $site;
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refreshComponent(array $data): void
|
public function refreshComponent(array $data): void
|
||||||
@ -34,7 +34,7 @@ public function refreshComponent(array $data): void
|
|||||||
$this->toast()->error(__('SSL creation failed!'));
|
$this->toast()->error(__('SSL creation failed!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->emit('refreshComponent');
|
$this->dispatch('refreshComponent');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -32,9 +32,9 @@ public function connect(): void
|
|||||||
{
|
{
|
||||||
app(CreateStorageProvider::class)->create(auth()->user(), $this->all());
|
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
|
public function render(): View
|
||||||
|
@ -25,7 +25,7 @@ public function delete(): void
|
|||||||
|
|
||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
|
|
||||||
$this->dispatchBrowserEvent('confirmed', true);
|
$this->dispatch('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
@ -13,7 +13,7 @@ class Initialize extends InstallationJob
|
|||||||
|
|
||||||
protected ?string $asUser;
|
protected ?string $asUser;
|
||||||
|
|
||||||
public function __construct(Server $server, string $asUser = null)
|
public function __construct(Server $server, ?string $asUser = null)
|
||||||
{
|
{
|
||||||
$this->server = $server->refresh();
|
$this->server = $server->refresh();
|
||||||
$this->asUser = $asUser;
|
$this->asUser = $asUser;
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
namespace App\Jobs\Server;
|
namespace App\Jobs\Server;
|
||||||
|
|
||||||
use App\Events\Broadcast;
|
use App\Events\Broadcast;
|
||||||
|
use App\Facades\Notifier;
|
||||||
use App\Jobs\Job;
|
use App\Jobs\Job;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Notifications\ServerDisconnected;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class CheckConnection extends Job
|
class CheckConnection extends Job
|
||||||
@ -39,7 +41,7 @@ public function failed(): void
|
|||||||
{
|
{
|
||||||
$this->server->status = 'disconnected';
|
$this->server->status = 'disconnected';
|
||||||
$this->server->save();
|
$this->server->save();
|
||||||
/** @todo notify */
|
Notifier::send($this->server, new ServerDisconnected($this->server));
|
||||||
event(
|
event(
|
||||||
new Broadcast('server-status-failed', [
|
new Broadcast('server-status-failed', [
|
||||||
'server' => $this->server,
|
'server' => $this->server,
|
||||||
|
@ -26,9 +26,7 @@ public function handle(): void
|
|||||||
new EditFileCommand(
|
new EditFileCommand(
|
||||||
$this->site->path.'/.env',
|
$this->site->path.'/.env',
|
||||||
$this->site->env
|
$this->site->env
|
||||||
),
|
)
|
||||||
'update-env',
|
|
||||||
$this->site->id
|
|
||||||
);
|
);
|
||||||
event(
|
event(
|
||||||
new Broadcast('deploy-site-env-finished', [
|
new Broadcast('deploy-site-env-finished', [
|
||||||
|
@ -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
|
public function destroyHook(): void
|
||||||
{
|
{
|
||||||
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
|
||||||
$this->sourceControl->provider()->destroyHook($this->site->repository, $this->hook_id);
|
$this->sourceControl->provider()->destroyHook($this->site->repository, $this->hook_id);
|
||||||
$this->delete();
|
$this->delete();
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
@ -2,19 +2,21 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Contracts\Notification;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property string $provider
|
* @property int $id
|
||||||
* @property string $label
|
* @property string provider
|
||||||
* @property array $data
|
* @property array data
|
||||||
* @property bool $connected
|
* @property string label
|
||||||
* @property bool $is_default
|
* @property bool connected
|
||||||
* @property User $user
|
|
||||||
*/
|
*/
|
||||||
class NotificationChannel extends AbstractModel
|
class NotificationChannel extends AbstractModel
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
use Notifiable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'provider',
|
'provider',
|
||||||
@ -25,15 +27,24 @@ class NotificationChannel extends AbstractModel
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'data' => 'json',
|
'project_id' => 'integer',
|
||||||
|
'data' => 'array',
|
||||||
'connected' => 'boolean',
|
'connected' => 'boolean',
|
||||||
'is_default' => 'boolean',
|
'is_default' => 'boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function provider(): \App\Contracts\NotificationChannel
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
app/Models/Project.php
Normal file
56
app/Models/Project.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property string $name
|
||||||
|
* @property Carbon $created_at
|
||||||
|
* @property Carbon $updated_at
|
||||||
|
* @property User $user
|
||||||
|
* @property Collection<Server> $servers
|
||||||
|
* @property Collection<NotificationChannel> $notificationChannels
|
||||||
|
*/
|
||||||
|
class Project extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::deleting(function (Project $project) {
|
||||||
|
$project->servers()->each(function (Server $server) {
|
||||||
|
$server->delete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function servers(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Server::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notificationChannels(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(NotificationChannel::class);
|
||||||
|
}
|
||||||
|
}
|
@ -4,20 +4,25 @@
|
|||||||
|
|
||||||
use App\Contracts\ServerType;
|
use App\Contracts\ServerType;
|
||||||
use App\Enums\ServerStatus;
|
use App\Enums\ServerStatus;
|
||||||
|
use App\Enums\ServiceStatus;
|
||||||
|
use App\Facades\Notifier;
|
||||||
use App\Facades\SSH;
|
use App\Facades\SSH;
|
||||||
use App\Jobs\Installation\Upgrade;
|
use App\Jobs\Installation\Upgrade;
|
||||||
use App\Jobs\Server\CheckConnection;
|
use App\Jobs\Server\CheckConnection;
|
||||||
use App\Jobs\Server\RebootServer;
|
use App\Jobs\Server\RebootServer;
|
||||||
|
use App\Notifications\ServerInstallationStarted;
|
||||||
use App\Support\Testing\SSHFake;
|
use App\Support\Testing\SSHFake;
|
||||||
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\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @property int $project_id
|
||||||
* @property int $user_id
|
* @property int $user_id
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property string $ssh_user
|
* @property string $ssh_user
|
||||||
@ -38,6 +43,7 @@
|
|||||||
* @property int $security_updates
|
* @property int $security_updates
|
||||||
* @property int $progress
|
* @property int $progress
|
||||||
* @property string $progress_step
|
* @property string $progress_step
|
||||||
|
* @property Project $project
|
||||||
* @property User $creator
|
* @property User $creator
|
||||||
* @property ServerProvider $serverProvider
|
* @property ServerProvider $serverProvider
|
||||||
* @property ServerLog[] $logs
|
* @property ServerLog[] $logs
|
||||||
@ -59,6 +65,7 @@ class Server extends AbstractModel
|
|||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'project_id',
|
||||||
'user_id',
|
'user_id',
|
||||||
'name',
|
'name',
|
||||||
'ssh_user',
|
'ssh_user',
|
||||||
@ -82,6 +89,7 @@ class Server extends AbstractModel
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
'project_id' => 'integer',
|
||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
'type_data' => 'json',
|
'type_data' => 'json',
|
||||||
'port' => 'integer',
|
'port' => 'integer',
|
||||||
@ -106,7 +114,9 @@ public static function boot(): void
|
|||||||
$site->delete();
|
$site->delete();
|
||||||
});
|
});
|
||||||
$server->provider()->delete();
|
$server->provider()->delete();
|
||||||
$server->logs()->delete();
|
$server->logs()->each(function (ServerLog $log) {
|
||||||
|
$log->delete();
|
||||||
|
});
|
||||||
$server->services()->delete();
|
$server->services()->delete();
|
||||||
$server->databases()->delete();
|
$server->databases()->delete();
|
||||||
$server->databaseUsers()->delete();
|
$server->databaseUsers()->delete();
|
||||||
@ -125,6 +135,11 @@ public static function boot(): void
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function project(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Project::class, 'project_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function creator(): BelongsTo
|
public function creator(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'user_id');
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
@ -213,6 +228,18 @@ public function defaultService($type): ?Service
|
|||||||
->where('is_default', 1)
|
->where('is_default', 1)
|
||||||
->first();
|
->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;
|
return $service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,10 +257,10 @@ public function getServiceByUnit($unit): ?Service
|
|||||||
public function install(): void
|
public function install(): void
|
||||||
{
|
{
|
||||||
$this->type()->install();
|
$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
|
public function ssh(?string $user = null): \App\Helpers\SSH|SSHFake
|
||||||
{
|
{
|
||||||
return SSH::init($this, $user);
|
return SSH::init($this, $user);
|
||||||
}
|
}
|
||||||
@ -263,7 +290,7 @@ public function provider(): \App\Contracts\ServerProvider
|
|||||||
return new $providerClass($this);
|
return new $providerClass($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function webserver(string $version = null): ?Service
|
public function webserver(?string $version = null): ?Service
|
||||||
{
|
{
|
||||||
if (! $version) {
|
if (! $version) {
|
||||||
return $this->defaultService('webserver');
|
return $this->defaultService('webserver');
|
||||||
@ -272,7 +299,7 @@ public function webserver(string $version = null): ?Service
|
|||||||
return $this->service('webserver', $version);
|
return $this->service('webserver', $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function database(string $version = null): ?Service
|
public function database(?string $version = null): ?Service
|
||||||
{
|
{
|
||||||
if (! $version) {
|
if (! $version) {
|
||||||
return $this->defaultService('database');
|
return $this->defaultService('database');
|
||||||
@ -281,7 +308,7 @@ public function database(string $version = null): ?Service
|
|||||||
return $this->service('database', $version);
|
return $this->service('database', $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function firewall(string $version = null): ?Service
|
public function firewall(?string $version = null): ?Service
|
||||||
{
|
{
|
||||||
if (! $version) {
|
if (! $version) {
|
||||||
return $this->defaultService('firewall');
|
return $this->defaultService('firewall');
|
||||||
@ -290,7 +317,7 @@ public function firewall(string $version = null): ?Service
|
|||||||
return $this->service('firewall', $version);
|
return $this->service('firewall', $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processManager(string $version = null): ?Service
|
public function processManager(?string $version = null): ?Service
|
||||||
{
|
{
|
||||||
if (! $version) {
|
if (! $version) {
|
||||||
return $this->defaultService('process_manager');
|
return $this->defaultService('process_manager');
|
||||||
@ -299,7 +326,7 @@ public function processManager(string $version = null): ?Service
|
|||||||
return $this->service('process_manager', $version);
|
return $this->service('process_manager', $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function php(string $version = null): ?Service
|
public function php(?string $version = null): ?Service
|
||||||
{
|
{
|
||||||
if (! $version) {
|
if (! $version) {
|
||||||
return $this->defaultService('php');
|
return $this->defaultService('php');
|
||||||
@ -334,10 +361,13 @@ public function sshKey(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var FilesystemAdapter $storageDisk */
|
||||||
|
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'public_key' => Str::replace("\n", '', Storage::disk(config('core.key_pairs_disk'))->get($this->id.'.pub')),
|
'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'),
|
'public_key_path' => $storageDisk->path($this->id.'.pub'),
|
||||||
'private_key_path' => Storage::disk(config('core.key_pairs_disk'))->path((string) $this->id),
|
'private_key_path' => $storageDisk->path((string) $this->id),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,17 @@ class ServerLog extends AbstractModel
|
|||||||
'site_id' => 'integer',
|
'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
|
public function getRouteKey(): string
|
||||||
{
|
{
|
||||||
return 'log';
|
return 'log';
|
||||||
|
@ -8,10 +8,14 @@
|
|||||||
use App\Enums\SslStatus;
|
use App\Enums\SslStatus;
|
||||||
use App\Events\Broadcast;
|
use App\Events\Broadcast;
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
|
use App\Facades\Notifier;
|
||||||
use App\Jobs\Site\ChangePHPVersion;
|
use App\Jobs\Site\ChangePHPVersion;
|
||||||
use App\Jobs\Site\Deploy;
|
use App\Jobs\Site\Deploy;
|
||||||
use App\Jobs\Site\DeployEnv;
|
use App\Jobs\Site\DeployEnv;
|
||||||
use App\Jobs\Site\UpdateBranch;
|
use App\Jobs\Site\UpdateBranch;
|
||||||
|
use App\Notifications\SiteInstallationFailed;
|
||||||
|
use App\Notifications\SiteInstallationSucceed;
|
||||||
|
use App\SSHCommands\Website\GetEnvCommand;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@ -354,8 +358,8 @@ public function enableAutoDeployment(): void
|
|||||||
throw new SourceControlIsNotConnected($this->source_control);
|
throw new SourceControlIsNotConnected($this->source_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
|
||||||
$gitHook = new GitHook([
|
$gitHook = new GitHook([
|
||||||
'site_id' => $this->id,
|
'site_id' => $this->id,
|
||||||
'source_control_id' => $this->sourceControl()->id,
|
'source_control_id' => $this->sourceControl()->id,
|
||||||
@ -406,7 +410,7 @@ public function installationFinished(): void
|
|||||||
'site' => $this,
|
'site' => $this,
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
/** @todo notify */
|
Notifier::send($this, new SiteInstallationSucceed($this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -422,7 +426,7 @@ public function installationFailed(Throwable $e): void
|
|||||||
'site' => $this,
|
'site' => $this,
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
/** @todo notify */
|
Notifier::send($this, new SiteInstallationFailed($this));
|
||||||
Log::error('install-site-error', [
|
Log::error('install-site-error', [
|
||||||
'error' => (string) $e,
|
'error' => (string) $e,
|
||||||
]);
|
]);
|
||||||
@ -439,4 +443,13 @@ public function isReady(): bool
|
|||||||
{
|
{
|
||||||
return $this->status === SiteStatus::READY;
|
return $this->status === SiteStatus::READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEnv(): string
|
||||||
|
{
|
||||||
|
return $this->server->ssh()->exec(
|
||||||
|
new GetEnvCommand(
|
||||||
|
$this->domain
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public function provider(): SourceControlProvider
|
|||||||
return new $providerClass($this);
|
return new $providerClass($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRepo(string $repo = null): ?array
|
public function getRepo(?string $repo = null): ?array
|
||||||
{
|
{
|
||||||
return $this->provider()->getRepo($repo);
|
return $this->provider()->getRepo($repo);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
* @property Collection $tokens
|
* @property Collection $tokens
|
||||||
* @property string $profile_photo_url
|
* @property string $profile_photo_url
|
||||||
* @property string $timezone
|
* @property string $timezone
|
||||||
|
* @property int $current_project_id
|
||||||
|
* @property Project $currentProject
|
||||||
|
* @property Collection<Project> $projects
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
@ -41,6 +44,7 @@ class User extends Authenticatable
|
|||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
'timezone',
|
'timezone',
|
||||||
|
'current_project_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
@ -53,6 +57,20 @@ class User extends Authenticatable
|
|||||||
protected $appends = [
|
protected $appends = [
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::created(function (User $user) {
|
||||||
|
$user->createDefaultProject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function servers(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Server::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function sshKeys(): HasMany
|
public function sshKeys(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(SshKey::class);
|
return $this->hasMany(SshKey::class);
|
||||||
@ -105,4 +123,36 @@ public function connectedSourceControls(): array
|
|||||||
|
|
||||||
return $connectedSourceControls;
|
return $connectedSourceControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function projects(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Project::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currentProject(): HasOne
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
$project = $this->projects()->first();
|
||||||
|
|
||||||
|
if (! $project) {
|
||||||
|
$project = new Project();
|
||||||
|
$project->user_id = $this->id;
|
||||||
|
$project->name = 'Default';
|
||||||
|
$project->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->current_project_id = $project->id;
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
return $project;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
namespace App\NotificationChannels;
|
||||||
|
|
||||||
|
use App\Contracts\Notification;
|
||||||
|
use App\Models\NotificationChannel;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
class Discord extends AbstractProvider
|
class Discord extends AbstractNotificationChannel
|
||||||
{
|
{
|
||||||
public function validationRules(): array
|
public function createRules(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'webhook_url' => 'required|url',
|
'webhook_url' => 'required|url',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function data(array $input): array
|
public function createData(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
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(
|
$connect = $this->checkConnection(
|
||||||
__('Congratulations! 🎉'),
|
__('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".
|
__('Manage your notification channels')."\n".
|
||||||
route('notification-channels')
|
route('notification-channels')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! $connect) {
|
if (! $connect) {
|
||||||
|
$this->notificationChannel->delete();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->notificationChannel->connected = true;
|
||||||
|
$this->notificationChannel->save();
|
||||||
|
|
||||||
return true;
|
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
|
private function checkConnection(string $subject, string $text): bool
|
||||||
{
|
{
|
||||||
$data = $this->notificationChannel->data;
|
$connect = Http::post($this->data()['webhook_url'], [
|
||||||
$connect = Http::post($data['webhook_url'], [
|
|
||||||
'content' => '*'.$subject.'*'."\n".$text,
|
'content' => '*'.$subject.'*'."\n".$text,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $connect->ok();
|
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;
|
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 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 [
|
return [
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function data(array $input): array
|
public function createData(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email' => $input['email'],
|
'email' => $input['email'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function data(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'email' => $this->notificationChannel->data['email'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function connect(): bool
|
public function connect(): bool
|
||||||
{
|
{
|
||||||
$this->notificationChannel->connected = true;
|
try {
|
||||||
$this->notificationChannel->save();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendMessage(string $subject, mixed $text): void
|
public function send(object $notifiable, Notification $notification): void
|
||||||
{
|
{
|
||||||
$data = $this->notificationChannel->data;
|
/** @var NotificationChannel $notifiable */
|
||||||
Mail::to($data['email'])->send(new NotificationChannelMessage($subject, $text));
|
$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;
|
namespace App\NotificationChannels;
|
||||||
|
|
||||||
|
use App\Contracts\Notification;
|
||||||
|
use App\Models\NotificationChannel;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
class Slack extends AbstractProvider
|
class Slack extends AbstractNotificationChannel
|
||||||
{
|
{
|
||||||
public function validationRules(): array
|
public function createRules(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'webhook_url' => 'required|url',
|
'webhook_url' => 'required|url',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function data(array $input): array
|
public function createData(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
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(
|
$connect = $this->checkConnection(
|
||||||
__('Congratulations! 🎉'),
|
__('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".
|
__('Manage your notification channels')."\n".
|
||||||
route('notification-channels')
|
route('notification-channels')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! $connect) {
|
if (! $connect) {
|
||||||
|
$this->notificationChannel->delete();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->notificationChannel->connected = true;
|
||||||
|
$this->notificationChannel->save();
|
||||||
|
|
||||||
return true;
|
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
|
private function checkConnection(string $subject, string $text): bool
|
||||||
{
|
{
|
||||||
$data = $this->notificationChannel->data;
|
$connect = Http::post($this->data()['webhook_url'], [
|
||||||
$connect = Http::post($data['webhook_url'], [
|
|
||||||
'text' => '*'.$subject.'*'."\n".$text,
|
'text' => '*'.$subject.'*'."\n".$text,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $connect->ok();
|
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;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Contracts\Notification;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class FailedToDeleteServerFromProvider implements Notification
|
class FailedToDeleteServerFromProvider extends AbstractNotification
|
||||||
{
|
{
|
||||||
use Queueable;
|
use Queueable;
|
||||||
|
|
||||||
@ -18,26 +17,18 @@ public function __construct(Server $server)
|
|||||||
$this->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", [
|
return __("We couldn't delete [:server] \nfrom :provider \nPlease check your provider and delete it manually", [
|
||||||
'server' => $this->server->name,
|
'server' => $this->server->name,
|
||||||
'provider' => $this->server->provider,
|
'provider' => $this->server->provider,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mail(): MailMessage
|
public function toEmail(object $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
return (new 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("We couldn't delete [".$this->server->name.'] from '.$this->server->provider)
|
||||||
->line('Please check your provider and delete it manually');
|
->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;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Contracts\Notification;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class ServerDisconnected implements Notification
|
class ServerDisconnected extends AbstractNotification
|
||||||
{
|
{
|
||||||
protected Server $server;
|
protected Server $server;
|
||||||
|
|
||||||
@ -15,25 +14,17 @@ public function __construct(Server $server)
|
|||||||
$this->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]", [
|
return __("We've disconnected from your server [:server]", [
|
||||||
'server' => $this->server->name,
|
'server' => $this->server->name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mail(): MailMessage
|
public function toEmail(object $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
|
->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 sever is online and make sure that has our public keys in it');
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Contracts\Notification;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class ServerInstallationFailed implements Notification
|
class ServerInstallationFailed extends AbstractNotification
|
||||||
{
|
{
|
||||||
protected Server $server;
|
protected Server $server;
|
||||||
|
|
||||||
@ -15,26 +14,18 @@ public function __construct(Server $server)
|
|||||||
$this->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", [
|
return __("Installation failed for server [:server] \nCheck your server's logs \n:logs", [
|
||||||
'server' => $this->server->name,
|
'server' => $this->server->name,
|
||||||
'logs' => url('/servers/'.$this->server->id.'/logs'),
|
'logs' => url('/servers/'.$this->server->id.'/logs'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function mail(): MailMessage
|
public function toEmail(object $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
|
->subject(__('Server installation failed!'))
|
||||||
->line('Your server ['.$this->server->name.'] installation has been failed.')
|
->line('Your server ['.$this->server->name.'] installation has been failed.')
|
||||||
->line('Check your server logs')
|
->line('Check your server logs')
|
||||||
->action('View Logs', url('/servers/'.$this->server->id.'/logs'));
|
->action('View Logs', url('/servers/'.$this->server->id.'/logs'));
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Contracts\Notification;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class ServerInstallationStarted implements Notification
|
class ServerInstallationStarted extends AbstractNotification
|
||||||
{
|
{
|
||||||
protected Server $server;
|
protected Server $server;
|
||||||
|
|
||||||
@ -15,26 +14,18 @@ public function __construct(Server $server)
|
|||||||
$this->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", [
|
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,
|
'server' => $this->server->name,
|
||||||
'progress' => url('/servers/'.$this->server->id),
|
'progress' => url('/servers/'.$this->server->id),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mail(): MailMessage
|
public function toEmail(object $notifiable): MailMessage
|
||||||
{
|
{
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
|
->subject(__('Server installation started!'))
|
||||||
->line('Your server\'s ['.$this->server->name.'] installation has been 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("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.')
|
->line('As soon as it finishes, We will notify you through this channel.')
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Contracts\Notification;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
|
||||||
class ServerInstallationSucceed implements Notification
|
class ServerInstallationSucceed extends AbstractNotification
|
||||||
{
|
{
|
||||||
protected Server $server;
|
protected Server $server;
|
||||||
|
|
||||||
@ -20,14 +19,10 @@ public function subject(): string
|
|||||||
return __('Server installation succeed!');
|
return __('Server installation succeed!');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function message(bool $mail = false): mixed
|
public function rawText(): string
|
||||||
{
|
{
|
||||||
$this->server->refresh();
|
$this->server->refresh();
|
||||||
|
|
||||||
if ($mail) {
|
|
||||||
return $this->mail();
|
|
||||||
}
|
|
||||||
|
|
||||||
return __("Installation succeed for server [:server] \nServer IP: :ip \nUser: :user\nPassword: :password\n:link", [
|
return __("Installation succeed for server [:server] \nServer IP: :ip \nUser: :user\nPassword: :password\n:link", [
|
||||||
'server' => $this->server->name,
|
'server' => $this->server->name,
|
||||||
'ip' => $this->server->ip,
|
'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();
|
$this->server->refresh();
|
||||||
|
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
|
->subject(__('Server installation succeed!'))
|
||||||
->line('Your server ['.$this->server->name.'] has been installed successfully.')
|
->line('Your server ['.$this->server->name.'] has been installed successfully.')
|
||||||
->line('Server IP: '.$this->server->ip)
|
->line('Server IP: '.$this->server->ip)
|
||||||
->line('User: '.$this->server->authentication['user'])
|
->line('User: '.$this->server->authentication['user'])
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user