mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-06 05:02:08 +00:00
Compare commits
144 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74e3524e92 | ||
|
|
d31f75d1ec | ||
|
|
0b34207148 | ||
|
|
3c2beded68 | ||
|
|
f33fdb3bfd | ||
|
|
96a0f29f19 | ||
|
|
49b3a75a8b | ||
|
|
f13fc737f1 | ||
|
|
b7121c5000 | ||
|
|
22a1d3882e | ||
|
|
82f74e2264 | ||
|
|
3dd5699cde | ||
|
|
a198bfc5c0 | ||
|
|
132807b55d | ||
|
|
735081af50 | ||
|
|
31651aeaab | ||
|
|
7f4230d026 | ||
|
|
6333d3fd13 | ||
|
|
fd9dae6e4b | ||
|
|
db5d7857c8 | ||
|
|
0f4eab3cf2 | ||
|
|
75b9f4fcbf | ||
|
|
b9b58b8985 | ||
|
|
64b8aa1c01 | ||
|
|
6b21dc132d | ||
|
|
7aca4930db | ||
|
|
7a92ecfa30 | ||
|
|
171f6f4608 | ||
|
|
d569c8d31f | ||
|
|
51d716253f | ||
|
|
971b17b364 | ||
|
|
db5ff7f16d | ||
|
|
5db045f392 | ||
|
|
42c143d19e | ||
|
|
7c1948ebd9 | ||
|
|
9cd15645a2 | ||
|
|
c0a4a5c2f5 | ||
|
|
518004afbc | ||
|
|
833a4b9367 | ||
|
|
6aa82724b4 | ||
|
|
cfbee40ecd | ||
|
|
79d589c7a9 | ||
|
|
6b82fc3011 | ||
|
|
d921456036 | ||
|
|
6cc93250b8 | ||
|
|
39082541ff | ||
|
|
8cff40fdd4 | ||
|
|
a777db1234 | ||
|
|
3fca169096 | ||
|
|
58b451f616 | ||
|
|
f9b82f711f | ||
|
|
d92b5db320 | ||
|
|
a164e4bf3a | ||
|
|
be3cbd9e21 | ||
|
|
43fed96af1 | ||
|
|
3d3d31ef29 | ||
|
|
d51e70bcaa | ||
|
|
32f4c6c982 | ||
|
|
8f47761200 | ||
|
|
342ebecef2 | ||
|
|
220a8fe2cc | ||
|
|
480cb00098 | ||
|
|
07ed550dc2 | ||
|
|
6045870398 | ||
|
|
2bf102cdf1 | ||
|
|
889a5b2bce | ||
|
|
df964a094b | ||
|
|
e395d4ecee | ||
|
|
d077e0c83c | ||
|
|
d931241edc | ||
|
|
64a9a72457 | ||
|
|
a8417aca16 | ||
|
|
b7b2ecad59 | ||
|
|
dcaa2f4168 | ||
|
|
7c7f54d224 | ||
|
|
b942f8c726 | ||
|
|
f661f23ee5 | ||
|
|
5a631df2a2 | ||
|
|
fc9bb7dac6 | ||
|
|
0a82dc2e8e | ||
|
|
c5eff85c28 | ||
|
|
d1627276a6 | ||
|
|
2be2a2621e | ||
|
|
995c303f27 | ||
|
|
9c03525369 | ||
|
|
afe0673fd1 | ||
|
|
37333f7fbe | ||
|
|
c9160cabc5 | ||
|
|
9e289d5e97 | ||
|
|
901a580e11 | ||
|
|
d196292551 | ||
|
|
8d856b0ec6 | ||
|
|
90fad52760 | ||
|
|
2817875461 | ||
|
|
bcbdee1dcc | ||
|
|
3de4f2805a | ||
|
|
995197cad9 | ||
|
|
89cc4d1df4 | ||
|
|
61f3b3592f | ||
|
|
8cb6f67a60 | ||
|
|
7c580f898c | ||
|
|
9ad6ce5851 | ||
|
|
a66090b594 | ||
|
|
d992a3f7d7 | ||
|
|
b418a78e2e | ||
|
|
cae9ae51ad | ||
|
|
04c92ec4bd | ||
|
|
54834891fb | ||
|
|
c9e2f4244d | ||
|
|
503b86ac13 | ||
|
|
ec051eba38 | ||
|
|
2f50f64ecf | ||
|
|
66fe124dd1 | ||
|
|
87e56c2f66 | ||
|
|
f044b0292c | ||
|
|
ee1d4cd45d | ||
|
|
b25f83e096 | ||
|
|
8b7e1e4169 | ||
|
|
ca9a2cb13a | ||
|
|
93af92743c | ||
|
|
0ebef3792d | ||
|
|
7a3bb14653 | ||
|
|
fbc0a39a1c | ||
|
|
473bad24b7 | ||
|
|
313d968985 | ||
|
|
b5775ff9d2 | ||
|
|
8f66a41c09 | ||
|
|
6721471c63 | ||
|
|
638421de40 | ||
|
|
7bc5338cb3 | ||
|
|
fafc4fb71e | ||
|
|
6b49d32102 | ||
|
|
3a391aa3cb | ||
|
|
42019321e3 | ||
|
|
b61860b3ab | ||
|
|
91950e1891 | ||
|
|
42715bba50 | ||
|
|
0aacad655d | ||
|
|
289480c954 | ||
|
|
3da7746629 | ||
|
|
8d48051a8d | ||
|
|
ec16c0f0f4 | ||
|
|
19d19112d9 | ||
|
|
1f37318f79 |
2
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
2
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
@@ -21,6 +21,6 @@ body:
|
|||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Version
|
label: Version
|
||||||
description: Coolify's version (see bottom left corner).
|
description: Coolify's version (see top of your screen).
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
20
.github/workflows/coolify-helper-next.yml
vendored
20
.github/workflows/coolify-helper-next.yml
vendored
@@ -18,15 +18,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -40,15 +40,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -64,13 +64,13 @@ jobs:
|
|||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|||||||
20
.github/workflows/coolify-helper.yml
vendored
20
.github/workflows/coolify-helper.yml
vendored
@@ -18,15 +18,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -40,15 +40,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -64,13 +64,13 @@ jobs:
|
|||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|||||||
20
.github/workflows/coolify-testing-host.yml
vendored
20
.github/workflows/coolify-testing-host.yml
vendored
@@ -18,15 +18,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -40,15 +40,15 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build image and push to registry
|
- name: Build image and push to registry
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
no-cache: true
|
no-cache: true
|
||||||
context: .
|
context: .
|
||||||
@@ -64,13 +64,13 @@ jobs:
|
|||||||
needs: [ amd64, aarch64 ]
|
needs: [ amd64, aarch64 ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to ghcr.io
|
- name: Login to ghcr.io
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|||||||
2
.github/workflows/docker-image.yml
vendored
2
.github/workflows/docker-image.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Cache Docker layers
|
- name: Cache Docker layers
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
|
|
||||||
$email = 'test@example.com';
|
|
||||||
$user = User::whereEmail($email)->first();
|
|
||||||
$teams = $user->teams;
|
|
||||||
foreach ($teams as $team) {
|
|
||||||
$servers = $team->servers;
|
|
||||||
if ($servers->count() > 0) {
|
|
||||||
foreach ($servers as $server) {
|
|
||||||
dump($server);
|
|
||||||
$server->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dump($team);
|
|
||||||
$team->delete();
|
|
||||||
}
|
|
||||||
if ($user) {
|
|
||||||
dump($user);
|
|
||||||
$user->delete();
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @label Send Email
|
|
||||||
* @description Send email to all users
|
|
||||||
*/
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
|
|
||||||
set_transanctional_email_settings();
|
|
||||||
|
|
||||||
$users = User::whereEmail('test@example.com');
|
|
||||||
foreach ($users as $user) {
|
|
||||||
Mail::send([], [], function ($message) use ($user) {
|
|
||||||
$message
|
|
||||||
->to($user->email)
|
|
||||||
->subject("Testing")
|
|
||||||
->text(
|
|
||||||
<<<EOF
|
|
||||||
Hello,
|
|
||||||
|
|
||||||
Welcome to Coolify Cloud.
|
|
||||||
Here is your user id: $user->id
|
|
||||||
|
|
||||||
EOF
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -30,5 +30,5 @@ Your horizon (Laravel scheduler): `localhost:8000/horizon` - Only reachable if y
|
|||||||
Mails are caught by Mailpit: `localhost:8025`
|
Mails are caught by Mailpit: `localhost:8025`
|
||||||
|
|
||||||
## New Service Contribution
|
## New Service Contribution
|
||||||
Check out the docs [here](https://coolify.io/docs/how-to-add-a-service).
|
Check out the docs [here](https://coolify.io/docs/resources/services/add-service).
|
||||||
|
|
||||||
|
|||||||
@@ -28,15 +28,16 @@ https://coolify.io/sponsorships
|
|||||||
|
|
||||||
Thank you so much!
|
Thank you so much!
|
||||||
|
|
||||||
Special thanks to our biggest sponsors, [CCCareers](https://cccareers.org/) and [Appwrite](https://appwrite.io)!
|
Special thanks to our biggest sponsor, [CCCareers](https://cccareers.org/)!
|
||||||
|
|
||||||
<a href="https://cccareers.org/" target="_blank"><img src="./other/logos/ccc-logo.webp" alt="cccareers logo" width="200"/></a>
|
<a href="https://cccareers.org/" target="_blank"><img src="./other/logos/ccc-logo.webp" alt="cccareers logo" width="200"/></a>
|
||||||
<a href="https://appwrite.io" target="_blank"><img src="./other/logos/appwrite.svg" alt="appwrite logo" width="200"/></a>
|
|
||||||
|
|
||||||
## Github Sponsors ($40+)
|
## Github Sponsors ($40+)
|
||||||
|
<a href="https://americancloud.com/?utm_source=coolify.io"><img src="https://github.com/American-Cloud.png" width="60px" alt="American Cloud"/></a>
|
||||||
<a href="https://cryptojobslist.com/?utm_source=coolify.io"><img src="https://github.com/cryptojobslist.png" width="60px" alt="CryptoJobsList" /></a>
|
<a href="https://cryptojobslist.com/?utm_source=coolify.io"><img src="https://github.com/cryptojobslist.png" width="60px" alt="CryptoJobsList" /></a>
|
||||||
<a href="https://typebot.io/?utm_source=coolify.io"><img src="https://pbs.twimg.com/profile_images/1509194008366657543/9I-C7uWT_400x400.jpg" width="60px" alt="typebot"/></a>
|
<a href="https://typebot.io/?utm_source=coolify.io"><img src="https://pbs.twimg.com/profile_images/1509194008366657543/9I-C7uWT_400x400.jpg" width="60px" alt="typebot"/></a>
|
||||||
<a href="https://bc.direct"><img width="60px" alt="BC Direct" src="https://github.com/coollabsio/coolify/assets/5845193/a4063c41-95ed-4a32-8814-cd1475572e37"/></a>
|
<a href="https://bc.direct"><img width="60px" alt="BC Direct" src="https://github.com/coollabsio/coolify/assets/5845193/a4063c41-95ed-4a32-8814-cd1475572e37"/></a>
|
||||||
|
<a href="https://www.uxwizz.com/?utm_source=coolify.io"><img width="60px" alt="UXWizz" src="https://github.com/UXWizz.png"/></a>
|
||||||
<a href="https://github.com/automazeio"><img src="https://github.com/automazeio.png" width="60px" alt="Corentin Clichy" /></a>
|
<a href="https://github.com/automazeio"><img src="https://github.com/automazeio.png" width="60px" alt="Corentin Clichy" /></a>
|
||||||
<a href="https://github.com/corentinclichy"><img src="https://github.com/corentinclichy.png" width="60px" alt="Corentin Clichy" /></a>
|
<a href="https://github.com/corentinclichy"><img src="https://github.com/corentinclichy.png" width="60px" alt="Corentin Clichy" /></a>
|
||||||
<a href="https://github.com/Niki2k1"><img src="https://github.com/Niki2k1.png" width="60px" alt="Niklas Lausch" /></a>
|
<a href="https://github.com/Niki2k1"><img src="https://github.com/Niki2k1.png" width="60px" alt="Niklas Lausch" /></a>
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ class StartDatabaseProxy
|
|||||||
$proxyContainerName = "{$database->uuid}-proxy";
|
$proxyContainerName = "{$database->uuid}-proxy";
|
||||||
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
||||||
$databaseType = $database->databaseType();
|
$databaseType = $database->databaseType();
|
||||||
$network = data_get($database, 'service.destination.network');
|
// $connectPredefined = data_get($database, 'service.connect_to_docker_network');
|
||||||
|
$network = $database->service->uuid;
|
||||||
$server = data_get($database, 'service.destination.server');
|
$server = data_get($database, 'service.destination.server');
|
||||||
$proxyContainerName = "{$database->service->uuid}-proxy";
|
$proxyContainerName = "{$database->service->uuid}-proxy";
|
||||||
switch ($databaseType) {
|
switch ($databaseType) {
|
||||||
@@ -124,6 +125,7 @@ class StartDatabaseProxy
|
|||||||
$dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2));
|
$dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2));
|
||||||
$nginxconf_base64 = base64_encode($nginxconf);
|
$nginxconf_base64 = base64_encode($nginxconf);
|
||||||
$dockerfile_base64 = base64_encode($dockerfile);
|
$dockerfile_base64 = base64_encode($dockerfile);
|
||||||
|
instant_remote_process(["docker rm -f $proxyContainerName"], $server, false);
|
||||||
instant_remote_process([
|
instant_remote_process([
|
||||||
"mkdir -p $configuration_dir",
|
"mkdir -p $configuration_dir",
|
||||||
"echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile",
|
"echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile",
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ class StopDatabaseProxy
|
|||||||
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database)
|
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database)
|
||||||
{
|
{
|
||||||
$server = data_get($database, 'destination.server');
|
$server = data_get($database, 'destination.server');
|
||||||
|
$uuid = $database->uuid;
|
||||||
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
||||||
|
$uuid = $database->service->uuid;
|
||||||
$server = data_get($database, 'service.server');
|
$server = data_get($database, 'service.server');
|
||||||
}
|
}
|
||||||
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $server);
|
instant_remote_process(["docker rm -f {$uuid}-proxy"], $server);
|
||||||
$database->is_public = false;
|
$database->is_public = false;
|
||||||
$database->save();
|
$database->save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ class CheckProxy
|
|||||||
$server->save();
|
$server->save();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($server->settings->is_cloudflare_tunnel) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$ip = $server->ip;
|
$ip = $server->ip;
|
||||||
if ($server->id === 0) {
|
if ($server->id === 0) {
|
||||||
$ip = 'host.docker.internal';
|
$ip = 'host.docker.internal';
|
||||||
|
|||||||
44
app/Actions/Server/ConfigureCloudflared.php
Normal file
44
app/Actions/Server/ConfigureCloudflared.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
class ConfigureCloudflared
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
public function handle(Server $server, string $cloudflare_token)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$config = [
|
||||||
|
"services" => [
|
||||||
|
"coolify-cloudflared" => [
|
||||||
|
"container_name" => "coolify-cloudflared",
|
||||||
|
"image" => "cloudflare/cloudflared:latest",
|
||||||
|
"restart" => RESTART_MODE,
|
||||||
|
"network_mode" => "host",
|
||||||
|
"command" => "tunnel run",
|
||||||
|
"environment" => [
|
||||||
|
"TUNNEL_TOKEN={$cloudflare_token}",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$config = Yaml::dump($config, 12, 2);
|
||||||
|
$docker_compose_yml_base64 = base64_encode($config);
|
||||||
|
$commands = collect([
|
||||||
|
"mkdir -p /tmp/cloudflared && cd /tmp/cloudflared",
|
||||||
|
"echo '$docker_compose_yml_base64' | base64 -d > docker-compose.yml",
|
||||||
|
"docker compose pull",
|
||||||
|
"docker compose down -v --remove-orphans > /dev/null 2>&1",
|
||||||
|
"docker compose up -d --remove-orphans",
|
||||||
|
]);
|
||||||
|
instant_remote_process($commands, $server);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ray($e);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ class InstallDocker
|
|||||||
{
|
{
|
||||||
$supported_os_type = $server->validateOS();
|
$supported_os_type = $server->validateOS();
|
||||||
if (!$supported_os_type) {
|
if (!$supported_os_type) {
|
||||||
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/servers#install-docker-engine-manually">documentation</a>.');
|
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
||||||
}
|
}
|
||||||
ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type);
|
ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type);
|
||||||
$dockerVersion = '24.0';
|
$dockerVersion = '24.0';
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ class UpdateCoolify
|
|||||||
public ?Server $server = null;
|
public ?Server $server = null;
|
||||||
public ?string $latestVersion = null;
|
public ?string $latestVersion = null;
|
||||||
public ?string $currentVersion = null;
|
public ?string $currentVersion = null;
|
||||||
|
public bool $async = false;
|
||||||
|
|
||||||
public function handle(bool $force)
|
public function handle(bool $force = false, bool $async = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$this->async = $async;
|
||||||
$settings = InstanceSettings::get();
|
$settings = InstanceSettings::get();
|
||||||
ray('Running InstanceAutoUpdateJob');
|
ray('Running InstanceAutoUpdateJob');
|
||||||
$this->server = Server::find(0);
|
$this->server = Server::find(0);
|
||||||
@@ -56,17 +58,31 @@ class UpdateCoolify
|
|||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
ray("Running update on local docker container. Updating to $this->latestVersion");
|
ray("Running update on local docker container. Updating to $this->latestVersion");
|
||||||
|
if ($this->async) {
|
||||||
|
ray('Running async update');
|
||||||
remote_process([
|
remote_process([
|
||||||
"sleep 10"
|
"sleep 10"
|
||||||
], $this->server);
|
], $this->server);
|
||||||
|
} else {
|
||||||
|
instant_remote_process([
|
||||||
|
"sleep 10"
|
||||||
|
], $this->server);
|
||||||
|
}
|
||||||
ray('Update done');
|
ray('Update done');
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
ray('Running update on production server');
|
ray('Running update on production server');
|
||||||
|
if ($this->async) {
|
||||||
remote_process([
|
remote_process([
|
||||||
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||||
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
|
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
|
||||||
], $this->server);
|
], $this->server);
|
||||||
|
} else {
|
||||||
|
instant_remote_process([
|
||||||
|
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||||
|
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
|
||||||
|
], $this->server);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class CleanupDatabase extends Command
|
|||||||
$keep_days = 60;
|
$keep_days = 60;
|
||||||
echo "Keep days: $keep_days\n";
|
echo "Keep days: $keep_days\n";
|
||||||
// Cleanup failed jobs table
|
// Cleanup failed jobs table
|
||||||
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(7));
|
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
|
||||||
$count = $failed_jobs->count();
|
$count = $failed_jobs->count();
|
||||||
echo "Delete $count entries from failed_jobs.\n";
|
echo "Delete $count entries from failed_jobs.\n";
|
||||||
if ($this->option('yes')) {
|
if ($this->option('yes')) {
|
||||||
|
|||||||
21
app/Console/Commands/Horizon.php
Normal file
21
app/Console/Commands/Horizon.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class Horizon extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'start:horizon';
|
||||||
|
protected $description = 'Start Horizon';
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if (config('coolify.is_horizon_enabled')) {
|
||||||
|
$this->info('Horizon is enabled. Starting.');
|
||||||
|
$this->call('horizon');
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,12 +34,14 @@ class Init extends Command
|
|||||||
$this->cleanup_stucked_helper_containers();
|
$this->cleanup_stucked_helper_containers();
|
||||||
$this->call('cleanup:queue');
|
$this->call('cleanup:queue');
|
||||||
$this->call('cleanup:stucked-resources');
|
$this->call('cleanup:stucked-resources');
|
||||||
|
if (!isCloud()) {
|
||||||
try {
|
try {
|
||||||
$server = Server::find(0)->first();
|
$server = Server::find(0)->first();
|
||||||
$server->setupDynamicProxyConfiguration();
|
$server->setupDynamicProxyConfiguration();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
|
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$settings = InstanceSettings::get();
|
$settings = InstanceSettings::get();
|
||||||
if (!is_null(env('AUTOUPDATE', null))) {
|
if (!is_null(env('AUTOUPDATE', null))) {
|
||||||
|
|||||||
21
app/Console/Commands/Scheduler.php
Normal file
21
app/Console/Commands/Scheduler.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class Scheduler extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'start:scheduler';
|
||||||
|
protected $description = 'Start Scheduler';
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if (config('coolify.is_scheduler_enabled')) {
|
||||||
|
$this->info('Scheduler is enabled. Starting.');
|
||||||
|
$this->call('schedule:work');
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,11 +48,9 @@ class Kernel extends ConsoleKernel
|
|||||||
$this->pull_helper_image($schedule);
|
$this->pull_helper_image($schedule);
|
||||||
$this->check_scheduled_tasks($schedule);
|
$this->check_scheduled_tasks($schedule);
|
||||||
|
|
||||||
if (!isCloud()) {
|
|
||||||
$schedule->command('cleanup:database --yes')->daily();
|
$schedule->command('cleanup:database --yes')->daily();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
private function pull_helper_image($schedule)
|
private function pull_helper_image($schedule)
|
||||||
{
|
{
|
||||||
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
|
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
|
||||||
@@ -72,43 +70,14 @@ class Kernel extends ConsoleKernel
|
|||||||
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
|
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
|
||||||
}
|
}
|
||||||
foreach ($containerServers as $server) {
|
foreach ($containerServers as $server) {
|
||||||
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
$schedule->job(new ContainerStatusJob($server))->everyTwoMinutes()->onOneServer();
|
||||||
if ($server->isLogDrainEnabled()) {
|
if ($server->isLogDrainEnabled()) {
|
||||||
$schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer();
|
$schedule->job(new CheckLogDrainContainerJob($server))->everyTwoMinutes()->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
$schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer();
|
$schedule->job(new ServerStatusJob($server))->everyTwoMinutes()->onOneServer();
|
||||||
}
|
}
|
||||||
// Delayed Jobs
|
|
||||||
// foreach ($containerServers as $server) {
|
|
||||||
// $schedule
|
|
||||||
// ->call(function () use ($server) {
|
|
||||||
// $randomSeconds = rand(1, 40);
|
|
||||||
// $job = new ContainerStatusJob($server);
|
|
||||||
// $job->delay($randomSeconds);
|
|
||||||
// ray('dispatching container status job in ' . $randomSeconds . ' seconds');
|
|
||||||
// dispatch($job);
|
|
||||||
// })->name('container-status-' . $server->id)->everyMinute()->onOneServer();
|
|
||||||
// if ($server->isLogDrainEnabled()) {
|
|
||||||
// $schedule
|
|
||||||
// ->call(function () use ($server) {
|
|
||||||
// $randomSeconds = rand(1, 40);
|
|
||||||
// $job = new CheckLogDrainContainerJob($server);
|
|
||||||
// $job->delay($randomSeconds);
|
|
||||||
// dispatch($job);
|
|
||||||
// })->name('log-drain-container-check-' . $server->id)->everyMinute()->onOneServer();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// foreach ($servers as $server) {
|
|
||||||
// $schedule
|
|
||||||
// ->call(function () use ($server) {
|
|
||||||
// $randomSeconds = rand(1, 40);
|
|
||||||
// $job = new ServerStatusJob($server);
|
|
||||||
// $job->delay($randomSeconds);
|
|
||||||
// dispatch($job);
|
|
||||||
// })->name('server-status-job-' . $server->id)->everyMinute()->onOneServer();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
private function instance_auto_update($schedule)
|
private function instance_auto_update($schedule)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Deploy extends Controller
|
|||||||
$force = $request->query->get('force') ?? false;
|
$force = $request->query->get('force') ?? false;
|
||||||
|
|
||||||
if ($uuids && $tags) {
|
if ($uuids && $tags) {
|
||||||
return response()->json(['error' => 'You can only use uuid or tag, not both.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
return response()->json(['error' => 'You can only use uuid or tag, not both.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
|
||||||
}
|
}
|
||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
return invalid_token();
|
return invalid_token();
|
||||||
@@ -54,7 +54,7 @@ class Deploy extends Controller
|
|||||||
} else if ($uuids) {
|
} else if ($uuids) {
|
||||||
return $this->by_uuids($uuids, $teamId, $force);
|
return $this->by_uuids($uuids, $teamId, $force);
|
||||||
}
|
}
|
||||||
return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
|
||||||
}
|
}
|
||||||
private function by_uuids(string $uuid, int $teamId, bool $force = false)
|
private function by_uuids(string $uuid, int $teamId, bool $force = false)
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ class Deploy extends Controller
|
|||||||
$uuids = collect(array_filter($uuids));
|
$uuids = collect(array_filter($uuids));
|
||||||
|
|
||||||
if (count($uuids) === 0) {
|
if (count($uuids) === 0) {
|
||||||
return response()->json(['error' => 'No UUIDs provided.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
return response()->json(['error' => 'No UUIDs provided.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
|
||||||
}
|
}
|
||||||
$deployments = collect();
|
$deployments = collect();
|
||||||
$payload = collect();
|
$payload = collect();
|
||||||
@@ -81,7 +81,7 @@ class Deploy extends Controller
|
|||||||
$payload->put('deployments', $deployments->toArray());
|
$payload->put('deployments', $deployments->toArray());
|
||||||
return response()->json($payload->toArray(), 200);
|
return response()->json($payload->toArray(), 200);
|
||||||
}
|
}
|
||||||
return response()->json(['error' => "No resources found.", 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
|
return response()->json(['error' => "No resources found.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404);
|
||||||
}
|
}
|
||||||
public function by_tags(string $tags, int $team_id, bool $force = false)
|
public function by_tags(string $tags, int $team_id, bool $force = false)
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@ class Deploy extends Controller
|
|||||||
$tags = collect(array_filter($tags));
|
$tags = collect(array_filter($tags));
|
||||||
|
|
||||||
if (count($tags) === 0) {
|
if (count($tags) === 0) {
|
||||||
return response()->json(['error' => 'No TAGs provided.', 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 400);
|
return response()->json(['error' => 'No TAGs provided.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400);
|
||||||
}
|
}
|
||||||
$message = collect([]);
|
$message = collect([]);
|
||||||
$deployments = collect();
|
$deployments = collect();
|
||||||
@@ -127,7 +127,7 @@ class Deploy extends Controller
|
|||||||
return response()->json($payload->toArray(), 200);
|
return response()->json($payload->toArray(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['error' => "No resources found with this tag.", 'docs' => 'https://coolify.io/docs/api/deploy-webhook'], 404);
|
return response()->json(['error' => "No resources found with this tag.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404);
|
||||||
}
|
}
|
||||||
public function deploy_resource($resource, bool $force = false): array
|
public function deploy_resource($resource, bool $force = false): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class Team extends Controller
|
|||||||
$teams = auth()->user()->teams;
|
$teams = auth()->user()->teams;
|
||||||
$team = $teams->where('id', $id)->first();
|
$team = $teams->where('id', $id)->first();
|
||||||
if (is_null($team)) {
|
if (is_null($team)) {
|
||||||
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api/team-by-id"], 404);
|
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid"], 404);
|
||||||
}
|
}
|
||||||
return response()->json($team);
|
return response()->json($team);
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ class Team extends Controller
|
|||||||
$teams = auth()->user()->teams;
|
$teams = auth()->user()->teams;
|
||||||
$team = $teams->where('id', $id)->first();
|
$team = $teams->where('id', $id)->first();
|
||||||
if (is_null($team)) {
|
if (is_null($team)) {
|
||||||
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api/team-by-id-members"], 404);
|
return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid-members"], 404);
|
||||||
}
|
}
|
||||||
return response()->json($team->members);
|
return response()->json($team->members);
|
||||||
}
|
}
|
||||||
|
|||||||
35
app/Http/Controllers/OauthController.php
Normal file
35
app/Http/Controllers/OauthController.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class OauthController extends Controller {
|
||||||
|
public function redirect(string $provider)
|
||||||
|
{
|
||||||
|
$socialite_provider = get_socialite_provider($provider);
|
||||||
|
return $socialite_provider->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callback(string $provider)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$oauthUser = get_socialite_provider($provider)->user();
|
||||||
|
$user = User::whereEmail($oauthUser->email)->first();
|
||||||
|
if (!$user) {
|
||||||
|
$user = User::create([
|
||||||
|
'name' => $oauthUser->name,
|
||||||
|
'email' => $oauthUser->email,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
Auth::login($user);
|
||||||
|
return redirect('/');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
ray($e->getMessage());
|
||||||
|
return redirect()->route('login')->withErrors([__('auth.failed.callback')]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,6 @@ class Github extends Controller
|
|||||||
public function manual(Request $request)
|
public function manual(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ray($request);
|
|
||||||
$return_payloads = collect([]);
|
$return_payloads = collect([]);
|
||||||
$x_github_delivery = request()->header('X-GitHub-Delivery');
|
$x_github_delivery = request()->header('X-GitHub-Delivery');
|
||||||
if (app()->isDownForMaintenance()) {
|
if (app()->isDownForMaintenance()) {
|
||||||
@@ -68,6 +67,10 @@ class Github extends Controller
|
|||||||
if (Str::isMatch('/refs\/heads\/*/', $branch)) {
|
if (Str::isMatch('/refs\/heads\/*/', $branch)) {
|
||||||
$branch = Str::after($branch, 'refs/heads/');
|
$branch = Str::after($branch, 'refs/heads/');
|
||||||
}
|
}
|
||||||
|
$added_files = data_get($payload, 'commits.*.added');
|
||||||
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Manual Webhook GitHub Push Event with branch: ' . $branch);
|
ray('Manual Webhook GitHub Push Event with branch: ' . $branch);
|
||||||
}
|
}
|
||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
@@ -118,6 +121,8 @@ class Github extends Controller
|
|||||||
}
|
}
|
||||||
if ($x_github_event === 'push') {
|
if ($x_github_event === 'push') {
|
||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2(7);
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
@@ -127,15 +132,30 @@ class Github extends Controller
|
|||||||
is_webhook: true,
|
is_webhook: true,
|
||||||
);
|
);
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'message' => 'Deployment queued.',
|
'message' => 'Deployment queued.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
|
} else {
|
||||||
|
$paths = str($application->watch_paths)->explode("\n");
|
||||||
|
$return_payloads->push([
|
||||||
|
'status' => 'failed',
|
||||||
|
'message' => 'Changed files do not match watch paths. Ignoring deployment.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
|
'details' => [
|
||||||
|
'changed_files' => $changed_files,
|
||||||
|
'watch_paths' => $paths,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Deployments disabled.',
|
'message' => 'Deployments disabled.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,6 +286,10 @@ class Github extends Controller
|
|||||||
if (Str::isMatch('/refs\/heads\/*/', $branch)) {
|
if (Str::isMatch('/refs\/heads\/*/', $branch)) {
|
||||||
$branch = Str::after($branch, 'refs/heads/');
|
$branch = Str::after($branch, 'refs/heads/');
|
||||||
}
|
}
|
||||||
|
$added_files = data_get($payload, 'commits.*.added');
|
||||||
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Webhook GitHub Push Event: ' . $id . ' with branch: ' . $branch);
|
ray('Webhook GitHub Push Event: ' . $id . ' with branch: ' . $branch);
|
||||||
}
|
}
|
||||||
if ($x_github_event === 'pull_request') {
|
if ($x_github_event === 'pull_request') {
|
||||||
@@ -298,32 +322,50 @@ class Github extends Controller
|
|||||||
$isFunctional = $application->destination->server->isFunctional();
|
$isFunctional = $application->destination->server->isFunctional();
|
||||||
if (!$isFunctional) {
|
if (!$isFunctional) {
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Server is not functional.',
|
'message' => 'Server is not functional.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($x_github_event === 'push') {
|
if ($x_github_event === 'push') {
|
||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2(7);
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
force_rebuild: false,
|
force_rebuild: false,
|
||||||
is_webhook: true
|
is_webhook: true,
|
||||||
);
|
);
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'message' => 'Deployment queued.',
|
'message' => 'Deployment queued.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
|
} else {
|
||||||
|
$paths = str($application->watch_paths)->explode("\n");
|
||||||
|
$return_payloads->push([
|
||||||
|
'status' => 'failed',
|
||||||
|
'message' => 'Changed files do not match watch paths. Ignoring deployment.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
|
'details' => [
|
||||||
|
'changed_files' => $changed_files,
|
||||||
|
'watch_paths' => $paths,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Deployments disabled.',
|
'message' => 'Deployments disabled.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ class Gitlab extends Controller
|
|||||||
]);
|
]);
|
||||||
return response($return_payloads);
|
return response($return_payloads);
|
||||||
}
|
}
|
||||||
|
$added_files = data_get($payload, 'commits.*.added');
|
||||||
|
$removed_files = data_get($payload, 'commits.*.removed');
|
||||||
|
$modified_files = data_get($payload, 'commits.*.modified');
|
||||||
|
$changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
|
||||||
ray('Manual Webhook GitLab Push Event with branch: ' . $branch);
|
ray('Manual Webhook GitLab Push Event with branch: ' . $branch);
|
||||||
}
|
}
|
||||||
if ($x_gitlab_event === 'merge_request') {
|
if ($x_gitlab_event === 'merge_request') {
|
||||||
@@ -113,19 +117,41 @@ class Gitlab extends Controller
|
|||||||
}
|
}
|
||||||
if ($x_gitlab_event === 'push') {
|
if ($x_gitlab_event === 'push') {
|
||||||
if ($application->isDeployable()) {
|
if ($application->isDeployable()) {
|
||||||
|
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||||
|
if ($is_watch_path_triggered || is_null($application->watch_paths)) {
|
||||||
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
ray('Deploying ' . $application->name . ' with branch ' . $branch);
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2(7);
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
application: $application,
|
application: $application,
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
force_rebuild: false,
|
force_rebuild: false,
|
||||||
is_webhook: true
|
is_webhook: true,
|
||||||
);
|
);
|
||||||
|
$return_payloads->push([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => 'Deployment queued.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$paths = str($application->watch_paths)->explode("\n");
|
||||||
|
$return_payloads->push([
|
||||||
|
'status' => 'failed',
|
||||||
|
'message' => 'Changed files do not match watch paths. Ignoring deployment.',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
|
'details' => [
|
||||||
|
'changed_files' => $changed_files,
|
||||||
|
'watch_paths' => $paths,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Deployments disabled',
|
'message' => 'Deployments disabled',
|
||||||
|
'application_uuid' => $application->uuid,
|
||||||
|
'application_name' => $application->name,
|
||||||
]);
|
]);
|
||||||
ray('Deployments disabled for ' . $application->name);
|
ray('Deployments disabled for ' . $application->name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->build_server = $this->server;
|
$this->build_server = $this->server;
|
||||||
$this->original_server = $this->server;
|
$this->original_server = $this->server;
|
||||||
}
|
}
|
||||||
if ($this->restart_only && $this->application->build_pack !== 'dockerimage') {
|
if ($this->restart_only && $this->application->build_pack !== 'dockerimage' && $this->application->build_pack !== 'dockerfile') {
|
||||||
$this->just_restart();
|
$this->just_restart();
|
||||||
if ($this->server->isProxyShouldRun()) {
|
if ($this->server->isProxyShouldRun()) {
|
||||||
dispatch(new ContainerStatusJob($this->server));
|
dispatch(new ContainerStatusJob($this->server));
|
||||||
@@ -298,6 +298,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
"ignore_errors" => true,
|
"ignore_errors" => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// $this->execute_remote_command(
|
// $this->execute_remote_command(
|
||||||
// [
|
// [
|
||||||
// "docker image prune -f >/dev/null 2>&1",
|
// "docker image prune -f >/dev/null 2>&1",
|
||||||
@@ -305,6 +307,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
// "ignore_errors" => true,
|
// "ignore_errors" => true,
|
||||||
// ]
|
// ]
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
|
||||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,17 +326,19 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
if (!$this->force_rebuild) {
|
|
||||||
$this->check_image_locally_or_remotely();
|
// Always rebuild dockerfile based container.
|
||||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
// if (!$this->force_rebuild) {
|
||||||
$this->create_workdir();
|
// $this->check_image_locally_or_remotely();
|
||||||
$this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
// if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
$this->generate_compose_file();
|
// $this->create_workdir();
|
||||||
$this->push_to_docker_registry();
|
// $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
||||||
$this->rolling_update();
|
// $this->generate_compose_file();
|
||||||
return;
|
// $this->push_to_docker_registry();
|
||||||
}
|
// $this->rolling_update();
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->generate_build_env_variables();
|
$this->generate_build_env_variables();
|
||||||
$this->add_build_env_variables_to_dockerfile();
|
$this->add_build_env_variables_to_dockerfile();
|
||||||
@@ -417,7 +423,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
"docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true
|
"docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$this->write_deployment_configurations();
|
|
||||||
|
|
||||||
// Start compose file
|
// Start compose file
|
||||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
@@ -425,7 +430,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), "hidden" => true],
|
||||||
);
|
);
|
||||||
|
$this->write_deployment_configurations();
|
||||||
} else {
|
} else {
|
||||||
|
$this->write_deployment_configurations();
|
||||||
$server_workdir = $this->application->workdir();
|
$server_workdir = $this->application->workdir();
|
||||||
ray("SOURCE_COMMIT={$this->commit} docker compose --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d");
|
ray("SOURCE_COMMIT={$this->commit} docker compose --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d");
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
@@ -437,14 +444,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), "hidden" => true],
|
||||||
);
|
);
|
||||||
|
$this->write_deployment_configurations();
|
||||||
} else {
|
} else {
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
|
||||||
);
|
);
|
||||||
|
$this->write_deployment_configurations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->application_deployment_queue->addLogEntry("New container started.");
|
$this->application_deployment_queue->addLogEntry("New container started.");
|
||||||
}
|
}
|
||||||
private function deploy_dockerfile_buildpack()
|
private function deploy_dockerfile_buildpack()
|
||||||
@@ -461,17 +469,17 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
$this->clone_repository();
|
$this->clone_repository();
|
||||||
if (!$this->force_rebuild) {
|
// if (!$this->force_rebuild) {
|
||||||
$this->check_image_locally_or_remotely();
|
// $this->check_image_locally_or_remotely();
|
||||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
// if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
$this->create_workdir();
|
// $this->create_workdir();
|
||||||
$this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
// $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
|
||||||
$this->generate_compose_file();
|
// $this->generate_compose_file();
|
||||||
$this->push_to_docker_registry();
|
// $this->push_to_docker_registry();
|
||||||
$this->rolling_update();
|
// $this->rolling_update();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->generate_build_env_variables();
|
$this->generate_build_env_variables();
|
||||||
@@ -731,7 +739,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
|
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
|
||||||
}
|
}
|
||||||
if ($nixpacks_php_fallback_path?->value === '/index.php' && $nixpacks_php_root_dir?->value === '/app/public' && $this->newVersionIsHealthy === false) {
|
if ($nixpacks_php_fallback_path?->value === '/index.php' && $nixpacks_php_root_dir?->value === '/app/public' && $this->newVersionIsHealthy === false) {
|
||||||
$this->application_deployment_queue->addLogEntry("There was a change in how Laravel is deployed. Please update your environment variables to match the new deployment method. More details here: https://coolify.io/docs/frameworks/laravel#requirements", 'stderr');
|
$this->application_deployment_queue->addLogEntry("There was a change in how Laravel is deployed. Please update your environment variables to match the new deployment method. More details here: https://coolify.io/docs/resources/laravel", 'stderr');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function rolling_update()
|
private function rolling_update()
|
||||||
@@ -822,6 +830,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
private function deploy_pull_request()
|
private function deploy_pull_request()
|
||||||
{
|
{
|
||||||
|
if ($this->application->build_pack === 'dockercompose') {
|
||||||
|
$this->deploy_docker_compose_buildpack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
@@ -888,6 +900,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if ($this->application->additional_networks->count() === 0) {
|
if ($this->application->additional_networks->count() === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ($this->pull_request_id !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$destination_ids = $this->application->additional_networks->pluck('id');
|
$destination_ids = $this->application->additional_networks->pluck('id');
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
$this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode.");
|
$this->application_deployment_queue->addLogEntry("Additional destinations are not supported in swarm mode.");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Actions\Proxy\StartProxy;
|
|||||||
use App\Actions\Shared\ComplexStatusCheck;
|
use App\Actions\Shared\ComplexStatusCheck;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\ServiceDatabase;
|
||||||
use App\Notifications\Container\ContainerRestarted;
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
use App\Notifications\Container\ContainerStopped;
|
use App\Notifications\Container\ContainerStopped;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
@@ -149,7 +150,32 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$uuid = data_get($labels, 'com.docker.compose.service');
|
$uuid = data_get($labels, 'com.docker.compose.service');
|
||||||
|
$type = data_get($labels, 'coolify.type');
|
||||||
|
|
||||||
if ($uuid) {
|
if ($uuid) {
|
||||||
|
if ($type === 'service') {
|
||||||
|
$database_id = data_get($labels, 'coolify.service.subId');
|
||||||
|
if ($database_id) {
|
||||||
|
$service_db = ServiceDatabase::where('id', $database_id)->first();
|
||||||
|
if ($service_db) {
|
||||||
|
$uuid = $service_db->service->uuid;
|
||||||
|
$isPublic = data_get($service_db, 'is_public');
|
||||||
|
if ($isPublic) {
|
||||||
|
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
|
} else {
|
||||||
|
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||||
|
}
|
||||||
|
})->first();
|
||||||
|
if (!$foundTcpProxy) {
|
||||||
|
StartDatabaseProxy::run($service_db);
|
||||||
|
// $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$database = $databases->where('uuid', $uuid)->first();
|
$database = $databases->where('uuid', $uuid)->first();
|
||||||
if ($database) {
|
if ($database) {
|
||||||
$isPublic = data_get($database, 'is_public');
|
$isPublic = data_get($database, 'is_public');
|
||||||
@@ -175,6 +201,8 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
// Notify user that this container should not be there.
|
// Notify user that this container should not be there.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
if (data_get($container, 'Name') === '/coolify-db') {
|
if (data_get($container, 'Name') === '/coolify-db') {
|
||||||
$foundDatabases[] = 0;
|
$foundDatabases[] = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$databaseType = $this->database->databaseType();
|
$databaseType = $this->database->databaseType();
|
||||||
$serviceUuid = $this->database->service->uuid;
|
$serviceUuid = $this->database->service->uuid;
|
||||||
$serviceName = str($this->database->service->name)->slug();
|
$serviceName = str($this->database->service->name)->slug();
|
||||||
if ($databaseType === 'standalone-postgresql') {
|
if (str($databaseType)->contains('postgres')) {
|
||||||
$this->container_name = "{$this->database->name}-$serviceUuid";
|
$this->container_name = "{$this->database->name}-$serviceUuid";
|
||||||
$this->directory_name = $serviceName . '-' . $this->container_name;
|
$this->directory_name = $serviceName . '-' . $this->container_name;
|
||||||
$commands[] = "docker exec $this->container_name env | grep POSTGRES_";
|
$commands[] = "docker exec $this->container_name env | grep POSTGRES_";
|
||||||
@@ -120,7 +120,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} else {
|
} else {
|
||||||
$databasesToBackup = $this->database->postgres_user;
|
$databasesToBackup = $this->database->postgres_user;
|
||||||
}
|
}
|
||||||
} else if ($databaseType === 'standalone-mysql') {
|
} else if (str($databaseType)->contains('mysql')) {
|
||||||
$this->container_name = "{$this->database->name}-$serviceUuid";
|
$this->container_name = "{$this->database->name}-$serviceUuid";
|
||||||
$this->directory_name = $serviceName . '-' . $this->container_name;
|
$this->directory_name = $serviceName . '-' . $this->container_name;
|
||||||
$commands[] = "docker exec $this->container_name env | grep MYSQL_";
|
$commands[] = "docker exec $this->container_name env | grep MYSQL_";
|
||||||
@@ -143,7 +143,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} else {
|
} else {
|
||||||
throw new \Exception('MYSQL_DATABASE not found');
|
throw new \Exception('MYSQL_DATABASE not found');
|
||||||
}
|
}
|
||||||
} else if ($databaseType === 'standalone-mariadb') {
|
} else if (str($databaseType)->contains('mariadb')) {
|
||||||
$this->container_name = "{$this->database->name}-$serviceUuid";
|
$this->container_name = "{$this->database->name}-$serviceUuid";
|
||||||
$this->directory_name = $serviceName . '-' . $this->container_name;
|
$this->directory_name = $serviceName . '-' . $this->container_name;
|
||||||
$commands[] = "docker exec $this->container_name env";
|
$commands[] = "docker exec $this->container_name env";
|
||||||
@@ -190,32 +190,32 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($databasesToBackup)) {
|
if (is_null($databasesToBackup)) {
|
||||||
if ($databaseType === 'standalone-postgresql') {
|
if (str($databaseType)->contains('postgres')) {
|
||||||
$databasesToBackup = [$this->database->postgres_db];
|
$databasesToBackup = [$this->database->postgres_db];
|
||||||
} else if ($databaseType === 'standalone-mongodb') {
|
} else if (str($databaseType)->contains('mongodb')) {
|
||||||
$databasesToBackup = ['*'];
|
$databasesToBackup = ['*'];
|
||||||
} else if ($databaseType === 'standalone-mysql') {
|
} else if (str($databaseType)->contains('mysql')) {
|
||||||
$databasesToBackup = [$this->database->mysql_database];
|
$databasesToBackup = [$this->database->mysql_database];
|
||||||
} else if ($databaseType === 'standalone-mariadb') {
|
} else if (str($databaseType)->contains('mariadb')) {
|
||||||
$databasesToBackup = [$this->database->mariadb_database];
|
$databasesToBackup = [$this->database->mariadb_database];
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($databaseType === 'standalone-postgresql') {
|
if (str($databaseType)->contains('postgres')) {
|
||||||
// Format: db1,db2,db3
|
// Format: db1,db2,db3
|
||||||
$databasesToBackup = explode(',', $databasesToBackup);
|
$databasesToBackup = explode(',', $databasesToBackup);
|
||||||
$databasesToBackup = array_map('trim', $databasesToBackup);
|
$databasesToBackup = array_map('trim', $databasesToBackup);
|
||||||
} else if ($databaseType === 'standalone-mongodb') {
|
} else if (str($databaseType)->contains('mongodb')) {
|
||||||
// Format: db1:collection1,collection2|db2:collection3,collection4
|
// Format: db1:collection1,collection2|db2:collection3,collection4
|
||||||
$databasesToBackup = explode('|', $databasesToBackup);
|
$databasesToBackup = explode('|', $databasesToBackup);
|
||||||
$databasesToBackup = array_map('trim', $databasesToBackup);
|
$databasesToBackup = array_map('trim', $databasesToBackup);
|
||||||
ray($databasesToBackup);
|
ray($databasesToBackup);
|
||||||
} else if ($databaseType === 'standalone-mysql') {
|
} else if (str($databaseType)->contains('mysql')) {
|
||||||
// Format: db1,db2,db3
|
// Format: db1,db2,db3
|
||||||
$databasesToBackup = explode(',', $databasesToBackup);
|
$databasesToBackup = explode(',', $databasesToBackup);
|
||||||
$databasesToBackup = array_map('trim', $databasesToBackup);
|
$databasesToBackup = array_map('trim', $databasesToBackup);
|
||||||
} else if ($databaseType === 'standalone-mariadb') {
|
} else if (str($databaseType)->contains('mariadb')) {
|
||||||
// Format: db1,db2,db3
|
// Format: db1,db2,db3
|
||||||
$databasesToBackup = explode(',', $databasesToBackup);
|
$databasesToBackup = explode(',', $databasesToBackup);
|
||||||
$databasesToBackup = array_map('trim', $databasesToBackup);
|
$databasesToBackup = array_map('trim', $databasesToBackup);
|
||||||
@@ -235,7 +235,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$size = 0;
|
$size = 0;
|
||||||
ray('Backing up ' . $database);
|
ray('Backing up ' . $database);
|
||||||
try {
|
try {
|
||||||
if ($databaseType === 'standalone-postgresql') {
|
if (str($databaseType)->contains('postgres')) {
|
||||||
$this->backup_file = "/pg-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
$this->backup_file = "/pg-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
||||||
$this->backup_location = $this->backup_dir . $this->backup_file;
|
$this->backup_location = $this->backup_dir . $this->backup_file;
|
||||||
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
||||||
@@ -244,7 +244,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
'scheduled_database_backup_id' => $this->backup->id,
|
'scheduled_database_backup_id' => $this->backup->id,
|
||||||
]);
|
]);
|
||||||
$this->backup_standalone_postgresql($database);
|
$this->backup_standalone_postgresql($database);
|
||||||
} else if ($databaseType === 'standalone-mongodb') {
|
} else if (str($databaseType)->contains('mongodb')) {
|
||||||
if ($database === '*') {
|
if ($database === '*') {
|
||||||
$database = 'all';
|
$database = 'all';
|
||||||
$databaseName = 'all';
|
$databaseName = 'all';
|
||||||
@@ -263,7 +263,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
'scheduled_database_backup_id' => $this->backup->id,
|
'scheduled_database_backup_id' => $this->backup->id,
|
||||||
]);
|
]);
|
||||||
$this->backup_standalone_mongodb($database);
|
$this->backup_standalone_mongodb($database);
|
||||||
} else if ($databaseType === 'standalone-mysql') {
|
} else if (str($databaseType)->contains('mysql')) {
|
||||||
$this->backup_file = "/mysql-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
$this->backup_file = "/mysql-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
||||||
$this->backup_location = $this->backup_dir . $this->backup_file;
|
$this->backup_location = $this->backup_dir . $this->backup_file;
|
||||||
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
||||||
@@ -272,7 +272,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
'scheduled_database_backup_id' => $this->backup->id,
|
'scheduled_database_backup_id' => $this->backup->id,
|
||||||
]);
|
]);
|
||||||
$this->backup_standalone_mysql($database);
|
$this->backup_standalone_mysql($database);
|
||||||
} else if ($databaseType === 'standalone-mariadb') {
|
} else if (str($databaseType)->contains('mariadb')) {
|
||||||
$this->backup_file = "/mariadb-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
$this->backup_file = "/mariadb-dump-$database-" . Carbon::now()->timestamp . ".dmp";
|
||||||
$this->backup_location = $this->backup_dir . $this->backup_file;
|
$this->backup_location = $this->backup_dir . $this->backup_file;
|
||||||
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ class InstanceAutoUpdateJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncr
|
|||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
UpdateCoolify::run($this->force);
|
UpdateCoolify::run(force: $this->force, async: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class ActivityMonitor extends Component
|
|||||||
public $activityId;
|
public $activityId;
|
||||||
public $eventToDispatch = 'activityFinished';
|
public $eventToDispatch = 'activityFinished';
|
||||||
public $isPollingActive = false;
|
public $isPollingActive = false;
|
||||||
|
public bool $showWaiting = false;
|
||||||
|
|
||||||
protected $activity;
|
protected $activity;
|
||||||
protected $listeners = ['activityMonitor' => 'newMonitorActivity'];
|
protected $listeners = ['activityMonitor' => 'newMonitorActivity'];
|
||||||
|
|||||||
@@ -8,7 +8,31 @@ use Livewire\Component;
|
|||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public $users = [];
|
public $active_subscribers = [];
|
||||||
|
public $inactive_subscribers = [];
|
||||||
|
public $search = '';
|
||||||
|
public function submitSearch() {
|
||||||
|
if ($this->search !== "") {
|
||||||
|
$this->inactive_subscribers = User::whereDoesntHave('teams', function ($query) {
|
||||||
|
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
||||||
|
})->where(function ($query) {
|
||||||
|
$query->where('name', 'like', "%{$this->search}%")
|
||||||
|
->orWhere('email', 'like', "%{$this->search}%");
|
||||||
|
})->get()->filter(function ($user) {
|
||||||
|
return $user->id !== 0;
|
||||||
|
});
|
||||||
|
$this->active_subscribers = User::whereHas('teams', function ($query) {
|
||||||
|
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
||||||
|
})->where(function ($query) {
|
||||||
|
$query->where('name', 'like', "%{$this->search}%")
|
||||||
|
->orWhere('email', 'like', "%{$this->search}%");
|
||||||
|
})->get()->filter(function ($user) {
|
||||||
|
return $user->id !== 0;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$this->getSubscribers();
|
||||||
|
}
|
||||||
|
}
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
if (!isCloud()) {
|
if (!isCloud()) {
|
||||||
@@ -17,7 +41,15 @@ class Index extends Component
|
|||||||
if (auth()->user()->id !== 0) {
|
if (auth()->user()->id !== 0) {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
$this->users = User::whereHas('teams', function ($query) {
|
$this->getSubscribers();
|
||||||
|
}
|
||||||
|
public function getSubscribers() {
|
||||||
|
$this->inactive_subscribers = User::whereDoesntHave('teams', function ($query) {
|
||||||
|
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
||||||
|
})->get()->filter(function ($user) {
|
||||||
|
return $user->id !== 0;
|
||||||
|
});
|
||||||
|
$this->active_subscribers = User::whereHas('teams', function ($query) {
|
||||||
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
$query->whereRelation('subscription', 'stripe_subscription_id', '!=', null);
|
||||||
})->get()->filter(function ($user) {
|
})->get()->filter(function ($user) {
|
||||||
return $user->id !== 0;
|
return $user->id !== 0;
|
||||||
|
|||||||
@@ -2,22 +2,24 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Boarding;
|
namespace App\Livewire\Boarding;
|
||||||
|
|
||||||
use App\Actions\Server\InstallDocker;
|
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Url;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
protected $listeners = ['serverInstalled' => 'validateServer'];
|
protected $listeners = ['serverInstalled' => 'validateServer'];
|
||||||
|
|
||||||
public string $currentState = 'welcome';
|
public string $currentState = 'welcome';
|
||||||
|
|
||||||
public ?string $selectedServerType = null;
|
public ?string $selectedServerType = null;
|
||||||
public ?Collection $privateKeys = null;
|
public ?Collection $privateKeys = null;
|
||||||
|
|
||||||
public ?int $selectedExistingPrivateKey = null;
|
public ?int $selectedExistingPrivateKey = null;
|
||||||
public ?string $privateKeyType = null;
|
public ?string $privateKeyType = null;
|
||||||
public ?string $privateKey = null;
|
public ?string $privateKey = null;
|
||||||
@@ -27,6 +29,7 @@ class Index extends Component
|
|||||||
public ?PrivateKey $createdPrivateKey = null;
|
public ?PrivateKey $createdPrivateKey = null;
|
||||||
|
|
||||||
public ?Collection $servers = null;
|
public ?Collection $servers = null;
|
||||||
|
|
||||||
public ?int $selectedExistingServer = null;
|
public ?int $selectedExistingServer = null;
|
||||||
public ?string $remoteServerName = null;
|
public ?string $remoteServerName = null;
|
||||||
public ?string $remoteServerDescription = null;
|
public ?string $remoteServerDescription = null;
|
||||||
@@ -38,7 +41,8 @@ class Index extends Component
|
|||||||
public ?Server $createdServer = null;
|
public ?Server $createdServer = null;
|
||||||
|
|
||||||
public Collection $projects;
|
public Collection $projects;
|
||||||
public ?int $selectedExistingProject = null;
|
|
||||||
|
public ?int $selectedProject = null;
|
||||||
public ?Project $createdProject = null;
|
public ?Project $createdProject = null;
|
||||||
|
|
||||||
public bool $dockerInstallationStarted = false;
|
public bool $dockerInstallationStarted = false;
|
||||||
@@ -62,6 +66,26 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->remoteServerDescription = 'Created by Coolify';
|
$this->remoteServerDescription = 'Created by Coolify';
|
||||||
$this->remoteServerHost = 'coolify-testing-host';
|
$this->remoteServerHost = 'coolify-testing-host';
|
||||||
}
|
}
|
||||||
|
// if ($this->currentState === 'create-project') {
|
||||||
|
// $this->getProjects();
|
||||||
|
// }
|
||||||
|
// if ($this->currentState === 'create-resource') {
|
||||||
|
// $this->selectExistingServer();
|
||||||
|
// $this->selectExistingProject();
|
||||||
|
// }
|
||||||
|
// if ($this->currentState === 'private-key') {
|
||||||
|
// $this->setServerType('remote');
|
||||||
|
// }
|
||||||
|
// if ($this->currentState === 'create-server') {
|
||||||
|
// $this->selectExistingPrivateKey();
|
||||||
|
// }
|
||||||
|
// if ($this->currentState === 'validate-server') {
|
||||||
|
// $this->selectExistingServer();
|
||||||
|
// }
|
||||||
|
// if ($this->currentState === 'select-existing-server') {
|
||||||
|
// $this->selectExistingServer();
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
public function explanation()
|
public function explanation()
|
||||||
{
|
{
|
||||||
@@ -89,6 +113,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->selectedServerType = $type;
|
$this->selectedServerType = $type;
|
||||||
if ($this->selectedServerType === 'localhost') {
|
if ($this->selectedServerType === 'localhost') {
|
||||||
$this->createdServer = Server::find(0);
|
$this->createdServer = Server::find(0);
|
||||||
|
$this->selectedExistingServer = 0;
|
||||||
if (!$this->createdServer) {
|
if (!$this->createdServer) {
|
||||||
return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
||||||
}
|
}
|
||||||
@@ -137,6 +162,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
}
|
}
|
||||||
public function selectExistingPrivateKey()
|
public function selectExistingPrivateKey()
|
||||||
{
|
{
|
||||||
|
if (is_null($this->selectedExistingPrivateKey)) {
|
||||||
|
$this->restartBoarding();
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
|
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
|
||||||
$this->privateKey = $this->createdPrivateKey->private_key;
|
$this->privateKey = $this->createdPrivateKey->private_key;
|
||||||
$this->currentState = 'create-server';
|
$this->currentState = 'create-server';
|
||||||
@@ -196,6 +225,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
||||||
$this->createdServer->settings->save();
|
$this->createdServer->settings->save();
|
||||||
$this->createdServer->addInitialNetwork();
|
$this->createdServer->addInitialNetwork();
|
||||||
|
$this->selectedExistingServer = $this->createdServer->id;
|
||||||
$this->currentState = 'validate-server';
|
$this->currentState = 'validate-server';
|
||||||
}
|
}
|
||||||
public function installServer()
|
public function installServer()
|
||||||
@@ -249,13 +279,13 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
{
|
{
|
||||||
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
|
$this->projects = Project::ownedByCurrentTeam(['name'])->get();
|
||||||
if ($this->projects->count() > 0) {
|
if ($this->projects->count() > 0) {
|
||||||
$this->selectedExistingProject = $this->projects->first()->id;
|
$this->selectedProject = $this->projects->first()->id;
|
||||||
}
|
}
|
||||||
$this->currentState = 'create-project';
|
$this->currentState = 'create-project';
|
||||||
}
|
}
|
||||||
public function selectExistingProject()
|
public function selectExistingProject()
|
||||||
{
|
{
|
||||||
$this->createdProject = Project::find($this->selectedExistingProject);
|
$this->createdProject = Project::find($this->selectedProject);
|
||||||
$this->currentState = 'create-resource';
|
$this->currentState = 'create-resource';
|
||||||
}
|
}
|
||||||
public function createNewProject()
|
public function createNewProject()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -13,9 +14,11 @@ class Dashboard extends Component
|
|||||||
{
|
{
|
||||||
public $projects = [];
|
public $projects = [];
|
||||||
public Collection $servers;
|
public Collection $servers;
|
||||||
|
public Collection $private_keys;
|
||||||
public $deployments_per_server;
|
public $deployments_per_server;
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
$this->private_keys = PrivateKey::ownedByCurrentTeam()->get();
|
||||||
$this->servers = Server::ownedByCurrentTeam()->get();
|
$this->servers = Server::ownedByCurrentTeam()->get();
|
||||||
$this->projects = Project::ownedByCurrentTeam()->get();
|
$this->projects = Project::ownedByCurrentTeam()->get();
|
||||||
$this->get_deployments();
|
$this->get_deployments();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Livewire\Destination\New;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
|
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ class Docker extends Component
|
|||||||
public string $name;
|
public string $name;
|
||||||
public string $network;
|
public string $network;
|
||||||
|
|
||||||
public Collection $servers;
|
public ?Collection $servers = null;
|
||||||
public Server $server;
|
public Server $server;
|
||||||
public ?int $server_id = null;
|
public ?int $server_id = null;
|
||||||
public bool $is_swarm = false;
|
public bool $is_swarm = false;
|
||||||
@@ -34,6 +34,9 @@ class Docker extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
if (is_null($this->servers)) {
|
||||||
|
$this->servers = Server::isReachable()->get();
|
||||||
|
}
|
||||||
if (request()->query('server_id')) {
|
if (request()->query('server_id')) {
|
||||||
$this->server_id = request()->query('server_id');
|
$this->server_id = request()->query('server_id');
|
||||||
} else {
|
} else {
|
||||||
@@ -46,8 +49,10 @@ class Docker extends Component
|
|||||||
} else {
|
} else {
|
||||||
$this->network = new Cuid2(7);
|
$this->network = new Cuid2(7);
|
||||||
}
|
}
|
||||||
|
if ($this->servers->count() > 0) {
|
||||||
$this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab();
|
$this->name = str("{$this->servers->first()->name}-{$this->network}")->kebab();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function generate_name()
|
public function generate_name()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Livewire\Destination;
|
namespace App\Livewire\Destination;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\StandaloneDocker;
|
||||||
|
use App\Models\SwarmDocker;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -11,6 +13,40 @@ class Show extends Component
|
|||||||
public Server $server;
|
public Server $server;
|
||||||
public Collection|array $networks = [];
|
public Collection|array $networks = [];
|
||||||
|
|
||||||
|
private function createNetworkAndAttachToProxy()
|
||||||
|
{
|
||||||
|
$connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
|
||||||
|
instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
|
||||||
|
}
|
||||||
|
public function add($name)
|
||||||
|
{
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
$found = $this->server->swarmDockers()->where('network', $name)->first();
|
||||||
|
if ($found) {
|
||||||
|
$this->dispatch('error', 'Network already added to this server.');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
SwarmDocker::create([
|
||||||
|
'name' => $this->server->name . "-" . $name,
|
||||||
|
'network' => $this->name,
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$found = $this->server->standaloneDockers()->where('network', $name)->first();
|
||||||
|
if ($found) {
|
||||||
|
$this->dispatch('error', 'Network already added to this server.');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
StandaloneDocker::create([
|
||||||
|
'name' => $this->server->name . "-" . $name,
|
||||||
|
'network' => $name,
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->createNetworkAndAttachToProxy();
|
||||||
|
}
|
||||||
|
}
|
||||||
public function scan()
|
public function scan()
|
||||||
{
|
{
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
@@ -26,6 +62,8 @@ class Show extends Component
|
|||||||
});
|
});
|
||||||
if ($this->networks->count() === 0) {
|
if ($this->networks->count() === 0) {
|
||||||
$this->dispatch('success', 'No new networks found.');
|
$this->dispatch('success', 'No new networks found.');
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
$this->dispatch('success', 'Scan done.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,6 @@ class LayoutPopups extends Component
|
|||||||
{
|
{
|
||||||
$this->dispatch('success', 'Realtime events configured!');
|
$this->dispatch('success', 'Realtime events configured!');
|
||||||
}
|
}
|
||||||
public function disableSponsorship()
|
|
||||||
{
|
|
||||||
auth()->user()->update(['is_notification_sponsorship_enabled' => false]);
|
|
||||||
}
|
|
||||||
public function disableNotifications()
|
|
||||||
{
|
|
||||||
auth()->user()->update(['is_notification_notifications_enabled' => false]);
|
|
||||||
}
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.layout-popups');
|
return view('livewire.layout-popups');
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Models\Team;
|
|||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class DiscordSettings extends Component
|
class Discord extends Component
|
||||||
{
|
{
|
||||||
public Team $team;
|
public Team $team;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
@@ -55,4 +55,8 @@ class DiscordSettings extends Component
|
|||||||
$this->team?->notify(new Test());
|
$this->team?->notify(new Test());
|
||||||
$this->dispatch('success', 'Test notification sent.');
|
$this->dispatch('success', 'Test notification sent.');
|
||||||
}
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.notifications.discord');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Notifications;
|
namespace App\Livewire\Notifications;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Livewire\Component;
|
|
||||||
use Log;
|
|
||||||
|
|
||||||
class EmailSettings extends Component
|
class Email extends Component
|
||||||
{
|
{
|
||||||
public Team $team;
|
public Team $team;
|
||||||
public string $emails;
|
public string $emails;
|
||||||
@@ -119,6 +118,7 @@ class EmailSettings extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
|
if (!$this->team->use_instance_email_settings) {
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'team.smtp_from_address' => 'required|email',
|
'team.smtp_from_address' => 'required|email',
|
||||||
'team.smtp_from_name' => 'required',
|
'team.smtp_from_name' => 'required',
|
||||||
@@ -129,6 +129,7 @@ class EmailSettings extends Component
|
|||||||
'team.smtp_password' => 'nullable',
|
'team.smtp_password' => 'nullable',
|
||||||
'team.smtp_timeout' => 'nullable',
|
'team.smtp_timeout' => 'nullable',
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
$this->team->save();
|
$this->team->save();
|
||||||
refreshSession();
|
refreshSession();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
@@ -189,4 +190,8 @@ class EmailSettings extends Component
|
|||||||
}
|
}
|
||||||
$this->dispatch('error', 'Instance SMTP/Resend settings are not enabled.');
|
$this->dispatch('error', 'Instance SMTP/Resend settings are not enabled.');
|
||||||
}
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.notifications.email');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,9 @@ use App\Models\Team;
|
|||||||
use App\Notifications\Test;
|
use App\Notifications\Test;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class TelegramSettings extends Component
|
class Telegram extends Component
|
||||||
{
|
{
|
||||||
|
|
||||||
public Team $team;
|
public Team $team;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'team.telegram_enabled' => 'nullable|boolean',
|
'team.telegram_enabled' => 'nullable|boolean',
|
||||||
@@ -61,4 +62,8 @@ class TelegramSettings extends Component
|
|||||||
$this->team?->notify(new Test());
|
$this->team?->notify(new Test());
|
||||||
$this->dispatch('success', 'Test notification sent.');
|
$this->dispatch('success', 'Test notification sent.');
|
||||||
}
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.notifications.telegram');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,11 +11,8 @@ class Index extends Component
|
|||||||
public int $userId;
|
public int $userId;
|
||||||
public string $email;
|
public string $email;
|
||||||
|
|
||||||
#[Validate('required')]
|
|
||||||
public string $current_password;
|
public string $current_password;
|
||||||
#[Validate('required|min:8')]
|
|
||||||
public string $new_password;
|
public string $new_password;
|
||||||
#[Validate('required|min:8|same:new_password')]
|
|
||||||
public string $new_password_confirmation;
|
public string $new_password_confirmation;
|
||||||
|
|
||||||
#[Validate('required')]
|
#[Validate('required')]
|
||||||
@@ -29,7 +26,9 @@ class Index extends Component
|
|||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate([
|
||||||
|
'name' => 'required',
|
||||||
|
]);
|
||||||
auth()->user()->update([
|
auth()->user()->update([
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
]);
|
]);
|
||||||
@@ -42,7 +41,11 @@ class Index extends Component
|
|||||||
public function resetPassword()
|
public function resetPassword()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate([
|
||||||
|
'current_password' => 'required',
|
||||||
|
'new_password' => 'required|min:8',
|
||||||
|
'new_password_confirmation' => 'required|min:8|same:new_password',
|
||||||
|
]);
|
||||||
if (!Hash::check($this->current_password, auth()->user()->password)) {
|
if (!Hash::check($this->current_password, auth()->user()->password)) {
|
||||||
$this->dispatch('error', 'Current password is incorrect.');
|
$this->dispatch('error', 'Current password is incorrect.');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use Livewire\Component;
|
|||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public Application $application;
|
public Application $application;
|
||||||
public array|Collection $deployments = [];
|
public ?Collection $deployments;
|
||||||
public int $deployments_count = 0;
|
public int $deployments_count = 0;
|
||||||
public string $current_url;
|
public string $current_url;
|
||||||
public int $skip = 0;
|
public int $skip = 0;
|
||||||
@@ -48,9 +48,9 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
private function show_more()
|
private function show_more()
|
||||||
{
|
{
|
||||||
if (count($this->deployments) !== 0) {
|
if ($this->deployments->count() !== 0) {
|
||||||
$this->show_next = true;
|
$this->show_next = true;
|
||||||
if (count($this->deployments) < $this->default_take) {
|
if ($this->deployments->count() < $this->default_take) {
|
||||||
$this->show_next = false;
|
$this->show_next = false;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -63,7 +63,6 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
public function previous_page(?int $take = null)
|
public function previous_page(?int $take = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($take) {
|
if ($take) {
|
||||||
$this->skip = $this->skip - $take;
|
$this->skip = $this->skip - $take;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class General extends Component
|
|||||||
'application.settings.is_static' => 'boolean|required',
|
'application.settings.is_static' => 'boolean|required',
|
||||||
'application.settings.is_raw_compose_deployment_enabled' => 'boolean|required',
|
'application.settings.is_raw_compose_deployment_enabled' => 'boolean|required',
|
||||||
'application.settings.is_build_server_enabled' => 'boolean|required',
|
'application.settings.is_build_server_enabled' => 'boolean|required',
|
||||||
|
'application.watch_paths' => 'nullable',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'application.name' => 'name',
|
'application.name' => 'name',
|
||||||
@@ -108,6 +109,7 @@ class General extends Component
|
|||||||
'application.settings.is_static' => 'Is static',
|
'application.settings.is_static' => 'Is static',
|
||||||
'application.settings.is_raw_compose_deployment_enabled' => 'Is raw compose deployment enabled',
|
'application.settings.is_raw_compose_deployment_enabled' => 'Is raw compose deployment enabled',
|
||||||
'application.settings.is_build_server_enabled' => 'Is build server enabled',
|
'application.settings.is_build_server_enabled' => 'Is build server enabled',
|
||||||
|
'application.watch_paths' => 'Watch paths',
|
||||||
];
|
];
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
@@ -251,7 +253,7 @@ class General extends Component
|
|||||||
if ($this->application->additional_servers->count() === 0) {
|
if ($this->application->additional_servers->count() === 0) {
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
||||||
$showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='text-white underline' href='https://coolify.io/docs/dns-settings'>documentation</a> for further help.");
|
$showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ class Heading extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/build-server">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/build-server">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
@@ -99,7 +99,7 @@ class Heading extends Component
|
|||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class BackupEdit extends Component
|
|||||||
|
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
// TODO: Delete backup from server and add a confirmation modal
|
try {
|
||||||
$this->backup->delete();
|
$this->backup->delete();
|
||||||
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
|
||||||
$previousUrl = url()->previous();
|
$previousUrl = url()->previous();
|
||||||
@@ -54,7 +54,9 @@ class BackupEdit extends Component
|
|||||||
} else {
|
} else {
|
||||||
return redirect()->route('project.database.backup.index', $this->parameters);
|
return redirect()->route('project.database.backup.index', $this->parameters);
|
||||||
}
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
@@ -63,7 +65,7 @@ class BackupEdit extends Component
|
|||||||
$this->custom_validate();
|
$this->custom_validate();
|
||||||
$this->backup->save();
|
$this->backup->save();
|
||||||
$this->backup->refresh();
|
$this->backup->refresh();
|
||||||
$this->dispatch('success', 'Backup updated successfully');
|
$this->dispatch('success', 'Backup updated successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->dispatch('error', $e->getMessage());
|
$this->dispatch('error', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ class Edit extends Component
|
|||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->validate();
|
|
||||||
try {
|
try {
|
||||||
|
$this->validate();
|
||||||
$this->project->save();
|
$this->project->save();
|
||||||
$this->dispatch('saved');
|
$this->dispatch('saved');
|
||||||
|
$this->dispatch('success', 'Project updated.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project;
|
namespace App\Livewire\Project;
|
||||||
|
|
||||||
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@@ -10,7 +11,9 @@ class Index extends Component
|
|||||||
{
|
{
|
||||||
public $projects;
|
public $projects;
|
||||||
public $servers;
|
public $servers;
|
||||||
|
public $private_keys;
|
||||||
public function mount() {
|
public function mount() {
|
||||||
|
$this->private_keys = PrivateKey::ownedByCurrentTeam()->get();
|
||||||
$this->projects = Project::ownedByCurrentTeam()->get();
|
$this->projects = Project::ownedByCurrentTeam()->get();
|
||||||
$this->servers = Server::ownedByCurrentTeam()->count();
|
$this->servers = Server::ownedByCurrentTeam()->count();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ use App\Models\GithubApp;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use App\Traits\SaveFromRedirect;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class GithubPrivateRepository extends Component
|
class GithubPrivateRepository extends Component
|
||||||
{
|
{
|
||||||
use SaveFromRedirect;
|
|
||||||
public $current_step = 'github_apps';
|
public $current_step = 'github_apps';
|
||||||
public $github_apps;
|
public $github_apps;
|
||||||
public GithubApp $github_app;
|
public GithubApp $github_app;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class Select extends Component
|
|||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$this->loadServices();
|
|
||||||
return view('livewire.project.new.select');
|
return view('livewire.project.new.select');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +70,14 @@ class Select extends Component
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
public function updatedSearch()
|
||||||
|
{
|
||||||
|
$this->loadServices();
|
||||||
|
}
|
||||||
public function loadServices(bool $force = false)
|
public function loadServices(bool $force = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$this->loadingServices = true;
|
||||||
if (count($this->allServices) > 0 && !$force) {
|
if (count($this->allServices) > 0 && !$force) {
|
||||||
if (!$this->search) {
|
if (!$this->search) {
|
||||||
$this->services = $this->allServices;
|
$this->services = $this->allServices;
|
||||||
@@ -90,8 +94,7 @@ class Select extends Component
|
|||||||
$this->allServices = getServiceTemplates();
|
$this->allServices = getServiceTemplates();
|
||||||
$this->services = $this->allServices->filter(function ($service, $key) {
|
$this->services = $this->allServices->filter(function ($service, $key) {
|
||||||
return str_contains(strtolower($key), strtolower($this->search));
|
return str_contains(strtolower($key), strtolower($this->search));
|
||||||
});;
|
});
|
||||||
$this->dispatch('success', 'Successfully loaded services.');
|
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
|||||||
@@ -36,6 +36,30 @@ class Configuration extends Component
|
|||||||
$this->applications = $this->service->applications->sort();
|
$this->applications = $this->service->applications->sort();
|
||||||
$this->databases = $this->service->databases->sort();
|
$this->databases = $this->service->databases->sort();
|
||||||
}
|
}
|
||||||
|
public function restartApplication($id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$application = $this->service->applications->find($id);
|
||||||
|
if ($application) {
|
||||||
|
$application->restart();
|
||||||
|
$this->dispatch('success', 'Application restarted successfully.');
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function restartDatabase($id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$database = $this->service->databases->find($id);
|
||||||
|
if ($database) {
|
||||||
|
$database->restart();
|
||||||
|
$this->dispatch('success', 'Database restarted successfully.');
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
public function check_status()
|
public function check_status()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ class Database extends Component
|
|||||||
}
|
}
|
||||||
$this->refreshFileStorages();
|
$this->refreshFileStorages();
|
||||||
}
|
}
|
||||||
public function instantSaveAdvanced()
|
public function instantSaveExclude()
|
||||||
|
{
|
||||||
|
$this->submit();
|
||||||
|
}
|
||||||
|
public function instantSaveLogDrain()
|
||||||
{
|
{
|
||||||
if (!$this->database->service->destination->server->isLogDrainEnabled()) {
|
if (!$this->database->service->destination->server->isLogDrainEnabled()) {
|
||||||
$this->database->is_log_drain_enabled = false;
|
$this->database->is_log_drain_enabled = false;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Livewire\Modal;
|
namespace App\Livewire\Project\Service;
|
||||||
|
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use LivewireUI\Modal\ModalComponent;
|
use Livewire\Component;
|
||||||
|
|
||||||
class EditCompose extends ModalComponent
|
class EditCompose extends Component
|
||||||
{
|
{
|
||||||
public Service $service;
|
public Service $service;
|
||||||
public $serviceId;
|
public $serviceId;
|
||||||
@@ -16,13 +16,13 @@ class EditCompose extends ModalComponent
|
|||||||
public function mount() {
|
public function mount() {
|
||||||
$this->service = Service::find($this->serviceId);
|
$this->service = Service::find($this->serviceId);
|
||||||
}
|
}
|
||||||
public function render()
|
|
||||||
{
|
public function saveEditedCompose() {
|
||||||
return view('livewire.modal.edit-compose');
|
|
||||||
}
|
|
||||||
public function submit() {
|
|
||||||
$this->dispatch('warning', "Saving new docker compose...");
|
$this->dispatch('warning', "Saving new docker compose...");
|
||||||
$this->dispatch('saveCompose', $this->service->docker_compose_raw);
|
$this->dispatch('saveCompose', $this->service->docker_compose_raw);
|
||||||
$this->closeModal();
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.service.edit-compose');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Project\Service;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Modal extends Component
|
|
||||||
{
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.project.service.modal');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,17 +16,24 @@ class Navbar extends Component
|
|||||||
public array $parameters;
|
public array $parameters;
|
||||||
public array $query;
|
public array $query;
|
||||||
public $isDeploymentProgress = false;
|
public $isDeploymentProgress = false;
|
||||||
|
|
||||||
public function getListeners()
|
public function getListeners()
|
||||||
{
|
{
|
||||||
|
$userId = auth()->user()->id;
|
||||||
return [
|
return [
|
||||||
|
"echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted',
|
||||||
"serviceStatusChanged"
|
"serviceStatusChanged"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
public function serviceStarted() {
|
||||||
|
$this->dispatch('success', 'Service status changed.');
|
||||||
|
}
|
||||||
public function serviceStatusChanged()
|
public function serviceStatusChanged()
|
||||||
{
|
{
|
||||||
$this->dispatch('refresh')->self();
|
$this->dispatch('refresh')->self();
|
||||||
}
|
}
|
||||||
public function check_status() {
|
public function check_status()
|
||||||
|
{
|
||||||
$this->dispatch('check_status');
|
$this->dispatch('check_status');
|
||||||
$this->dispatch('success', 'Service status updated.');
|
$this->dispatch('success', 'Service status updated.');
|
||||||
}
|
}
|
||||||
@@ -44,7 +51,7 @@ class Navbar extends Component
|
|||||||
$this->isDeploymentProgress = false;
|
$this->isDeploymentProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function deploy()
|
public function start()
|
||||||
{
|
{
|
||||||
$this->checkDeployments();
|
$this->checkDeployments();
|
||||||
if ($this->isDeploymentProgress) {
|
if ($this->isDeploymentProgress) {
|
||||||
@@ -73,9 +80,9 @@ class Navbar extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PullImage::run($this->service);
|
PullImage::run($this->service);
|
||||||
$this->dispatch('image-pulled');
|
|
||||||
StopService::run($this->service);
|
StopService::run($this->service);
|
||||||
$this->service->parse();
|
$this->service->parse();
|
||||||
|
$this->dispatch('imagePulled');
|
||||||
$activity = StartService::run($this->service);
|
$activity = StartService::run($this->service);
|
||||||
$this->dispatch('activityMonitor', $activity->id);
|
$this->dispatch('activityMonitor', $activity->id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ class ServiceApplicationView extends Component
|
|||||||
$this->validate();
|
$this->validate();
|
||||||
$this->application->save();
|
$this->application->save();
|
||||||
updateCompose($this->application);
|
updateCompose($this->application);
|
||||||
$this->dispatch('success', 'Application saved.');
|
if (str($this->application->fqdn)->contains(',')) {
|
||||||
|
$this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.');
|
||||||
|
} else {
|
||||||
|
$this->dispatch('success', 'Service saved.');
|
||||||
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project\Service;
|
namespace App\Livewire\Project\Service;
|
||||||
|
|
||||||
|
use App\Models\Service;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class StackForm extends Component
|
class StackForm extends Component
|
||||||
{
|
{
|
||||||
public $service;
|
public Service $service;
|
||||||
public $fields = [];
|
public $fields = [];
|
||||||
protected $listeners = ["saveCompose"];
|
protected $listeners = ["saveCompose"];
|
||||||
public $rules = [
|
public $rules = [
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class Destination extends Component
|
|||||||
public function redeploy(int $network_id, int $server_id)
|
public function redeploy(int $network_id, int $server_id)
|
||||||
{
|
{
|
||||||
if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
|
if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
|
||||||
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/server/multiple-servers">documentation</a>');
|
$this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab.<br>More information here: <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/multiple-servers">documentation</a>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$deployment_uuid = new Cuid2(7);
|
$deployment_uuid = new Cuid2(7);
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ class All extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$environment->is_build_time = false;
|
$environment->is_build_time = false;
|
||||||
|
$environment->is_multiline = false;
|
||||||
$environment->is_preview = $isPreview ? true : false;
|
$environment->is_preview = $isPreview ? true : false;
|
||||||
switch ($this->resource->type()) {
|
switch ($this->resource->type()) {
|
||||||
case 'application':
|
case 'application':
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class Add extends Component
|
|||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$isValid = validate_cron_expression($this->frequency);
|
$isValid = validate_cron_expression($this->frequency);
|
||||||
if (!$isValid) {
|
if (!$isValid) {
|
||||||
@@ -46,6 +47,9 @@ class Add extends Component
|
|||||||
'container' => $this->container,
|
'container' => $this->container,
|
||||||
]);
|
]);
|
||||||
$this->clear();
|
$this->clear();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clear()
|
public function clear()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class Tags extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->resource->tags()->where('id', $id)->exists()) {
|
if ($this->resource->tags()->where('id', $id)->exists()) {
|
||||||
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='text-warning'>$name</span> already added.");
|
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$name</span> already added.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->resource->tags()->syncWithoutDetaching($id);
|
$this->resource->tags()->syncWithoutDetaching($id);
|
||||||
@@ -66,7 +66,7 @@ class Tags extends Component
|
|||||||
$tags = str($this->new_tag)->trim()->explode(' ');
|
$tags = str($this->new_tag)->trim()->explode(' ');
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
if ($this->resource->tags()->where('name', $tag)->exists()) {
|
if ($this->resource->tags()->where('name', $tag)->exists()) {
|
||||||
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='text-warning'>$tag</span> already added.");
|
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$tag</span> already added.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$found = Tag::where(['name' => $tag, 'team_id' => currentTeam()->id])->first();
|
$found = Tag::where(['name' => $tag, 'team_id' => currentTeam()->id])->first();
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class RealtimeConnection extends Component
|
|
||||||
{
|
|
||||||
public $checkConnection = false;
|
|
||||||
public $showNotification = false;
|
|
||||||
public $isNotificationEnabled = true;
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.realtime-connection');
|
|
||||||
}
|
|
||||||
public function disable()
|
|
||||||
{
|
|
||||||
auth()->user()->update(['is_notification_realtime_enabled' => false]);
|
|
||||||
$this->showNotification = false;
|
|
||||||
}
|
|
||||||
public function mount() {
|
|
||||||
$this->isNotificationEnabled = auth()->user()->is_notification_realtime_enabled;
|
|
||||||
$this->checkConnection = auth()->user()->id === 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ class Create extends Component
|
|||||||
'value' => 'private Key',
|
'value' => 'private Key',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function generateNewKey()
|
public function generateNewRSAKey()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->rateLimit(10);
|
$this->rateLimit(10);
|
||||||
@@ -37,6 +37,17 @@ class Create extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function generateNewEDKey()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->rateLimit(10);
|
||||||
|
$this->name = generate_random_name();
|
||||||
|
$this->description = 'Created by Coolify';
|
||||||
|
['private' => $this->value, 'public' => $this->publicKey] = generateSSHKey('ed25519');
|
||||||
|
} catch(\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
public function updated($updateProperty)
|
public function updated($updateProperty)
|
||||||
{
|
{
|
||||||
if ($updateProperty === 'value') {
|
if ($updateProperty === 'value') {
|
||||||
@@ -67,7 +78,7 @@ class Create extends Component
|
|||||||
'team_id' => currentTeam()->id
|
'team_id' => currentTeam()->id
|
||||||
]);
|
]);
|
||||||
if ($this->from === 'server') {
|
if ($this->from === 'server') {
|
||||||
return redirect()->route('server.create');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Livewire\Component;
|
|||||||
class Show extends Component
|
class Show extends Component
|
||||||
{
|
{
|
||||||
public PrivateKey $private_key;
|
public PrivateKey $private_key;
|
||||||
public $public_key;
|
public $public_key = "Loading...";
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'private_key.name' => 'required|string',
|
'private_key.name' => 'required|string',
|
||||||
'private_key.description' => 'nullable|string',
|
'private_key.description' => 'nullable|string',
|
||||||
@@ -25,11 +25,13 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail();
|
$this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail();
|
||||||
$this->public_key = $this->private_key->publicKey();
|
|
||||||
}catch(\Throwable $e) {
|
}catch(\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function loadPublicKey() {
|
||||||
|
$this->public_key = $this->private_key->publicKey();
|
||||||
|
}
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -50,6 +52,7 @@ class Show extends Component
|
|||||||
$this->private_key->private_key = formatPrivateKey($this->private_key->private_key);
|
$this->private_key->private_key = formatPrivateKey($this->private_key->private_key);
|
||||||
$this->private_key->save();
|
$this->private_key->save();
|
||||||
refresh_server_connection($this->private_key);
|
refresh_server_connection($this->private_key);
|
||||||
|
$this->dispatch('success', 'Private key updated.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|||||||
45
app/Livewire/Server/ConfigureCloudflareTunnels.php
Normal file
45
app/Livewire/Server/ConfigureCloudflareTunnels.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Actions\Server\ConfigureCloudflared;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class ConfigureCloudflareTunnels extends Component
|
||||||
|
{
|
||||||
|
public $server_id;
|
||||||
|
public string $cloudflare_token;
|
||||||
|
public string $ssh_domain;
|
||||||
|
public function alreadyConfigured()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$server = Server::ownedByCurrentTeam()->where('id', $this->server_id)->firstOrFail();
|
||||||
|
$server->settings->is_cloudflare_tunnel = true;
|
||||||
|
$server->settings->save();
|
||||||
|
$this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
|
||||||
|
$this->dispatch('serverInstalled');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$server = Server::ownedByCurrentTeam()->where('id', $this->server_id)->firstOrFail();
|
||||||
|
ConfigureCloudflared::run($server, $this->cloudflare_token);
|
||||||
|
$server->settings->is_cloudflare_tunnel = true;
|
||||||
|
$server->ip = $this->ssh_domain;
|
||||||
|
$server->save();
|
||||||
|
$server->settings->save();
|
||||||
|
$this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
|
||||||
|
$this->dispatch('serverInstalled');
|
||||||
|
} catch(\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.configure-cloudflare-tunnels');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,7 +82,7 @@ class Form extends Component
|
|||||||
$this->server->settings->is_usable = true;
|
$this->server->settings->is_usable = true;
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
} else {
|
} else {
|
||||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.');
|
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class ByIp extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->name = generate_random_name();
|
$this->name = generate_random_name();
|
||||||
$this->private_key_id = $this->private_keys->first()->id;
|
$this->private_key_id = $this->private_keys->first()?->id;
|
||||||
$this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true);
|
$this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true);
|
||||||
if ($this->swarm_managers->count() > 0) {
|
if ($this->swarm_managers->count() > 0) {
|
||||||
$this->selected_swarm_cluster = $this->swarm_managers->first()->id;
|
$this->selected_swarm_cluster = $this->swarm_managers->first()->id;
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ class Deploy extends Component
|
|||||||
{
|
{
|
||||||
$this->server->refresh();
|
$this->server->refresh();
|
||||||
}
|
}
|
||||||
public function restart() {
|
public function restart()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$this->stop();
|
$this->stop();
|
||||||
$this->dispatch('checkProxy');
|
$this->dispatch('checkProxy');
|
||||||
|
|||||||
@@ -42,7 +42,11 @@ class Resources extends Component
|
|||||||
$this->dispatch('success', 'Resource statuses refreshed.');
|
$this->dispatch('success', 'Resource statuses refreshed.');
|
||||||
}
|
}
|
||||||
public function loadUnmanagedContainers() {
|
public function loadUnmanagedContainers() {
|
||||||
|
try {
|
||||||
$this->unmanagedContainers = $this->server->loadUnmanagedContainers();
|
$this->unmanagedContainers = $this->server->loadUnmanagedContainers();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function mount() {
|
public function mount() {
|
||||||
$this->unmanagedContainers = collect();
|
$this->unmanagedContainers = collect();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ShowPrivateKey extends Component
|
|||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->dispatch('success', 'Server is reachable.');
|
$this->dispatch('success', 'Server is reachable.');
|
||||||
} else {
|
} else {
|
||||||
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh#openssh">documentation</a> for further help.');
|
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ValidateAndInstall extends Component
|
|||||||
{
|
{
|
||||||
$this->uptime = $this->server->validateConnection();
|
$this->uptime = $this->server->validateConnection();
|
||||||
if (!$this->uptime) {
|
if (!$this->uptime) {
|
||||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.';
|
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->dispatch('validateOS');
|
$this->dispatch('validateOS');
|
||||||
|
|||||||
43
app/Livewire/Settings/Auth.php
Normal file
43
app/Livewire/Settings/Auth.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Settings;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use App\Models\OauthSetting;
|
||||||
|
|
||||||
|
class Auth extends Component {
|
||||||
|
public $oauth_settings_map;
|
||||||
|
|
||||||
|
protected function rules() {
|
||||||
|
return OauthSetting::all()->reduce(function($carry, $setting) {
|
||||||
|
$carry["oauth_settings_map.$setting->provider.enabled"] = 'required';
|
||||||
|
$carry["oauth_settings_map.$setting->provider.client_id"] = 'nullable';
|
||||||
|
$carry["oauth_settings_map.$setting->provider.client_secret"] = 'nullable';
|
||||||
|
$carry["oauth_settings_map.$setting->provider.redirect_uri"] = 'nullable';
|
||||||
|
$carry["oauth_settings_map.$setting->provider.tenant"] = 'nullable';
|
||||||
|
return $carry;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mount() {
|
||||||
|
$this->oauth_settings_map = OauthSetting::all()->sortBy('provider')->reduce(function($carry, $setting) {
|
||||||
|
$carry[$setting->provider] = $setting;
|
||||||
|
return $carry;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateOauthSettings() {
|
||||||
|
foreach (array_values($this->oauth_settings_map) as &$setting) {
|
||||||
|
$setting->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function instantSave() {
|
||||||
|
$this->updateOauthSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit() {
|
||||||
|
$this->updateOauthSettings();
|
||||||
|
$this->dispatch('success', 'Instance settings updated successfully!');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,6 +58,8 @@ class Email extends Component
|
|||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
$this->validate([
|
$this->validate([
|
||||||
|
'settings.smtp_from_address' => 'required|email',
|
||||||
|
'settings.smtp_from_name' => 'required',
|
||||||
'settings.resend_api_key' => 'required'
|
'settings.resend_api_key' => 'required'
|
||||||
]);
|
]);
|
||||||
$this->settings->save();
|
$this->settings->save();
|
||||||
@@ -90,6 +92,8 @@ class Email extends Component
|
|||||||
try {
|
try {
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
$this->validate([
|
$this->validate([
|
||||||
|
'settings.smtp_from_address' => 'required|email',
|
||||||
|
'settings.smtp_from_name' => 'required',
|
||||||
'settings.smtp_host' => 'required',
|
'settings.smtp_host' => 'required',
|
||||||
'settings.smtp_port' => 'required|numeric',
|
'settings.smtp_port' => 'required|numeric',
|
||||||
'settings.smtp_encryption' => 'nullable',
|
'settings.smtp_encryption' => 'nullable',
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class License extends Component
|
|||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.settings.license')->layout('layouts.subscription');
|
return view('livewire.settings.license');
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Index extends Component
|
|||||||
if (!isCloud()) {
|
if (!isCloud()) {
|
||||||
return redirect(RouteServiceProvider::HOME);
|
return redirect(RouteServiceProvider::HOME);
|
||||||
}
|
}
|
||||||
if (data_get(currentTeam(), 'subscription')) {
|
if (data_get(currentTeam(), 'subscription') && isSubscriptionActive()) {
|
||||||
return redirect()->route('subscription.show');
|
return redirect()->route('subscription.show');
|
||||||
}
|
}
|
||||||
$this->settings = InstanceSettings::get();
|
$this->settings = InstanceSettings::get();
|
||||||
@@ -31,6 +31,6 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.subscription.index')->layout('layouts.subscription');
|
return view('livewire.subscription.index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use Livewire\Component;
|
|||||||
class SwitchTeam extends Component
|
class SwitchTeam extends Component
|
||||||
{
|
{
|
||||||
public string $selectedTeamId = 'default';
|
public string $selectedTeamId = 'default';
|
||||||
|
public function mount() {
|
||||||
|
$this->selectedTeamId = auth()->user()->currentTeam()->id;
|
||||||
|
}
|
||||||
public function updatedSelectedTeamId()
|
public function updatedSelectedTeamId()
|
||||||
{
|
{
|
||||||
$this->switch_to($this->selectedTeamId);
|
$this->switch_to($this->selectedTeamId);
|
||||||
|
|||||||
@@ -2,14 +2,73 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Tags;
|
namespace App\Livewire\Tags;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Api\Deploy;
|
||||||
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Url;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public $tags = [];
|
#[Url()]
|
||||||
public function mount() {
|
public ?string $tag = null;
|
||||||
$this->tags = Tag::where('team_id', currentTeam()->id)->get()->unique('name')->sortBy('name');
|
|
||||||
|
public Collection $tags;
|
||||||
|
public Collection $applications;
|
||||||
|
public Collection $services;
|
||||||
|
public $webhook = null;
|
||||||
|
public $deployments_per_tag_per_server = [];
|
||||||
|
|
||||||
|
public function updatedTag()
|
||||||
|
{
|
||||||
|
$tag = $this->tags->where('name', $this->tag)->first();
|
||||||
|
$this->webhook = generatTagDeployWebhook($tag->name);
|
||||||
|
$this->applications = $tag->applications()->get();
|
||||||
|
$this->services = $tag->services()->get();
|
||||||
|
$this->get_deployments();
|
||||||
|
}
|
||||||
|
public function get_deployments()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$resource_ids = $this->applications->pluck('id');
|
||||||
|
$this->deployments_per_tag_per_server = ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->whereIn('application_id', $resource_ids)->get([
|
||||||
|
"id",
|
||||||
|
"application_id",
|
||||||
|
"application_name",
|
||||||
|
"deployment_url",
|
||||||
|
"pull_request_id",
|
||||||
|
"server_name",
|
||||||
|
"server_id",
|
||||||
|
"status"
|
||||||
|
])->sortBy('id')->groupBy('server_name')->toArray();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function redeploy_all()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$message = collect([]);
|
||||||
|
$this->applications->each(function ($resource) use ($message) {
|
||||||
|
$deploy = new Deploy();
|
||||||
|
$message->push($deploy->deploy_resource($resource));
|
||||||
|
});
|
||||||
|
$this->services->each(function ($resource) use ($message) {
|
||||||
|
$deploy = new Deploy();
|
||||||
|
$message->push($deploy->deploy_resource($resource));
|
||||||
|
});
|
||||||
|
$this->dispatch('success', 'Mass deployment started.');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name');
|
||||||
|
if ($this->tag) {
|
||||||
|
$this->updatedTag();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Livewire\Team\Notification;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Index extends Component
|
|
||||||
{
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return view('livewire.team.notification.index');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,8 +37,8 @@ class Upgrade extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->showProgress = true;
|
$this->showProgress = true;
|
||||||
UpdateCoolify::run(true);
|
UpdateCoolify::run(force: true, async: true);
|
||||||
$this->dispatch('success', "Upgrading to {$this->latestVersion} version...");
|
$this->dispatch('success', "Updating Coolify to {$this->latestVersion} version...");
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Enums\ApplicationDeploymentStatus;
|
|||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
@@ -903,4 +904,27 @@ class Application extends BaseModel
|
|||||||
: explode(',', $this->fqdn),
|
: explode(',', $this->fqdn),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
public function watchPaths(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
set: function ($value) {
|
||||||
|
if ($value) {
|
||||||
|
return trim($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public function isWatchPathsTriggered(Collection $modified_files): bool
|
||||||
|
{
|
||||||
|
if (is_null($this->watch_paths)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$watch_paths = collect(explode("\n", $this->watch_paths));
|
||||||
|
$matches = $modified_files->filter(function ($file) use ($watch_paths) {
|
||||||
|
return $watch_paths->contains(function ($glob) use ($file) {
|
||||||
|
return fnmatch($glob, $file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return $matches->count() > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,9 @@ class EnvironmentVariable extends Model
|
|||||||
static::created(function (EnvironmentVariable $environment_variable) {
|
static::created(function (EnvironmentVariable $environment_variable) {
|
||||||
if ($environment_variable->application_id && !$environment_variable->is_preview) {
|
if ($environment_variable->application_id && !$environment_variable->is_preview) {
|
||||||
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)->where('application_id', $environment_variable->application_id)->where('is_preview', true)->first();
|
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)->where('application_id', $environment_variable->application_id)->where('is_preview', true)->first();
|
||||||
$application = Application::find($environment_variable->application_id);
|
|
||||||
if ($application->build_pack === 'dockerfile') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!$found) {
|
if (!$found) {
|
||||||
|
$application = Application::find($environment_variable->application_id);
|
||||||
|
if ($application->build_pack !== 'dockerfile') {
|
||||||
ModelsEnvironmentVariable::create([
|
ModelsEnvironmentVariable::create([
|
||||||
'key' => $environment_variable->key,
|
'key' => $environment_variable->key,
|
||||||
'value' => $environment_variable->value,
|
'value' => $environment_variable->value,
|
||||||
@@ -40,6 +38,7 @@ class EnvironmentVariable extends Model
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$environment_variable->update([
|
$environment_variable->update([
|
||||||
'version' => config('version')
|
'version' => config('version')
|
||||||
]);
|
]);
|
||||||
|
|||||||
21
app/Models/OauthSetting.php
Normal file
21
app/Models/OauthSetting.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
|
||||||
|
class OauthSetting extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected function clientSecret(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn (string | null $value) => empty($value) ? null : Crypt::decryptString($value),
|
||||||
|
set: fn (string | null $value) => empty($value) ? null : Crypt::encryptString($value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,11 @@ class ServiceApplication extends BaseModel
|
|||||||
$service->fileStorages()->delete();
|
$service->fileStorages()->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public function restart()
|
||||||
|
{
|
||||||
|
$container_id = $this->name . '-' . $this->service->uuid;
|
||||||
|
instant_remote_process(["docker restart {$container_id}"], $this->service->server);
|
||||||
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
return data_get($this, 'is_log_drain_enabled', false);
|
return data_get($this, 'is_log_drain_enabled', false);
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ class ServiceDatabase extends BaseModel
|
|||||||
$service->fileStorages()->delete();
|
$service->fileStorages()->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public function restart()
|
||||||
|
{
|
||||||
|
$container_id = $this->name . '-' . $this->service->uuid;
|
||||||
|
remote_process(["docker restart {$container_id}"], $this->service->server);
|
||||||
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
return data_get($this, 'is_log_drain_enabled', false);
|
return data_get($this, 'is_log_drain_enabled', false);
|
||||||
@@ -52,8 +57,7 @@ class ServiceDatabase extends BaseModel
|
|||||||
if ($this->service->server->isLocalhost() || isDev()) {
|
if ($this->service->server->isLocalhost() || isDev()) {
|
||||||
$realIp = base_ip();
|
$realIp = base_ip();
|
||||||
}
|
}
|
||||||
$url = "{$realIp}:{$port}";
|
return "{$realIp}:{$port}";
|
||||||
return $url;
|
|
||||||
}
|
}
|
||||||
public function service()
|
public function service()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -177,9 +177,6 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
|||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!data_get(auth()->user(), 'is_notification_notifications_enabled')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($this->smtp_enabled || $this->resend_enabled || $this->discord_enabled || $this->telegram_enabled || $this->use_instance_email_settings) {
|
if ($this->smtp_enabled || $this->resend_enabled || $this->discord_enabled || $this->telegram_enabled || $this->use_instance_email_settings) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,13 +53,13 @@ class HighDiskUsage extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toDiscord(): string
|
public function toDiscord(): string
|
||||||
{
|
{
|
||||||
$message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/automated-cleanup.";
|
$message = "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.";
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
public function toTelegram(): array
|
public function toTelegram(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"message" => "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/automated-cleanup."
|
"message" => "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->cleanup_after_percentage}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup."
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
],
|
],
|
||||||
MaintenanceModeDisabled::class => [
|
MaintenanceModeDisabled::class => [
|
||||||
MaintenanceModeDisabledNotification::class,
|
MaintenanceModeDisabledNotification::class,
|
||||||
|
],
|
||||||
|
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
||||||
|
\SocialiteProviders\Azure\AzureExtendSocialite::class.'@handle',
|
||||||
],
|
],
|
||||||
ProxyStarted::class => [
|
ProxyStarted::class => [
|
||||||
ProxyStartedNotification::class,
|
ProxyStartedNotification::class,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Actions\Fortify\ResetUserPassword;
|
|||||||
use App\Actions\Fortify\UpdateUserPassword;
|
use App\Actions\Fortify\UpdateUserPassword;
|
||||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\OauthSetting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -56,13 +57,15 @@ class FortifyServiceProvider extends ServiceProvider
|
|||||||
|
|
||||||
Fortify::loginView(function () {
|
Fortify::loginView(function () {
|
||||||
$settings = InstanceSettings::get();
|
$settings = InstanceSettings::get();
|
||||||
|
$enabled_oauth_providers = OauthSetting::where('enabled', true)->get();
|
||||||
$users = User::count();
|
$users = User::count();
|
||||||
if ($users == 0) {
|
if ($users == 0) {
|
||||||
// If there are no users, redirect to registration
|
// If there are no users, redirect to registration
|
||||||
return redirect()->route('register');
|
return redirect()->route('register');
|
||||||
}
|
}
|
||||||
return view('auth.login', [
|
return view('auth.login', [
|
||||||
'is_registration_enabled' => $settings->is_registration_enabled
|
'is_registration_enabled' => $settings->is_registration_enabled,
|
||||||
|
'enabled_oauth_providers' => $enabled_oauth_providers,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ class Button extends Component
|
|||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public bool $disabled = false,
|
public bool $disabled = false,
|
||||||
public bool $isModal = false,
|
|
||||||
public bool $noStyle = false,
|
public bool $noStyle = false,
|
||||||
public ?string $modalId = null,
|
public ?string $modalId = null,
|
||||||
public string $defaultClass = "btn btn-primary btn-sm font-normal text-white normal-case no-animation rounded border-none"
|
public string $defaultClass = "button"
|
||||||
) {
|
) {
|
||||||
if ($this->noStyle) {
|
if ($this->noStyle) {
|
||||||
$this->defaultClass = "";
|
$this->defaultClass = "";
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ class Checkbox extends Component
|
|||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string|null $id = null,
|
public ?string $id = null,
|
||||||
public string|null $name = null,
|
public ?string $name = null,
|
||||||
public string|null $value = null,
|
public ?string $value = null,
|
||||||
public string|null $label = null,
|
public ?string $label = null,
|
||||||
public string|null $helper = null,
|
public ?string $helper = null,
|
||||||
public string|bool $instantSave = false,
|
public string|bool $instantSave = false,
|
||||||
public bool $disabled = false,
|
public bool $disabled = false,
|
||||||
public string $defaultClass = "toggle toggle-xs toggle-warning rounded disabled:bg-coolgray-200 disabled:opacity-50 placeholder:text-neutral-700",
|
public string $defaultClass = "dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed",
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Input extends Component
|
|||||||
public ?string $helper = null,
|
public ?string $helper = null,
|
||||||
public bool $allowToPeak = true,
|
public bool $allowToPeak = true,
|
||||||
public bool $isMultiline = false,
|
public bool $isMultiline = false,
|
||||||
public string $defaultClass = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
public string $defaultClass = "input",
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,9 @@ class Input extends Component
|
|||||||
{
|
{
|
||||||
if (is_null($this->id)) $this->id = new Cuid2(7);
|
if (is_null($this->id)) $this->id = new Cuid2(7);
|
||||||
if (is_null($this->name)) $this->name = $this->id;
|
if (is_null($this->name)) $this->name = $this->id;
|
||||||
|
if ($this->type === 'password') {
|
||||||
|
$this->defaultClass = $this->defaultClass . " pr-[2.8rem]";
|
||||||
|
}
|
||||||
// $this->label = Str::title($this->label);
|
// $this->label = Str::title($this->label);
|
||||||
return view('components.forms.input');
|
return view('components.forms.input');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ class Select extends Component
|
|||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string|null $id = null,
|
public ?string $id = null,
|
||||||
public string|null $name = null,
|
public ?string $name = null,
|
||||||
public string|null $label = null,
|
public ?string $label = null,
|
||||||
public string|null $helper = null,
|
public ?string $helper = null,
|
||||||
public bool $required = false,
|
public bool $required = false,
|
||||||
public string $defaultClass = "select select-sm w-full rounded text-sm bg-coolgray-100 font-normal disabled:bg-coolgray-200/50 disabled:border-none"
|
public string $defaultClass = "select"
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class Textarea extends Component
|
|||||||
public ?string $helper = null,
|
public ?string $helper = null,
|
||||||
public bool $realtimeValidation = false,
|
public bool $realtimeValidation = false,
|
||||||
public bool $allowToPeak = true,
|
public bool $allowToPeak = true,
|
||||||
public string $defaultClass = "textarea leading-normal bg-coolgray-100 rounded text-white w-full scrollbar disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50",
|
public string $defaultClass = "input scrollbar",
|
||||||
public string $defaultClassInput = "input input-sm bg-coolgray-100 rounded text-white w-full disabled:bg-coolgray-200/50 disabled:border-none placeholder:text-coolgray-500 read-only:text-neutral-500 read-only:bg-coolgray-200/50"
|
public string $defaultClassInput = "input"
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ function get_team_id_from_token()
|
|||||||
}
|
}
|
||||||
function invalid_token()
|
function invalid_token()
|
||||||
{
|
{
|
||||||
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api/authentication'], 400);
|
return response()->json(['error' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api-reference/authorization'], 400);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Models\Application;
|
|||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
|
||||||
function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null, bool $only_this_server = false)
|
function queue_application_deployment(Application $application, string $deployment_uuid, int | null $pull_request_id = 0, string $commit = 'HEAD', bool $force_rebuild = false, bool $is_webhook = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, Server $server = null, StandaloneDocker $destination = null, bool $only_this_server = false)
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ const DATABASE_DOCKER_IMAGES = [
|
|||||||
'couchdb',
|
'couchdb',
|
||||||
'neo4j',
|
'neo4j',
|
||||||
'influxdb',
|
'influxdb',
|
||||||
'clickhouse/clickhouse-server'
|
'clickhouse/clickhouse-server',
|
||||||
|
'supabase/postgres'
|
||||||
];
|
];
|
||||||
const SPECIFIC_SERVICES = [
|
const SPECIFIC_SERVICES = [
|
||||||
'quay.io/minio/minio',
|
'quay.io/minio/minio',
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
||||||
$resource->service->save();
|
$resource->service->save();
|
||||||
|
|
||||||
if (!str($resource->fqdn)->contains(',')) {
|
if ($resource->fqdn && !str($resource->fqdn)->contains(',')) {
|
||||||
// Update FQDN
|
// Update FQDN
|
||||||
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ use Lcobucci\JWT\Encoding\JoseEncoder;
|
|||||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||||
use Lcobucci\JWT\Token\Builder;
|
use Lcobucci\JWT\Token\Builder;
|
||||||
|
use phpseclib3\Crypt\EC;
|
||||||
use Poliander\Cron\CronExpression;
|
use Poliander\Cron\CronExpression;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
use phpseclib3\Crypt\RSA;
|
use phpseclib3\Crypt\RSA;
|
||||||
@@ -110,7 +111,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
|
|||||||
ray($error);
|
ray($error);
|
||||||
if ($error instanceof TooManyRequestsException) {
|
if ($error instanceof TooManyRequestsException) {
|
||||||
if (isset($livewire)) {
|
if (isset($livewire)) {
|
||||||
return $livewire->dispatch('error', 'Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.');
|
return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
|
||||||
}
|
}
|
||||||
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
|
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
|
||||||
}
|
}
|
||||||
@@ -165,13 +166,22 @@ function generate_random_name(?string $cuid = null): string
|
|||||||
}
|
}
|
||||||
return Str::kebab("{$generator->getName()}-$cuid");
|
return Str::kebab("{$generator->getName()}-$cuid");
|
||||||
}
|
}
|
||||||
function generateSSHKey()
|
function generateSSHKey(string $type = 'rsa')
|
||||||
{
|
{
|
||||||
|
if ($type === 'rsa') {
|
||||||
$key = RSA::createKey();
|
$key = RSA::createKey();
|
||||||
return [
|
return [
|
||||||
'private' => $key->toString('PKCS1'),
|
'private' => $key->toString('PKCS1'),
|
||||||
'public' => $key->getPublicKey()->toString('OpenSSH', ['comment' => 'coolify-generated-ssh-key'])
|
'public' => $key->getPublicKey()->toString('OpenSSH', ['comment' => 'coolify-generated-ssh-key'])
|
||||||
];
|
];
|
||||||
|
} else if ($type === 'ed25519') {
|
||||||
|
$key = EC::createKey('Ed25519');
|
||||||
|
return [
|
||||||
|
'private' => $key->toString('OpenSSH'),
|
||||||
|
'public' => $key->getPublicKey()->toString('OpenSSH', ['comment' => 'coolify-generated-ssh-key'])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
throw new Exception('Invalid key type');
|
||||||
}
|
}
|
||||||
function formatPrivateKey(string $privateKey)
|
function formatPrivateKey(string $privateKey)
|
||||||
{
|
{
|
||||||
@@ -280,6 +290,10 @@ function base_url(bool $withPort = true): string
|
|||||||
return url('/');
|
return url('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSubscribed()
|
||||||
|
{
|
||||||
|
return isSubscriptionActive() || auth()->user()->isInstanceAdmin();
|
||||||
|
}
|
||||||
function isDev(): bool
|
function isDev(): bool
|
||||||
{
|
{
|
||||||
return config('app.env') === 'local';
|
return config('app.env') === 'local';
|
||||||
@@ -429,7 +443,7 @@ function sslip(Server $server)
|
|||||||
|
|
||||||
function getServiceTemplates()
|
function getServiceTemplates()
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
if (!isDev()) {
|
||||||
$services = File::get(base_path('templates/service-templates.json'));
|
$services = File::get(base_path('templates/service-templates.json'));
|
||||||
$services = collect(json_decode($services))->sortKeys();
|
$services = collect(json_decode($services))->sortKeys();
|
||||||
} else {
|
} else {
|
||||||
@@ -444,13 +458,6 @@ function getServiceTemplates()
|
|||||||
$services = collect([]);
|
$services = collect([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// $version = config('version');
|
|
||||||
// $services = $services->map(function ($service) use ($version) {
|
|
||||||
// if (version_compare($version, data_get($service, 'minVersion', '0.0.0'), '<')) {
|
|
||||||
// $service->disabled = true;
|
|
||||||
// }
|
|
||||||
// return $service;
|
|
||||||
// });
|
|
||||||
return $services;
|
return $services;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,11 +954,10 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
|
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
if ($savedService->fqdn) {
|
if ($savedService->fqdn) {
|
||||||
$fqdn = $savedService->fqdn . ',' . $fqdn;
|
data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn);
|
||||||
} else {
|
} else {
|
||||||
$fqdn = $fqdn;
|
data_set($savedService, 'fqdn', $fqdn);
|
||||||
}
|
}
|
||||||
$savedService->fqdn = $fqdn;
|
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
@@ -963,7 +969,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
// Caddy needs exact port in some cases.
|
// Caddy needs exact port in some cases.
|
||||||
|
|
||||||
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) {
|
if ($predefinedPort && !$key->endsWith("_{$predefinedPort}")) {
|
||||||
if ($resource->server->proxyType() === 'CADDY') {
|
if ($resource->server->proxyType() === 'CADDY') {
|
||||||
$env = EnvironmentVariable::where([
|
$env = EnvironmentVariable::where([
|
||||||
@@ -1001,6 +1006,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
'service_id' => $resource->id,
|
'service_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||||
|
if (!is_null($command)) {
|
||||||
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
||||||
if (Str::lower($forService) === $serviceName) {
|
if (Str::lower($forService) === $serviceName) {
|
||||||
$fqdn = generateFqdn($resource->server, $containerName);
|
$fqdn = generateFqdn($resource->server, $containerName);
|
||||||
@@ -1058,6 +1064,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($value->contains(':-')) {
|
if ($value->contains(':-')) {
|
||||||
$key = $value->before(':');
|
$key = $value->before(':');
|
||||||
@@ -1240,39 +1247,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
$baseName = generateApplicationContainerName($resource, $pull_request_id);
|
$baseName = generateApplicationContainerName($resource, $pull_request_id);
|
||||||
$containerName = "$serviceName-$baseName";
|
$containerName = "$serviceName-$baseName";
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
if (count($serviceVolumes) > 0) {
|
if (count($serviceVolumes) > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $pull_request_id, $topLevelVolumes) {
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||||
if (is_string($volume)) {
|
|
||||||
$volume = str($volume);
|
|
||||||
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
|
||||||
$name = $volume->before(':');
|
|
||||||
$mount = $volume->after(':');
|
|
||||||
$newName = $resource->uuid . "-{$name}-pr-$pull_request_id";
|
|
||||||
$volume = str("$newName:$mount");
|
|
||||||
$topLevelVolumes->put($newName, [
|
|
||||||
'name' => $newName,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} else if (is_array($volume)) {
|
|
||||||
$source = data_get($volume, 'source');
|
|
||||||
if ($source) {
|
|
||||||
$newSource = $resource->uuid . "-{$source}-pr-$pull_request_id";
|
|
||||||
data_set($volume, 'source', $newSource);
|
|
||||||
if (!str($source)->startsWith('/')) {
|
|
||||||
$topLevelVolumes->put($newSource, [
|
|
||||||
'name' => $newSource,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $volume->value();
|
|
||||||
});
|
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (count($serviceVolumes) > 0) {
|
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) {
|
|
||||||
if (is_string($volume)) {
|
if (is_string($volume)) {
|
||||||
$volume = str($volume);
|
$volume = str($volume);
|
||||||
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
if ($volume->contains(':') && !$volume->startsWith('/')) {
|
||||||
@@ -1286,38 +1262,79 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($name->startsWith('~')) {
|
if ($name->startsWith('~')) {
|
||||||
$name = $name->replaceFirst('~', $dir);
|
$name = $name->replaceFirst('~', $dir);
|
||||||
}
|
}
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$name = $name . "-pr-$pull_request_id";
|
||||||
|
}
|
||||||
$volume = str("$name:$mount");
|
$volume = str("$name:$mount");
|
||||||
|
} else {
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$name = $name . "-pr-$pull_request_id";
|
||||||
|
$volume = str("$name:$mount");
|
||||||
|
$topLevelVolumes->put($name, [
|
||||||
|
'name' => $name,
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
$topLevelVolumes->put($name->value(), [
|
$topLevelVolumes->put($name->value(), [
|
||||||
'name' => $name->value(),
|
'name' => $name->value(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ($volume->startsWith('/')) {
|
||||||
|
$name = $volume->before(':');
|
||||||
|
$mount = $volume->after(':');
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$name = $name . "-pr-$pull_request_id";
|
||||||
|
}
|
||||||
|
$volume = str("$name:$mount");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (is_array($volume)) {
|
} else if (is_array($volume)) {
|
||||||
$source = data_get($volume, 'source');
|
$source = data_get($volume, 'source');
|
||||||
if ($source) {
|
$target = data_get($volume, 'target');
|
||||||
if ((str($source)->startsWith('.') || str($source)->startsWith('~')) && !str($source)->startsWith('/')) {
|
$read_only = data_get($volume, 'read_only');
|
||||||
|
if ($source && $target) {
|
||||||
|
if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) {
|
||||||
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||||
if (str($source, '.')) {
|
if (str($source, '.')) {
|
||||||
$source = str('.', $dir, $source);
|
$source = str($source)->replaceFirst('.', $dir);
|
||||||
}
|
}
|
||||||
if (str($source, '~')) {
|
if (str($source, '~')) {
|
||||||
$source = str('~', $dir, $source);
|
$source = str($source)->replaceFirst('~', $dir);
|
||||||
}
|
}
|
||||||
data_set($volume, 'source', $source);
|
if ($pull_request_id !== 0) {
|
||||||
|
$source = $source . "-pr-$pull_request_id";
|
||||||
|
}
|
||||||
|
if ($read_only) {
|
||||||
|
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||||
} else {
|
} else {
|
||||||
data_set($volume, 'source', $source);
|
data_set($volume, 'source', $source . ':' . $target);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$source = $source . "-pr-$pull_request_id";
|
||||||
|
}
|
||||||
|
if ($read_only) {
|
||||||
|
data_set($volume, 'source', $source . ':' . $target . ':ro');
|
||||||
|
} else {
|
||||||
|
data_set($volume, 'source', $source . ':' . $target);
|
||||||
|
}
|
||||||
|
if (!str($source)->startsWith('/')) {
|
||||||
$topLevelVolumes->put($source, [
|
$topLevelVolumes->put($source, [
|
||||||
'name' => $source,
|
'name' => $source,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (is_array($volume)) {
|
||||||
|
return data_get($volume, 'source');
|
||||||
|
}
|
||||||
return $volume->value();
|
return $volume->value();
|
||||||
});
|
});
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Decide if the service is a database
|
// Decide if the service is a database
|
||||||
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
||||||
data_set($service, 'is_database', $isDatabase);
|
data_set($service, 'is_database', $isDatabase);
|
||||||
@@ -1450,13 +1467,14 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
])->first();
|
])->first();
|
||||||
$value = Str::of(replaceVariables($value));
|
$value = Str::of(replaceVariables($value));
|
||||||
$key = $value;
|
$key = $value;
|
||||||
|
|
||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'application_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||||
|
ray($command, $generatedValue);
|
||||||
|
if (!is_null($command)) {
|
||||||
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
|
||||||
if (Str::lower($forService) === $serviceName) {
|
if (Str::lower($forService) === $serviceName) {
|
||||||
$fqdn = generateFqdn($server, $containerName);
|
$fqdn = generateFqdn($server, $containerName);
|
||||||
@@ -1469,7 +1487,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($foundEnv) {
|
if ($foundEnv) {
|
||||||
$fqdn = data_get($foundEnv, 'value');
|
$fqdn = data_get($foundEnv, 'value');
|
||||||
} else {
|
} else {
|
||||||
if ($command->value() === 'URL') {
|
if ($command?->value() === 'URL') {
|
||||||
$fqdn = Str::of($fqdn)->after('://')->value();
|
$fqdn = Str::of($fqdn)->after('://')->value();
|
||||||
}
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
@@ -1492,6 +1510,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($value->contains(':-')) {
|
if ($value->contains(':-')) {
|
||||||
$key = $value->before(':');
|
$key = $value->before(':');
|
||||||
@@ -1602,6 +1621,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
|
|
||||||
return $service;
|
return $service;
|
||||||
});
|
});
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$services->each(function ($service, $serviceName) use ($pull_request_id, $services) {
|
||||||
|
$services[$serviceName . "-pr-$pull_request_id"] = $service;
|
||||||
|
data_forget($services, $serviceName);
|
||||||
|
});
|
||||||
|
}
|
||||||
$finalServices = [
|
$finalServices = [
|
||||||
'version' => $dockerComposeVersion,
|
'version' => $dockerComposeVersion,
|
||||||
'services' => $services->toArray(),
|
'services' => $services->toArray(),
|
||||||
@@ -1635,7 +1660,7 @@ function parseEnvVariable(Str|string $value)
|
|||||||
$forService = null;
|
$forService = null;
|
||||||
$generatedValue = null;
|
$generatedValue = null;
|
||||||
$port = null;
|
$port = null;
|
||||||
|
if ($value->startsWith('SERVICE')) {
|
||||||
if ($count === 2) {
|
if ($count === 2) {
|
||||||
if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
|
if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
|
||||||
// SERVICE_FQDN_UMAMI
|
// SERVICE_FQDN_UMAMI
|
||||||
@@ -1660,6 +1685,7 @@ function parseEnvVariable(Str|string $value)
|
|||||||
$command = $value->after('SERVICE_')->beforeLast('_');
|
$command = $value->after('SERVICE_')->beforeLast('_');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
'command' => $command,
|
'command' => $command,
|
||||||
'forService' => $forService,
|
'forService' => $forService,
|
||||||
|
|||||||
37
bootstrap/helpers/socialite.php
Normal file
37
bootstrap/helpers/socialite.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\OauthSetting;
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
|
||||||
|
function get_socialite_provider(string $provider)
|
||||||
|
{
|
||||||
|
$oauth_setting = OauthSetting::firstWhere('provider', $provider);
|
||||||
|
|
||||||
|
if ($provider == 'azure') {
|
||||||
|
$azure_config = new \SocialiteProviders\Manager\Config(
|
||||||
|
$oauth_setting->client_id,
|
||||||
|
$oauth_setting->client_secret,
|
||||||
|
$oauth_setting->redirect_uri,
|
||||||
|
['tenant' => $oauth_setting->tenant],
|
||||||
|
);
|
||||||
|
return Socialite::driver('azure')->setConfig($azure_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = [
|
||||||
|
'client_id' => $oauth_setting->client_id,
|
||||||
|
'client_secret' => $oauth_setting->client_secret,
|
||||||
|
'redirect' => $oauth_setting->redirect_uri,
|
||||||
|
];
|
||||||
|
|
||||||
|
$provider_class_map = [
|
||||||
|
'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class,
|
||||||
|
'github' => \Laravel\Socialite\Two\GithubProvider::class,
|
||||||
|
'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class,
|
||||||
|
'google' => \Laravel\Socialite\Two\GoogleProvider::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
return Socialite::buildProvider(
|
||||||
|
$provider_class_map[$provider],
|
||||||
|
$config
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ function isSubscriptionActive()
|
|||||||
// return $subscription->paddle_status === 'active';
|
// return $subscription->paddle_status === 'active';
|
||||||
// }
|
// }
|
||||||
if (isStripe()) {
|
if (isStripe()) {
|
||||||
return $subscription->stripe_invoice_paid === true && $subscription->stripe_cancel_at_period_end === false;
|
return $subscription->stripe_invoice_paid === true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"laravel/horizon": "^5.15",
|
"laravel/horizon": "^5.15",
|
||||||
"laravel/prompts": "^0.1.6",
|
"laravel/prompts": "^0.1.6",
|
||||||
"laravel/sanctum": "^v3.2.1",
|
"laravel/sanctum": "^v3.2.1",
|
||||||
|
"laravel/socialite": "^5.12",
|
||||||
"laravel/tinker": "^v2.8.1",
|
"laravel/tinker": "^v2.8.1",
|
||||||
"laravel/ui": "^4.2",
|
"laravel/ui": "^4.2",
|
||||||
"lcobucci/jwt": "^5.0.0",
|
"lcobucci/jwt": "^5.0.0",
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"pusher/pusher-php-server": "^7.2",
|
"pusher/pusher-php-server": "^7.2",
|
||||||
"resend/resend-laravel": "^0.5.0",
|
"resend/resend-laravel": "^0.5.0",
|
||||||
"sentry/sentry-laravel": "^3.4",
|
"sentry/sentry-laravel": "^3.4",
|
||||||
|
"socialiteproviders/microsoft-azure": "^5.1",
|
||||||
"spatie/laravel-activitylog": "^4.7.3",
|
"spatie/laravel-activitylog": "^4.7.3",
|
||||||
"spatie/laravel-data": "^3.4.3",
|
"spatie/laravel-data": "^3.4.3",
|
||||||
"spatie/laravel-ray": "^1.32.4",
|
"spatie/laravel-ray": "^1.32.4",
|
||||||
@@ -39,7 +41,6 @@
|
|||||||
"stripe/stripe-php": "^12.0",
|
"stripe/stripe-php": "^12.0",
|
||||||
"symfony/yaml": "^6.2",
|
"symfony/yaml": "^6.2",
|
||||||
"visus/cuid2": "^2.0.0",
|
"visus/cuid2": "^2.0.0",
|
||||||
"wire-elements/modal": "^2.0",
|
|
||||||
"yosymfony/toml": "^1.0"
|
"yosymfony/toml": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|||||||
829
composer.lock
generated
829
composer.lock
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user