mirror of
https://github.com/vitodeploy/vito.git
synced 2025-07-01 14:06:15 +00:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
f06b8f7d20 | |||
f120a570e8 | |||
2d7f225ff2 | |||
31bd146239 | |||
10a6bb57a8 | |||
fd2244d382 | |||
551f1ce40e | |||
1ce92d9361 | |||
ec6e55e30c | |||
4cda14f4b8 | |||
5e6d338bdc | |||
7312e3f515 | |||
b771db882b | |||
94977797cc | |||
c45872df55 | |||
16fae5334c | |||
7b8deddeca | |||
1bf3c94358 | |||
700cc5f44c | |||
9d13cc0756 | |||
f51d7900f0 | |||
4bd4b34d24 | |||
7c5505be16 | |||
7249cf9ed6 | |||
8282d39722 | |||
38e23a1ceb | |||
1e1204fe40 | |||
7d98986f52 | |||
2c81e324f6 | |||
422da431ec | |||
6c27215ea1 | |||
fb840204ad | |||
e07e197dd9 | |||
3a2dba4ad3 |
@ -15,9 +15,9 @@ DB_USERNAME=root
|
|||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
|
|
||||||
BROADCAST_DRIVER=null
|
BROADCAST_DRIVER=null
|
||||||
CACHE_DRIVER=redis
|
CACHE_DRIVER=file
|
||||||
FILESYSTEM_DRIVER=local
|
FILESYSTEM_DRIVER=local
|
||||||
QUEUE_CONNECTION=sync
|
QUEUE_CONNECTION=default
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=database
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
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/
|
2
.github/workflows/code-style.yml
vendored
2
.github/workflows/code-style.yml
vendored
@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
code-style:
|
code-style:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
|
23
CONTRIBUTING.md
Normal file
23
CONTRIBUTING.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Contributing
|
||||||
|
Thank you for your interest in contributing! There are a couple of contribution guidelines that make it easier to apply the incoming suggestions.
|
||||||
|
|
||||||
|
If you want to contribute please start with the issues. Issues labeled with "Bug" are the higher priorities.
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
1. Issues are the best place to propose a new feature.
|
||||||
|
2. If you are adding a feature that there is no issue for yet, please first open an issue and label it as "feature" and lets discuss it before you implement it.
|
||||||
|
3. Search the issues before proposing a feature to see if it is already under discussion. Referencing existing issues is a good way to increase the priority of your own.
|
||||||
|
4. We don't have an issue template yet, but the more detailed your explanation, the more quickly we'll be able to evaluate it.
|
||||||
|
5. Search for the issue that you also have. Give it a reaction (and comment, if you have something to add). We note that!
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
1. Open PRs represent issues that we're actively thinking about merging (at a pace we can manage). If we think a proposal needs more discussion, or that the existing code would require a lot of back-and-forth to merge, we might close it and suggest you make an issue.
|
||||||
|
2. All PRs should be made against the `main` branch. This can be changed in the future.
|
||||||
|
3. If you are making changes to the front-end layer, Please build the assets via `npm run build` and push it with the other changes.
|
||||||
|
4. Write tests for your code. Tests can be Unit or Feature.
|
||||||
|
5. Code refactors will be closed. For the architectural refactors open an issue first.
|
||||||
|
6. Use `./vendor/bin/pint` to style your code before opening a PR otherwise the actions will fail.
|
||||||
|
7. Typo fixes in documentation are welcome, but if it's at all debatable we might just close it.
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
1. If you think we closed something incorrectly, feel free to (politely) tell us why! We're human and make mistakes.
|
14
README.md
14
README.md
@ -10,9 +10,21 @@ ## Documentation
|
|||||||
|
|
||||||
https://vitodeploy.com
|
https://vitodeploy.com
|
||||||
|
|
||||||
|
## Feedbacks
|
||||||
|
|
||||||
|
https://features.vitodeploy.com
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
https://https://features.vitodeploy.com/roadmap
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Feel free to open a PR
|
Please read the contribution guide [Here](/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Please read the security policy [Here](/SECURITY.md)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
11
SECURITY.md
Normal file
11
SECURITY.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 0.x | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you see a vulnerability, please open an issue or report it directly to me (sa.vaziry@gmail.com)
|
@ -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']],
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Actions\Database;
|
namespace App\Actions\Service;
|
||||||
|
|
||||||
|
use App\Enums\ServiceStatus;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
@ -18,23 +19,21 @@ public function install(Server $server, array $input): Service
|
|||||||
|
|
||||||
$phpMyAdmin = $server->defaultService('phpmyadmin');
|
$phpMyAdmin = $server->defaultService('phpmyadmin');
|
||||||
if ($phpMyAdmin) {
|
if ($phpMyAdmin) {
|
||||||
if ($phpMyAdmin->status === 'ready') {
|
throw ValidationException::withMessages([
|
||||||
throw ValidationException::withMessages([
|
'allowed_ip' => __('Already installed'),
|
||||||
'install' => __('Already installed'),
|
]);
|
||||||
])->errorBag('installPHPMyAdmin');
|
|
||||||
}
|
|
||||||
$phpMyAdmin->delete();
|
|
||||||
}
|
}
|
||||||
$phpMyAdmin = new Service([
|
$phpMyAdmin = new Service([
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
'type' => 'phpmyadmin',
|
'type' => 'phpmyadmin',
|
||||||
'type_data' => [
|
'type_data' => [
|
||||||
'allowed_ip' => $input['allowed_ip'],
|
'allowed_ip' => $input['allowed_ip'],
|
||||||
|
'port' => $input['port'],
|
||||||
'php' => $server->defaultService('php')->version,
|
'php' => $server->defaultService('php')->version,
|
||||||
],
|
],
|
||||||
'name' => 'phpmyadmin',
|
'name' => 'phpmyadmin',
|
||||||
'version' => '5.1.2',
|
'version' => '5.1.2',
|
||||||
'status' => 'installing',
|
'status' => ServiceStatus::INSTALLING,
|
||||||
'is_default' => 1,
|
'is_default' => 1,
|
||||||
]);
|
]);
|
||||||
$phpMyAdmin->save();
|
$phpMyAdmin->save();
|
||||||
@ -50,6 +49,12 @@ private function validate(array $input): void
|
|||||||
{
|
{
|
||||||
Validator::make($input, [
|
Validator::make($input, [
|
||||||
'allowed_ip' => 'required',
|
'allowed_ip' => 'required',
|
||||||
])->validateWithBag('installPHPMyAdmin');
|
'port' => [
|
||||||
|
'required',
|
||||||
|
'numeric',
|
||||||
|
'min:1',
|
||||||
|
'max:65535',
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -49,11 +49,6 @@ public function create(Server $server, array $input): Site
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// detect php version
|
|
||||||
if ($site->type()->language() === 'php') {
|
|
||||||
$site->php_version = $input['php_version'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate type
|
// validate type
|
||||||
$this->validateType($site, $input);
|
$this->validateType($site, $input);
|
||||||
|
|
||||||
|
35
app/Actions/Site/UpdateSourceControl.php
Executable file
35
app/Actions/Site/UpdateSourceControl.php
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Site;
|
||||||
|
|
||||||
|
use App\Models\Site;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class UpdateSourceControl
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public function update(Site $site, array $input): void
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$site->source_control_id = $input['source_control'];
|
||||||
|
$site->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
protected function validate(array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'source_control' => [
|
||||||
|
'required',
|
||||||
|
Rule::exists('source_controls', 'id'),
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Actions\SourceControl;
|
namespace App\Actions\SourceControl;
|
||||||
|
|
||||||
use App\Models\SourceControl;
|
use App\Models\SourceControl;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@ -16,6 +17,7 @@ public function connect(array $input): void
|
|||||||
'provider' => $input['provider'],
|
'provider' => $input['provider'],
|
||||||
'profile' => $input['name'],
|
'profile' => $input['name'],
|
||||||
'access_token' => $input['token'],
|
'access_token' => $input['token'],
|
||||||
|
'url' => Arr::has($input, 'url') ? $input['url'] : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $sourceControl->provider()->connect()) {
|
if (! $sourceControl->provider()->connect()) {
|
||||||
@ -44,6 +46,11 @@ private function validate(array $input): void
|
|||||||
'token' => [
|
'token' => [
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
|
'url' => [
|
||||||
|
'nullable',
|
||||||
|
'url:http,https',
|
||||||
|
'ends_with:/',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
Validator::make($input, $rules)->validate();
|
Validator::make($input, $rules)->validate();
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,15 @@ public function create(User $user, array $input): void
|
|||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
'provider' => $input['provider'],
|
'provider' => $input['provider'],
|
||||||
'profile' => $input['name'],
|
'profile' => $input['name'],
|
||||||
'credentials' => [
|
|
||||||
'token' => $input['token'],
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->validateProvider($input, $storageProvider->provider()->validationRules());
|
||||||
|
|
||||||
|
$storageProvider->credentials = $storageProvider->provider()->credentialData($input);
|
||||||
|
|
||||||
if (! $storageProvider->provider()->connect()) {
|
if (! $storageProvider->provider()->connect()) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'token' => __("Couldn't connect to the provider"),
|
'provider' => __("Couldn't connect to the provider"),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$storageProvider->save();
|
$storageProvider->save();
|
||||||
@ -44,9 +46,11 @@ private function validate(User $user, array $input): void
|
|||||||
'required',
|
'required',
|
||||||
Rule::unique('storage_providers', 'profile')->where('user_id', $user->id),
|
Rule::unique('storage_providers', 'profile')->where('user_id', $user->id),
|
||||||
],
|
],
|
||||||
'token' => [
|
|
||||||
'required',
|
|
||||||
],
|
|
||||||
])->validate();
|
])->validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function validateProvider(array $input, array $rules): void
|
||||||
|
{
|
||||||
|
Validator::make($input, $rules)->validate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,10 @@ public function update(User $user, array $input): void
|
|||||||
Validator::make($input, [
|
Validator::make($input, [
|
||||||
'name' => ['required', 'string', 'max:255'],
|
'name' => ['required', 'string', 'max:255'],
|
||||||
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
|
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
|
||||||
|
'timezone' => [
|
||||||
|
'required',
|
||||||
|
Rule::in(timezone_identifiers_list()),
|
||||||
|
],
|
||||||
])->validateWithBag('updateProfileInformation');
|
])->validateWithBag('updateProfileInformation');
|
||||||
|
|
||||||
if ($input['email'] !== $user->email) {
|
if ($input['email'] !== $user->email) {
|
||||||
@ -27,6 +31,7 @@ public function update(User $user, array $input): void
|
|||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => $input['email'],
|
||||||
|
'timezone' => $input['timezone'],
|
||||||
])->save();
|
])->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,6 +44,7 @@ protected function updateVerifiedUser(User $user, array $input): void
|
|||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => $input['email'],
|
||||||
|
'timezone' => $input['timezone'],
|
||||||
])->save();
|
])->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,6 +6,8 @@ interface SiteType
|
|||||||
{
|
{
|
||||||
public function language(): string;
|
public function language(): string;
|
||||||
|
|
||||||
|
public function supportedFeatures(): array;
|
||||||
|
|
||||||
public function createValidationRules(array $input): array;
|
public function createValidationRules(array $input): array;
|
||||||
|
|
||||||
public function createFields(array $input): array;
|
public function createFields(array $input): 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;
|
||||||
|
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
interface StorageProvider
|
interface StorageProvider
|
||||||
{
|
{
|
||||||
|
public function validationRules(): array;
|
||||||
|
|
||||||
|
public function credentialData(array $input): array;
|
||||||
|
|
||||||
public function connect(): bool;
|
public function connect(): bool;
|
||||||
|
|
||||||
public function upload(Server $server, string $src, string $dest): array;
|
public function upload(Server $server, string $src, string $dest): array;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
16
app/Enums/SiteFeature.php
Normal file
16
app/Enums/SiteFeature.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use BenSampo\Enum\Enum;
|
||||||
|
|
||||||
|
final class SiteFeature extends Enum
|
||||||
|
{
|
||||||
|
const DEPLOYMENT = 'deployment';
|
||||||
|
|
||||||
|
const ENV = 'env';
|
||||||
|
|
||||||
|
const SSL = 'ssl';
|
||||||
|
|
||||||
|
const QUEUES = 'queues';
|
||||||
|
}
|
@ -11,6 +11,4 @@ final class SourceControl extends Enum
|
|||||||
const GITLAB = 'gitlab';
|
const GITLAB = 'gitlab';
|
||||||
|
|
||||||
const BITBUCKET = 'bitbucket';
|
const BITBUCKET = 'bitbucket';
|
||||||
|
|
||||||
const CUSTOM = 'custom';
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
final class StorageProvider extends Enum
|
final class StorageProvider extends Enum
|
||||||
{
|
{
|
||||||
const GOOGLE = 'google';
|
|
||||||
|
|
||||||
const DROPBOX = 'dropbox';
|
const DROPBOX = 'dropbox';
|
||||||
|
|
||||||
|
const FTP = 'ftp';
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class SourceControlIsNotConnected extends Exception
|
class SourceControlIsNotConnected extends Exception
|
||||||
{
|
{
|
||||||
public function __construct(protected SourceControl|string $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');
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
@ -87,7 +87,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);
|
||||||
|
39
app/Http/Controllers/GitHookController.php
Normal file
39
app/Http/Controllers/GitHookController.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
|
use App\Models\GitHook;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class GitHookController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request)
|
||||||
|
{
|
||||||
|
if (! $request->input('secret')) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var GitHook $gitHook */
|
||||||
|
$gitHook = GitHook::query()
|
||||||
|
->where('secret', $request->input('secret'))
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
foreach ($gitHook->actions as $action) {
|
||||||
|
if ($action == 'deploy') {
|
||||||
|
try {
|
||||||
|
$gitHook->site->deploy();
|
||||||
|
} catch (SourceControlIsNotConnected) {
|
||||||
|
// TODO: send notification
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::error('git-hook-exception', (array) $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
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');
|
||||||
|
}
|
||||||
|
}
|
60
app/Http/Livewire/Application/AutoDeployment.php
Normal file
60
app/Http/Livewire/Application/AutoDeployment.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Application;
|
||||||
|
|
||||||
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
|
use App\Models\Site;
|
||||||
|
use App\Traits\HasToast;
|
||||||
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Livewire\Component;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class AutoDeployment extends Component
|
||||||
|
{
|
||||||
|
use HasToast;
|
||||||
|
use RefreshComponentOnBroadcast;
|
||||||
|
|
||||||
|
public Site $site;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function enable(): void
|
||||||
|
{
|
||||||
|
if (! $this->site->auto_deployment) {
|
||||||
|
try {
|
||||||
|
$this->site->enableAutoDeployment();
|
||||||
|
|
||||||
|
$this->site->refresh();
|
||||||
|
|
||||||
|
$this->toast()->success(__('Auto deployment has been enabled.'));
|
||||||
|
} catch (SourceControlIsNotConnected) {
|
||||||
|
$this->toast()->error(__('Source control is not connected. Check site\'s settings.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function disable(): void
|
||||||
|
{
|
||||||
|
if ($this->site->auto_deployment) {
|
||||||
|
try {
|
||||||
|
$this->site->disableAutoDeployment();
|
||||||
|
|
||||||
|
$this->site->refresh();
|
||||||
|
|
||||||
|
$this->toast()->success(__('Auto deployment has been disabled.'));
|
||||||
|
} catch (SourceControlIsNotConnected) {
|
||||||
|
$this->toast()->error(__('Source control is not connected. Check site\'s settings.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('livewire.application.auto-deployment');
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ public function save(): void
|
|||||||
session()->flash('status', 'script-updated');
|
session()->flash('status', 'script-updated');
|
||||||
|
|
||||||
$this->emitTo(Deploy::class, '$refresh');
|
$this->emitTo(Deploy::class, '$refresh');
|
||||||
|
$this->emitTo(AutoDeployment::class, '$refresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
namespace App\Http\Livewire\Php;
|
namespace App\Http\Livewire\Php;
|
||||||
|
|
||||||
use App\Actions\PHP\InstallNewPHP;
|
use App\Actions\PHP\InstallNewPHP;
|
||||||
|
use App\Actions\PHP\InstallPHPExtension;
|
||||||
use App\Actions\PHP\UpdatePHPIni;
|
use App\Actions\PHP\UpdatePHPIni;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\SSHCommands\PHP\GetPHPIniCommand;
|
use App\SSHCommands\PHP\GetPHPIniCommand;
|
||||||
use App\Traits\RefreshComponentOnBroadcast;
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
@ -24,6 +26,10 @@ class InstalledVersions extends Component
|
|||||||
|
|
||||||
public string $ini = 'Loading php.ini';
|
public string $ini = 'Loading php.ini';
|
||||||
|
|
||||||
|
public ?int $extensionId = null;
|
||||||
|
|
||||||
|
public string $extension = '';
|
||||||
|
|
||||||
public function install(string $version): void
|
public function install(string $version): void
|
||||||
{
|
{
|
||||||
app(InstallNewPHP::class)->install($this->server, [
|
app(InstallNewPHP::class)->install($this->server, [
|
||||||
@ -35,6 +41,7 @@ public function install(string $version): void
|
|||||||
|
|
||||||
public function restart(int $id): void
|
public function restart(int $id): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = Service::query()->findOrFail($id);
|
$service = Service::query()->findOrFail($id);
|
||||||
$service->restart();
|
$service->restart();
|
||||||
|
|
||||||
@ -43,6 +50,7 @@ public function restart(int $id): void
|
|||||||
|
|
||||||
public function uninstall(): void
|
public function uninstall(): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = Service::query()->findOrFail($this->uninstallId);
|
$service = Service::query()->findOrFail($this->uninstallId);
|
||||||
$service->uninstall();
|
$service->uninstall();
|
||||||
|
|
||||||
@ -56,6 +64,7 @@ public function loadIni(int $id): void
|
|||||||
$this->iniId = $id;
|
$this->iniId = $id;
|
||||||
$this->ini = 'Loading php.ini';
|
$this->ini = 'Loading php.ini';
|
||||||
|
|
||||||
|
/** @var Service $service */
|
||||||
$service = Service::query()->findOrFail($this->iniId);
|
$service = Service::query()->findOrFail($this->iniId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -67,6 +76,7 @@ public function loadIni(int $id): void
|
|||||||
|
|
||||||
public function saveIni(): void
|
public function saveIni(): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = Service::query()->findOrFail($this->iniId);
|
$service = Service::query()->findOrFail($this->iniId);
|
||||||
|
|
||||||
app(UpdatePHPIni::class)->update($service, $this->all()['ini']);
|
app(UpdatePHPIni::class)->update($service, $this->all()['ini']);
|
||||||
@ -76,10 +86,32 @@ public function saveIni(): void
|
|||||||
session()->flash('status', 'ini-updated');
|
session()->flash('status', 'ini-updated');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function installExtension(): void
|
||||||
|
{
|
||||||
|
/** @var Service $service */
|
||||||
|
$service = Service::query()->findOrFail($this->extensionId);
|
||||||
|
|
||||||
|
app(InstallPHPExtension::class)->handle($service, [
|
||||||
|
'name' => $this->extension,
|
||||||
|
]);
|
||||||
|
|
||||||
|
session()->flash('status', 'started-installation');
|
||||||
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
if ($this->extensionId) {
|
||||||
|
/** @var Service $php */
|
||||||
|
$php = Service::query()->findOrFail($this->extensionId);
|
||||||
|
$installedExtensions = $php->type_data['extensions'] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
return view('livewire.php.installed-versions', [
|
return view('livewire.php.installed-versions', [
|
||||||
'phps' => $this->server->services()->where('type', 'php')->get(),
|
'phps' => $this->server->services()->where('type', 'php')->get(),
|
||||||
|
'installedExtensions' => $installedExtensions ?? [],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,13 @@ class UpdateProfileInformation extends Component
|
|||||||
|
|
||||||
public string $email;
|
public string $email;
|
||||||
|
|
||||||
|
public string $timezone;
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->name = auth()->user()->name;
|
$this->name = auth()->user()->name;
|
||||||
$this->email = auth()->user()->email;
|
$this->email = auth()->user()->email;
|
||||||
|
$this->timezone = auth()->user()->timezone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
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->emitTo(ProjectsList::class, '$refresh');
|
||||||
|
|
||||||
|
$this->dispatchBrowserEvent('created', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
app/Http/Livewire/Services/InstallPHPMyAdmin.php
Normal file
31
app/Http/Livewire/Services/InstallPHPMyAdmin.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Services;
|
||||||
|
|
||||||
|
use App\Actions\Service\InstallPHPMyAdmin as InstallPHPMyAdminAction;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class InstallPHPMyAdmin extends Component
|
||||||
|
{
|
||||||
|
public Server $server;
|
||||||
|
|
||||||
|
public string $allowed_ip;
|
||||||
|
|
||||||
|
public string $port = '5433';
|
||||||
|
|
||||||
|
public function install(): void
|
||||||
|
{
|
||||||
|
app(InstallPHPMyAdminAction::class)->install($this->server, $this->all());
|
||||||
|
|
||||||
|
$this->dispatchBrowserEvent('started', true);
|
||||||
|
|
||||||
|
$this->emitTo(ServicesList::class, '$refresh');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
return view('livewire.services.install-phpmyadmin');
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Livewire\Services;
|
namespace App\Http\Livewire\Services;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
use App\Traits\RefreshComponentOnBroadcast;
|
use App\Traits\RefreshComponentOnBroadcast;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -15,6 +16,7 @@ class ServicesList extends Component
|
|||||||
|
|
||||||
public function stop(int $id): void
|
public function stop(int $id): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
||||||
|
|
||||||
$service->stop();
|
$service->stop();
|
||||||
@ -24,6 +26,7 @@ public function stop(int $id): void
|
|||||||
|
|
||||||
public function start(int $id): void
|
public function start(int $id): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
||||||
|
|
||||||
$service->start();
|
$service->start();
|
||||||
@ -33,6 +36,7 @@ public function start(int $id): void
|
|||||||
|
|
||||||
public function restart(int $id): void
|
public function restart(int $id): void
|
||||||
{
|
{
|
||||||
|
/** @var Service $service */
|
||||||
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
||||||
|
|
||||||
$service->restart();
|
$service->restart();
|
||||||
@ -40,6 +44,16 @@ public function restart(int $id): void
|
|||||||
$this->refreshComponent([]);
|
$this->refreshComponent([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function uninstall(int $id): void
|
||||||
|
{
|
||||||
|
/** @var Service $service */
|
||||||
|
$service = $this->server->services()->where('id', $id)->firstOrFail();
|
||||||
|
|
||||||
|
$service->uninstall();
|
||||||
|
|
||||||
|
$this->refreshComponent([]);
|
||||||
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
return view('livewire.services.services-list', [
|
return view('livewire.services.services-list', [
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Sites;
|
namespace App\Http\Livewire\Sites;
|
||||||
|
|
||||||
use App\Enums\SiteType;
|
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\SourceControl;
|
use App\Models\SourceControl;
|
||||||
@ -16,23 +15,12 @@ class CreateSite extends Component
|
|||||||
|
|
||||||
public Server $server;
|
public Server $server;
|
||||||
|
|
||||||
public string $type = SiteType::LARAVEL;
|
public array $inputs = [
|
||||||
|
'type' => '',
|
||||||
public string $domain;
|
'web_directory' => 'public',
|
||||||
|
'source_control' => '',
|
||||||
public string $alias;
|
'php_version' => '',
|
||||||
|
];
|
||||||
public string $php_version = '';
|
|
||||||
|
|
||||||
public string $web_directory = 'public';
|
|
||||||
|
|
||||||
public string $source_control = '';
|
|
||||||
|
|
||||||
public string $repository;
|
|
||||||
|
|
||||||
public string $branch;
|
|
||||||
|
|
||||||
public bool $composer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws SourceControlIsNotConnected
|
* @throws SourceControlIsNotConnected
|
||||||
@ -41,7 +29,7 @@ public function create(): void
|
|||||||
{
|
{
|
||||||
$site = app(\App\Actions\Site\CreateSite::class)->create(
|
$site = app(\App\Actions\Site\CreateSite::class)->create(
|
||||||
$this->server,
|
$this->server,
|
||||||
$this->all()
|
$this->inputs
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->redirect(route('servers.sites.show', [
|
$this->redirect(route('servers.sites.show', [
|
||||||
|
33
app/Http/Livewire/Sites/UpdateSourceControlProvider.php
Normal file
33
app/Http/Livewire/Sites/UpdateSourceControlProvider.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Sites;
|
||||||
|
|
||||||
|
use App\Actions\Site\UpdateSourceControl;
|
||||||
|
use App\Models\Site;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class UpdateSourceControlProvider extends Component
|
||||||
|
{
|
||||||
|
public Site $site;
|
||||||
|
|
||||||
|
public $source_control = null;
|
||||||
|
|
||||||
|
public function update(): void
|
||||||
|
{
|
||||||
|
app(UpdateSourceControl::class)->update($this->site, $this->all());
|
||||||
|
|
||||||
|
$this->resetErrorBag();
|
||||||
|
|
||||||
|
session()->flash('status', 'source-control-updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): View
|
||||||
|
{
|
||||||
|
if (! $this->source_control) {
|
||||||
|
$this->source_control = $this->site->source_control_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('livewire.sites.update-source-control-provider');
|
||||||
|
}
|
||||||
|
}
|
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');
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
@ -14,6 +14,20 @@ class ConnectProvider extends Component
|
|||||||
|
|
||||||
public string $token;
|
public string $token;
|
||||||
|
|
||||||
|
public string $host;
|
||||||
|
|
||||||
|
public string $port;
|
||||||
|
|
||||||
|
public string $path = '/';
|
||||||
|
|
||||||
|
public string $username;
|
||||||
|
|
||||||
|
public string $password;
|
||||||
|
|
||||||
|
public int $ssl = 1;
|
||||||
|
|
||||||
|
public int $passive = 0;
|
||||||
|
|
||||||
public function connect(): void
|
public function connect(): void
|
||||||
{
|
{
|
||||||
app(CreateStorageProvider::class)->create(auth()->user(), $this->all());
|
app(CreateStorageProvider::class)->create(auth()->user(), $this->all());
|
||||||
|
@ -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,6 +3,7 @@
|
|||||||
namespace App\Jobs\Installation;
|
namespace App\Jobs\Installation;
|
||||||
|
|
||||||
use App\Actions\FirewallRule\CreateRule;
|
use App\Actions\FirewallRule\CreateRule;
|
||||||
|
use App\Enums\ServiceStatus;
|
||||||
use App\Jobs\Job;
|
use App\Jobs\Job;
|
||||||
use App\Models\FirewallRule;
|
use App\Models\FirewallRule;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
@ -32,6 +33,9 @@ public function handle(): void
|
|||||||
$this->downloadSource();
|
$this->downloadSource();
|
||||||
$this->setUpVHost();
|
$this->setUpVHost();
|
||||||
$this->restartPHP();
|
$this->restartPHP();
|
||||||
|
$this->service->update([
|
||||||
|
'status' => ServiceStatus::READY,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +45,7 @@ private function setUpFirewall(): void
|
|||||||
{
|
{
|
||||||
$this->firewallRule = FirewallRule::query()
|
$this->firewallRule = FirewallRule::query()
|
||||||
->where('server_id', $this->service->server_id)
|
->where('server_id', $this->service->server_id)
|
||||||
->where('port', '54331')
|
->where('port', $this->service->type_data['port'])
|
||||||
->first();
|
->first();
|
||||||
if ($this->firewallRule) {
|
if ($this->firewallRule) {
|
||||||
$this->firewallRule->source = $this->service->type_data['allowed_ip'];
|
$this->firewallRule->source = $this->service->type_data['allowed_ip'];
|
||||||
@ -52,7 +56,7 @@ private function setUpFirewall(): void
|
|||||||
[
|
[
|
||||||
'type' => 'allow',
|
'type' => 'allow',
|
||||||
'protocol' => 'tcp',
|
'protocol' => 'tcp',
|
||||||
'port' => '54331',
|
'port' => $this->service->type_data['port'],
|
||||||
'source' => $this->service->type_data['allowed_ip'],
|
'source' => $this->service->type_data['allowed_ip'],
|
||||||
'mask' => '0',
|
'mask' => '0',
|
||||||
]
|
]
|
||||||
@ -78,6 +82,7 @@ private function setUpVHost(): void
|
|||||||
{
|
{
|
||||||
$vhost = File::get(resource_path('commands/webserver/nginx/phpmyadmin-vhost.conf'));
|
$vhost = File::get(resource_path('commands/webserver/nginx/phpmyadmin-vhost.conf'));
|
||||||
$vhost = Str::replace('__php_version__', $this->service->server->defaultService('php')->version, $vhost);
|
$vhost = Str::replace('__php_version__', $this->service->server->defaultService('php')->version, $vhost);
|
||||||
|
$vhost = Str::replace('__port__', $this->service->type_data['port'], $vhost);
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new CreateNginxPHPMyAdminVHostCommand($vhost),
|
new CreateNginxPHPMyAdminVHostCommand($vhost),
|
||||||
'create-phpmyadmin-vhost'
|
'create-phpmyadmin-vhost'
|
||||||
@ -98,6 +103,9 @@ private function restartPHP(): void
|
|||||||
public function failed(Throwable $throwable): Throwable
|
public function failed(Throwable $throwable): Throwable
|
||||||
{
|
{
|
||||||
$this->firewallRule?->removeFromServer();
|
$this->firewallRule?->removeFromServer();
|
||||||
|
$this->service->update([
|
||||||
|
'status' => ServiceStatus::INSTALLATION_FAILED,
|
||||||
|
]);
|
||||||
throw $throwable;
|
throw $throwable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ private function removeFirewallRule(): void
|
|||||||
/** @var ?FirewallRule $rule */
|
/** @var ?FirewallRule $rule */
|
||||||
$rule = FirewallRule::query()
|
$rule = FirewallRule::query()
|
||||||
->where('server_id', $this->service->server_id)
|
->where('server_id', $this->service->server_id)
|
||||||
->where('port', '54331')
|
->where('port', $this->service->type_data['port'])
|
||||||
->first();
|
->first();
|
||||||
$rule?->removeFromServer();
|
$rule?->removeFromServer();
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
abstract class Job implements ShouldQueue, ShouldBeUnique
|
abstract class Job implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
use App\Enums\DeploymentStatus;
|
use App\Enums\DeploymentStatus;
|
||||||
use App\Events\Broadcast;
|
use App\Events\Broadcast;
|
||||||
use App\Helpers\SSH;
|
|
||||||
use App\Jobs\Job;
|
use App\Jobs\Job;
|
||||||
use App\Models\Deployment;
|
use App\Models\Deployment;
|
||||||
use App\SSHCommands\System\RunScriptCommand;
|
use App\SSHCommands\System\RunScriptCommand;
|
||||||
@ -18,13 +17,11 @@ class Deploy extends Job
|
|||||||
|
|
||||||
protected string $script;
|
protected string $script;
|
||||||
|
|
||||||
protected SSH $ssh;
|
public function __construct(Deployment $deployment, string $path)
|
||||||
|
|
||||||
public function __construct(Deployment $deployment, string $path, string $script)
|
|
||||||
{
|
{
|
||||||
|
$this->script = $deployment->deploymentScript->content;
|
||||||
$this->deployment = $deployment;
|
$this->deployment = $deployment;
|
||||||
$this->path = $path;
|
$this->path = $path;
|
||||||
$this->script = $script;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,28 +29,31 @@ public function __construct(Deployment $deployment, string $path, string $script
|
|||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$this->ssh = $this->deployment->site->server->ssh();
|
$ssh = $this->deployment->site->server->ssh();
|
||||||
$this->ssh->exec(
|
try {
|
||||||
new RunScriptCommand($this->path, $this->script),
|
$ssh->exec(
|
||||||
'deploy',
|
new RunScriptCommand($this->path, $this->script),
|
||||||
$this->deployment->site_id
|
'deploy',
|
||||||
);
|
$this->deployment->site_id
|
||||||
$this->deployment->status = DeploymentStatus::FINISHED;
|
);
|
||||||
$this->deployment->log_id = $this->ssh->log->id;
|
$this->deployment->status = DeploymentStatus::FINISHED;
|
||||||
$this->deployment->save();
|
$this->deployment->log_id = $ssh->log->id;
|
||||||
event(
|
$this->deployment->save();
|
||||||
new Broadcast('deploy-site-finished', [
|
event(
|
||||||
'deployment' => $this->deployment,
|
new Broadcast('deploy-site-finished', [
|
||||||
])
|
'deployment' => $this->deployment,
|
||||||
);
|
])
|
||||||
|
);
|
||||||
|
} catch (Throwable) {
|
||||||
|
$this->deployment->log_id = $ssh->log->id;
|
||||||
|
$this->deployment->save();
|
||||||
|
$this->failed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function failed(): void
|
public function failed(): void
|
||||||
{
|
{
|
||||||
$this->deployment->status = DeploymentStatus::FAILED;
|
$this->deployment->status = DeploymentStatus::FAILED;
|
||||||
if ($this->ssh->log) {
|
|
||||||
$this->deployment->log_id = $this->ssh->log->id;
|
|
||||||
}
|
|
||||||
$this->deployment->save();
|
$this->deployment->save();
|
||||||
event(
|
event(
|
||||||
new Broadcast('deploy-site-failed', [
|
new Broadcast('deploy-site-failed', [
|
||||||
|
@ -52,7 +52,7 @@ public function handle(): void
|
|||||||
$this->site->id
|
$this->site->id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! Str::contains($result, 'Wordpress installed!')) {
|
if (! Str::contains($result, 'Success')) {
|
||||||
throw new FailedToInstallWordpress($result);
|
throw new FailedToInstallWordpress($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public function getPathAttribute(): string
|
|||||||
|
|
||||||
public function getStoragePathAttribute(): string
|
public function getStoragePathAttribute(): string
|
||||||
{
|
{
|
||||||
return '/'.$this->backup->database->name.'/'.$this->name.'.zip';
|
return '/'.$this->name.'.zip';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function restore(Database $database): void
|
public function restore(Database $database): void
|
||||||
|
@ -57,19 +57,19 @@ public function server(): BelongsTo
|
|||||||
/**
|
/**
|
||||||
* create database on server
|
* create database on server
|
||||||
*/
|
*/
|
||||||
public function createOnServer(): void
|
public function createOnServer(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
dispatch(new CreateOnServer($this))->onConnection('ssh');
|
dispatch(new CreateOnServer($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* delete database from server
|
* delete database from server
|
||||||
*/
|
*/
|
||||||
public function deleteFromServer(): void
|
public function deleteFromServer(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
$this->status = DatabaseStatus::DELETING;
|
$this->status = DatabaseStatus::DELETING;
|
||||||
$this->save();
|
$this->save();
|
||||||
dispatch(new DeleteFromServer($this))->onConnection('ssh');
|
dispatch(new DeleteFromServer($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function backups(): HasMany
|
public function backups(): HasMany
|
||||||
|
@ -54,17 +54,17 @@ public function scopeHasDatabase(Builder $query, string $databaseName): Builder
|
|||||||
return $query->where('databases', 'like', "%\"$databaseName\"%");
|
return $query->where('databases', 'like', "%\"$databaseName\"%");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createOnServer(): void
|
public function createOnServer(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
dispatch(new CreateOnServer($this))->onConnection('ssh');
|
dispatch(new CreateOnServer($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteFromServer(): void
|
public function deleteFromServer(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
$this->status = DatabaseStatus::DELETING;
|
$this->status = DatabaseStatus::DELETING;
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
dispatch(new DeleteFromServer($this))->onConnection('ssh');
|
dispatch(new DeleteFromServer($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function linkNewDatabase(string $name): void
|
public function linkNewDatabase(string $name): void
|
||||||
@ -79,14 +79,14 @@ public function linkNewDatabase(string $name): void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function linkUser(): void
|
public function linkUser(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
dispatch(new LinkUser($this))->onConnection('ssh');
|
dispatch(new LinkUser($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unlinkUser(): void
|
public function unlinkUser(string $queue = 'ssh'): void
|
||||||
{
|
{
|
||||||
dispatch(new UnlinkUser($this))->onConnection('ssh');
|
dispatch(new UnlinkUser($this))->onConnection($queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFullUserAttribute(): string
|
public function getFullUserAttribute(): string
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Exceptions\FailedToDeployGitHook;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
@ -22,6 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
class GitHook extends AbstractModel
|
class GitHook extends AbstractModel
|
||||||
{
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'site_id',
|
'site_id',
|
||||||
'source_control_id',
|
'source_control_id',
|
||||||
@ -55,9 +57,6 @@ public function scopeHasEvent(Builder $query, string $event): Builder
|
|||||||
return $query->where('events', 'like', "%\"{$event}\"%");
|
return $query->where('events', 'like', "%\"{$event}\"%");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FailedToDeployGitHook
|
|
||||||
*/
|
|
||||||
public function deployHook(): void
|
public function deployHook(): void
|
||||||
{
|
{
|
||||||
$this->update(
|
$this->update(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
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 +39,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 +61,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 +85,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',
|
||||||
@ -125,6 +129,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');
|
||||||
@ -233,7 +242,7 @@ public function install(): void
|
|||||||
// $this->team->notify(new ServerInstallationStarted($this));
|
// $this->team->notify(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 +272,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 +281,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 +290,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 +299,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 +308,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 +343,13 @@ public function sshKey(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var \Illuminate\Filesystem\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),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public function uninstaller(): mixed
|
|||||||
return new $uninstaller($this);
|
return new $uninstaller($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnitAttribute($value): string
|
public function getUnitAttribute($value): ?string
|
||||||
{
|
{
|
||||||
if ($value) {
|
if ($value) {
|
||||||
return $value;
|
return $value;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
use App\Enums\DeploymentStatus;
|
use App\Enums\DeploymentStatus;
|
||||||
use App\Enums\SiteStatus;
|
use App\Enums\SiteStatus;
|
||||||
use App\Enums\SslStatus;
|
use App\Enums\SslStatus;
|
||||||
use App\Exceptions\FailedToDeployGitHook;
|
use App\Events\Broadcast;
|
||||||
use App\Exceptions\SourceControlIsNotConnected;
|
use App\Exceptions\SourceControlIsNotConnected;
|
||||||
use App\Jobs\Site\ChangePHPVersion;
|
use App\Jobs\Site\ChangePHPVersion;
|
||||||
use App\Jobs\Site\Deploy;
|
use App\Jobs\Site\Deploy;
|
||||||
@ -19,7 +19,8 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,13 +267,7 @@ public function deploy(): Deployment
|
|||||||
}
|
}
|
||||||
$deployment->save();
|
$deployment->save();
|
||||||
|
|
||||||
dispatch(
|
dispatch(new Deploy($deployment, $this->path))->onConnection('ssh');
|
||||||
new Deploy(
|
|
||||||
$deployment,
|
|
||||||
$this->path,
|
|
||||||
$this->deployment_script_text
|
|
||||||
)
|
|
||||||
)->onConnection('ssh');
|
|
||||||
|
|
||||||
return $deployment;
|
return $deployment;
|
||||||
}
|
}
|
||||||
@ -347,22 +342,16 @@ public function getWebDirectoryPathAttribute(): string
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws SourceControlIsNotConnected
|
* @throws SourceControlIsNotConnected
|
||||||
* @throws ValidationException
|
|
||||||
* @throws FailedToDeployGitHook
|
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function enableAutoDeployment(): void
|
public function enableAutoDeployment(): void
|
||||||
{
|
{
|
||||||
if ($this->gitHook) {
|
if ($this->gitHook) {
|
||||||
throw ValidationException::withMessages([
|
return;
|
||||||
'auto_deployment' => __('Auto deployment already enabled'),
|
|
||||||
])->errorBag('auto_deployment');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->sourceControl()) {
|
if (! $this->sourceControl()) {
|
||||||
throw ValidationException::withMessages([
|
throw new SourceControlIsNotConnected($this->source_control);
|
||||||
'auto_deployment' => __('Your application does not use any source controls'),
|
|
||||||
])->errorBag('auto_deployment');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -370,7 +359,7 @@ public function enableAutoDeployment(): void
|
|||||||
$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,
|
||||||
'secret' => generate_uid(),
|
'secret' => Str::uuid()->toString(),
|
||||||
'actions' => ['deploy'],
|
'actions' => ['deploy'],
|
||||||
'events' => ['push'],
|
'events' => ['push'],
|
||||||
]);
|
]);
|
||||||
@ -405,4 +394,49 @@ public function getSshKeyNameAttribute(): string
|
|||||||
{
|
{
|
||||||
return str('site_'.$this->id)->toString();
|
return str('site_'.$this->id)->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function installationFinished(): void
|
||||||
|
{
|
||||||
|
$this->update([
|
||||||
|
'status' => SiteStatus::READY,
|
||||||
|
'progress' => 100,
|
||||||
|
]);
|
||||||
|
event(
|
||||||
|
new Broadcast('install-site-finished', [
|
||||||
|
'site' => $this,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
/** @todo notify */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function installationFailed(Throwable $e): void
|
||||||
|
{
|
||||||
|
$this->update([
|
||||||
|
'status' => SiteStatus::INSTALLATION_FAILED,
|
||||||
|
]);
|
||||||
|
event(
|
||||||
|
new Broadcast('install-site-failed', [
|
||||||
|
'site' => $this,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
/** @todo notify */
|
||||||
|
Log::error('install-site-error', [
|
||||||
|
'error' => (string) $e,
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasFeature(string $feature): bool
|
||||||
|
{
|
||||||
|
return in_array($feature, $this->type()->supportedFeatures());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isReady(): bool
|
||||||
|
{
|
||||||
|
return $this->status === SiteStatus::READY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
26
app/SSHCommands/Nginx/GetNginxVHostCommand.php
Executable file
26
app/SSHCommands/Nginx/GetNginxVHostCommand.php
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\SSHCommands\Nginx;
|
||||||
|
|
||||||
|
use App\SSHCommands\Command;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class GetNginxVHostCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected string $domain
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function file(): string
|
||||||
|
{
|
||||||
|
return File::get(resource_path('commands/webserver/nginx/get-vhost.sh'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
return str($this->file())
|
||||||
|
->replace('__domain__', $this->domain)
|
||||||
|
->toString();
|
||||||
|
}
|
||||||
|
}
|
40
app/SSHCommands/Storage/DownloadFromFTPCommand.php
Normal file
40
app/SSHCommands/Storage/DownloadFromFTPCommand.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\SSHCommands\Storage;
|
||||||
|
|
||||||
|
use App\SSHCommands\Command;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class DownloadFromFTPCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected string $src,
|
||||||
|
protected string $dest,
|
||||||
|
protected string $host,
|
||||||
|
protected string $port,
|
||||||
|
protected string $username,
|
||||||
|
protected string $password,
|
||||||
|
protected bool $ssl,
|
||||||
|
protected bool $passive,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function file(): string
|
||||||
|
{
|
||||||
|
return File::get(resource_path('commands/storage/download-from-ftp.sh'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
return str($this->file())
|
||||||
|
->replace('__src__', $this->src)
|
||||||
|
->replace('__dest__', $this->dest)
|
||||||
|
->replace('__host__', $this->host)
|
||||||
|
->replace('__port__', $this->port)
|
||||||
|
->replace('__username__', $this->username)
|
||||||
|
->replace('__password__', $this->password)
|
||||||
|
->replace('__ssl__', $this->ssl ? 's' : '')
|
||||||
|
->replace('__passive__', $this->passive ? '--ftp-pasv' : '')
|
||||||
|
->toString();
|
||||||
|
}
|
||||||
|
}
|
40
app/SSHCommands/Storage/UploadToFTPCommand.php
Normal file
40
app/SSHCommands/Storage/UploadToFTPCommand.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\SSHCommands\Storage;
|
||||||
|
|
||||||
|
use App\SSHCommands\Command;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class UploadToFTPCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
protected string $src,
|
||||||
|
protected string $dest,
|
||||||
|
protected string $host,
|
||||||
|
protected string $port,
|
||||||
|
protected string $username,
|
||||||
|
protected string $password,
|
||||||
|
protected bool $ssl,
|
||||||
|
protected bool $passive,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function file(): string
|
||||||
|
{
|
||||||
|
return File::get(resource_path('commands/storage/upload-to-ftp.sh'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): string
|
||||||
|
{
|
||||||
|
return str($this->file())
|
||||||
|
->replace('__src__', $this->src)
|
||||||
|
->replace('__dest__', $this->dest)
|
||||||
|
->replace('__host__', $this->host)
|
||||||
|
->replace('__port__', $this->port)
|
||||||
|
->replace('__username__', $this->username)
|
||||||
|
->replace('__password__', $this->password)
|
||||||
|
->replace('__ssl__', $this->ssl ? 's' : '')
|
||||||
|
->replace('__passive__', $this->passive ? '--ftp-pasv' : '')
|
||||||
|
->toString();
|
||||||
|
}
|
||||||
|
}
|
@ -63,7 +63,7 @@ public function data(array $input): array
|
|||||||
/**
|
/**
|
||||||
* @throws CouldNotConnectToProvider
|
* @throws CouldNotConnectToProvider
|
||||||
*/
|
*/
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->connectToEc2ClientTest($credentials);
|
$this->connectToEc2ClientTest($credentials);
|
||||||
@ -164,10 +164,12 @@ private function createKeyPair(): void
|
|||||||
$result = $this->ec2Client->createKeyPair([
|
$result = $this->ec2Client->createKeyPair([
|
||||||
'KeyName' => $keyName,
|
'KeyName' => $keyName,
|
||||||
]);
|
]);
|
||||||
Storage::disk(config('core.key_pairs_disk'))->put((string) $this->server->id, $result['KeyMaterial']);
|
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||||
|
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||||
|
$storageDisk->put((string) $this->server->id, $result['KeyMaterial']);
|
||||||
generate_public_key(
|
generate_public_key(
|
||||||
Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id),
|
$storageDisk->path((string) $this->server->id),
|
||||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id.'.pub'),
|
$storageDisk->path($this->server->id.'.pub'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,15 @@ abstract class AbstractProvider implements ServerProvider
|
|||||||
{
|
{
|
||||||
protected ?Server $server;
|
protected ?Server $server;
|
||||||
|
|
||||||
public function __construct(Server $server = null)
|
public function __construct(?Server $server = null)
|
||||||
{
|
{
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function generateKeyPair(): void
|
protected function generateKeyPair(): void
|
||||||
{
|
{
|
||||||
generate_key_pair(Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id));
|
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||||
|
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||||
|
generate_key_pair($storageDisk->path((string) $this->server->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public function data(array $input): array
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -59,13 +59,15 @@ public function regions(): array
|
|||||||
|
|
||||||
public function create(): void
|
public function create(): void
|
||||||
{
|
{
|
||||||
|
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||||
|
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||||
File::copy(
|
File::copy(
|
||||||
storage_path(config('core.ssh_private_key_name')),
|
storage_path(config('core.ssh_private_key_name')),
|
||||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id)
|
$storageDisk->path($this->server->id)
|
||||||
);
|
);
|
||||||
File::copy(
|
File::copy(
|
||||||
storage_path(config('core.ssh_public_key_name')),
|
storage_path(config('core.ssh_public_key_name')),
|
||||||
Storage::disk(config('core.key_pairs_disk'))->path($this->server->id.'.pub')
|
$storageDisk->path($this->server->id.'.pub')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public function data(array $input): array
|
|||||||
/**
|
/**
|
||||||
* @throws CouldNotConnectToProvider
|
* @throws CouldNotConnectToProvider
|
||||||
*/
|
*/
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
||||||
if (! $connect->ok()) {
|
if (! $connect->ok()) {
|
||||||
|
@ -45,7 +45,7 @@ public function data(array $input): array
|
|||||||
/**
|
/**
|
||||||
* @throws CouldNotConnectToProvider
|
* @throws CouldNotConnectToProvider
|
||||||
*/
|
*/
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/servers');
|
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/servers');
|
||||||
if (! $connect->ok()) {
|
if (! $connect->ok()) {
|
||||||
|
@ -57,7 +57,7 @@ public function data(array $input): array
|
|||||||
/**
|
/**
|
||||||
* @throws CouldNotConnectToProvider
|
* @throws CouldNotConnectToProvider
|
||||||
*/
|
*/
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
||||||
if (! $connect->ok()) {
|
if (! $connect->ok()) {
|
||||||
|
@ -59,7 +59,7 @@ public function data(array $input): array
|
|||||||
/**
|
/**
|
||||||
* @throws CouldNotConnectToProvider
|
* @throws CouldNotConnectToProvider
|
||||||
*/
|
*/
|
||||||
public function connect(array $credentials = null): bool
|
public function connect(?array $credentials = null): bool
|
||||||
{
|
{
|
||||||
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
$connect = Http::withToken($credentials['token'])->get($this->apiUrl.'/account');
|
||||||
if (! $connect->ok()) {
|
if (! $connect->ok()) {
|
||||||
@ -85,7 +85,9 @@ public function regions(): array
|
|||||||
public function create(): void
|
public function create(): void
|
||||||
{
|
{
|
||||||
// generate key pair
|
// generate key pair
|
||||||
generate_key_pair(Storage::disk(config('core.key_pairs_disk'))->path((string) $this->server->id));
|
/** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */
|
||||||
|
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
|
||||||
|
generate_key_pair($storageDisk->path((string) $this->server->id));
|
||||||
|
|
||||||
$createSshKey = Http::withToken($this->server->serverProvider->credentials['token'])
|
$createSshKey = Http::withToken($this->server->serverProvider->credentials['token'])
|
||||||
->post($this->apiUrl.'/ssh-keys', [
|
->post($this->apiUrl.'/ssh-keys', [
|
||||||
|
@ -16,7 +16,7 @@ public function __construct(Server $server)
|
|||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function progress(int $percentage, string $step = null): Closure
|
protected function progress(int $percentage, ?string $step = null): Closure
|
||||||
{
|
{
|
||||||
return function () use ($percentage, $step) {
|
return function () use ($percentage, $step) {
|
||||||
$this->server->progress = $percentage;
|
$this->server->progress = $percentage;
|
||||||
|
@ -47,7 +47,7 @@ public function create(
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function delete(int $id, int $siteId = null): void
|
public function delete(int $id, ?int $siteId = null): void
|
||||||
{
|
{
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new DeleteWorkerCommand($id),
|
new DeleteWorkerCommand($id),
|
||||||
@ -59,7 +59,7 @@ public function delete(int $id, int $siteId = null): void
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function restart(int $id, int $siteId = null): void
|
public function restart(int $id, ?int $siteId = null): void
|
||||||
{
|
{
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new RestartWorkerCommand($id),
|
new RestartWorkerCommand($id),
|
||||||
@ -71,7 +71,7 @@ public function restart(int $id, int $siteId = null): void
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function stop(int $id, int $siteId = null): void
|
public function stop(int $id, ?int $siteId = null): void
|
||||||
{
|
{
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new StopWorkerCommand($id),
|
new StopWorkerCommand($id),
|
||||||
@ -83,7 +83,7 @@ public function stop(int $id, int $siteId = null): void
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function start(int $id, int $siteId = null): void
|
public function start(int $id, ?int $siteId = null): void
|
||||||
{
|
{
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new StartWorkerCommand($id),
|
new StartWorkerCommand($id),
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
use App\SSHCommands\Nginx\ChangeNginxPHPVersionCommand;
|
use App\SSHCommands\Nginx\ChangeNginxPHPVersionCommand;
|
||||||
use App\SSHCommands\Nginx\CreateNginxVHostCommand;
|
use App\SSHCommands\Nginx\CreateNginxVHostCommand;
|
||||||
use App\SSHCommands\Nginx\DeleteNginxSiteCommand;
|
use App\SSHCommands\Nginx\DeleteNginxSiteCommand;
|
||||||
|
use App\SSHCommands\Nginx\GetNginxVHostCommand;
|
||||||
use App\SSHCommands\Nginx\UpdateNginxRedirectsCommand;
|
use App\SSHCommands\Nginx\UpdateNginxRedirectsCommand;
|
||||||
use App\SSHCommands\Nginx\UpdateNginxVHostCommand;
|
use App\SSHCommands\Nginx\UpdateNginxVHostCommand;
|
||||||
use App\SSHCommands\SSL\CreateCustomSSLCommand;
|
use App\SSHCommands\SSL\CreateCustomSSLCommand;
|
||||||
@ -39,19 +40,30 @@ public function createVHost(Site $site): void
|
|||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
public function updateVHost(Site $site, bool $noSSL = false): void
|
public function updateVHost(Site $site, bool $noSSL = false, ?string $vhost = null): void
|
||||||
{
|
{
|
||||||
$this->service->server->ssh()->exec(
|
$this->service->server->ssh()->exec(
|
||||||
new UpdateNginxVHostCommand(
|
new UpdateNginxVHostCommand(
|
||||||
$site->domain,
|
$site->domain,
|
||||||
$site->path,
|
$site->path,
|
||||||
$this->generateVhost($site, $noSSL)
|
$vhost ?? $this->generateVhost($site, $noSSL)
|
||||||
),
|
),
|
||||||
'update-vhost',
|
'update-vhost',
|
||||||
$site->id
|
$site->id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getVHost(Site $site): string
|
||||||
|
{
|
||||||
|
return $this->service->server->ssh()->exec(
|
||||||
|
new GetNginxVHostCommand(
|
||||||
|
$site->domain
|
||||||
|
),
|
||||||
|
'get-vhost',
|
||||||
|
$site->id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Throwable
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
namespace App\SiteTypes;
|
namespace App\SiteTypes;
|
||||||
|
|
||||||
use App\Enums\SiteStatus;
|
use App\Enums\SiteFeature;
|
||||||
use App\Events\Broadcast;
|
|
||||||
use App\Jobs\Site\CloneRepository;
|
use App\Jobs\Site\CloneRepository;
|
||||||
use App\Jobs\Site\ComposerInstall;
|
use App\Jobs\Site\ComposerInstall;
|
||||||
use App\Jobs\Site\CreateVHost;
|
use App\Jobs\Site\CreateVHost;
|
||||||
use App\Jobs\Site\DeployKey;
|
use App\Jobs\Site\DeployKey;
|
||||||
use Illuminate\Support\Facades\Bus;
|
use Illuminate\Support\Facades\Bus;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@ -20,12 +18,22 @@ public function language(): string
|
|||||||
return 'php';
|
return 'php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportedFeatures(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
SiteFeature::DEPLOYMENT,
|
||||||
|
SiteFeature::ENV,
|
||||||
|
SiteFeature::SSL,
|
||||||
|
SiteFeature::QUEUES,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function createValidationRules(array $input): array
|
public function createValidationRules(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'php_version' => [
|
'php_version' => [
|
||||||
'required',
|
'required',
|
||||||
'in:'.implode(',', $this->site->server->installedPHPVersions()),
|
Rule::in($this->site->server->installedPHPVersions()),
|
||||||
],
|
],
|
||||||
'source_control' => [
|
'source_control' => [
|
||||||
'required',
|
'required',
|
||||||
@ -47,13 +55,14 @@ public function createFields(array $input): array
|
|||||||
'source_control_id' => $input['source_control'] ?? '',
|
'source_control_id' => $input['source_control'] ?? '',
|
||||||
'repository' => $input['repository'] ?? '',
|
'repository' => $input['repository'] ?? '',
|
||||||
'branch' => $input['branch'] ?? '',
|
'branch' => $input['branch'] ?? '',
|
||||||
|
'php_version' => $input['php_version'] ?? '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function data(array $input): array
|
public function data(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'composer' => (bool) $input['composer'],
|
'composer' => isset($input['composer']) && $input['composer'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,33 +85,12 @@ function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$chain[] = function () {
|
$chain[] = function () {
|
||||||
$this->site->update([
|
$this->site->installationFinished();
|
||||||
'status' => SiteStatus::READY,
|
|
||||||
'progress' => 100,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-finished', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
/** @todo notify */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Bus::chain($chain)
|
Bus::chain($chain)
|
||||||
->catch(function (Throwable $e) {
|
->catch(function (Throwable $e) {
|
||||||
$this->site->update([
|
$this->site->installationFailed($e);
|
||||||
'status' => SiteStatus::INSTALLATION_FAILED,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-failed', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
/** @todo notify */
|
|
||||||
Log::error('install-site-error', [
|
|
||||||
'error' => (string) $e,
|
|
||||||
]);
|
|
||||||
throw $e;
|
|
||||||
})
|
})
|
||||||
->onConnection('ssh-long')
|
->onConnection('ssh-long')
|
||||||
->dispatch();
|
->dispatch();
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
namespace App\SiteTypes;
|
namespace App\SiteTypes;
|
||||||
|
|
||||||
use App\Enums\SiteStatus;
|
use App\Enums\SiteFeature;
|
||||||
use App\Events\Broadcast;
|
|
||||||
use App\Jobs\Site\CreateVHost;
|
use App\Jobs\Site\CreateVHost;
|
||||||
use App\Jobs\Site\InstallWordpress;
|
use App\Jobs\Site\InstallWordpress;
|
||||||
|
use App\Models\Database;
|
||||||
|
use App\Models\DatabaseUser;
|
||||||
use App\SSHCommands\Wordpress\UpdateWordpressCommand;
|
use App\SSHCommands\Wordpress\UpdateWordpressCommand;
|
||||||
|
use Closure;
|
||||||
use Illuminate\Support\Facades\Bus;
|
use Illuminate\Support\Facades\Bus;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Validation\Rule;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class Wordpress extends AbstractSiteType
|
class Wordpress extends AbstractSiteType
|
||||||
@ -18,94 +20,100 @@ public function language(): string
|
|||||||
return 'php';
|
return 'php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportedFeatures(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
SiteFeature::SSL,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function createValidationRules(array $input): array
|
public function createValidationRules(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
'php_version' => [
|
||||||
|
'required',
|
||||||
|
Rule::in($this->site->server->installedPHPVersions()),
|
||||||
|
],
|
||||||
'title' => 'required',
|
'title' => 'required',
|
||||||
'username' => 'required',
|
'username' => 'required',
|
||||||
'password' => 'required',
|
'password' => 'required',
|
||||||
'email' => 'required|email',
|
'email' => 'required|email',
|
||||||
'database' => 'required',
|
'database' => [
|
||||||
'database_user' => 'required',
|
'required',
|
||||||
|
Rule::unique('databases', 'name')->where(function ($query) {
|
||||||
|
return $query->where('server_id', $this->site->server_id);
|
||||||
|
}),
|
||||||
|
function (string $attribute, mixed $value, Closure $fail) {
|
||||||
|
if (! $this->site->server->database()) {
|
||||||
|
$fail(__('Database is not installed'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'database_user' => [
|
||||||
|
'required',
|
||||||
|
Rule::unique('database_users', 'username')->where(function ($query) {
|
||||||
|
return $query->where('server_id', $this->site->server_id);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
'database_password' => 'required',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createFields(array $input): array
|
public function createFields(array $input): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'web_directory' => $input['web_directory'] ?? '',
|
'web_directory' => '',
|
||||||
|
'php_version' => $input['php_version'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function data(array $input): array
|
public function data(array $input): array
|
||||||
{
|
{
|
||||||
$data = $this->site->type_data;
|
return [
|
||||||
$data['url'] = $this->site->url;
|
'url' => $this->site->url,
|
||||||
if (isset($input['title']) && $input['title']) {
|
'title' => $input['title'],
|
||||||
$data['title'] = $input['title'];
|
'username' => $input['username'],
|
||||||
}
|
'email' => $input['email'],
|
||||||
if (isset($input['username']) && $input['username']) {
|
'password' => $input['password'],
|
||||||
$data['username'] = $input['username'];
|
'database' => $input['database'],
|
||||||
}
|
'database_user' => $input['database_user'],
|
||||||
if (isset($input['email']) && $input['email']) {
|
'database_password' => $input['database_password'],
|
||||||
$data['email'] = $input['email'];
|
];
|
||||||
}
|
|
||||||
if (isset($input['password']) && $input['password']) {
|
|
||||||
$data['password'] = $input['password'];
|
|
||||||
}
|
|
||||||
if (isset($input['database']) && $input['database']) {
|
|
||||||
$data['database'] = $input['database'];
|
|
||||||
}
|
|
||||||
if (isset($input['database_user']) && $input['database_user']) {
|
|
||||||
$data['database_user'] = $input['database_user'];
|
|
||||||
}
|
|
||||||
if (isset($input['url']) && $input['url']) {
|
|
||||||
$data['url'] = $input['url'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function install(): void
|
public function install(): void
|
||||||
{
|
{
|
||||||
$chain = [
|
$chain = [
|
||||||
new CreateVHost($this->site),
|
new CreateVHost($this->site),
|
||||||
$this->progress(30),
|
$this->progress(15),
|
||||||
|
function () {
|
||||||
|
/** @var Database $database */
|
||||||
|
$database = $this->site->server->databases()->create([
|
||||||
|
'name' => $this->site->type_data['database'],
|
||||||
|
]);
|
||||||
|
$database->createOnServer('sync');
|
||||||
|
/** @var DatabaseUser $databaseUser */
|
||||||
|
$databaseUser = $this->site->server->databaseUsers()->create([
|
||||||
|
'username' => $this->site->type_data['database_user'],
|
||||||
|
'password' => $this->site->type_data['database_password'],
|
||||||
|
'databases' => [$this->site->type_data['database']],
|
||||||
|
]);
|
||||||
|
$databaseUser->createOnServer('sync');
|
||||||
|
$databaseUser->unlinkUser('sync');
|
||||||
|
$databaseUser->linkUser('sync');
|
||||||
|
},
|
||||||
|
$this->progress(50),
|
||||||
new InstallWordpress($this->site),
|
new InstallWordpress($this->site),
|
||||||
$this->progress(65),
|
$this->progress(75),
|
||||||
function () {
|
function () {
|
||||||
$this->site->php()?->restart();
|
$this->site->php()?->restart();
|
||||||
|
$this->site->installationFinished();
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
$chain[] = function () {
|
|
||||||
$this->site->update([
|
|
||||||
'status' => SiteStatus::READY,
|
|
||||||
'progress' => 100,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-finished', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
/** @todo notify */
|
|
||||||
};
|
|
||||||
|
|
||||||
Bus::chain($chain)
|
Bus::chain($chain)
|
||||||
->catch(function (Throwable $e) {
|
->catch(function (Throwable $e) {
|
||||||
$this->site->update([
|
$this->site->installationFailed($e);
|
||||||
'status' => SiteStatus::INSTALLATION_FAILED,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-failed', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
/** @todo notify */
|
|
||||||
Log::error('install-site-error', [
|
|
||||||
'error' => (string) $e,
|
|
||||||
]);
|
|
||||||
throw $e;
|
|
||||||
})
|
})
|
||||||
->onConnection('ssh-long')
|
->onConnection('ssh-long')
|
||||||
->dispatch();
|
->dispatch();
|
||||||
@ -139,32 +147,13 @@ function () {
|
|||||||
'update-wordpress',
|
'update-wordpress',
|
||||||
$this->site->id
|
$this->site->id
|
||||||
);
|
);
|
||||||
$this->site->update([
|
$this->site->installationFinished();
|
||||||
'status' => SiteStatus::READY,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-finished', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
Bus::chain($chain)
|
Bus::chain($chain)
|
||||||
->catch(function (Throwable $e) {
|
->catch(function (Throwable $e) {
|
||||||
$this->site->update([
|
$this->site->installationFailed($e);
|
||||||
'status' => SiteStatus::INSTALLATION_FAILED,
|
|
||||||
]);
|
|
||||||
event(
|
|
||||||
new Broadcast('install-site-failed', [
|
|
||||||
'site' => $this->site,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
/** @todo notify */
|
|
||||||
Log::error('install-site-error', [
|
|
||||||
'error' => (string) $e,
|
|
||||||
]);
|
|
||||||
throw $e;
|
|
||||||
})
|
})
|
||||||
->onConnection('ssh')
|
->onConnection('ssh')
|
||||||
->dispatch();
|
->dispatch();
|
||||||
|
@ -24,7 +24,7 @@ public function connect(): bool
|
|||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getRepo(string $repo = null): mixed
|
public function getRepo(?string $repo = null): mixed
|
||||||
{
|
{
|
||||||
$res = Http::withToken($this->sourceControl->access_token)
|
$res = Http::withToken($this->sourceControl->access_token)
|
||||||
->get($this->apiUrl."/repositories/$repo");
|
->get($this->apiUrl."/repositories/$repo");
|
||||||
@ -46,7 +46,7 @@ public function deployHook(string $repo, array $events, string $secret): array
|
|||||||
{
|
{
|
||||||
$response = Http::withToken($this->sourceControl->access_token)->post($this->apiUrl."/repositories/$repo/hooks", [
|
$response = Http::withToken($this->sourceControl->access_token)->post($this->apiUrl."/repositories/$repo/hooks", [
|
||||||
'description' => 'deploy',
|
'description' => 'deploy',
|
||||||
'url' => url('/git-hooks?secret='.$secret),
|
'url' => url('/api/git-hooks?secret='.$secret),
|
||||||
'events' => [
|
'events' => [
|
||||||
'repo:'.implode(',', $events),
|
'repo:'.implode(',', $events),
|
||||||
],
|
],
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\SourceControlProviders;
|
|
||||||
|
|
||||||
class Custom extends AbstractSourceControlProvider
|
|
||||||
{
|
|
||||||
public function connect(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRepo(string $repo = null): string
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fullRepoUrl(string $repo, string $key): string
|
|
||||||
{
|
|
||||||
return $repo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deployHook(string $repo, array $events, string $secret): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function destroyHook(string $repo, string $hookId): void
|
|
||||||
{
|
|
||||||
// TODO: Implement destroyHook() method.
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastCommit(string $repo, string $branch): ?array
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deployKey(string $title, string $repo, string $key): void
|
|
||||||
{
|
|
||||||
// TODO: Implement deployKey() method.
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,7 +25,7 @@ public function connect(): bool
|
|||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getRepo(string $repo = null): mixed
|
public function getRepo(?string $repo = null): mixed
|
||||||
{
|
{
|
||||||
if ($repo) {
|
if ($repo) {
|
||||||
$url = $this->apiUrl.'/repos/'.$repo;
|
$url = $this->apiUrl.'/repos/'.$repo;
|
||||||
@ -59,7 +59,7 @@ public function deployHook(string $repo, array $events, string $secret): array
|
|||||||
'name' => 'web',
|
'name' => 'web',
|
||||||
'events' => $events,
|
'events' => $events,
|
||||||
'config' => [
|
'config' => [
|
||||||
'url' => url('/git-hooks?secret='.$secret),
|
'url' => url('/api/git-hooks?secret='.$secret),
|
||||||
'content_type' => 'json',
|
'content_type' => 'json',
|
||||||
],
|
],
|
||||||
'active' => true,
|
'active' => true,
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
class Gitlab extends AbstractSourceControlProvider
|
class Gitlab extends AbstractSourceControlProvider
|
||||||
{
|
{
|
||||||
protected string $apiUrl = 'https://gitlab.com/api/v4';
|
protected string $defaultApiHost = 'https://gitlab.com/';
|
||||||
|
|
||||||
|
protected string $apiVersion = 'api/v4';
|
||||||
|
|
||||||
public function connect(): bool
|
public function connect(): bool
|
||||||
{
|
{
|
||||||
$res = Http::withToken($this->sourceControl->access_token)
|
$res = Http::withToken($this->sourceControl->access_token)
|
||||||
->get($this->apiUrl.'/projects');
|
->get($this->getApiUrl().'/projects');
|
||||||
|
|
||||||
return $res->successful();
|
return $res->successful();
|
||||||
}
|
}
|
||||||
@ -23,11 +25,11 @@ public function connect(): bool
|
|||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getRepo(string $repo = null): mixed
|
public function getRepo(?string $repo = null): mixed
|
||||||
{
|
{
|
||||||
$repository = $repo ? urlencode($repo) : null;
|
$repository = $repo ? urlencode($repo) : null;
|
||||||
$res = Http::withToken($this->sourceControl->access_token)
|
$res = Http::withToken($this->sourceControl->access_token)
|
||||||
->get($this->apiUrl.'/projects/'.$repository.'/repository/commits');
|
->get($this->getApiUrl().'/projects/'.$repository.'/repository/commits');
|
||||||
|
|
||||||
$this->handleResponseErrors($res, $repo);
|
$this->handleResponseErrors($res, $repo);
|
||||||
|
|
||||||
@ -36,7 +38,9 @@ public function getRepo(string $repo = null): mixed
|
|||||||
|
|
||||||
public function fullRepoUrl(string $repo, string $key): string
|
public function fullRepoUrl(string $repo, string $key): string
|
||||||
{
|
{
|
||||||
return sprintf('git@gitlab.com-%s:%s.git', $key, $repo);
|
$host = parse_url($this->getApiUrl())['host'];
|
||||||
|
|
||||||
|
return sprintf('git@%s-%s:%s.git', $host, $key, $repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,10 +50,10 @@ public function deployHook(string $repo, array $events, string $secret): array
|
|||||||
{
|
{
|
||||||
$repository = urlencode($repo);
|
$repository = urlencode($repo);
|
||||||
$response = Http::withToken($this->sourceControl->access_token)->post(
|
$response = Http::withToken($this->sourceControl->access_token)->post(
|
||||||
$this->apiUrl.'/projects/'.$repository.'/hooks',
|
$this->getApiUrl().'/projects/'.$repository.'/hooks',
|
||||||
[
|
[
|
||||||
'description' => 'deploy',
|
'description' => 'deploy',
|
||||||
'url' => url('/git-hooks?secret='.$secret),
|
'url' => url('/api/git-hooks?secret='.$secret),
|
||||||
'push_events' => in_array('push', $events),
|
'push_events' => in_array('push', $events),
|
||||||
'issues_events' => false,
|
'issues_events' => false,
|
||||||
'job_events' => false,
|
'job_events' => false,
|
||||||
@ -81,7 +85,7 @@ public function destroyHook(string $repo, string $hookId): void
|
|||||||
{
|
{
|
||||||
$repository = urlencode($repo);
|
$repository = urlencode($repo);
|
||||||
$response = Http::withToken($this->sourceControl->access_token)->delete(
|
$response = Http::withToken($this->sourceControl->access_token)->delete(
|
||||||
$this->apiUrl.'/projects/'.$repository.'/hooks/'.$hookId
|
$this->getApiUrl().'/projects/'.$repository.'/hooks/'.$hookId
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($response->status() != 204) {
|
if ($response->status() != 204) {
|
||||||
@ -96,7 +100,7 @@ public function getLastCommit(string $repo, string $branch): ?array
|
|||||||
{
|
{
|
||||||
$repository = urlencode($repo);
|
$repository = urlencode($repo);
|
||||||
$res = Http::withToken($this->sourceControl->access_token)
|
$res = Http::withToken($this->sourceControl->access_token)
|
||||||
->get($this->apiUrl.'/projects/'.$repository.'/repository/commits?ref_name='.$branch);
|
->get($this->getApiUrl().'/projects/'.$repository.'/repository/commits?ref_name='.$branch);
|
||||||
|
|
||||||
$this->handleResponseErrors($res, $repo);
|
$this->handleResponseErrors($res, $repo);
|
||||||
|
|
||||||
@ -123,7 +127,7 @@ public function deployKey(string $title, string $repo, string $key): void
|
|||||||
{
|
{
|
||||||
$repository = urlencode($repo);
|
$repository = urlencode($repo);
|
||||||
$response = Http::withToken($this->sourceControl->access_token)->post(
|
$response = Http::withToken($this->sourceControl->access_token)->post(
|
||||||
$this->apiUrl.'/projects/'.$repository.'/deploy_keys',
|
$this->getApiUrl().'/projects/'.$repository.'/deploy_keys',
|
||||||
[
|
[
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
@ -135,4 +139,13 @@ public function deployKey(string $title, string $repo, string $key): void
|
|||||||
throw new FailedToDeployGitKey(json_decode($response->body())->message);
|
throw new FailedToDeployGitKey(json_decode($response->body())->message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApiUrl(): string
|
||||||
|
{
|
||||||
|
$host = $this->sourceControl->url === null
|
||||||
|
? $this->defaultApiHost
|
||||||
|
: $this->sourceControl->url;
|
||||||
|
|
||||||
|
return $host.$this->apiVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,20 @@ class Dropbox extends AbstractStorageProvider
|
|||||||
{
|
{
|
||||||
protected string $apiUrl = 'https://api.dropboxapi.com/2';
|
protected string $apiUrl = 'https://api.dropboxapi.com/2';
|
||||||
|
|
||||||
|
public function validationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'token' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function credentialData(array $input): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'token' => $input['token'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function connect(): bool
|
public function connect(): bool
|
||||||
{
|
{
|
||||||
$res = Http::withToken($this->storageProvider->credentials['token'])
|
$res = Http::withToken($this->storageProvider->credentials['token'])
|
||||||
|
129
app/StorageProviders/FTP.php
Normal file
129
app/StorageProviders/FTP.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\StorageProviders;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\SSHCommands\Storage\DownloadFromFTPCommand;
|
||||||
|
use App\SSHCommands\Storage\UploadToFTPCommand;
|
||||||
|
use FTP\Connection;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class FTP extends AbstractStorageProvider
|
||||||
|
{
|
||||||
|
public function validationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'host' => 'required',
|
||||||
|
'port' => 'required|numeric',
|
||||||
|
'path' => 'required',
|
||||||
|
'username' => 'required',
|
||||||
|
'password' => 'required',
|
||||||
|
'ssl' => 'required',
|
||||||
|
'passive' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function credentialData(array $input): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'host' => $input['host'],
|
||||||
|
'port' => $input['port'],
|
||||||
|
'path' => $input['path'],
|
||||||
|
'username' => $input['username'],
|
||||||
|
'password' => $input['password'],
|
||||||
|
'ssl' => (bool) $input['ssl'],
|
||||||
|
'passive' => (bool) $input['passive'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect(): bool
|
||||||
|
{
|
||||||
|
$connection = $this->connection();
|
||||||
|
|
||||||
|
$isConnected = $connection && $this->login($connection);
|
||||||
|
|
||||||
|
if ($isConnected) {
|
||||||
|
ftp_close($connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function upload(Server $server, string $src, string $dest): array
|
||||||
|
{
|
||||||
|
$server->ssh()->exec(
|
||||||
|
new UploadToFTPCommand(
|
||||||
|
$src,
|
||||||
|
$this->storageProvider->credentials['path'].'/'.$dest,
|
||||||
|
$this->storageProvider->credentials['host'],
|
||||||
|
$this->storageProvider->credentials['port'],
|
||||||
|
$this->storageProvider->credentials['username'],
|
||||||
|
$this->storageProvider->credentials['password'],
|
||||||
|
$this->storageProvider->credentials['ssl'],
|
||||||
|
$this->storageProvider->credentials['passive'],
|
||||||
|
),
|
||||||
|
'upload-to-ftp'
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'size' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function download(Server $server, string $src, string $dest): void
|
||||||
|
{
|
||||||
|
$server->ssh()->exec(
|
||||||
|
new DownloadFromFTPCommand(
|
||||||
|
$this->storageProvider->credentials['path'].'/'.$src,
|
||||||
|
$dest,
|
||||||
|
$this->storageProvider->credentials['host'],
|
||||||
|
$this->storageProvider->credentials['port'],
|
||||||
|
$this->storageProvider->credentials['username'],
|
||||||
|
$this->storageProvider->credentials['password'],
|
||||||
|
$this->storageProvider->credentials['ssl'],
|
||||||
|
$this->storageProvider->credentials['passive'],
|
||||||
|
),
|
||||||
|
'download-from-ftp'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(array $paths): void
|
||||||
|
{
|
||||||
|
$connection = $this->connection();
|
||||||
|
|
||||||
|
if ($connection && $this->login($connection)) {
|
||||||
|
if ($this->storageProvider->credentials['passive']) {
|
||||||
|
ftp_pasv($connection, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
ftp_delete($connection, $this->storageProvider->credentials['path'].'/'.$path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ftp_close($connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function connection(): bool|Connection
|
||||||
|
{
|
||||||
|
$credentials = $this->storageProvider->credentials;
|
||||||
|
if ($credentials['ssl']) {
|
||||||
|
return ftp_ssl_connect($credentials['host'], $credentials['port'], 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ftp_connect($credentials['host'], $credentials['port'], 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function login(Connection $connection): bool
|
||||||
|
{
|
||||||
|
$credentials = $this->storageProvider->credentials;
|
||||||
|
|
||||||
|
return ftp_login($connection, $credentials['username'], $credentials['password']);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ class SSHFake
|
|||||||
|
|
||||||
protected string $output = '';
|
protected string $output = '';
|
||||||
|
|
||||||
public function init(Server $server, string $asUser = null): self
|
public function init(Server $server, ?string $asUser = null): self
|
||||||
{
|
{
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ public function assertExecuted(array|string $commands): void
|
|||||||
PHPUnit::assertTrue(true, $allExecuted);
|
PHPUnit::assertTrue(true, $allExecuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (! is_array($commands)) {
|
if (! is_array($commands)) {
|
||||||
$commands = [$commands];
|
$commands = [$commands];
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
"laravel/socialite": "^5.2",
|
"laravel/socialite": "^5.2",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"livewire/livewire": "^2.12",
|
"livewire/livewire": "^2.12",
|
||||||
"phpseclib/phpseclib": "~3.0"
|
"phpseclib/phpseclib": "~3.0",
|
||||||
|
"opcodesio/log-viewer": "^2.5",
|
||||||
|
"ext-ftp": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
@ -23,7 +25,6 @@
|
|||||||
"laravel/sail": "^1.18",
|
"laravel/sail": "^1.18",
|
||||||
"mockery/mockery": "^1.4.4",
|
"mockery/mockery": "^1.4.4",
|
||||||
"nunomaduro/collision": "^7.0",
|
"nunomaduro/collision": "^7.0",
|
||||||
"opcodesio/log-viewer": "^2.5",
|
|
||||||
"phpunit/phpunit": "^10.0",
|
"phpunit/phpunit": "^10.0",
|
||||||
"spatie/laravel-ignition": "^2.0"
|
"spatie/laravel-ignition": "^2.0"
|
||||||
},
|
},
|
||||||
|
2189
composer.lock
generated
2189
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -25,11 +25,12 @@
|
|||||||
use App\ServiceHandlers\Webserver\Nginx;
|
use App\ServiceHandlers\Webserver\Nginx;
|
||||||
use App\SiteTypes\Laravel;
|
use App\SiteTypes\Laravel;
|
||||||
use App\SiteTypes\PHPSite;
|
use App\SiteTypes\PHPSite;
|
||||||
|
use App\SiteTypes\Wordpress;
|
||||||
use App\SourceControlProviders\Bitbucket;
|
use App\SourceControlProviders\Bitbucket;
|
||||||
use App\SourceControlProviders\Custom;
|
|
||||||
use App\SourceControlProviders\Github;
|
use App\SourceControlProviders\Github;
|
||||||
use App\SourceControlProviders\Gitlab;
|
use App\SourceControlProviders\Gitlab;
|
||||||
use App\StorageProviders\Dropbox;
|
use App\StorageProviders\Dropbox;
|
||||||
|
use App\StorageProviders\FTP;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
/*
|
/*
|
||||||
@ -38,8 +39,8 @@
|
|||||||
'ssh_user' => env('SSH_USER', 'vito'),
|
'ssh_user' => env('SSH_USER', 'vito'),
|
||||||
'ssh_public_key_name' => env('SSH_PUBLIC_KEY_NAME', 'ssh-public.key'),
|
'ssh_public_key_name' => env('SSH_PUBLIC_KEY_NAME', 'ssh-public.key'),
|
||||||
'ssh_private_key_name' => env('SSH_PRIVATE_KEY_NAME', 'ssh-private.pem'),
|
'ssh_private_key_name' => env('SSH_PRIVATE_KEY_NAME', 'ssh-private.pem'),
|
||||||
'logs_disk' => env('SERVER_LOGS_DISK', 'server-logs-local'),
|
'logs_disk' => env('SERVER_LOGS_DISK', 'server-logs-local'), // should to be FilesystemAdapter storage
|
||||||
'key_pairs_disk' => env('KEY_PAIRS_DISK', 'key-pairs-local'),
|
'key_pairs_disk' => env('KEY_PAIRS_DISK', 'key-pairs-local'), // should to be FilesystemAdapter storage
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* General
|
* General
|
||||||
@ -262,12 +263,12 @@
|
|||||||
'site_types' => [
|
'site_types' => [
|
||||||
\App\Enums\SiteType::PHP,
|
\App\Enums\SiteType::PHP,
|
||||||
\App\Enums\SiteType::LARAVEL,
|
\App\Enums\SiteType::LARAVEL,
|
||||||
// \App\Enums\SiteType::WORDPRESS,
|
\App\Enums\SiteType::WORDPRESS,
|
||||||
],
|
],
|
||||||
'site_types_class' => [
|
'site_types_class' => [
|
||||||
\App\Enums\SiteType::PHP => PHPSite::class,
|
\App\Enums\SiteType::PHP => PHPSite::class,
|
||||||
\App\Enums\SiteType::LARAVEL => Laravel::class,
|
\App\Enums\SiteType::LARAVEL => Laravel::class,
|
||||||
// \App\Enums\SiteType::WORDPRESS => Wordpress::class,
|
\App\Enums\SiteType::WORDPRESS => Wordpress::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -283,7 +284,6 @@
|
|||||||
'github' => Github::class,
|
'github' => Github::class,
|
||||||
'gitlab' => Gitlab::class,
|
'gitlab' => Gitlab::class,
|
||||||
'bitbucket' => Bitbucket::class,
|
'bitbucket' => Bitbucket::class,
|
||||||
'custom' => Custom::class,
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -291,11 +291,12 @@
|
|||||||
*/
|
*/
|
||||||
'php_extensions' => [
|
'php_extensions' => [
|
||||||
'imagick',
|
'imagick',
|
||||||
'geoip',
|
|
||||||
'exif',
|
'exif',
|
||||||
'gmagick',
|
'gmagick',
|
||||||
'gmp',
|
'gmp',
|
||||||
'intl',
|
'intl',
|
||||||
|
'sqlite3',
|
||||||
|
'opcache',
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -323,7 +324,6 @@
|
|||||||
'https' => 443,
|
'https' => 443,
|
||||||
'mysql' => 3306,
|
'mysql' => 3306,
|
||||||
'ftp' => 21,
|
'ftp' => 21,
|
||||||
'phpmyadmin' => 54331,
|
|
||||||
'tcp' => '',
|
'tcp' => '',
|
||||||
'udp' => '',
|
'udp' => '',
|
||||||
],
|
],
|
||||||
@ -355,8 +355,10 @@
|
|||||||
*/
|
*/
|
||||||
'storage_providers' => [
|
'storage_providers' => [
|
||||||
'dropbox',
|
'dropbox',
|
||||||
|
'ftp',
|
||||||
],
|
],
|
||||||
'storage_providers_class' => [
|
'storage_providers_class' => [
|
||||||
'dropbox' => Dropbox::class,
|
'dropbox' => Dropbox::class,
|
||||||
|
'ftp' => FTP::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
'disks' => [
|
'disks' => [
|
||||||
|
|
||||||
|
// should be FilesystemAdapter
|
||||||
'local' => [
|
'local' => [
|
||||||
'driver' => 'local',
|
'driver' => 'local',
|
||||||
'root' => storage_path('app'),
|
'root' => storage_path('app'),
|
||||||
|
217
config/log-viewer.php
Normal file
217
config/log-viewer.php
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Opcodes\LogViewer\Level;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer can be disabled, so it's no longer accessible via browser.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enabled' => env('LOG_VIEWER_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| You may change the domain where Log Viewer should be active.
|
||||||
|
| If the domain is empty, all domains will be valid.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'route_domain' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer Route
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer will be available under this URL.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'route_path' => 'log-viewer',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Back to system URL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| When set, displays a link to easily get back to this URL.
|
||||||
|
| Set to `null` to hide this link.
|
||||||
|
|
|
||||||
|
| Optional label to display for the above URL.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'back_to_system_url' => config('app.url', null),
|
||||||
|
|
||||||
|
'back_to_system_label' => null, // Displayed by default: "Back to {{ app.name }}"
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer time zone.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| The time zone in which to display the times in the UI. Defaults to
|
||||||
|
| the application's timezone defined in config/app.php.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timezone' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer route middleware.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Optional middleware to use when loading the initial Log Viewer page.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'web',
|
||||||
|
\Opcodes\LogViewer\Http\Middleware\AuthorizeLogViewer::class,
|
||||||
|
'auth',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer API middleware.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Optional middleware to use on every API request. The same API is also
|
||||||
|
| used from within the Log Viewer user interface.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'api_middleware' => [
|
||||||
|
\Opcodes\LogViewer\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||||
|
\Opcodes\LogViewer\Http\Middleware\AuthorizeLogViewer::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer Remote hosts.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log Viewer supports viewing Laravel logs from remote hosts. They must
|
||||||
|
| be running Log Viewer as well. Below you can define the hosts you
|
||||||
|
| would like to show in this Log Viewer instance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'hosts' => [
|
||||||
|
'local' => [
|
||||||
|
'name' => ucfirst(env('APP_ENV', 'local')),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 'staging' => [
|
||||||
|
// 'name' => 'Staging',
|
||||||
|
// 'host' => 'https://staging.example.com/log-viewer',
|
||||||
|
// 'auth' => [ // Example of HTTP Basic auth
|
||||||
|
// 'username' => 'username',
|
||||||
|
// 'password' => 'password',
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
//
|
||||||
|
// 'production' => [
|
||||||
|
// 'name' => 'Production',
|
||||||
|
// 'host' => 'https://example.com/log-viewer',
|
||||||
|
// 'auth' => [ // Example of Bearer token auth
|
||||||
|
// 'token' => env('LOG_VIEWER_PRODUCTION_TOKEN'),
|
||||||
|
// ],
|
||||||
|
// 'headers' => [
|
||||||
|
// 'X-Foo' => 'Bar',
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Include file patterns
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'include_files' => [
|
||||||
|
'*.log',
|
||||||
|
'**/*.log',
|
||||||
|
// '/absolute/paths/supported',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Exclude file patterns.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| This will take precedence over included files.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'exclude_files' => [
|
||||||
|
// 'my_secret.log'
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Shorter stack trace filters.
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Lines containing any of these strings will be excluded from the full log.
|
||||||
|
| This setting is only active when the function is enabled via the user interface.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'shorter_stack_trace_excludes' => [
|
||||||
|
'/vendor/symfony/',
|
||||||
|
'/vendor/laravel/framework/',
|
||||||
|
'/vendor/barryvdh/laravel-debugbar/',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Log matching patterns
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Regexes for matching log files
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'patterns' => [
|
||||||
|
'laravel' => [
|
||||||
|
'log_matching_regex' => '/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}\.?(\d{6}([\+-]\d\d:\d\d)?)?)\].*/',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This pattern, used for processing Laravel logs, returns these results:
|
||||||
|
* $matches[0] - the full log line being tested.
|
||||||
|
* $matches[1] - full timestamp between the square brackets (includes microseconds and timezone offset)
|
||||||
|
* $matches[2] - timestamp microseconds, if available
|
||||||
|
* $matches[3] - timestamp timezone offset, if available
|
||||||
|
* $matches[4] - contents between timestamp and the severity level
|
||||||
|
* $matches[5] - environment (local, production, etc)
|
||||||
|
* $matches[6] - log severity (info, debug, error, etc)
|
||||||
|
* $matches[7] - the log text, the rest of the text.
|
||||||
|
*/
|
||||||
|
'log_parsing_regex' => '/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}\.?(\d{6}([\+-]\d\d:\d\d)?)?)\](.*?(\w+)\.|.*?)('
|
||||||
|
.implode('|', array_filter(Level::caseValues()))
|
||||||
|
.')?: (.*?)( in [\/].*?:[0-9]+)?$/is',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache driver to use for storing the log indices. Indices are used to speed up
|
||||||
|
| log navigation. Defaults to your application's default cache driver.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cache_driver' => env('LOG_VIEWER_CACHE_DRIVER', null),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Chunk size when scanning log files lazily
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| The size in MB of files to scan before updating the progress bar when searching across all files.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lazy_scan_chunk_size_in_mb' => 50,
|
||||||
|
];
|
@ -13,7 +13,7 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('QUEUE_CONNECTION', 'sync'),
|
'default' => env('QUEUE_CONNECTION', 'default'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -139,85 +139,125 @@
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
'images' => [
|
'images' => [
|
||||||
'us-east-1' => [
|
'af-south-1' => [
|
||||||
'ubuntu_18' => 'ami-0279c3b3186e54acd',
|
'ubuntu_20' => 'ami-03684d4c2541e5333',
|
||||||
'ubuntu_20' => 'ami-083654bd07b5da81d',
|
'ubuntu_22' => 'ami-05759acc7d8973892',
|
||||||
],
|
|
||||||
'us-east-2' => [
|
|
||||||
'ubuntu_18' => 'ami-020db2c14939a8efb',
|
|
||||||
'ubuntu_20' => 'ami-0629230e074c580f2',
|
|
||||||
],
|
|
||||||
'us-west-1' => [
|
|
||||||
'ubuntu_18' => 'ami-083f68207d3376798',
|
|
||||||
'ubuntu_20' => 'ami-053ac55bdcfe96e85',
|
|
||||||
],
|
|
||||||
'us-west-2' => [
|
|
||||||
'ubuntu_18' => 'ami-09889d8d54f9e0a0e',
|
|
||||||
'ubuntu_20' => 'ami-036d46416a34a611c',
|
|
||||||
],
|
],
|
||||||
'ap-east-1' => [
|
'ap-east-1' => [
|
||||||
'ubuntu_18' => 'ami-032c0a4bd39a5772c',
|
'ubuntu_20' => 'ami-0b19a97bf326b4931',
|
||||||
'ubuntu_20' => 'ami-0a9c1cc3697104990',
|
'ubuntu_22' => 'ami-03490b1b7425e5fe3',
|
||||||
],
|
|
||||||
'ap-south-1' => [
|
|
||||||
'ubuntu_18' => 'ami-00782a7608c7fc226',
|
|
||||||
'ubuntu_20' => 'ami-0567e0d2b4b2169ae',
|
|
||||||
],
|
],
|
||||||
'ap-northeast-1' => [
|
'ap-northeast-1' => [
|
||||||
'ubuntu_18' => 'ami-085e9421f80dbe728',
|
'ubuntu_20' => 'ami-0e25df74d27e028e6',
|
||||||
'ubuntu_20' => 'ami-036d0684fc96830ca',
|
'ubuntu_22' => 'ami-09a81b370b76de6a2',
|
||||||
],
|
],
|
||||||
'ap-northeast-2' => [
|
'ap-northeast-2' => [
|
||||||
'ubuntu_18' => 'ami-0252a84eb1d66c2a0',
|
'ubuntu_20' => 'ami-003a709e1e4ce3729',
|
||||||
'ubuntu_20' => 'ami-0f8b8babb98cc66d0',
|
'ubuntu_22' => 'ami-086cae3329a3f7d75',
|
||||||
|
],
|
||||||
|
'ap-northeast-3' => [
|
||||||
|
'ubuntu_20' => 'ami-06c1367bd83de7d47',
|
||||||
|
'ubuntu_22' => 'ami-0690c54203f5f67da',
|
||||||
|
],
|
||||||
|
'ap-south-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0b88997c830e88c76',
|
||||||
|
'ubuntu_22' => 'ami-0287a05f0ef0e9d9a',
|
||||||
|
],
|
||||||
|
'ap-south-2' => [
|
||||||
|
'ubuntu_20' => 'ami-049e2ae605332dba6',
|
||||||
|
'ubuntu_22' => 'ami-06fe902e167e67d33',
|
||||||
],
|
],
|
||||||
'ap-southeast-1' => [
|
'ap-southeast-1' => [
|
||||||
'ubuntu_18' => 'ami-0907c2c44ea451f84',
|
'ubuntu_20' => 'ami-0a6461ddb52e9db63',
|
||||||
'ubuntu_20' => 'ami-0fed77069cd5a6d6c',
|
'ubuntu_22' => 'ami-078c1149d8ad719a7',
|
||||||
],
|
],
|
||||||
'ap-southeast-2' => [
|
'ap-southeast-2' => [
|
||||||
'ubuntu_18' => 'ami-00abf0511a7f4cee5',
|
'ubuntu_20' => 'ami-0a9fb81cc3289919c',
|
||||||
'ubuntu_20' => 'ami-0bf8b986de7e3c7ce',
|
'ubuntu_22' => 'ami-0df4b2961410d4cff',
|
||||||
|
],
|
||||||
|
'ap-southeast-3' => [
|
||||||
|
'ubuntu_20' => 'ami-05ee5bed682a3fff0',
|
||||||
|
'ubuntu_22' => 'ami-0fb6d1fdeeea10488',
|
||||||
|
],
|
||||||
|
'ap-southeast-4' => [
|
||||||
|
'ubuntu_20' => 'ami-02f9759882b112414',
|
||||||
|
'ubuntu_22' => 'ami-043a030d3eeabec75',
|
||||||
],
|
],
|
||||||
'ca-central-1' => [
|
'ca-central-1' => [
|
||||||
'ubuntu_18' => 'ami-0e471deaa43652c4a',
|
'ubuntu_20' => 'ami-0daaea212e620de87',
|
||||||
'ubuntu_20' => 'ami-0bb84e7329f4fa1f7',
|
'ubuntu_22' => 'ami-06873c81b882339ac',
|
||||||
|
],
|
||||||
|
'cn-north-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0c8bcac1fe3389a72',
|
||||||
|
'ubuntu_22' => 'ami-0728a1a4cc9e07753',
|
||||||
|
],
|
||||||
|
'cn-northwest-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0415bfb3ea62e17c0',
|
||||||
|
'ubuntu_22' => 'ami-05529cf859783e600',
|
||||||
],
|
],
|
||||||
'eu-central-1' => [
|
'eu-central-1' => [
|
||||||
'ubuntu_18' => 'ami-00d5e377dd7fad751',
|
'ubuntu_20' => 'ami-0b369586722023326',
|
||||||
'ubuntu_20' => 'ami-0a49b025fffbbdac6',
|
'ubuntu_22' => 'ami-06dd92ecc74fdfb36',
|
||||||
],
|
],
|
||||||
'eu-west-1' => [
|
'eu-central-2' => [
|
||||||
'ubuntu_18' => 'ami-095b735dce49535b5',
|
'ubuntu_20' => 'ami-070c78d5ed65f11c8',
|
||||||
'ubuntu_20' => 'ami-08edbb0e85d6a0a07',
|
'ubuntu_22' => 'ami-07cf963e6321c9e6a',
|
||||||
],
|
|
||||||
'eu-west-2' => [
|
|
||||||
'ubuntu_18' => 'ami-008485ca60c91a0f3',
|
|
||||||
'ubuntu_20' => 'ami-0fdf70ed5c34c5f52',
|
|
||||||
],
|
|
||||||
'eu-west-3' => [
|
|
||||||
'ubuntu_18' => 'ami-0df7d9cc2767d16cd',
|
|
||||||
'ubuntu_20' => 'ami-06d79c60d7454e2af',
|
|
||||||
],
|
|
||||||
'eu-south-1' => [
|
|
||||||
'ubuntu_18' => 'ami-09f165dd6bd167be5',
|
|
||||||
'ubuntu_20' => 'ami-0f8ce9c417115413d',
|
|
||||||
],
|
],
|
||||||
'eu-north-1' => [
|
'eu-north-1' => [
|
||||||
'ubuntu_18' => 'ami-038904f9024f34a0c',
|
'ubuntu_20' => 'ami-0c5863072fc83557e',
|
||||||
'ubuntu_20' => 'ami-0bd9c26722573e69b',
|
'ubuntu_22' => 'ami-0fe8bec493a81c7da',
|
||||||
|
],
|
||||||
|
'eu-south-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0966ff128f1497260',
|
||||||
|
'ubuntu_22' => 'ami-0b03947fd0ce0eed2',
|
||||||
|
],
|
||||||
|
'eu-south-2' => [
|
||||||
|
'ubuntu_20' => 'ami-087296a5b46cb95ce',
|
||||||
|
'ubuntu_22' => 'ami-03486abd2962c176f',
|
||||||
|
],
|
||||||
|
'eu-west-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0e3e7f215a53e2a86',
|
||||||
|
'ubuntu_22' => 'ami-0694d931cee176e7d',
|
||||||
|
],
|
||||||
|
'eu-west-2' => [
|
||||||
|
'ubuntu_20' => 'ami-0b22eee5ba6bb6772',
|
||||||
|
'ubuntu_22' => 'ami-0505148b3591e4c07',
|
||||||
|
],
|
||||||
|
'eu-west-3' => [
|
||||||
|
'ubuntu_20' => 'ami-0f14fa1f9c69f4111',
|
||||||
|
'ubuntu_22' => 'ami-00983e8a26e4c9bd9',
|
||||||
|
],
|
||||||
|
'il-central-1' => [
|
||||||
|
'ubuntu_20' => 'ami-0703881563bf5fab7',
|
||||||
|
'ubuntu_22' => 'ami-03869c813f5a2e20c',
|
||||||
|
],
|
||||||
|
'me-central-1' => [
|
||||||
|
'ubuntu_20' => 'ami-04a5bde3b044c7c21',
|
||||||
|
'ubuntu_22' => 'ami-02168d82d5c12118f',
|
||||||
],
|
],
|
||||||
'me-south-1' => [
|
'me-south-1' => [
|
||||||
'ubuntu_18' => 'ami-0ef669c57b73af73b',
|
'ubuntu_20' => 'ami-0165b692f5714e330',
|
||||||
'ubuntu_20' => 'ami-0b4946d7420c44be4',
|
'ubuntu_22' => 'ami-0f8d2a6080634ee69',
|
||||||
],
|
],
|
||||||
'sa-east-1' => [
|
'sa-east-1' => [
|
||||||
'ubuntu_18' => 'ami-0ed2b3edeb28afa59',
|
'ubuntu_20' => 'ami-095ca107fb46b81e6',
|
||||||
'ubuntu_20' => 'ami-0e66f5495b4efdd0f',
|
'ubuntu_22' => 'ami-0b6c2d49148000cd5',
|
||||||
],
|
],
|
||||||
'af-south-1' => [
|
'us-east-1' => [
|
||||||
'ubuntu_18' => 'ami-0191bb2cf509687ee',
|
'ubuntu_20' => 'ami-0fe0238291c8e3f07',
|
||||||
'ubuntu_20' => 'ami-0ff86122fd4ad7208',
|
'ubuntu_22' => 'ami-0fc5d935ebf8bc3bc',
|
||||||
|
],
|
||||||
|
'us-east-2' => [
|
||||||
|
'ubuntu_20' => 'ami-0b6968e5c7117349a',
|
||||||
|
'ubuntu_22' => 'ami-0e83be366243f524a',
|
||||||
|
],
|
||||||
|
'us-west-1' => [
|
||||||
|
'ubuntu_20' => 'ami-092efbcc9a2d2be8a',
|
||||||
|
'ubuntu_22' => 'ami-0cbd40f694b804622',
|
||||||
|
],
|
||||||
|
'us-west-2' => [
|
||||||
|
'ubuntu_20' => 'ami-0a55cdf919d10eac9',
|
||||||
|
'ubuntu_22' => 'ami-0efcece6bed30fd98',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
29
database/factories/GitHookFactory.php
Normal file
29
database/factories/GitHookFactory.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\GitHook;
|
||||||
|
use App\Models\Site;
|
||||||
|
use App\Models\SourceControl;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class GitHookFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = GitHook::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'secret' => $this->faker->word(),
|
||||||
|
'events' => $this->faker->words(),
|
||||||
|
'actions' => $this->faker->words(),
|
||||||
|
'hook_id' => $this->faker->word(),
|
||||||
|
'hook_response' => $this->faker->words(),
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
'site_id' => Site::factory(),
|
||||||
|
'source_control_id' => SourceControl::factory(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
25
database/factories/ProjectFactory.php
Normal file
25
database/factories/ProjectFactory.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends Factory<Project>
|
||||||
|
*/
|
||||||
|
class ProjectFactory extends Factory
|
||||||
|
{
|
||||||
|
protected $model = Project::class;
|
||||||
|
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'user_id' => $this->faker->randomNumber(),
|
||||||
|
'name' => $this->faker->name(),
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'updated_at' => Carbon::now(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,34 @@ class SourceControlFactory extends Factory
|
|||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'provider' => $this->faker->randomElement(\App\Enums\SourceControl::getValues()),
|
|
||||||
'access_token' => Str::random(10),
|
'access_token' => Str::random(10),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function gitlab(): Factory
|
||||||
|
{
|
||||||
|
return $this->state(function (array $attributes) {
|
||||||
|
return [
|
||||||
|
'provider' => \App\Enums\SourceControl::GITLAB,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function github(): Factory
|
||||||
|
{
|
||||||
|
return $this->state(function (array $attributes) {
|
||||||
|
return [
|
||||||
|
'provider' => \App\Enums\SourceControl::GITHUB,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bitbucket(): Factory
|
||||||
|
{
|
||||||
|
return $this->state(function (array $attributes) {
|
||||||
|
return [
|
||||||
|
'provider' => \App\Enums\SourceControl::BITBUCKET,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('projects', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->bigInteger('user_id');
|
||||||
|
$table->string('name');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('projects');
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('project_id')->nullable()->after('id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('project_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user