From f1313b646837bc5549792dac28065b89e853580f Mon Sep 17 00:00:00 2001 From: dominicbachmann Date: Tue, 5 Apr 2022 01:13:25 +0200 Subject: [PATCH 01/56] Implemented typing for dockerfile configuration --- src/lib/types/composeFile.ts | 49 +++++++++++++++++++ src/routes/databases/[id]/start.json.ts | 3 +- src/routes/services/[id]/ghost/start.json.ts | 3 +- .../services/[id]/languagetool/start.json.ts | 3 +- .../services/[id]/meilisearch/start.json.ts | 3 +- src/routes/services/[id]/minio/start.json.ts | 3 +- src/routes/services/[id]/n8n/start.json.ts | 3 +- src/routes/services/[id]/nocodb/start.json.ts | 3 +- .../[id]/plausibleanalytics/start.json.ts | 3 +- .../services/[id]/uptimekuma/start.json.ts | 3 +- .../services/[id]/vaultwarden/start.json.ts | 3 +- .../services/[id]/vscodeserver/start.json.ts | 3 +- .../services/[id]/wordpress/start.json.ts | 3 +- 13 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 src/lib/types/composeFile.ts diff --git a/src/lib/types/composeFile.ts b/src/lib/types/composeFile.ts new file mode 100644 index 000000000..b7e88210f --- /dev/null +++ b/src/lib/types/composeFile.ts @@ -0,0 +1,49 @@ +import { makeLabelForServices } from '../buildPacks/common'; + +export type ComposeFile = { + version: ComposerFileVersion; + services: Record; + networks: Record; + volumes?: Record; +}; + +export type ComposeFileService = { + container_name: string; + image?: string; + networks: string[]; + environment: Record; + volumes?: string[]; + ulimits?: unknown; + labels?: string[]; + restart: ComposeFileRestartOption; + depends_on?: string[]; + command?: string; + build?: string; +}; + +export type ComposerFileVersion = + | '3.8' + | '3.7' + | '3.6' + | '3.5' + | '3.4' + | '3.3' + | '3.2' + | '3.1' + | '3.0' + | '2.4' + | '2.3' + | '2.2' + | '2.1' + | '2.0'; + +export type ComposeFileRestartOption = 'no' | 'always' | 'on-failure' | 'unless-stopped'; + +export type ComposeFileNetwork = { + external: boolean; +}; + +export type ComposeFileVolume = { + external?: boolean; + name?: string; +}; diff --git a/src/routes/databases/[id]/start.json.ts b/src/routes/databases/[id]/start.json.ts index bca2995d4..59fd7c1ea 100644 --- a/src/routes/databases/[id]/start.json.ts +++ b/src/routes/databases/[id]/start.json.ts @@ -6,6 +6,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { makeLabelForStandaloneDatabase } from '$lib/buildPacks/common'; import { startTcpProxy } from '$lib/haproxy'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -33,7 +34,7 @@ export const post: RequestHandler = async (event) => { const { workdir } = await createDirectories({ repository: type, buildId: id }); - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/ghost/start.json.ts b/src/routes/services/[id]/ghost/start.json.ts index 4fd9e7fa4..9e0b4ba11 100644 --- a/src/routes/services/[id]/ghost/start.json.ts +++ b/src/routes/services/[id]/ghost/start.json.ts @@ -11,6 +11,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -75,7 +76,7 @@ export const post: RequestHandler = async (event) => { config.ghost.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/languagetool/start.json.ts b/src/routes/services/[id]/languagetool/start.json.ts index a6a81d475..ac0f6a5bb 100644 --- a/src/routes/services/[id]/languagetool/start.json.ts +++ b/src/routes/services/[id]/languagetool/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -32,7 +33,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/meilisearch/start.json.ts b/src/routes/services/[id]/meilisearch/start.json.ts index 646a8b1ba..5a5a9d5c0 100644 --- a/src/routes/services/[id]/meilisearch/start.json.ts +++ b/src/routes/services/[id]/meilisearch/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -37,7 +38,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/minio/start.json.ts b/src/routes/services/[id]/minio/start.json.ts index bcffd9e8f..6e14a42ca 100644 --- a/src/routes/services/[id]/minio/start.json.ts +++ b/src/routes/services/[id]/minio/start.json.ts @@ -8,6 +8,7 @@ import getPort, { portNumbers } from 'get-port'; import { getDomain } from '$lib/components/common'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -55,7 +56,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/n8n/start.json.ts b/src/routes/services/[id]/n8n/start.json.ts index e5ad7e930..3df1855d0 100644 --- a/src/routes/services/[id]/n8n/start.json.ts +++ b/src/routes/services/[id]/n8n/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -33,7 +34,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/nocodb/start.json.ts b/src/routes/services/[id]/nocodb/start.json.ts index ebc59ce97..1642038b3 100644 --- a/src/routes/services/[id]/nocodb/start.json.ts +++ b/src/routes/services/[id]/nocodb/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -30,7 +31,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/plausibleanalytics/start.json.ts b/src/routes/services/[id]/plausibleanalytics/start.json.ts index 836bd0178..6ca37c5e8 100644 --- a/src/routes/services/[id]/plausibleanalytics/start.json.ts +++ b/src/routes/services/[id]/plausibleanalytics/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -120,7 +121,7 @@ COPY ./init.query /docker-entrypoint-initdb.d/init.query COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile); - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/uptimekuma/start.json.ts b/src/routes/services/[id]/uptimekuma/start.json.ts index 845873bb0..7a72326e1 100644 --- a/src/routes/services/[id]/uptimekuma/start.json.ts +++ b/src/routes/services/[id]/uptimekuma/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -31,7 +32,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/vaultwarden/start.json.ts b/src/routes/services/[id]/vaultwarden/start.json.ts index f977adda3..ae13d9015 100644 --- a/src/routes/services/[id]/vaultwarden/start.json.ts +++ b/src/routes/services/[id]/vaultwarden/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { getServiceImage, ErrorHandler } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -32,7 +33,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/vscodeserver/start.json.ts b/src/routes/services/[id]/vscodeserver/start.json.ts index 6f51fcf2a..dbe0c120c 100644 --- a/src/routes/services/[id]/vscodeserver/start.json.ts +++ b/src/routes/services/[id]/vscodeserver/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -41,7 +42,7 @@ export const post: RequestHandler = async (event) => { config.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { diff --git a/src/routes/services/[id]/wordpress/start.json.ts b/src/routes/services/[id]/wordpress/start.json.ts index 98e7d6aab..c0a28e0bd 100644 --- a/src/routes/services/[id]/wordpress/start.json.ts +++ b/src/routes/services/[id]/wordpress/start.json.ts @@ -5,6 +5,7 @@ import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; +import type { ComposeFile } from '$lib/types/composeFile'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -65,7 +66,7 @@ export const post: RequestHandler = async (event) => { config.wordpress.environmentVariables[secret.name] = secret.value; }); } - const composeFile = { + const composeFile: ComposeFile = { version: '3.8', services: { [id]: { From e1efd9355ff051b840a0d1eebe3b2e39740fb780 Mon Sep 17 00:00:00 2001 From: Dhaval Soneji Date: Tue, 5 Apr 2022 14:03:36 +0100 Subject: [PATCH 02/56] Add plausible/analytics:stable docker tag --- src/lib/database/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index 3e473f094..75366dbc9 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -110,7 +110,7 @@ export const supportedServiceTypesAndVersions = [ fancyName: 'Plausible Analytics', baseImage: 'plausible/analytics', images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], - versions: ['latest'], + versions: ['latest', 'stable'], ports: { main: 8000 } From 8e9e6607e5c67c4785fa18a473c1ad8606990e23 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 15:56:25 +0200 Subject: [PATCH 03/56] feat: Wordpress on-demand SFTP --- prisma/schema.prisma | 6 + src/lib/components/Setting.svelte | 5 +- src/lib/database/services.ts | 6 +- src/lib/haproxy/index.ts | 6 +- .../services/[id]/_Services/_Services.svelte | 16 +- .../services/[id]/_Services/_Wordpress.svelte | 69 +++++++++ src/routes/services/[id]/__layout.svelte | 5 +- src/routes/services/[id]/index.json.ts | 5 +- src/routes/services/[id]/index.svelte | 6 +- .../services/[id]/wordpress/settings.json.ts | 138 ++++++++++++++++++ 10 files changed, 238 insertions(+), 24 deletions(-) create mode 100644 src/routes/services/[id]/wordpress/settings.json.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 986a773bf..d5e322337 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -332,6 +332,12 @@ model Wordpress { mysqlRootUserPassword String mysqlDatabase String? mysqlPublicPort Int? + ftpEnabled Boolean @default(false) + ftpUser String? + ftpPassword String? + ftpPublicPort Int? + ftpHostKey String? + ftpHostKeyPrivate String? serviceId String @unique service Service @relation(fields: [serviceId], references: [id]) createdAt DateTime @default(now()) diff --git a/src/lib/components/Setting.svelte b/src/lib/components/Setting.svelte index c8764bed7..7d87dd6fb 100644 --- a/src/lib/components/Setting.svelte +++ b/src/lib/components/Setting.svelte @@ -7,6 +7,7 @@ export let isCenter = true; export let disabled = false; export let dataTooltip = null; + export let loading = false;
@@ -26,7 +27,7 @@ on:click aria-pressed="false" class="relative mx-20 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out" - class:opacity-50={disabled} + class:opacity-50={disabled || loading} class:bg-green-600={setting} class:bg-stone-700={!setting} > @@ -40,6 +41,7 @@ class=" absolute inset-0 flex h-full w-full items-center justify-center transition-opacity duration-200 ease-in" class:opacity-0={setting} class:opacity-100={!setting} + class:animate-spin={loading} aria-hidden="true" > @@ -57,6 +59,7 @@ aria-hidden="true" class:opacity-100={setting} class:opacity-0={!setting} + class:animate-spin={loading} > {:else if service.type === 'wordpress'} - + {:else if service.type === 'ghost'} {:else if service.type === 'meilisearch'} @@ -151,17 +152,4 @@ {/if}
- diff --git a/src/routes/services/[id]/_Services/_Wordpress.svelte b/src/routes/services/[id]/_Services/_Wordpress.svelte index 883178a22..dc7eb4ebb 100644 --- a/src/routes/services/[id]/_Services/_Wordpress.svelte +++ b/src/routes/services/[id]/_Services/_Wordpress.svelte @@ -1,9 +1,55 @@
@@ -28,6 +74,29 @@ define('SUBDOMAIN_INSTALL', false);` : 'N/A'}>{service.wordpress.extraConfig}
+
+ changeSettings('ftpEnabled')} + title="Enable sFTP connection to WordPress data" + description="Enables an on-demand sFTP connection to the WordPress data directory. This is useful if you want to use sFTP to upload files." + /> +
+{#if service.wordpress.ftpEnabled} +
+ + +
+
+ + +
+
+ + +
+{/if}
MySQL
diff --git a/src/routes/services/[id]/__layout.svelte b/src/routes/services/[id]/__layout.svelte index 362f89786..37158d711 100644 --- a/src/routes/services/[id]/__layout.svelte +++ b/src/routes/services/[id]/__layout.svelte @@ -16,7 +16,7 @@ const endpoint = `/services/${params.id}.json`; const res = await fetch(endpoint); if (res.ok) { - const { service, isRunning } = await res.json(); + const { service, isRunning, settings } = await res.json(); if (!service || Object.entries(service).length === 0) { return { status: 302, @@ -45,7 +45,8 @@ stuff: { service, isRunning, - readOnly + readOnly, + settings } }; } diff --git a/src/routes/services/[id]/index.json.ts b/src/routes/services/[id]/index.json.ts index 676ff6405..f75ff87f6 100644 --- a/src/routes/services/[id]/index.json.ts +++ b/src/routes/services/[id]/index.json.ts @@ -17,7 +17,7 @@ export const get: RequestHandler = async (event) => { const { id } = event.params; try { const service = await db.getService({ id, teamId }); - const { destinationDockerId, destinationDocker, type, version } = service; + const { destinationDockerId, destinationDocker, type, version, settings } = service; let isRunning = false; if (destinationDockerId) { @@ -46,7 +46,8 @@ export const get: RequestHandler = async (event) => { return { body: { isRunning, - service + service, + settings } }; } catch (error) { diff --git a/src/routes/services/[id]/index.svelte b/src/routes/services/[id]/index.svelte index 9f64e039b..a16591266 100644 --- a/src/routes/services/[id]/index.svelte +++ b/src/routes/services/[id]/index.svelte @@ -6,7 +6,8 @@ props: { service: stuff.service, isRunning: stuff.isRunning, - readOnly: stuff.readOnly + readOnly: stuff.readOnly, + settings: stuff.settings } }; } @@ -37,6 +38,7 @@ export let service; export let isRunning; export let readOnly; + export let settings; if (browser && window.location.hostname === 'demo.coolify.io' && !service.fqdn) { service.fqdn = `http://${cuid()}.demo.coolify.io`; @@ -76,4 +78,4 @@ - + diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts new file mode 100644 index 000000000..728d4919f --- /dev/null +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -0,0 +1,138 @@ +import { dev } from '$app/env'; +import { asyncExecShell, getEngine, getUserDetails } from '$lib/common'; +import { decrypt, encrypt } from '$lib/crypto'; +import * as db from '$lib/database'; +import { generateDatabaseConfiguration, ErrorHandler, generatePassword } from '$lib/database'; +import { checkContainer, startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy'; +import type { RequestHandler } from '@sveltejs/kit'; +import cuid from 'cuid'; +import fs from 'fs/promises'; +import getPort, { portNumbers } from 'get-port'; + +export const post: RequestHandler = async (event) => { + const { status, body, teamId } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = event.params; + const data = await db.prisma.setting.findFirst(); + const { minPort, maxPort } = data; + + const { ftpEnabled } = await event.request.json(); + const publicPort = await getPort({ port: portNumbers(minPort, maxPort) }); + let ftpUser = cuid(); + const ftpPassword = generatePassword(); + + const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys'; + try { + const { stdout: password } = await asyncExecShell( + `echo ${ftpPassword} | openssl passwd -1 -stdin` + ); + const data = await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpEnabled }, + include: { service: { include: { destinationDocker: true } } } + }); + const { + service: { destinationDockerId, destinationDocker }, + ftpPublicPort: oldPublicPort, + ftpUser: user, + ftpHostKey, + ftpHostKeyPrivate + } = data; + if (user) ftpUser = user; + try { + await fs.stat(hostkeyDir); + } catch (error) { + await asyncExecShell(`mkdir -p ${hostkeyDir}`); + } + if (!ftpHostKey) { + await asyncExecShell( + `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f /tmp/${id} < /dev/null` + ); + const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`); + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpHostKey: encrypt(ftpHostKey.replace('\n', '')) } + }); + } else { + await asyncExecShell(`echo ${decrypt(ftpHostKey)} > ${hostkeyDir}/${id}.ed25519`); + } + if (!ftpHostKeyPrivate) { + await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f /tmp/${id}.rsa < /dev/null`); + const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat /tmp/${id}.rsa`); + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate.replace('\n', '')) } + }); + } else { + await asyncExecShell(`echo ${decrypt(ftpHostKeyPrivate)} > ${hostkeyDir}/${id}.rsa`); + } + if (destinationDockerId) { + const { network, engine } = destinationDocker; + const host = getEngine(engine); + if (ftpEnabled) { + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpPublicPort: publicPort, ftpUser, ftpPassword: encrypt(ftpPassword) } + }); + + try { + const isRunning = await checkContainer(engine, `${id}-ftp`); + if (isRunning) { + await asyncExecShell( + `DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` + ); + } + } catch (error) { + console.log(error); + // + } + + await asyncExecShell( + `DOCKER_HOST=${host} docker run --restart always --add-host 'host.docker.internal:host-gateway' --network ${network} --name ${id}-ftp -v ${id}-wordpress-data:/home/${ftpUser} -v ${hostkeyDir}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key -v ${hostkeyDir}/${id}.rsa:/etc/ssh/ssh_host_rsa_key -d atmoz/sftp '${ftpUser}:${password.replace( + '\n', + '' + )}:e:1001'` + ); + + await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22); + } else { + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpPublicPort: null } + }); + try { + const isRunning = await checkContainer(engine, `${id}-ftp`); + if (isRunning) { + await asyncExecShell( + `DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` + ); + } + } catch (error) { + console.log(error); + // + } + + await stopTcpHttpProxy(destinationDocker, oldPublicPort); + } + } + if (ftpEnabled) { + return { + status: 201, + body: { + publicPort, + ftpUser, + ftpPassword + } + }; + } else { + return { + status: 200, + body: {} + }; + } + } catch (error) { + console.log(error); + return ErrorHandler(error); + } +}; From fe9d0503fb328aa3cbf359f75b6794d7eba85d36 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 17:15:06 +0200 Subject: [PATCH 04/56] feat: Finalize on-demand sftp for wp --- .../migration.sql | 29 ++++++++++ .../services/[id]/_Services/_Wordpress.svelte | 46 ++++++++-------- .../services/[id]/wordpress/settings.json.ts | 54 +++++++++---------- 3 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 prisma/migrations/20220405151428_wordpress_sftp/migration.sql diff --git a/prisma/migrations/20220405151428_wordpress_sftp/migration.sql b/prisma/migrations/20220405151428_wordpress_sftp/migration.sql new file mode 100644 index 000000000..6c3c4b907 --- /dev/null +++ b/prisma/migrations/20220405151428_wordpress_sftp/migration.sql @@ -0,0 +1,29 @@ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Wordpress" ( + "id" TEXT NOT NULL PRIMARY KEY, + "extraConfig" TEXT, + "tablePrefix" TEXT, + "mysqlUser" TEXT NOT NULL, + "mysqlPassword" TEXT NOT NULL, + "mysqlRootUser" TEXT NOT NULL, + "mysqlRootUserPassword" TEXT NOT NULL, + "mysqlDatabase" TEXT, + "mysqlPublicPort" INTEGER, + "ftpEnabled" BOOLEAN NOT NULL DEFAULT false, + "ftpUser" TEXT, + "ftpPassword" TEXT, + "ftpPublicPort" INTEGER, + "ftpHostKey" TEXT, + "ftpHostKeyPrivate" TEXT, + "serviceId" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress"; +DROP TABLE "Wordpress"; +ALTER TABLE "new_Wordpress" RENAME TO "Wordpress"; +CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/src/routes/services/[id]/_Services/_Wordpress.svelte b/src/routes/services/[id]/_Services/_Wordpress.svelte index dc7eb4ebb..3ea53edd3 100644 --- a/src/routes/services/[id]/_Services/_Wordpress.svelte +++ b/src/routes/services/[id]/_Services/_Wordpress.svelte @@ -26,28 +26,31 @@ : 'Loading...'; } async function changeSettings(name) { - ftpLoading = true; - let ftpEnabled = service.wordpress.ftpEnabled; + if (ftpLoading) return; + if (isRunning) { + ftpLoading = true; + let ftpEnabled = service.wordpress.ftpEnabled; - if (name === 'ftpEnabled') { - ftpEnabled = !ftpEnabled; - } - try { - const { - publicPort, - ftpUser: user, - ftpPassword: password - } = await post(`/services/${id}/wordpress/settings.json`, { - ftpEnabled - }); - ftpUrl = generateUrl(publicPort); - ftpUser = user; - ftpPassword = password; - service.wordpress.ftpEnabled = ftpEnabled; - } catch ({ error }) { - return errorNotification(error); - } finally { - ftpLoading = false; + if (name === 'ftpEnabled') { + ftpEnabled = !ftpEnabled; + } + try { + const { + publicPort, + ftpUser: user, + ftpPassword: password + } = await post(`/services/${id}/wordpress/settings.json`, { + ftpEnabled + }); + ftpUrl = generateUrl(publicPort); + ftpUser = user; + ftpPassword = password; + service.wordpress.ftpEnabled = ftpEnabled; + } catch ({ error }) { + return errorNotification(error); + } finally { + ftpLoading = false; + } } } @@ -78,6 +81,7 @@ define('SUBDOMAIN_INSTALL', false);` changeSettings('ftpEnabled')} title="Enable sFTP connection to WordPress data" description="Enables an on-demand sFTP connection to the WordPress data directory. This is useful if you want to use sFTP to upload files." diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 728d4919f..6d6d730ae 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -40,34 +40,34 @@ export const post: RequestHandler = async (event) => { ftpHostKeyPrivate } = data; if (user) ftpUser = user; - try { - await fs.stat(hostkeyDir); - } catch (error) { - await asyncExecShell(`mkdir -p ${hostkeyDir}`); - } - if (!ftpHostKey) { - await asyncExecShell( - `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f /tmp/${id} < /dev/null` - ); - const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`); - await db.prisma.wordpress.update({ - where: { serviceId: id }, - data: { ftpHostKey: encrypt(ftpHostKey.replace('\n', '')) } - }); - } else { - await asyncExecShell(`echo ${decrypt(ftpHostKey)} > ${hostkeyDir}/${id}.ed25519`); - } - if (!ftpHostKeyPrivate) { - await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f /tmp/${id}.rsa < /dev/null`); - const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat /tmp/${id}.rsa`); - await db.prisma.wordpress.update({ - where: { serviceId: id }, - data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate.replace('\n', '')) } - }); - } else { - await asyncExecShell(`echo ${decrypt(ftpHostKeyPrivate)} > ${hostkeyDir}/${id}.rsa`); - } if (destinationDockerId) { + try { + await fs.stat(hostkeyDir); + } catch (error) { + await asyncExecShell(`mkdir -p ${hostkeyDir}`); + } + if (!ftpHostKey) { + await asyncExecShell( + `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519` + ); + const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`); + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpHostKey: encrypt(ftpHostKey) } + }); + } else { + await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`); + } + if (!ftpHostKeyPrivate) { + await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`); + const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`); + await db.prisma.wordpress.update({ + where: { serviceId: id }, + data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) } + }); + } else { + await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`); + } const { network, engine } = destinationDocker; const host = getEngine(engine); if (ftpEnabled) { From d2dcd0abc8400cc0d75546039caa2f38963f48e8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 17:15:21 +0200 Subject: [PATCH 05/56] chore:version++ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2aa11b114..ac2396dab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.3.3", + "version": "2.4.0", "license": "AGPL-3.0", "scripts": { "dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev", From 09841ad4cb3e909a10c8ad15b4204fd0a3f3005e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 17:21:40 +0200 Subject: [PATCH 06/56] fix: Add openssl to image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9494ff702..df4614a13 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ WORKDIR /app LABEL coolify.managed true -RUN apk add --no-cache git git-lfs openssh-client curl jq cmake sqlite +RUN apk add --no-cache git git-lfs openssh-client curl jq cmake sqlite openssl RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@6 RUN pnpm add -g pnpm From 4ba2205af4dbfac0dfb6ab215a44b897ae75a120 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 17:37:03 +0200 Subject: [PATCH 07/56] fix: Permission issues --- src/lib/components/Setting.svelte | 5 +++-- src/routes/services/[id]/wordpress/settings.json.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/components/Setting.svelte b/src/lib/components/Setting.svelte index 7d87dd6fb..d7b028861 100644 --- a/src/lib/components/Setting.svelte +++ b/src/lib/components/Setting.svelte @@ -28,8 +28,9 @@ aria-pressed="false" class="relative mx-20 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out" class:opacity-50={disabled || loading} - class:bg-green-600={setting} - class:bg-stone-700={!setting} + class:bg-green-600={!loading && setting} + class:bg-stone-700={!loading && !setting} + class:bg-yellow-500={loading} > Use setting { } else { await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`); } + await asyncExecShell(`chmod -R 600 ${hostkeyDir}`); const { network, engine } = destinationDocker; const host = getEngine(engine); if (ftpEnabled) { From 3a835b420ed96e686150872d1e1b009c7f31af73 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 5 Apr 2022 23:44:18 +0200 Subject: [PATCH 08/56] WIP --- .../services/[id]/wordpress/settings.json.ts | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 13d6685bf..86810ca25 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -8,6 +8,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import cuid from 'cuid'; import fs from 'fs/promises'; import getPort, { portNumbers } from 'get-port'; +import yaml from 'js-yaml'; export const post: RequestHandler = async (event) => { const { status, body, teamId } = await getUserDetails(event); @@ -68,7 +69,6 @@ export const post: RequestHandler = async (event) => { } else { await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`); } - await asyncExecShell(`chmod -R 600 ${hostkeyDir}`); const { network, engine } = destinationDocker; const host = getEngine(engine); if (ftpEnabled) { @@ -88,12 +88,40 @@ export const post: RequestHandler = async (event) => { console.log(error); // } - + const volumes = [ + `${id}-wordpress-data:/home/${ftpUser}`, + `${hostkeyDir}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`, + `${hostkeyDir}/${id}.rsa:/etc/ssh/ssh_host_rsa_key` + ]; + const compose = { + version: '3.8', + services: { + [`${id}-ftp`]: { + image: `atmoz/sftp:alpine`, + command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:1001'`, + extra_hosts: ['host.docker.internal:host-gateway'], + container_name: `${id}-ftp`, + volumes, + networks: [network], + depends_on: [], + restart: 'always' + } + }, + networks: { + [network]: { + external: true + } + }, + volumes: { + [`${id}-wordpress-data`]: { + external: true, + name: `${id}-wordpress-data` + } + } + }; + await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose)); await asyncExecShell( - `DOCKER_HOST=${host} docker run --restart always --add-host 'host.docker.internal:host-gateway' --network ${network} --name ${id}-ftp -v ${id}-wordpress-data:/home/${ftpUser} -v ${hostkeyDir}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key -v ${hostkeyDir}/${id}.rsa:/etc/ssh/ssh_host_rsa_key -d atmoz/sftp '${ftpUser}:${password.replace( - '\n', - '' - )}:e:1001'` + `DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d` ); await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22); From 39fa64e20d1d9b9ec13f4acbad053b3b646a532f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 10:29:42 +0200 Subject: [PATCH 09/56] fix: On-demand sFTP for wp --- .../services/[id]/wordpress/settings.json.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 86810ca25..3356be86b 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -21,13 +21,10 @@ export const post: RequestHandler = async (event) => { const { ftpEnabled } = await event.request.json(); const publicPort = await getPort({ port: portNumbers(minPort, maxPort) }); let ftpUser = cuid(); - const ftpPassword = generatePassword(); + let ftpPassword = generatePassword(); const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys'; try { - const { stdout: password } = await asyncExecShell( - `echo ${ftpPassword} | openssl passwd -1 -stdin` - ); const data = await db.prisma.wordpress.update({ where: { serviceId: id }, data: { ftpEnabled }, @@ -37,10 +34,16 @@ export const post: RequestHandler = async (event) => { service: { destinationDockerId, destinationDocker }, ftpPublicPort: oldPublicPort, ftpUser: user, + ftpPassword: savedPassword, ftpHostKey, ftpHostKeyPrivate } = data; if (user) ftpUser = user; + if (savedPassword) ftpPassword = decrypt(savedPassword); + + const { stdout: password } = await asyncExecShell( + `echo ${ftpPassword} | openssl passwd -1 -stdin` + ); if (destinationDockerId) { try { await fs.stat(hostkeyDir); @@ -74,7 +77,11 @@ export const post: RequestHandler = async (event) => { if (ftpEnabled) { await db.prisma.wordpress.update({ where: { serviceId: id }, - data: { ftpPublicPort: publicPort, ftpUser, ftpPassword: encrypt(ftpPassword) } + data: { + ftpPublicPort: publicPort, + ftpUser: user ? undefined : ftpUser, + ftpPassword: savedPassword ? undefined : encrypt(ftpPassword) + } }); try { @@ -125,6 +132,9 @@ export const post: RequestHandler = async (event) => { ); await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22); + await asyncExecShell( + `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub` + ); } else { await db.prisma.wordpress.update({ where: { serviceId: id }, @@ -141,8 +151,10 @@ export const post: RequestHandler = async (event) => { console.log(error); // } - await stopTcpHttpProxy(destinationDocker, oldPublicPort); + await asyncExecShell( + `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ` + ); } } if (ftpEnabled) { From 9a05bfa8999b514d46c92eec3e453efd1fd53993 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 10:30:53 +0200 Subject: [PATCH 10/56] fix: Fix for fix haha --- src/routes/services/[id]/wordpress/settings.json.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 3356be86b..796510989 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -132,9 +132,6 @@ export const post: RequestHandler = async (event) => { ); await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22); - await asyncExecShell( - `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub` - ); } else { await db.prisma.wordpress.update({ where: { serviceId: id }, @@ -152,9 +149,6 @@ export const post: RequestHandler = async (event) => { // } await stopTcpHttpProxy(destinationDocker, oldPublicPort); - await asyncExecShell( - `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ` - ); } } if (ftpEnabled) { @@ -175,5 +169,9 @@ export const post: RequestHandler = async (event) => { } catch (error) { console.log(error); return ErrorHandler(error); + } finally { + await asyncExecShell( + `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ` + ); } }; From 7a2f29f6a39bf64839509b782afbb70ed7e464c3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 13:35:53 +0200 Subject: [PATCH 11/56] feat: PHP Composer support --- src/lib/buildPacks/php.ts | 16 ++++++++++++++-- .../[id]/configuration/buildpack.svelte | 10 ++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/lib/buildPacks/php.ts b/src/lib/buildPacks/php.ts index 14ee5d0cb..cfb39d20a 100644 --- a/src/lib/buildPacks/php.ts +++ b/src/lib/buildPacks/php.ts @@ -4,6 +4,12 @@ import { promises as fs } from 'fs'; const createDockerfile = async (data, image, htaccessFound): Promise => { const { workdir, baseDirectory } = data; const Dockerfile: Array = []; + let composerFound = false; + try { + await fs.readFile(`${workdir}${baseDirectory || ''}/composer.json`); + composerFound = true; + } catch (error) {} + Dockerfile.push(`FROM ${image}`); Dockerfile.push(`LABEL coolify.image=true`); Dockerfile.push('WORKDIR /app'); @@ -11,6 +17,10 @@ const createDockerfile = async (data, image, htaccessFound): Promise => { if (htaccessFound) { Dockerfile.push(`COPY .${baseDirectory || ''}/.htaccess ./`); } + if (composerFound) { + Dockerfile.push(`RUN composer install`); + } + Dockerfile.push(`COPY /entrypoint.sh /opt/docker/provision/entrypoint.d/30-entrypoint.sh`); Dockerfile.push(`EXPOSE 80`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); @@ -21,12 +31,14 @@ export default async function (data) { try { let htaccessFound = false; try { - const d = await fs.readFile(`${workdir}${baseDirectory || ''}/.htaccess`); + await fs.readFile(`${workdir}${baseDirectory || ''}/.htaccess`); htaccessFound = true; } catch (e) { // } - const image = htaccessFound ? 'webdevops/php-apache' : 'webdevops/php-nginx'; + const image = htaccessFound + ? 'webdevops/php-apache:8.0-alpine' + : 'webdevops/php-nginx:8.0-alpine'; await createDockerfile(data, image, htaccessFound); await buildImage(data); } catch (error) { diff --git a/src/routes/applications/[id]/configuration/buildpack.svelte b/src/routes/applications/[id]/configuration/buildpack.svelte index cd005768c..c885f3bf5 100644 --- a/src/routes/applications/[id]/configuration/buildpack.svelte +++ b/src/routes/applications/[id]/configuration/buildpack.svelte @@ -81,6 +81,9 @@ ); const indexHtml = files.find((file) => file.name === 'index.html' && file.type === 'blob'); const indexPHP = files.find((file) => file.name === 'index.php' && file.type === 'blob'); + const composerPHP = files.find( + (file) => file.name === 'composer.json' && file.type === 'blob' + ); if (yarnLock) packageManager = 'yarn'; if (pnpmLock) packageManager = 'pnpm'; @@ -103,7 +106,7 @@ foundConfig = findBuildPack('python'); } else if (indexHtml) { foundConfig = findBuildPack('static', packageManager); - } else if (indexPHP) { + } else if (indexPHP || composerPHP) { foundConfig = findBuildPack('php'); } else { foundConfig = findBuildPack('node', packageManager); @@ -127,6 +130,9 @@ ); const indexHtml = files.find((file) => file.name === 'index.html' && file.type === 'file'); const indexPHP = files.find((file) => file.name === 'index.php' && file.type === 'file'); + const composerPHP = files.find( + (file) => file.name === 'composer.json' && file.type === 'file' + ); if (yarnLock) packageManager = 'yarn'; if (pnpmLock) packageManager = 'pnpm'; @@ -146,7 +152,7 @@ foundConfig = findBuildPack('python'); } else if (indexHtml) { foundConfig = findBuildPack('static', packageManager); - } else if (indexPHP) { + } else if (indexPHP || composerPHP) { foundConfig = findBuildPack('php'); } else { foundConfig = findBuildPack('node', packageManager); From fe2cc5a99aa5dc71a00cf6fbc5527bafa30aad3b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 14:27:51 +0200 Subject: [PATCH 12/56] feat: Working on-demand sftp to wp data --- .../services/[id]/wordpress/settings.json.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 796510989..080326cfc 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -97,9 +97,17 @@ export const post: RequestHandler = async (event) => { } const volumes = [ `${id}-wordpress-data:/home/${ftpUser}`, - `${hostkeyDir}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`, - `${hostkeyDir}/${id}.rsa:/etc/ssh/ssh_host_rsa_key` + `${ + dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys' + }/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`, + `${ + dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys' + }/${id}.rsa:/etc/ssh/ssh_host_rsa_key`, + `${ + dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys' + }/${id}.sh:/etc/sftp.d/chmod.sh` ]; + const compose = { version: '3.8', services: { @@ -126,6 +134,11 @@ export const post: RequestHandler = async (event) => { } } }; + await fs.writeFile( + `${hostkeyDir}/${id}.sh`, + `#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key` + ); + await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`); await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose)); await asyncExecShell( `DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d` @@ -138,14 +151,10 @@ export const post: RequestHandler = async (event) => { data: { ftpPublicPort: null } }); try { - const isRunning = await checkContainer(engine, `${id}-ftp`); - if (isRunning) { - await asyncExecShell( - `DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` - ); - } + await asyncExecShell( + `DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` + ); } catch (error) { - console.log(error); // } await stopTcpHttpProxy(destinationDocker, oldPublicPort); @@ -171,7 +180,7 @@ export const post: RequestHandler = async (event) => { return ErrorHandler(error); } finally { await asyncExecShell( - `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ` + `rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh` ); } }; From 352bb651257e185e9108b9c0e579e052589b065f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 14:57:41 +0200 Subject: [PATCH 13/56] ui: fix --- src/routes/applications/[id]/configuration/source.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/applications/[id]/configuration/source.svelte b/src/routes/applications/[id]/configuration/source.svelte index b1df17aa3..953c23d69 100644 --- a/src/routes/applications/[id]/configuration/source.svelte +++ b/src/routes/applications/[id]/configuration/source.svelte @@ -62,7 +62,7 @@
{#if !filteredSources || filteredSources.length === 0}
-
No configurable Git Source found
+
No configurable Git Source found
Date: Wed, 6 Apr 2022 15:55:17 +0200 Subject: [PATCH 14/56] feat: Admin team sees everything --- src/lib/database/applications.ts | 42 +++-- src/lib/database/databases.ts | 25 ++- src/lib/database/destinations.ts | 23 ++- src/lib/database/gitSources.ts | 23 ++- src/lib/database/services.ts | 44 ++++-- src/routes/applications/_Application.svelte | 1 + src/routes/databases/index.svelte | 1 + .../destinations/[id]/_LocalDocker.svelte | 52 ++----- src/routes/destinations/[id]/index.json.ts | 2 +- src/routes/destinations/index.svelte | 1 + src/routes/services/index.svelte | 1 + src/routes/sources/[id]/_Gitlab.svelte | 144 +++++++++--------- src/routes/sources/index.svelte | 1 + 13 files changed, 210 insertions(+), 150 deletions(-) diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index 1d8140144..1c6e172c2 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -5,7 +5,13 @@ import { getDomain, removeDestinationDocker } from '$lib/common'; import { prisma } from './common'; export async function listApplications(teamId) { - return await prisma.application.findMany({ where: { teams: { some: { id: teamId } } } }); + if (teamId === '0') { + return await prisma.application.findMany({ include: { teams: true } }); + } + return await prisma.application.findMany({ + where: { teams: { some: { id: teamId } } }, + include: { teams: true } + }); } export async function newApplication({ name, teamId }) { @@ -130,16 +136,30 @@ export async function getApplicationById({ id }) { return { ...body }; } export async function getApplication({ id, teamId }) { - let body = await prisma.application.findFirst({ - where: { id, teams: { some: { id: teamId } } }, - include: { - destinationDocker: true, - settings: true, - gitSource: { include: { githubApp: true, gitlabApp: true } }, - secrets: true, - persistentStorage: true - } - }); + let body = {}; + if (teamId === '0') { + body = await prisma.application.findFirst({ + where: { id }, + include: { + destinationDocker: true, + settings: true, + gitSource: { include: { githubApp: true, gitlabApp: true } }, + secrets: true, + persistentStorage: true + } + }); + } else { + body = await prisma.application.findFirst({ + where: { id, teams: { some: { id: teamId } } }, + include: { + destinationDocker: true, + settings: true, + gitSource: { include: { githubApp: true, gitlabApp: true } }, + secrets: true, + persistentStorage: true + } + }); + } if (body?.gitSource?.githubApp?.clientSecret) { body.gitSource.githubApp.clientSecret = decrypt(body.gitSource.githubApp.clientSecret); diff --git a/src/lib/database/databases.ts b/src/lib/database/databases.ts index be5ddacd3..7fc237944 100644 --- a/src/lib/database/databases.ts +++ b/src/lib/database/databases.ts @@ -7,7 +7,14 @@ import getPort, { portNumbers } from 'get-port'; import { asyncExecShell, getEngine, removeContainer } from '$lib/common'; export async function listDatabases(teamId) { - return await prisma.database.findMany({ where: { teams: { some: { id: teamId } } } }); + if (teamId === '0') { + return await prisma.database.findMany({ include: { teams: true } }); + } else { + return await prisma.database.findMany({ + where: { teams: { some: { id: teamId } } }, + include: { teams: true } + }); + } } export async function newDatabase({ name, teamId }) { const dbUser = cuid(); @@ -31,10 +38,18 @@ export async function newDatabase({ name, teamId }) { } export async function getDatabase({ id, teamId }) { - const body = await prisma.database.findFirst({ - where: { id, teams: { some: { id: teamId } } }, - include: { destinationDocker: true, settings: true } - }); + let body = {}; + if (teamId === '0') { + body = await prisma.database.findFirst({ + where: { id }, + include: { destinationDocker: true, settings: true } + }); + } else { + body = await prisma.database.findFirst({ + where: { id, teams: { some: { id: teamId } } }, + include: { destinationDocker: true, settings: true } + }); + } if (body.dbUserPassword) body.dbUserPassword = decrypt(body.dbUserPassword); if (body.rootUserPassword) body.rootUserPassword = decrypt(body.rootUserPassword); diff --git a/src/lib/database/destinations.ts b/src/lib/database/destinations.ts index 3f3aadec5..5bd63c81b 100644 --- a/src/lib/database/destinations.ts +++ b/src/lib/database/destinations.ts @@ -6,7 +6,13 @@ import { getDatabaseImage } from '.'; import { prisma } from './common'; export async function listDestinations(teamId) { - return await prisma.destinationDocker.findMany({ where: { teams: { some: { id: teamId } } } }); + if (teamId === '0') { + return await prisma.destinationDocker.findMany({ include: { teams: true } }); + } + return await prisma.destinationDocker.findMany({ + where: { teams: { some: { id: teamId } } }, + include: { teams: true } + }); } export async function configureDestinationForService({ id, destinationId }) { @@ -124,12 +130,17 @@ export async function removeDestination({ id }) { } export async function getDestination({ id, teamId }) { - let destination = await prisma.destinationDocker.findFirst({ - where: { id, teams: { some: { id: teamId } } } - }); - if (destination.remoteEngine) { - destination.sshPrivateKey = decrypt(destination.sshPrivateKey); + let destination = {}; + if (teamId === '0') { + destination = await prisma.destinationDocker.findFirst({ + where: { id } + }); + } else { + destination = await prisma.destinationDocker.findFirst({ + where: { id, teams: { some: { id: teamId } } } + }); } + return destination; } export async function getDestinationByApplicationId({ id, teamId }) { diff --git a/src/lib/database/gitSources.ts b/src/lib/database/gitSources.ts index 927907964..7e4e90633 100644 --- a/src/lib/database/gitSources.ts +++ b/src/lib/database/gitSources.ts @@ -2,9 +2,14 @@ import { decrypt, encrypt } from '$lib/crypto'; import { prisma } from './common'; export async function listSources(teamId) { + if (teamId === '0') { + return await prisma.gitSource.findMany({ + include: { githubApp: true, gitlabApp: true, teams: true } + }); + } return await prisma.gitSource.findMany({ where: { teams: { some: { id: teamId } } }, - include: { githubApp: true, gitlabApp: true } + include: { githubApp: true, gitlabApp: true, teams: true } }); } @@ -31,10 +36,18 @@ export async function removeSource({ id }) { } export async function getSource({ id, teamId }) { - let body = await prisma.gitSource.findFirst({ - where: { id, teams: { some: { id: teamId } } }, - include: { githubApp: true, gitlabApp: true } - }); + let body = {}; + if (teamId === '0') { + body = await prisma.gitSource.findFirst({ + where: { id }, + include: { githubApp: true, gitlabApp: true } + }); + } else { + body = await prisma.gitSource.findFirst({ + where: { id, teams: { some: { id: teamId } } }, + include: { githubApp: true, gitlabApp: true } + }); + } if (body?.githubApp?.clientSecret) body.githubApp.clientSecret = decrypt(body.githubApp.clientSecret); if (body?.githubApp?.webhookSecret) diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts index bc25b9327..d578a500c 100644 --- a/src/lib/database/services.ts +++ b/src/lib/database/services.ts @@ -5,7 +5,14 @@ import { generatePassword } from '.'; import { prisma } from './common'; export async function listServices(teamId) { - return await prisma.service.findMany({ where: { teams: { some: { id: teamId } } } }); + if (teamId === '0') { + return await prisma.service.findMany({ include: { teams: true } }); + } else { + return await prisma.service.findMany({ + where: { teams: { some: { id: teamId } } }, + include: { teams: true } + }); + } } export async function newService({ name, teamId }) { @@ -13,19 +20,28 @@ export async function newService({ name, teamId }) { } export async function getService({ id, teamId }) { - const body = await prisma.service.findFirst({ - where: { id, teams: { some: { id: teamId } } }, - include: { - destinationDocker: true, - plausibleAnalytics: true, - minio: true, - vscodeserver: true, - wordpress: true, - ghost: true, - serviceSecret: true, - meiliSearch: true - } - }); + let body = {}; + const include = { + destinationDocker: true, + plausibleAnalytics: true, + minio: true, + vscodeserver: true, + wordpress: true, + ghost: true, + serviceSecret: true, + meiliSearch: true + }; + if (teamId === '0') { + body = await prisma.service.findFirst({ + where: { id }, + include + }); + } else { + body = await prisma.service.findFirst({ + where: { id, teams: { some: { id: teamId } } }, + include + }); + } if (body.plausibleAnalytics?.postgresqlPassword) body.plausibleAnalytics.postgresqlPassword = decrypt( diff --git a/src/routes/applications/_Application.svelte b/src/routes/applications/_Application.svelte index 16d19a42f..fb6a157c7 100644 --- a/src/routes/applications/_Application.svelte +++ b/src/routes/applications/_Application.svelte @@ -54,6 +54,7 @@ {/if}
{application.name}
+
Team {application.teams[0].name}
{#if application.fqdn}
{application.fqdn}
{/if} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index f6834cd0b..6caa4d90e 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -59,6 +59,7 @@
{database.name}
+
Team {database.teams[0].name}
{#if !database.type}
Configuration missing diff --git a/src/routes/destinations/[id]/_LocalDocker.svelte b/src/routes/destinations/[id]/_LocalDocker.svelte index 329d23c2f..1ed6d3b99 100644 --- a/src/routes/destinations/[id]/_LocalDocker.svelte +++ b/src/routes/destinations/[id]/_LocalDocker.svelte @@ -184,41 +184,19 @@ value={destination.network} />
-
-
${ - cannotDisable - ? 'You cannot disable this proxy as FQDN is configured for Coolify.' - : '' - }`} - /> -
- - - - + diff --git a/src/routes/destinations/[id]/index.json.ts b/src/routes/destinations/[id]/index.json.ts index e88c29825..d64df8c08 100644 --- a/src/routes/destinations/[id]/index.json.ts +++ b/src/routes/destinations/[id]/index.json.ts @@ -8,7 +8,7 @@ import type { RequestHandler } from '@sveltejs/kit'; export const get: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); if (status === 401) return { status, body }; - + console.log(teamId); const { id } = event.params; try { const destination = await db.getDestination({ id, teamId }); diff --git a/src/routes/destinations/index.svelte b/src/routes/destinations/index.svelte index 01f860b21..a7b6b9a7e 100644 --- a/src/routes/destinations/index.svelte +++ b/src/routes/destinations/index.svelte @@ -57,6 +57,7 @@
{destination.name}
+
Team {destination.teams[0].name}
{destination.network}
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index 4cba9a702..f2a6e5fb0 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -74,6 +74,7 @@
{service.name}
+
Team {service.teams[0].name}
{#if !service.type || !service.fqdn}
Configuration missing diff --git a/src/routes/sources/[id]/_Gitlab.svelte b/src/routes/sources/[id]/_Gitlab.svelte index 56bb0288d..7823aebe9 100644 --- a/src/routes/sources/[id]/_Gitlab.svelte +++ b/src/routes/sources/[id]/_Gitlab.svelte @@ -91,93 +91,95 @@ {#if !source.gitlabApp?.appId} -
-
- - -
- {#if payload.applicationType === 'group'} +
+
- - + +
- {/if} + {#if payload.applicationType === 'group'} +
+ + +
+ {/if} -
- -
+
+ +
- - -
-
-
Configuration
- -
+ /> +
+
+
+
Configuration
+ +
-
-
- - +
+ + +
+
- -
- {#if payload.applicationType === 'group'} + {#if payload.applicationType === 'group'} +
+ + +
+ {/if}
- - + +
- {/if} -
- - -
-
- - -
-
+
+ + +
+ +
{:else}
diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index bd9039514..d80579272 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -60,6 +60,7 @@ class:border-l-4={source.gitlabApp && !source.gitlabAppId} >
{source.name}
+
Team {source.teams[0].name}
{#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
Configuration missing From d18bb9cc748f2ecfa1f3bae87557469550a75c67 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 17:18:25 +0200 Subject: [PATCH 15/56] Extend typings --- src/lib/queues/builder.ts | 11 ++++------- src/lib/types/composeFile.ts | 6 +++--- src/routes/services/[id]/wordpress/settings.json.ts | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts index f6d57862e..a09e2c3bf 100644 --- a/src/lib/queues/builder.ts +++ b/src/lib/queues/builder.ts @@ -20,12 +20,9 @@ import { setDefaultConfiguration } from '$lib/buildPacks/common'; import yaml from 'js-yaml'; +import type { ComposeFile } from '$lib/types/composeFile'; export default async function (job) { - /* - Edge cases: - 1 - Change build pack and redeploy, what should happen? - */ let { id: applicationId, repository, @@ -274,7 +271,7 @@ export default async function (job) { } }; }); - const compose = { + const composeFile: ComposeFile = { version: '3.8', services: { [imageId]: { @@ -283,7 +280,7 @@ export default async function (job) { volumes, env_file: envFound ? [`${workdir}/.env`] : [], networks: [docker.network], - labels: labels, + labels, depends_on: [], restart: 'always' } @@ -295,7 +292,7 @@ export default async function (job) { }, volumes: Object.assign({}, ...composeVolumes) }; - await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(compose)); + await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile)); await asyncExecShell( `DOCKER_HOST=${host} docker compose --project-directory ${workdir} up -d` ); diff --git a/src/lib/types/composeFile.ts b/src/lib/types/composeFile.ts index b7e88210f..43b8d2e7b 100644 --- a/src/lib/types/composeFile.ts +++ b/src/lib/types/composeFile.ts @@ -1,5 +1,3 @@ -import { makeLabelForServices } from '../buildPacks/common'; - export type ComposeFile = { version: ComposerFileVersion; services: Record; @@ -11,10 +9,12 @@ export type ComposeFileService = { container_name: string; image?: string; networks: string[]; - environment: Record; + environment?: Record; volumes?: string[]; ulimits?: unknown; labels?: string[]; + env_file?: string[]; + extra_hosts?: string[]; restart: ComposeFileRestartOption; depends_on?: string[]; command?: string; diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 080326cfc..e82b6baba 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -4,6 +4,7 @@ import { decrypt, encrypt } from '$lib/crypto'; import * as db from '$lib/database'; import { generateDatabaseConfiguration, ErrorHandler, generatePassword } from '$lib/database'; import { checkContainer, startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy'; +import type { ComposeFile } from '$lib/types/composeFile'; import type { RequestHandler } from '@sveltejs/kit'; import cuid from 'cuid'; import fs from 'fs/promises'; @@ -108,7 +109,7 @@ export const post: RequestHandler = async (event) => { }/${id}.sh:/etc/sftp.d/chmod.sh` ]; - const compose = { + const compose: ComposeFile = { version: '3.8', services: { [`${id}-ftp`]: { From ae4942ba29877f286d68245f3ca0a177f1b8a472 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 19:17:28 +0200 Subject: [PATCH 16/56] feat: Able to change service version/tag --- src/lib/components/common.ts | 139 ++++++++++++++++++ src/lib/database/common.ts | 132 +---------------- src/lib/haproxy/configuration.ts | 3 +- src/lib/letsencrypt/index.ts | 3 +- .../databases/[id]/configuration/type.json.ts | 3 +- .../[id]/configuration/version.json.ts | 3 +- .../services/[id]/_Services/_Services.svelte | 17 ++- .../services/[id]/configuration/type.json.ts | 3 +- .../[id]/configuration/version.json.ts | 4 +- .../[id]/configuration/version.svelte | 24 ++- 10 files changed, 193 insertions(+), 138 deletions(-) diff --git a/src/lib/components/common.ts b/src/lib/components/common.ts index f6d0f232c..f8c28cdb2 100644 --- a/src/lib/components/common.ts +++ b/src/lib/components/common.ts @@ -43,3 +43,142 @@ export function changeQueryParams(buildId) { queryParams.set('buildId', buildId); return history.pushState(null, null, '?' + queryParams.toString()); } + +export const supportedDatabaseTypesAndVersions = [ + { + name: 'mongodb', + fancyName: 'MongoDB', + baseImage: 'bitnami/mongodb', + versions: ['5.0.5', '4.4.11', '4.2.18', '4.0.27'] + }, + { name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0.27', '5.7.36'] }, + { + name: 'postgresql', + fancyName: 'PostgreSQL', + baseImage: 'bitnami/postgresql', + versions: ['14.1.0', '13.5.0', '12.9.0', '11.14.0', '10.19.0', '9.6.24'] + }, + { + name: 'redis', + fancyName: 'Redis', + baseImage: 'bitnami/redis', + versions: ['6.2.6', '6.0.16', '5.0.14'] + }, + { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } +]; +export const supportedServiceTypesAndVersions = [ + { + name: 'plausibleanalytics', + fancyName: 'Plausible Analytics', + baseImage: 'plausible/analytics', + images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], + versions: ['latest', 'stable'], + recommendedVersion: 'stable', + ports: { + main: 8000 + } + }, + { + name: 'nocodb', + fancyName: 'NocoDB', + baseImage: 'nocodb/nocodb', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8080 + } + }, + { + name: 'minio', + fancyName: 'MinIO', + baseImage: 'minio/minio', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 9001 + } + }, + { + name: 'vscodeserver', + fancyName: 'VSCode Server', + baseImage: 'codercom/code-server', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8080 + } + }, + { + name: 'wordpress', + fancyName: 'Wordpress', + baseImage: 'wordpress', + images: ['bitnami/mysql:5.7'], + versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], + recommendedVersion: 'latest', + ports: { + main: 80 + } + }, + { + name: 'vaultwarden', + fancyName: 'Vaultwarden', + baseImage: 'vaultwarden/server', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 80 + } + }, + { + name: 'languagetool', + fancyName: 'LanguageTool', + baseImage: 'silviof/docker-languagetool', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8010 + } + }, + { + name: 'n8n', + fancyName: 'n8n', + baseImage: 'n8nio/n8n', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 5678 + } + }, + { + name: 'uptimekuma', + fancyName: 'Uptime Kuma', + baseImage: 'louislam/uptime-kuma', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 3001 + } + }, + { + name: 'ghost', + fancyName: 'Ghost', + baseImage: 'bitnami/ghost', + images: ['bitnami/mariadb'], + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 2368 + } + }, + { + name: 'meilisearch', + fancyName: 'Meilisearch', + baseImage: 'getmeili/meilisearch', + images: [], + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 7700 + } + } +]; diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index 75366dbc9..287dcd834 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -1,5 +1,9 @@ import { dev } from '$app/env'; import { sentry } from '$lib/common'; +import { + supportedDatabaseTypesAndVersions, + supportedServiceTypesAndVersions +} from '$lib/components/common'; import * as Prisma from '@prisma/client'; import { default as ProdPrisma } from '@prisma/client'; import type { PrismaClientOptions } from '@prisma/client/runtime'; @@ -82,134 +86,6 @@ export async function generateSshKeyPair(): Promise<{ publicKey: string; private }); } -export const supportedDatabaseTypesAndVersions = [ - { - name: 'mongodb', - fancyName: 'MongoDB', - baseImage: 'bitnami/mongodb', - versions: ['5.0.5', '4.4.11', '4.2.18', '4.0.27'] - }, - { name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0.27', '5.7.36'] }, - { - name: 'postgresql', - fancyName: 'PostgreSQL', - baseImage: 'bitnami/postgresql', - versions: ['14.1.0', '13.5.0', '12.9.0', '11.14.0', '10.19.0', '9.6.24'] - }, - { - name: 'redis', - fancyName: 'Redis', - baseImage: 'bitnami/redis', - versions: ['6.2.6', '6.0.16', '5.0.14'] - }, - { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } -]; -export const supportedServiceTypesAndVersions = [ - { - name: 'plausibleanalytics', - fancyName: 'Plausible Analytics', - baseImage: 'plausible/analytics', - images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], - versions: ['latest', 'stable'], - ports: { - main: 8000 - } - }, - { - name: 'nocodb', - fancyName: 'NocoDB', - baseImage: 'nocodb/nocodb', - versions: ['latest'], - ports: { - main: 8080 - } - }, - { - name: 'minio', - fancyName: 'MinIO', - baseImage: 'minio/minio', - versions: ['latest'], - ports: { - main: 9001 - } - }, - { - name: 'vscodeserver', - fancyName: 'VSCode Server', - baseImage: 'codercom/code-server', - versions: ['latest'], - ports: { - main: 8080 - } - }, - { - name: 'wordpress', - fancyName: 'Wordpress', - baseImage: 'wordpress', - images: ['bitnami/mysql:5.7'], - versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], - ports: { - main: 80 - } - }, - { - name: 'vaultwarden', - fancyName: 'Vaultwarden', - baseImage: 'vaultwarden/server', - versions: ['latest'], - ports: { - main: 80 - } - }, - { - name: 'languagetool', - fancyName: 'LanguageTool', - baseImage: 'silviof/docker-languagetool', - versions: ['latest'], - ports: { - main: 8010 - } - }, - { - name: 'n8n', - fancyName: 'n8n', - baseImage: 'n8nio/n8n', - versions: ['latest'], - ports: { - main: 5678 - } - }, - { - name: 'uptimekuma', - fancyName: 'Uptime Kuma', - baseImage: 'louislam/uptime-kuma', - versions: ['latest'], - ports: { - main: 3001 - } - }, - { - name: 'ghost', - fancyName: 'Ghost', - baseImage: 'bitnami/ghost', - images: ['bitnami/mariadb'], - versions: ['latest'], - ports: { - main: 2368 - } - }, - { - name: 'meilisearch', - fancyName: 'Meilisearch', - baseImage: 'getmeili/meilisearch', - images: [], - versions: ['latest'], - ports: { - main: 7700 - } - } -]; - export function getVersions(type) { const found = supportedDatabaseTypesAndVersions.find((t) => t.name === type); if (found) { diff --git a/src/lib/haproxy/configuration.ts b/src/lib/haproxy/configuration.ts index a7f223e0e..831d9490b 100644 --- a/src/lib/haproxy/configuration.ts +++ b/src/lib/haproxy/configuration.ts @@ -6,6 +6,7 @@ import crypto from 'crypto'; import * as db from '$lib/database'; import { checkContainer, checkHAProxy } from '.'; import { asyncExecShell, getDomain, getEngine } from '$lib/common'; +import { supportedServiceTypesAndVersions } from '$lib/components/common'; const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555'; @@ -223,7 +224,7 @@ export async function configureHAProxy() { const { fqdn, id, type, destinationDocker, destinationDockerId, updatedAt } = service; if (destinationDockerId) { const { engine } = destinationDocker; - const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type); + const found = supportedServiceTypesAndVersions.find((a) => a.name === type); if (found) { const port = found.ports.main; const publicPort = service[type]?.publicPort; diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index eb74aa252..c9f9c037b 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -4,6 +4,7 @@ import * as db from '$lib/database'; import { dev } from '$app/env'; import cuid from 'cuid'; import getPort, { portNumbers } from 'get-port'; +import { supportedServiceTypesAndVersions } from '$lib/components/common'; export async function letsEncrypt(domain, id = null, isCoolify = false) { try { @@ -160,7 +161,7 @@ export async function generateSSLCerts() { type, destinationDocker: { engine } } = service; - const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type); + const found = supportedServiceTypesAndVersions.find((a) => a.name === type); if (found) { const domain = getDomain(fqdn); const isHttps = fqdn.startsWith('https://'); diff --git a/src/routes/databases/[id]/configuration/type.json.ts b/src/routes/databases/[id]/configuration/type.json.ts index 6f797e415..8ab007891 100644 --- a/src/routes/databases/[id]/configuration/type.json.ts +++ b/src/routes/databases/[id]/configuration/type.json.ts @@ -1,6 +1,7 @@ import { getUserDetails } from '$lib/common'; +import { supportedDatabaseTypesAndVersions } from '$lib/components/common'; import * as db from '$lib/database'; -import { ErrorHandler, supportedDatabaseTypesAndVersions } from '$lib/database'; +import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; export const get: RequestHandler = async (event) => { diff --git a/src/routes/databases/[id]/configuration/version.json.ts b/src/routes/databases/[id]/configuration/version.json.ts index 3477d832d..000717016 100644 --- a/src/routes/databases/[id]/configuration/version.json.ts +++ b/src/routes/databases/[id]/configuration/version.json.ts @@ -1,6 +1,7 @@ import { getUserDetails } from '$lib/common'; +import { supportedDatabaseTypesAndVersions } from '$lib/components/common'; import * as db from '$lib/database'; -import { ErrorHandler, supportedDatabaseTypesAndVersions } from '$lib/database'; +import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; export const get: RequestHandler = async (event) => { diff --git a/src/routes/services/[id]/_Services/_Services.svelte b/src/routes/services/[id]/_Services/_Services.svelte index a36feb047..637944b65 100644 --- a/src/routes/services/[id]/_Services/_Services.svelte +++ b/src/routes/services/[id]/_Services/_Services.svelte @@ -92,7 +92,22 @@ />
- +
+ + + +
diff --git a/src/routes/services/[id]/configuration/type.json.ts b/src/routes/services/[id]/configuration/type.json.ts index daf1cc71a..42c5344e6 100644 --- a/src/routes/services/[id]/configuration/type.json.ts +++ b/src/routes/services/[id]/configuration/type.json.ts @@ -1,6 +1,7 @@ import { getUserDetails } from '$lib/common'; +import { supportedServiceTypesAndVersions } from '$lib/components/common'; import * as db from '$lib/database'; -import { ErrorHandler, supportedServiceTypesAndVersions } from '$lib/database'; +import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; export const get: RequestHandler = async (event) => { diff --git a/src/routes/services/[id]/configuration/version.json.ts b/src/routes/services/[id]/configuration/version.json.ts index f1a1a9522..bf93e167b 100644 --- a/src/routes/services/[id]/configuration/version.json.ts +++ b/src/routes/services/[id]/configuration/version.json.ts @@ -1,6 +1,7 @@ import { getUserDetails } from '$lib/common'; +import { supportedServiceTypesAndVersions } from '$lib/components/common'; import * as db from '$lib/database'; -import { ErrorHandler, supportedServiceTypesAndVersions } from '$lib/database'; +import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; export const get: RequestHandler = async (event) => { @@ -14,6 +15,7 @@ export const get: RequestHandler = async (event) => { return { status: 200, body: { + type, versions: supportedServiceTypesAndVersions.find((name) => name.name === type).versions } }; diff --git a/src/routes/services/[id]/configuration/version.svelte b/src/routes/services/[id]/configuration/version.svelte index 5f2930487..bda5bb46c 100644 --- a/src/routes/services/[id]/configuration/version.svelte +++ b/src/routes/services/[id]/configuration/version.svelte @@ -31,11 +31,16 @@ import { errorNotification } from '$lib/form'; import { goto } from '$app/navigation'; import { post } from '$lib/api'; + import { supportedServiceTypesAndVersions } from '$lib/components/common'; const { id } = $page.params; const from = $page.url.searchParams.get('from'); export let versions; + export let type; + let recommendedVersion = supportedServiceTypesAndVersions.find( + ({ name }) => name === type + )?.recommendedVersion; async function handleSubmit(version) { try { await post(`/services/${id}/configuration/version.json`, { version }); @@ -49,13 +54,26 @@
Select a Service version
- +{#if from} +
+ Warning: you are about to change the version of this service.
This could cause problem + after you restart the service, + like losing your data, incompatibility issues, etc.
Only do if you know what you are doing. +
+{/if}
{#each versions as version}
handleSubmit(version)}> - {version} + {#if recommendedVersion === version} + recommended + {/if}
From 9f2f5b40c341e2a48a3342eaebf1ddb3006d348e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 20:44:24 +0200 Subject: [PATCH 17/56] Only show teams for root team --- src/routes/applications/_Application.svelte | 5 ++++- src/routes/databases/index.svelte | 5 ++++- src/routes/destinations/index.svelte | 4 +++- src/routes/services/index.svelte | 5 ++++- src/routes/sources/index.svelte | 4 +++- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/routes/applications/_Application.svelte b/src/routes/applications/_Application.svelte index fb6a157c7..8f183eb13 100644 --- a/src/routes/applications/_Application.svelte +++ b/src/routes/applications/_Application.svelte @@ -15,6 +15,7 @@ import Docker from '$lib/components/svg/applications/Docker.svelte'; import Astro from '$lib/components/svg/applications/Astro.svelte'; import Eleventy from '$lib/components/svg/applications/Eleventy.svelte'; + import { session } from '$app/stores'; const buildPack = application?.buildPack?.toLowerCase(); @@ -54,7 +55,9 @@ {/if}
{application.name}
-
Team {application.teams[0].name}
+ {#if $session.teamId === '0'} +
Team {application.teams[0].name}
+ {/if} {#if application.fqdn}
{application.fqdn}
{/if} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 6caa4d90e..32156ef4b 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -8,6 +8,7 @@ import Redis from '$lib/components/svg/databases/Redis.svelte'; import { post } from '$lib/api'; import { goto } from '$app/navigation'; + import { session } from '$app/stores'; async function newDatabase() { const { id } = await post('/databases/new', {}); @@ -59,7 +60,9 @@
{database.name}
-
Team {database.teams[0].name}
+ {#if $session.teamId === '0'} +
Team {database.teams[0].name}
+ {/if} {#if !database.type}
Configuration missing diff --git a/src/routes/destinations/index.svelte b/src/routes/destinations/index.svelte index a7b6b9a7e..df186e35f 100644 --- a/src/routes/destinations/index.svelte +++ b/src/routes/destinations/index.svelte @@ -57,7 +57,9 @@
{destination.name}
-
Team {destination.teams[0].name}
+ {#if $session.teamId === '0'} +
Team {destination.teams[0].name}
+ {/if}
{destination.network}
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index f2a6e5fb0..d590761a2 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -12,6 +12,7 @@ import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte'; import Ghost from '$lib/components/svg/services/Ghost.svelte'; import MeiliSearch from '$lib/components/svg/services/MeiliSearch.svelte'; + import { session } from '$app/stores'; export let services; async function newService() { @@ -74,7 +75,9 @@
{service.name}
-
Team {service.teams[0].name}
+ {#if $session.teamId === '0'} +
Team {service.teams[0].name}
+ {/if} {#if !service.type || !service.fqdn}
Configuration missing diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index d80579272..c57efdaa6 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -60,7 +60,9 @@ class:border-l-4={source.gitlabApp && !source.gitlabAppId} >
{source.name}
-
Team {source.teams[0].name}
+ {#if $session.teamId === '0'} +
Team {source.teams[0].name}
+ {/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
Configuration missing From f3cdda29bc099ae018b58742e7eacc97c5fdd33e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 21:37:42 +0200 Subject: [PATCH 18/56] code improvement --- .env.template | 3 ++- prisma/schema.prisma | 2 +- src/lib/database/services.ts | 12 ------------ src/lib/types/composeFile.ts | 6 +++++- src/routes/services/[id]/languagetool/index.json.ts | 2 +- src/routes/services/[id]/meilisearch/index.json.ts | 2 +- src/routes/services/[id]/vaultwarden/index.json.ts | 2 +- src/routes/services/[id]/vscodeserver/index.json.ts | 2 +- 8 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.env.template b/.env.template index ce02dc5bd..0fa7427f3 100644 --- a/.env.template +++ b/.env.template @@ -2,4 +2,5 @@ COOLIFY_APP_ID= COOLIFY_SECRET_KEY=12341234123412341234123412341234 COOLIFY_DATABASE_URL=file:../db/dev.db COOLIFY_SENTRY_DSN= -COOLIFY_IS_ON="docker" \ No newline at end of file +COOLIFY_IS_ON="docker" +COOLIFY_WHITE_LABELED="false" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d5e322337..7f37f9a2b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -336,7 +336,7 @@ model Wordpress { ftpUser String? ftpPassword String? ftpPublicPort Int? - ftpHostKey String? + ftpHostKey String? ftpHostKeyPrivate String? serviceId String @unique service Service @relation(fields: [serviceId], references: [id]) diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts index d578a500c..b4d355946 100644 --- a/src/lib/database/services.ts +++ b/src/lib/database/services.ts @@ -220,18 +220,6 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, usernam export async function updateService({ id, fqdn, name }) { return await prisma.service.update({ where: { id }, data: { fqdn, name } }); } -export async function updateLanguageToolService({ id, fqdn, name }) { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); -} -export async function updateMeiliSearchService({ id, fqdn, name }) { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); -} -export async function updateVaultWardenService({ id, fqdn, name }) { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); -} -export async function updateVsCodeServer({ id, fqdn, name }) { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); -} export async function updateWordpress({ id, fqdn, name, mysqlDatabase, extraConfig }) { return await prisma.service.update({ where: { id }, diff --git a/src/lib/types/composeFile.ts b/src/lib/types/composeFile.ts index 43b8d2e7b..1e2a0723c 100644 --- a/src/lib/types/composeFile.ts +++ b/src/lib/types/composeFile.ts @@ -18,7 +18,11 @@ export type ComposeFileService = { restart: ComposeFileRestartOption; depends_on?: string[]; command?: string; - build?: string; + build?: { + context: string; + dockerfile: string; + args?: Record; + }; }; export type ComposerFileVersion = diff --git a/src/routes/services/[id]/languagetool/index.json.ts b/src/routes/services/[id]/languagetool/index.json.ts index c253112b9..d717502c5 100644 --- a/src/routes/services/[id]/languagetool/index.json.ts +++ b/src/routes/services/[id]/languagetool/index.json.ts @@ -13,7 +13,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateMeiliSearchService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/meilisearch/index.json.ts b/src/routes/services/[id]/meilisearch/index.json.ts index e33112fe8..d717502c5 100644 --- a/src/routes/services/[id]/meilisearch/index.json.ts +++ b/src/routes/services/[id]/meilisearch/index.json.ts @@ -13,7 +13,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateLanguageToolService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/vaultwarden/index.json.ts b/src/routes/services/[id]/vaultwarden/index.json.ts index 08d80a547..5ec3fa69a 100644 --- a/src/routes/services/[id]/vaultwarden/index.json.ts +++ b/src/routes/services/[id]/vaultwarden/index.json.ts @@ -12,7 +12,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateVaultWardenService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/vscodeserver/index.json.ts b/src/routes/services/[id]/vscodeserver/index.json.ts index d1ec862bc..d717502c5 100644 --- a/src/routes/services/[id]/vscodeserver/index.json.ts +++ b/src/routes/services/[id]/vscodeserver/index.json.ts @@ -13,7 +13,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateVsCodeServer({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error); From 3e8a8364dcb19418b0eafaa3a07f3b379f973e83 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 6 Apr 2022 22:01:41 +0200 Subject: [PATCH 19/56] feat: Basic white labeled version --- src/app.d.ts | 3 +-- src/app.html | 1 - src/hooks.ts | 3 +++ src/routes/__layout.svelte | 16 +++++++++++++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/app.d.ts b/src/app.d.ts index 0557299b9..a88bd7502 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -19,14 +19,13 @@ declare namespace App { } interface SessionData { + whiteLabeled: boolean; version?: string; userId?: string | null; teamId?: string | null; permission?: string; isAdmin?: boolean; expires?: string | null; - gitlabToken?: string | null; - ghToken?: string | null; } type DateTimeFormatOptions = { diff --git a/src/app.html b/src/app.html index 2dc97f37d..a0336e87d 100644 --- a/src/app.html +++ b/src/app.html @@ -2,7 +2,6 @@ - Coolify %svelte.head% diff --git a/src/hooks.ts b/src/hooks.ts index d6c6eca6d..c72c7fd6c 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -7,6 +7,8 @@ import { version } from '$lib/common'; import cookie from 'cookie'; import { dev } from '$app/env'; +const whiteLabeled = process.env['COOLIFY_WHITE_LABELED'] === 'true'; + export const handle = handleSession( { secret: process.env['COOLIFY_SECRET_KEY'], @@ -71,6 +73,7 @@ export const handle = handleSession( export const getSession: GetSession = function ({ locals }) { return { version, + whiteLabeled, ...locals.session.data }; }; diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index ce9cd7c0f..8d5922450 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -134,13 +134,18 @@ Coolify + {#if !$session.whiteLabeled} + + {/if} {#if $session.userId} + {#if $session.whiteLabeled} + Powered by Coolify + {/if} + From aae108032c3b43a268a96829e15b70ed6f403c75 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 18:45:21 +0200 Subject: [PATCH 32/56] ui:fix --- src/routes/applications/index.svelte | 2 +- src/routes/databases/index.svelte | 2 +- src/routes/destinations/index.svelte | 2 +- src/routes/teams/index.svelte | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/applications/index.svelte b/src/routes/applications/index.svelte index 784629325..e13b3f240 100644 --- a/src/routes/applications/index.svelte +++ b/src/routes/applications/index.svelte @@ -56,7 +56,7 @@ {/each}
{#if otherApplications.length > 0 && $session.teamId === '0'} -
Other Team's Applications
+
Other Team's Applications
{#each otherApplications as application} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 5cf67e356..bb19b0ab8 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -90,7 +90,7 @@ {/each}
{#if otherDatabases.length > 0 && $session.teamId === '0'} -
Other Team's Databases
+
Other Team's Databases
{#if otherDestinations.length > 0 && $session.teamId === '0'} -
Other Team's Destinations
+
Other Team's Destinations
{#each otherDestinations as destination} diff --git a/src/routes/teams/index.svelte b/src/routes/teams/index.svelte index 7ff8dede8..88d1a3b4e 100644 --- a/src/routes/teams/index.svelte +++ b/src/routes/teams/index.svelte @@ -103,7 +103,7 @@ {/if}
-
Current Team
+
Current Team
-
Other Teams
+
Other Teams
{:else}
- {#if $session.teamId === '0' && ownApplications.length > 0} -
Your Team's Applications
+ {#if $session.teamId === '0' && ownApplications.length > 0 && otherApplications.length > 0} +
Current Team
{/if}
{#each ownApplications as application} @@ -56,7 +56,7 @@ {/each}
{#if otherApplications.length > 0 && $session.teamId === '0'} -
Other Team's Applications
+
Other Team's
{#each otherApplications as application} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index bb19b0ab8..554954e2f 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -52,8 +52,8 @@
{:else}
- {#if $session.teamId === '0' && ownDatabases.length > 0} -
Your Team's Databases
+ {#if $session.teamId === '0' && ownDatabases.length > 0 && otherDatabases.length > 0} +
Current Team
{/if}
{#each ownDatabases as database} @@ -90,7 +90,7 @@ {/each}
{#if otherDatabases.length > 0 && $session.teamId === '0'} -
Other Team's Databases
+
Other Team's
{:else}
- {#if $session.teamId === '0' && ownDestinations.length > 0} -
Your Team's Destinations
+ {#if $session.teamId === '0' && ownDestinations.length > 0 && otherDestinations.length > 0} +
Current Team
{/if}
{#each ownDestinations as destination} @@ -81,7 +81,7 @@
{#if otherDestinations.length > 0 && $session.teamId === '0'} -
Other Team's Destinations
+
Other Team's
{:else}
- {#if $session.teamId === '0' && ownServices.length > 0} -
Your Team's Applications
+ {#if $session.teamId === '0' && ownServices.length > 0 && otherServices.length > 0} +
Current Team
{/if}
{#each ownServices as service} @@ -105,7 +105,7 @@ {/each}
{#if otherServices.length > 0 && $session.teamId === '0'} -
Other Team's Applications
+
Other Team's
{:else}
- {#if $session.teamId === '0' && ownSources.length > 0} -
Your Team's Applications
+ {#if $session.teamId === '0' && ownSources.length > 0 && otherSources.length > 0} +
Current Team
{/if}
{#each ownSources as source} @@ -90,7 +90,7 @@
{#if otherSources.length > 0 && $session.teamId === '0'} -
Other Team's Applications
+
Other Team's
-
Other Teams
+
Other Team's
{:else} -
+
{#if $session.teamId === '0' && ownDatabases.length > 0 && otherDatabases.length > 0}
Current Team
{/if} diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index 702187d07..bee9b08f1 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -105,7 +105,7 @@ {/each}
{#if otherServices.length > 0 && $session.teamId === '0'} -
Other Team's
+
Other Team's
{#if otherSources.length > 0 && $session.teamId === '0'} -
Other Team's
+
Other Team's
{#if otherApplications.length > 0 && $session.teamId === '0'} -
Other Team's
+
Others
{#each otherApplications as application} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 488dd5bba..5e271bcfe 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -76,7 +76,7 @@ {database.name}
{#if $session.teamId === '0'} -
Team {database.teams[0].name}
+
{database.teams[0].name}
{/if} {#if !database.type}
@@ -90,7 +90,7 @@ {/each}
{#if otherDatabases.length > 0 && $session.teamId === '0'} -
Other Team's
+
Others
{#if $session.teamId === '0'} -
Team {database.teams[0].name}
+
{database.teams[0].name}
{/if} {#if !database.type}
diff --git a/src/routes/destinations/index.svelte b/src/routes/destinations/index.svelte index 782958aa5..34a9faefb 100644 --- a/src/routes/destinations/index.svelte +++ b/src/routes/destinations/index.svelte @@ -72,7 +72,7 @@
{destination.name}
{#if $session.teamId === '0'} -
Team {destination.teams[0].name}
+
{destination.teams[0].name}
{/if}
{destination.network}
@@ -81,14 +81,14 @@
{#if otherDestinations.length > 0 && $session.teamId === '0'} -
Other Team's
+
Others
{#each otherDestinations as destination}
{destination.name}
{#if $session.teamId === '0'} -
Team {destination.teams[0].name}
+
{destination.teams[0].name}
{/if}
{destination.network}
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index bee9b08f1..293c51087 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -58,7 +58,7 @@ {:else}
{#if $session.teamId === '0' && ownServices.length > 0 && otherServices.length > 0} -
Current Team
+
Current Team
{/if}
{#each ownServices as service} @@ -91,7 +91,7 @@ {service.name}
{#if $session.teamId === '0'} -
Team {service.teams[0].name}
+
{service.teams[0].name}
{/if} {#if !service.type || !service.fqdn}
@@ -105,7 +105,7 @@ {/each}
{#if otherServices.length > 0 && $session.teamId === '0'} -
Other Team's
+
Others
{#if $session.teamId === '0'} -
Team {service.teams[0].name}
+
{service.teams[0].name}
{/if} {#if !service.type || !service.fqdn}
diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index 3f1953a39..224916fb8 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -62,7 +62,7 @@ {:else}
{#if $session.teamId === '0' && ownSources.length > 0 && otherSources.length > 0} -
Current Team
+
Current Team
{/if}
{#each ownSources as source} @@ -75,7 +75,7 @@ >
{source.name}
{#if $session.teamId === '0'} -
Team {source.teams[0].name}
+
{source.teams[0].name}
{/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
@@ -90,7 +90,7 @@
{#if otherSources.length > 0 && $session.teamId === '0'} -
Other Team's
+
Others
{#each otherSources as source} @@ -102,7 +102,7 @@ >
{source.name}
{#if $session.teamId === '0'} -
Team {source.teams[0].name}
+
{source.teams[0].name}
{/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)}
diff --git a/src/routes/teams/index.svelte b/src/routes/teams/index.svelte index 87e491d20..79e600ca6 100644 --- a/src/routes/teams/index.svelte +++ b/src/routes/teams/index.svelte @@ -123,7 +123,7 @@ {/each}
-
Other Team's
+
Others
{#each otherTeams as team} From 3abe1610bf7eebab06d787cfdfbfee1a4a282d18 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 20:37:08 +0200 Subject: [PATCH 36/56] fix: Do not trigger >1 webhooks on GitLab --- src/lib/database/gitSources.ts | 1 - src/routes/webhooks/gitlab/events.ts | 19 +++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/lib/database/gitSources.ts b/src/lib/database/gitSources.ts index 7e4e90633..0ed6f29b1 100644 --- a/src/lib/database/gitSources.ts +++ b/src/lib/database/gitSources.ts @@ -26,7 +26,6 @@ export async function newSource({ name, teamId, type, htmlUrl, apiUrl, organizat }); } export async function removeSource({ id }) { - // TODO: Disconnect application with this sourceId! Maybe not needed? const source = await prisma.gitSource.delete({ where: { id }, include: { githubApp: true, gitlabApp: true } diff --git a/src/routes/webhooks/gitlab/events.ts b/src/routes/webhooks/gitlab/events.ts index 4a1eeafcc..f8bb54383 100644 --- a/src/routes/webhooks/gitlab/events.ts +++ b/src/routes/webhooks/gitlab/events.ts @@ -22,6 +22,15 @@ export const post: RequestHandler = async (event) => { const allowedActions = ['opened', 'reopen', 'close', 'open', 'update']; const body = await event.request.json(); const buildId = cuid(); + const webhookToken = event.request.headers.get('x-gitlab-token'); + if (!webhookToken) { + return { + status: 500, + body: { + message: 'Ooops, something is not okay, are you okay?' + } + }; + } try { const { object_kind: objectKind } = body; if (objectKind === 'push') { @@ -77,16 +86,6 @@ export const post: RequestHandler = async (event) => { }; } } else if (objectKind === 'merge_request') { - const webhookToken = event.request.headers.get('x-gitlab-token'); - if (!webhookToken) { - return { - status: 500, - body: { - message: 'Ooops, something is not okay, are you okay?' - } - }; - } - const isDraft = body.object_attributes.work_in_progress; const action = body.object_attributes.action; const projectId = Number(body.project.id); From 1bd2ccbc16b5fc56751f3741d8e81a41efe904ff Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 21:12:41 +0200 Subject: [PATCH 37/56] fix: Possible fix for spikes in CPU usage --- src/lib/letsencrypt/index.ts | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index c9f9c037b..edbc48395 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -3,6 +3,7 @@ import { checkContainer, reloadHaproxy } from '$lib/haproxy'; import * as db from '$lib/database'; import { dev } from '$app/env'; import cuid from 'cuid'; +import fs from 'fs/promises'; import getPort, { portNumbers } from 'get-port'; import { supportedServiceTypesAndVersions } from '$lib/components/common'; @@ -182,12 +183,35 @@ export async function generateSSLCerts() { if (isHttps) ssls.push({ domain, id: 'coolify', isCoolify: true }); } if (ssls.length > 0) { + const sslDir = dev ? '/tmp/ssl' : '/app/ssl'; + if (dev) { + try { + await asyncExecShell(`mkdir -p ${sslDir}`); + } catch (error) { + // + } + } + const files = await fs.readdir(sslDir); + let certificates = []; + if (files.length > 0) { + for (const file of files) { + file.endsWith('.pem') && certificates.push(file.replace(/\.pem$/, '')); + } + } for (const ssl of ssls) { if (!dev) { - console.log('Checking SSL for', ssl.domain); + if (certificates.includes(ssl.domain)) { + console.log(`Certificate for ${ssl.domain} already exists`); + return; + } + console.log('Generating SSL for', ssl.domain); await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); } else { - console.log('Checking SSL for', ssl.domain); + if (certificates.includes(ssl.domain)) { + console.log(`Certificate for ${ssl.domain} already exists`); + return; + } + console.log('Generating SSL for', ssl.domain); } } } From 84b4cc5d540ea1ba8e830f33f89cae847a7ef867 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 21:18:36 +0200 Subject: [PATCH 38/56] fix: Last commit --- src/lib/letsencrypt/index.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index edbc48395..240b561ea 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -202,16 +202,16 @@ export async function generateSSLCerts() { if (!dev) { if (certificates.includes(ssl.domain)) { console.log(`Certificate for ${ssl.domain} already exists`); - return; + } else { + console.log('Generating SSL for', ssl.domain); + await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); } - console.log('Generating SSL for', ssl.domain); - await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); } else { if (certificates.includes(ssl.domain)) { console.log(`Certificate for ${ssl.domain} already exists`); - return; + } else { + console.log('Generating SSL for', ssl.domain); } - console.log('Generating SSL for', ssl.domain); } } } From 6462982d12c7f2ec97943ef30799cd6dd6502c2a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 21:24:05 +0200 Subject: [PATCH 39/56] fix: www or not-www, that's the question --- src/lib/letsencrypt/index.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index 240b561ea..12b527890 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -200,14 +200,20 @@ export async function generateSSLCerts() { } for (const ssl of ssls) { if (!dev) { - if (certificates.includes(ssl.domain)) { + if ( + certificates.includes(ssl.domain) || + certificates.includes(ssl.domain.replace('www', '')) + ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { console.log('Generating SSL for', ssl.domain); await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify); } } else { - if (certificates.includes(ssl.domain)) { + if ( + certificates.includes(ssl.domain) || + certificates.includes(ssl.domain.replace('www', '')) + ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { console.log('Generating SSL for', ssl.domain); From f779b3bb5421a65c70c700f5ebdd4d037f5a6af2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 21:29:45 +0200 Subject: [PATCH 40/56] fix: fix for the fix that fixes the fix --- src/lib/letsencrypt/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index 12b527890..fb1fa46ac 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -202,7 +202,7 @@ export async function generateSSLCerts() { if (!dev) { if ( certificates.includes(ssl.domain) || - certificates.includes(ssl.domain.replace('www', '')) + certificates.includes(ssl.domain.replace('www.', '')) ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { @@ -212,7 +212,7 @@ export async function generateSSLCerts() { } else { if ( certificates.includes(ssl.domain) || - certificates.includes(ssl.domain.replace('www', '')) + certificates.includes(ssl.domain.replace('www.', '')) ) { console.log(`Certificate for ${ssl.domain} already exists`); } else { From b96c1a23ec1ff9e35972bd3f715146abd2d20645 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 23:26:06 +0200 Subject: [PATCH 41/56] fix: Ton of updates for users/teams --- src/lib/database/users.ts | 46 +++-- src/routes/__layout.svelte | 15 +- src/routes/applications/index.svelte | 5 +- src/routes/databases/index.svelte | 7 +- src/routes/destinations/index.svelte | 5 +- src/routes/iam/index.json.ts | 130 +++++++++++++ src/routes/iam/index.svelte | 178 ++++++++++++++++++ src/routes/iam/password.json.ts | 22 +++ .../{teams => iam/team}/[id]/__layout.svelte | 6 +- .../{teams => iam/team}/[id]/index.json.ts | 0 .../{teams => iam/team}/[id]/index.svelte | 12 +- .../team}/[id]/invitation/accept.json.ts | 0 .../team}/[id]/invitation/invite.json.ts | 0 .../team}/[id]/invitation/revoke.json.ts | 0 .../team}/[id]/permission/change.json.ts | 0 .../team}/[id]/remove/user.json.ts | 0 src/routes/services/index.svelte | 7 +- src/routes/sources/index.svelte | 5 +- src/routes/teams/index.json.ts | 27 --- src/routes/teams/index.svelte | 146 -------------- 20 files changed, 383 insertions(+), 228 deletions(-) create mode 100644 src/routes/iam/index.json.ts create mode 100644 src/routes/iam/index.svelte create mode 100644 src/routes/iam/password.json.ts rename src/routes/{teams => iam/team}/[id]/__layout.svelte (83%) rename src/routes/{teams => iam/team}/[id]/index.json.ts (100%) rename src/routes/{teams => iam/team}/[id]/index.svelte (94%) rename src/routes/{teams => iam/team}/[id]/invitation/accept.json.ts (100%) rename src/routes/{teams => iam/team}/[id]/invitation/invite.json.ts (100%) rename src/routes/{teams => iam/team}/[id]/invitation/revoke.json.ts (100%) rename src/routes/{teams => iam/team}/[id]/permission/change.json.ts (100%) rename src/routes/{teams => iam/team}/[id]/remove/user.json.ts (100%) delete mode 100644 src/routes/teams/index.json.ts delete mode 100644 src/routes/teams/index.svelte diff --git a/src/lib/database/users.ts b/src/lib/database/users.ts index 7e5cc481e..36b130b35 100644 --- a/src/lib/database/users.ts +++ b/src/lib/database/users.ts @@ -32,26 +32,42 @@ export async function login({ email, password, isLogin }) { if (users === 0) { await prisma.setting.update({ where: { id }, data: { isRegistrationEnabled: false } }); // Create default network & start Coolify Proxy - asyncExecShell(`docker network create --attachable coolify`) - .then(() => { - console.log('Network created'); - }) - .catch(() => { - console.log('Network already exists.'); - }); - - startCoolifyProxy('/var/run/docker.sock') - .then(() => { - console.log('Coolify Proxy started.'); - }) - .catch((err) => { - console.log(err); - }); + await asyncExecShell(`docker network create --attachable coolify`); + await startCoolifyProxy('/var/run/docker.sock'); uid = '0'; } if (userFound) { if (userFound.type === 'email') { + if (userFound.password === 'RESETME') { + const hashedPassword = await hashPassword(password); + if (userFound.updatedAt < new Date(Date.now() - 1000 * 60 * 10)) { + await prisma.user.update({ + where: { email: userFound.email }, + data: { password: 'RESETTIMEOUT' } + }); + throw { + error: 'Password reset link has expired. Please request a new one.' + }; + } else { + await prisma.user.update({ + where: { email: userFound.email }, + data: { password: hashedPassword } + }); + return { + status: 200, + headers: { + 'Set-Cookie': `teamId=${uid}; HttpOnly; Path=/; Max-Age=15778800;` + }, + body: { + userId: userFound.id, + teamId: userFound.id, + permission: userFound.permission, + isAdmin: true + } + }; + } + } const passwordMatch = await bcrypt.compare(password, userFound.password); if (!passwordMatch) { throw { diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index 010298059..09b030328 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -434,13 +434,12 @@
- + {#if $session.teamId === '0'} {/if} +
{:else}
- {#if $session.teamId === '0' && ownApplications.length > 0 && otherApplications.length > 0} -
Current Team
- {/if}
{#each ownApplications as application} {/each}
{#if otherApplications.length > 0 && $session.teamId === '0'} -
Others
+
Other Applications
{#each otherApplications as application} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 5e271bcfe..7185e7f28 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -52,9 +52,6 @@
{:else}
- {#if $session.teamId === '0' && ownDatabases.length > 0 && otherDatabases.length > 0} -
Current Team
- {/if} {/each}
{#if otherDatabases.length > 0 && $session.teamId === '0'} -
Others
+
Other Databases
{:else}
- {#if $session.teamId === '0' && ownDestinations.length > 0 && otherDestinations.length > 0} -
Current Team
- {/if}
{#if otherDestinations.length > 0 && $session.teamId === '0'} -
Others
+
Other Destinations
{#each otherDestinations as destination} diff --git a/src/routes/iam/index.json.ts b/src/routes/iam/index.json.ts new file mode 100644 index 000000000..fa44e55ba --- /dev/null +++ b/src/routes/iam/index.json.ts @@ -0,0 +1,130 @@ +import { getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const get: RequestHandler = async (event) => { + const { teamId, userId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + try { + const account = await db.prisma.user.findUnique({ + where: { id: userId }, + select: { id: true, email: true, teams: true } + }); + let accounts = []; + if (teamId === '0') { + accounts = await db.prisma.user.findMany({ select: { id: true, email: true, teams: true } }); + } + + const teams = await db.prisma.permission.findMany({ + where: { userId: teamId === '0' ? undefined : userId }, + include: { team: { include: { _count: { select: { users: true } } } } } + }); + + const invitations = await db.prisma.teamInvitation.findMany({ where: { uid: userId } }); + return { + status: 200, + body: { + teams, + invitations, + account, + accounts + } + }; + } catch (error) { + return ErrorHandler(error); + } +}; + +export const post: RequestHandler = async (event) => { + const { teamId, userId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + if (teamId !== '0') + return { status: 401, body: { message: 'You are not authorized to perform this action' } }; + + const { id } = await event.request.json(); + try { + const aloneInTeams = await db.prisma.team.findMany({ where: { users: { every: { id } } } }); + if (aloneInTeams.length > 0) { + for (const team of aloneInTeams) { + const applications = await db.prisma.application.findMany({ + where: { teams: { every: { id: team.id } } } + }); + if (applications.length > 0) { + for (const application of applications) { + await db.prisma.application.update({ + where: { id: application.id }, + data: { teams: { connect: { id: '0' } } } + }); + } + } + const services = await db.prisma.service.findMany({ + where: { teams: { every: { id: team.id } } } + }); + if (services.length > 0) { + for (const service of services) { + await db.prisma.service.update({ + where: { id: service.id }, + data: { teams: { connect: { id: '0' } } } + }); + } + } + const databases = await db.prisma.database.findMany({ + where: { teams: { every: { id: team.id } } } + }); + if (databases.length > 0) { + for (const database of databases) { + await db.prisma.database.update({ + where: { id: database.id }, + data: { teams: { connect: { id: '0' } } } + }); + } + } + const sources = await db.prisma.gitSource.findMany({ + where: { teams: { every: { id: team.id } } } + }); + if (sources.length > 0) { + for (const source of sources) { + await db.prisma.gitSource.update({ + where: { id: source.id }, + data: { teams: { connect: { id: '0' } } } + }); + } + } + const destinations = await db.prisma.destinationDocker.findMany({ + where: { teams: { every: { id: team.id } } } + }); + if (destinations.length > 0) { + for (const destination of destinations) { + await db.prisma.destinationDocker.update({ + where: { id: destination.id }, + data: { teams: { connect: { id: '0' } } } + }); + } + } + await db.prisma.teamInvitation.deleteMany({ where: { teamId: team.id } }); + await db.prisma.permission.deleteMany({ where: { teamId: team.id } }); + await db.prisma.user.delete({ where: { id } }); + await db.prisma.team.delete({ where: { id: team.id } }); + } + } + + const notAloneInTeams = await db.prisma.team.findMany({ where: { users: { some: { id } } } }); + if (notAloneInTeams.length > 0) { + for (const team of notAloneInTeams) { + await db.prisma.team.update({ + where: { id: team.id }, + data: { users: { disconnect: { id } } } + }); + } + } + return { + status: 201 + }; + } catch (error) { + return { + status: 500 + }; + } +}; diff --git a/src/routes/iam/index.svelte b/src/routes/iam/index.svelte new file mode 100644 index 000000000..0541abbb8 --- /dev/null +++ b/src/routes/iam/index.svelte @@ -0,0 +1,178 @@ + + + + +
+
Identity and Access Management System
+
+ + +
+ {#if $session.teamId === '0' && accounts.length > 0} +
Accounts
+ {:else} +
Account
+ {/if} +
+ + + + {#if accounts.length > 1} + + + {/if} + + + + + {#each accounts as account} + + + + + {/each} + +
EmailActions
{account.email} +
resetPassword(account.id)}> + +
+
deleteUser(account.id)}> + +
+
+
+
+ +
diff --git a/src/routes/iam/password.json.ts b/src/routes/iam/password.json.ts new file mode 100644 index 000000000..b8ba2ca8e --- /dev/null +++ b/src/routes/iam/password.json.ts @@ -0,0 +1,22 @@ +import { getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { teamId, userId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = await event.request.json(); + try { + await db.prisma.user.update({ where: { id }, data: { password: 'RESETME' } }); + return { + status: 201 + }; + } catch (error) { + console.log(error); + return { + status: 500 + }; + } +}; diff --git a/src/routes/teams/[id]/__layout.svelte b/src/routes/iam/team/[id]/__layout.svelte similarity index 83% rename from src/routes/teams/[id]/__layout.svelte rename to src/routes/iam/team/[id]/__layout.svelte index 9ad4eb110..972ca111f 100644 --- a/src/routes/teams/[id]/__layout.svelte +++ b/src/routes/iam/team/[id]/__layout.svelte @@ -1,14 +1,14 @@ diff --git a/src/routes/teams/[id]/index.json.ts b/src/routes/iam/team/[id]/index.json.ts similarity index 100% rename from src/routes/teams/[id]/index.json.ts rename to src/routes/iam/team/[id]/index.json.ts diff --git a/src/routes/teams/[id]/index.svelte b/src/routes/iam/team/[id]/index.svelte similarity index 94% rename from src/routes/teams/[id]/index.svelte rename to src/routes/iam/team/[id]/index.svelte index 964b57612..541b21379 100644 --- a/src/routes/teams/[id]/index.svelte +++ b/src/routes/iam/team/[id]/index.svelte @@ -1,7 +1,7 @@ - - - -
-
Teams
- {#if $session.isAdmin} - - - - {/if} -
- -{#if invitations.length > 0} -
-
-
Pending invitations
-
-
- {#each invitations as invitation} -
-
- Invited to {invitation.teamName} with - {invitation.permission} permission. -
- - -
- {/each} -
-
-{/if} - From 2b0df270dfd81129fc9d7f34e2149e94273e8a8c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 7 Apr 2022 23:58:56 +0200 Subject: [PATCH 42/56] fix: small typo --- src/routes/services/[id]/_Services/_Services.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/services/[id]/_Services/_Services.svelte b/src/routes/services/[id]/_Services/_Services.svelte index 637944b65..41dd86ff6 100644 --- a/src/routes/services/[id]/_Services/_Services.svelte +++ b/src/routes/services/[id]/_Services/_Services.svelte @@ -93,7 +93,7 @@
- + Date: Fri, 8 Apr 2022 00:09:09 +0200 Subject: [PATCH 43/56] fix: Unique storage paths --- .../20220407220809_unique_storage_fix/migration.sql | 5 +++++ prisma/schema.prisma | 4 ++-- src/routes/iam/index.svelte | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20220407220809_unique_storage_fix/migration.sql diff --git a/prisma/migrations/20220407220809_unique_storage_fix/migration.sql b/prisma/migrations/20220407220809_unique_storage_fix/migration.sql new file mode 100644 index 000000000..9b645cc3b --- /dev/null +++ b/prisma/migrations/20220407220809_unique_storage_fix/migration.sql @@ -0,0 +1,5 @@ +-- DropIndex +DROP INDEX "ApplicationPersistentStorage_path_key"; + +-- DropIndex +DROP INDEX "ApplicationPersistentStorage_applicationId_key"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7f37f9a2b..2c97a9e8b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -117,8 +117,8 @@ model ApplicationSettings { model ApplicationPersistentStorage { id String @id @default(cuid()) application Application @relation(fields: [applicationId], references: [id]) - applicationId String @unique - path String @unique + applicationId String + path String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/src/routes/iam/index.svelte b/src/routes/iam/index.svelte index 0541abbb8..f2554813e 100644 --- a/src/routes/iam/index.svelte +++ b/src/routes/iam/index.svelte @@ -77,7 +77,7 @@
-
Identity and Access Management System
+
Identity and Access Management
-
+
{#if $session.teamId === '0' && accounts.length > 0}
Accounts
{:else} diff --git a/src/routes/index.svelte b/src/routes/index.svelte index 1a5f61b4b..84cf7188f 100644 --- a/src/routes/index.svelte +++ b/src/routes/index.svelte @@ -92,7 +92,7 @@
diff --git a/src/routes/new/source/_Github.svelte b/src/routes/new/source/_Github.svelte deleted file mode 100644 index e8f2d33c4..000000000 --- a/src/routes/new/source/_Github.svelte +++ /dev/null @@ -1,96 +0,0 @@ - - -
-
-
-
-
Configuration
- -
-
- - - -
-
- - -
- -
- - -
-
- - -
-
-
- - -
- -
-
-
-
diff --git a/src/routes/new/source/_Gitlab.svelte b/src/routes/new/source/_Gitlab.svelte deleted file mode 100644 index 219bc56b0..000000000 --- a/src/routes/new/source/_Gitlab.svelte +++ /dev/null @@ -1,73 +0,0 @@ - - -
-
-
-
Configuration
- -
-
- - -
-
- - -
- -
- - -
-
- - -
-
-
diff --git a/src/routes/new/source/index.svelte b/src/routes/new/source/index.svelte deleted file mode 100644 index 73384561a..000000000 --- a/src/routes/new/source/index.svelte +++ /dev/null @@ -1,66 +0,0 @@ - - -
-
Add New Git Source
-
- -
-
Official providers
-
- - - -
-
-
- {#if gitSource.type === 'github'} - - {:else if gitSource.type === 'gitlab'} - - {:else if gitSource.type === 'bitbucket'} -
Not implemented yet
- {/if} -
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index 06e74873b..389ee8036 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -13,6 +13,7 @@ import Ghost from '$lib/components/svg/services/Ghost.svelte'; import MeiliSearch from '$lib/components/svg/services/MeiliSearch.svelte'; import { session } from '$app/stores'; + import { getDomain } from '$lib/components/common'; export let services; async function newService() { @@ -87,9 +88,12 @@
{service.name}
- {#if $session.teamId === '0'} + {#if $session.teamId === '0' && otherServices.length > 0}
{service.teams[0].name}
{/if} + {#if service.fqdn} +
{getDomain(service.fqdn)}
+ {/if} {#if !service.type || !service.fqdn}
Configuration missing @@ -134,6 +138,9 @@ {#if $session.teamId === '0'}
{service.teams[0].name}
{/if} + {#if service.fqdn} +
{getDomain(service.fqdn)}
+ {/if} {#if !service.type || !service.fqdn}
Configuration missing diff --git a/src/routes/sources/[id]/_Github.svelte b/src/routes/sources/[id]/_Github.svelte index 102971353..b2866d195 100644 --- a/src/routes/sources/[id]/_Github.svelte +++ b/src/routes/sources/[id]/_Github.svelte @@ -3,13 +3,19 @@ import { page, session } from '$app/stores'; import { post } from '$lib/api'; import { errorNotification } from '$lib/form'; + import { toast } from '@zerodevx/svelte-toast'; const { id } = $page.params; let loading = false; async function handleSubmit() { loading = true; try { - return await post(`/sources/${id}.json`, { name: source.name }); + await post(`/sources/${id}.json`, { + name: source.name, + htmlUrl: source.htmlUrl, + apiUrl: source.apiUrl + }); + toast.push('Settings saved.'); } catch ({ error }) { return errorNotification(error); } finally { @@ -38,7 +44,18 @@ }, 100); } - function newGithubApp() { + async function newGithubApp() { + loading = true; + try { + await post(`/sources/${id}/github.json`, { + type: 'github', + name: source.name, + htmlUrl: source.htmlUrl, + apiUrl: source.apiUrl + }); + } catch ({ error }) { + return errorNotification(error); + } const left = screen.width / 2 - 1020 / 2; const top = screen.height / 2 - 618 / 2; const newWindow = open( @@ -59,31 +76,72 @@ } -{#if !source.githubAppId} - -{:else if source.githubApp?.installationId} -
-
-
General
- {#if $session.isAdmin} - - - {/if} -
-
-
- - +
+ {#if !source.githubAppId} + +
+
General
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ {#if source.apiUrl && source.htmlUrl && source.name} +
+ +
+ {/if} + + {:else if source.githubAppId} +
+
+
General
+ {#if $session.isAdmin} + + + {/if} +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ {:else} +
+
- -{:else} - -{/if} + {/if} +
diff --git a/src/routes/sources/[id]/_Gitlab.svelte b/src/routes/sources/[id]/_Gitlab.svelte index 7823aebe9..bf3b48733 100644 --- a/src/routes/sources/[id]/_Gitlab.svelte +++ b/src/routes/sources/[id]/_Gitlab.svelte @@ -1,35 +1,73 @@ -{#if !source.gitlabApp?.appId} -
-
-
- - -
- {#if payload.applicationType === 'group'} -
- - -
- {/if} - -
- -
- - - -
-
-
Configuration
+
+ +
+
General
+ {#if $session.isAdmin} -
+ {#if source.gitlabAppId} + + {/if} + {/if} +
+
+ {#if !source.gitlabAppId} +
+ + +
-
-
- - + + +
+ {/if} + {/if} + +
+
+ + +
+
+ {#if source.gitlabApp.groupName} +
+ +
+ {/if} +
+ + +
+
+ + +
+
+
+ + {#if !source.gitlabAppId} + + {/if} +
- {#if payload.applicationType === 'group'} -
- - -
- {/if} +
- - + +
- - Secret +
- -
-{:else} -
-
-
-
General
- {#if $session.isAdmin} - - - {/if} -
-
-
- - -
-
-
-
-{/if} +
+ + {#if !source.gitlabAppId} + + {/if} +
diff --git a/src/routes/sources/[id]/github.json.ts b/src/routes/sources/[id]/github.json.ts new file mode 100644 index 000000000..e0f1d3b61 --- /dev/null +++ b/src/routes/sources/[id]/github.json.ts @@ -0,0 +1,18 @@ +import { getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + const { id } = event.params; + + try { + let { type, name, htmlUrl, apiUrl } = await event.request.json(); + await db.addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl }); + return { status: 201 }; + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/sources/[id]/gitlab.json.ts b/src/routes/sources/[id]/gitlab.json.ts index 8420669e6..b1ed314bf 100644 --- a/src/routes/sources/[id]/gitlab.json.ts +++ b/src/routes/sources/[id]/gitlab.json.ts @@ -9,11 +9,23 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; try { - let { oauthId, groupName, appId, appSecret } = await event.request.json(); + let { type, name, htmlUrl, apiUrl, oauthId, appId, appSecret, groupName } = + await event.request.json(); oauthId = Number(oauthId); - await db.addSource({ id, teamId, oauthId, groupName, appId, appSecret }); + await db.addGitLabSource({ + id, + teamId, + type, + name, + htmlUrl, + apiUrl, + oauthId, + appId, + appSecret, + groupName + }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/sources/[id]/index.json.ts b/src/routes/sources/[id]/index.json.ts index 58fb7008b..cd19e6785 100644 --- a/src/routes/sources/[id]/index.json.ts +++ b/src/routes/sources/[id]/index.json.ts @@ -43,10 +43,10 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - const { name } = await event.request.json(); + const { name, htmlUrl, apiUrl } = await event.request.json(); try { - await db.updateGitsource({ id, name }); + await db.updateGitsource({ id, name, htmlUrl, apiUrl }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/sources/[id]/index.svelte b/src/routes/sources/[id]/index.svelte index 83f171412..015c98a1f 100644 --- a/src/routes/sources/[id]/index.svelte +++ b/src/routes/sources/[id]/index.svelte @@ -29,9 +29,41 @@
@@ -40,10 +72,21 @@ {source.name}
-
- {#if source.type === 'github'} - - {:else if source.type === 'gitlab'} - +
+ {#if !source.gitlabAppId && !source.githubAppId} +
+
Select a provider
+
+ + +
+
{/if} +
+ {#if source.type === 'github'} + + {:else if source.type === 'gitlab'} + + {/if} +
diff --git a/src/routes/sources/[id]/newGithubApp.svelte b/src/routes/sources/[id]/newGithubApp.svelte index c8cb4f6f3..b6a74c3ba 100644 --- a/src/routes/sources/[id]/newGithubApp.svelte +++ b/src/routes/sources/[id]/newGithubApp.svelte @@ -36,6 +36,7 @@ export let settings; onMount(() => { const { organization, id, htmlUrl } = source; + console.log(source); const { fqdn } = settings; const host = dev ? 'http://localhost:3000' diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index c763e0b58..e07c21973 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -22,6 +22,9 @@
@@ -71,7 +78,7 @@ class:border-l-4={source.gitlabApp && !source.gitlabAppId} >
{source.name}
- {#if $session.teamId === '0'} + {#if $session.teamId === '0' && otherSources.length > 0}
{source.teams[0].name}
{/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)} @@ -79,7 +86,7 @@ Configuration missing
{:else} -
{source.htmlUrl}
+
{getDomain(source.htmlUrl)}
{/if}
diff --git a/src/routes/new/source/index.json.ts b/src/routes/sources/new.ts similarity index 64% rename from src/routes/new/source/index.json.ts rename to src/routes/sources/new.ts index 803b597e9..25943f8bc 100644 --- a/src/routes/new/source/index.json.ts +++ b/src/routes/sources/new.ts @@ -1,4 +1,4 @@ -import { getUserDetails } from '$lib/common'; +import { getUserDetails, uniqueName } from '$lib/common'; import * as db from '$lib/database'; import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; @@ -7,9 +7,9 @@ export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); if (status === 401) return { status, body }; - const { name, type, htmlUrl, apiUrl, organization } = await event.request.json(); + const name = uniqueName(); try { - const { id } = await db.newSource({ name, teamId, type, htmlUrl, apiUrl, organization }); + const { id } = await db.newSource({ teamId, name }); return { status: 201, body: { id } }; } catch (e) { return ErrorHandler(e); From a165b219500572416b7566a517a770864901d589 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 10:47:01 +0200 Subject: [PATCH 47/56] ui: fix --- src/routes/sources/[id]/_Github.svelte | 2 +- src/routes/sources/[id]/_Gitlab.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/sources/[id]/_Github.svelte b/src/routes/sources/[id]/_Github.svelte index b2866d195..af776cfea 100644 --- a/src/routes/sources/[id]/_Github.svelte +++ b/src/routes/sources/[id]/_Github.svelte @@ -76,7 +76,7 @@ } -
+
{#if !source.githubAppId}
diff --git a/src/routes/sources/[id]/_Gitlab.svelte b/src/routes/sources/[id]/_Gitlab.svelte index bf3b48733..89e43cfe3 100644 --- a/src/routes/sources/[id]/_Gitlab.svelte +++ b/src/routes/sources/[id]/_Gitlab.svelte @@ -121,7 +121,7 @@ } -
+
General
From 1657e5a151cd28f2b805cbf56798b8b6749ed615 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 10:54:40 +0200 Subject: [PATCH 48/56] fix: no line during buildLog --- src/lib/common.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/common.ts b/src/lib/common.ts index 4eec73539..57cdabba2 100644 --- a/src/lib/common.ts +++ b/src/lib/common.ts @@ -52,12 +52,14 @@ export const sentry = Sentry; export const uniqueName = () => uniqueNamesGenerator(customConfig); export const saveBuildLog = async ({ line, buildId, applicationId }) => { - if (line.includes('ghs_')) { - const regex = /ghs_.*@/g; - line = line.replace(regex, '@'); + if (line) { + if (line.includes('ghs_')) { + const regex = /ghs_.*@/g; + line = line.replace(regex, '@'); + } + const addTimestamp = `${generateTimestamp()} ${line}`; + return await buildLogQueue.add(buildId, { buildId, line: addTimestamp, applicationId }); } - const addTimestamp = `${generateTimestamp()} ${line}`; - return await buildLogQueue.add(buildId, { buildId, line: addTimestamp, applicationId }); }; export const isTeamIdTokenAvailable = (request) => { From 0b709c93a8a2fa9892b720255a87717c2741e11c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 10:57:44 +0200 Subject: [PATCH 49/56] fix: html/apiUrls cannot end with / --- src/routes/sources/[id]/_Github.svelte | 8 ++++---- src/routes/sources/[id]/_Gitlab.svelte | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routes/sources/[id]/_Github.svelte b/src/routes/sources/[id]/_Github.svelte index af776cfea..6b8aa0c89 100644 --- a/src/routes/sources/[id]/_Github.svelte +++ b/src/routes/sources/[id]/_Github.svelte @@ -12,8 +12,8 @@ try { await post(`/sources/${id}.json`, { name: source.name, - htmlUrl: source.htmlUrl, - apiUrl: source.apiUrl + htmlUrl: source.htmlUrl.replace(/\/$/, ''), + apiUrl: source.apiUrl.replace(/\/$/, '') }); toast.push('Settings saved.'); } catch ({ error }) { @@ -50,8 +50,8 @@ await post(`/sources/${id}/github.json`, { type: 'github', name: source.name, - htmlUrl: source.htmlUrl, - apiUrl: source.apiUrl + htmlUrl: source.htmlUrl.replace(/\/$/, ''), + apiUrl: source.apiUrl.replace(/\/$/, '') }); } catch ({ error }) { return errorNotification(error); diff --git a/src/routes/sources/[id]/_Gitlab.svelte b/src/routes/sources/[id]/_Gitlab.svelte index 89e43cfe3..b528b1850 100644 --- a/src/routes/sources/[id]/_Gitlab.svelte +++ b/src/routes/sources/[id]/_Gitlab.svelte @@ -38,8 +38,8 @@ await post(`/sources/${id}/gitlab.json`, { type: 'gitlab', name: source.name, - htmlUrl: source.htmlUrl, - apiUrl: source.apiUrl, + htmlUrl: source.htmlUrl.replace(/\/$/, ''), + apiUrl: source.apiUrl.replace(/\/$/, ''), oauthId: source.gitlabApp.oauthId, appId: source.gitlabApp.appId, appSecret: source.gitlabApp.appSecret, @@ -56,8 +56,8 @@ try { await post(`/sources/${id}.json`, { name: source.name, - htmlUrl: source.htmlUrl, - apiUrl: source.apiUrl + htmlUrl: source.htmlUrl.replace(/\/$/, ''), + apiUrl: source.apiUrl.replace(/\/$/, '') }); } catch ({ error }) { return errorNotification(error); From d9ba1a0b5c6fb42087cbd830263cdbfe770f1130 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 11:16:07 +0200 Subject: [PATCH 50/56] fix: typo --- src/routes/sources/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index e07c21973..f8891531d 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -94,7 +94,7 @@
{#if otherSources.length > 0 && $session.teamId === '0'} -
Other Srouces
+
Other Sources
{#each otherSources as source} From ce71dccbc1285cbe1956675706530de437b1da2e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 11:19:01 +0200 Subject: [PATCH 51/56] fix: Missing buildpack --- src/routes/applications/index.svelte | 112 ++++++++++++++------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/src/routes/applications/index.svelte b/src/routes/applications/index.svelte index 0c69c47fe..5fb4979cc 100644 --- a/src/routes/applications/index.svelte +++ b/src/routes/applications/index.svelte @@ -68,60 +68,7 @@ {#each ownApplications as application}
- {#if application.buildPack.toLowerCase() === 'rust'} - - {:else if application.buildPack.toLowerCase() === 'node'} - - {:else if application.buildPack.toLowerCase() === 'react'} - - {:else if application.buildPack.toLowerCase() === 'svelte'} - - {:else if application.buildPack.toLowerCase() === 'vuejs'} - - {:else if application.buildPack.toLowerCase() === 'php'} - - {:else if application.buildPack.toLowerCase() === 'python'} - - {:else if application.buildPack.toLowerCase() === 'static'} - - {:else if application.buildPack.toLowerCase() === 'nestjs'} - - {:else if application.buildPack.toLowerCase() === 'nuxtjs'} - - {:else if application.buildPack.toLowerCase() === 'nextjs'} - - {:else if application.buildPack.toLowerCase() === 'gatsby'} - - {:else if application.buildPack.toLowerCase() === 'docker'} - - {:else if application.buildPack.toLowerCase() === 'astro'} - - {:else if application.buildPack.toLowerCase() === 'eleventy'} - - {/if} - -
{application.name}
- {#if $session.teamId === '0' && otherApplications.length > 0} -
Team {application.teams[0].name}
- {/if} - {#if application.fqdn} -
{getDomain(application.fqdn)}
- {/if} - {#if !application.gitSourceId || !application.destinationDockerId || !application.fqdn} -
- Configuration missing -
- {/if} -
-
- {/each} -
- {#if otherApplications.length > 0 && $session.teamId === '0'} -
Other Applications
- + {#if otherApplications.length > 0 && $session.teamId === '0'} +
Other Applications
+
+ {#each otherApplications as application} + +
+ {#if application.buildPack} + {#if application.buildPack.toLowerCase() === 'rust'} + + {:else if application.buildPack.toLowerCase() === 'node'} + + {:else if application.buildPack.toLowerCase() === 'react'} + + {:else if application.buildPack.toLowerCase() === 'svelte'} + + {:else if application.buildPack.toLowerCase() === 'vuejs'} + + {:else if application.buildPack.toLowerCase() === 'php'} + + {:else if application.buildPack.toLowerCase() === 'python'} + + {:else if application.buildPack.toLowerCase() === 'static'} + + {:else if application.buildPack.toLowerCase() === 'nestjs'} + + {:else if application.buildPack.toLowerCase() === 'nuxtjs'} + + {:else if application.buildPack.toLowerCase() === 'nextjs'} + + {:else if application.buildPack.toLowerCase() === 'gatsby'} + + {:else if application.buildPack.toLowerCase() === 'docker'} + + {:else if application.buildPack.toLowerCase() === 'astro'} + + {:else if application.buildPack.toLowerCase() === 'eleventy'} + + {/if} + {/if}
{application.name}
{#if $session.teamId === '0'} From 13acf09dcc119e42594829428e3f5c8d03ef9081 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 14:03:21 +0200 Subject: [PATCH 52/56] ui: fixes --- src/routes/applications/[id]/configuration/source.svelte | 8 ++++++-- src/routes/applications/index.svelte | 6 +++--- src/routes/databases/index.svelte | 2 +- src/routes/destinations/index.svelte | 2 +- src/routes/services/index.svelte | 6 +++--- src/routes/sources/index.svelte | 4 ++-- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/routes/applications/[id]/configuration/source.svelte b/src/routes/applications/[id]/configuration/source.svelte index 953c23d69..1be6330d1 100644 --- a/src/routes/applications/[id]/configuration/source.svelte +++ b/src/routes/applications/[id]/configuration/source.svelte @@ -54,6 +54,10 @@ return errorNotification(error); } } + async function newSource() { + const { id } = await post('/sources/new', {}); + return await goto(`/sources/${id}`, { replaceState: true }); + }
@@ -64,7 +68,7 @@ {:else} diff --git a/src/routes/applications/index.svelte b/src/routes/applications/index.svelte index 5fb4979cc..3221f6634 100644 --- a/src/routes/applications/index.svelte +++ b/src/routes/applications/index.svelte @@ -58,7 +58,7 @@ {/if}
- {#if !applications || applications.length === 0} + {#if !applications || ownApplications.length === 0}
No applications found
@@ -107,7 +107,7 @@
Team {application.teams[0].name}
{/if} {#if application.fqdn} -
{getDomain(application.fqdn)}
+
{getDomain(application.fqdn) || ''}
{/if} {#if !application.gitSourceId || !application.destinationDockerId || !application.fqdn}
@@ -163,7 +163,7 @@
Team {application.teams[0].name}
{/if} {#if application.fqdn} -
{getDomain(application.fqdn)}
+
{getDomain(application.fqdn) || ''}
{/if} {#if !application.gitSourceId || !application.destinationDockerId || !application.fqdn}
diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index c160bc009..4ace17e27 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -46,7 +46,7 @@
- {#if !databases || databases.length === 0} + {#if !databases || ownDatabases.length === 0}
No databases found
diff --git a/src/routes/destinations/index.svelte b/src/routes/destinations/index.svelte index 84d1fc0bb..7c04f8aab 100644 --- a/src/routes/destinations/index.svelte +++ b/src/routes/destinations/index.svelte @@ -57,7 +57,7 @@ {/if}
- {#if !destinations || destinations.length === 0} + {#if !destinations || ownDestinations.length === 0}
No destination found
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index 389ee8036..e829256c4 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -52,7 +52,7 @@
- {#if !services || services.length === 0} + {#if !services || ownServices.length === 0}
No services found
@@ -92,7 +92,7 @@
{service.teams[0].name}
{/if} {#if service.fqdn} -
{getDomain(service.fqdn)}
+
{getDomain(service.fqdn) || ''}
{/if} {#if !service.type || !service.fqdn}
@@ -139,7 +139,7 @@
{service.teams[0].name}
{/if} {#if service.fqdn} -
{getDomain(service.fqdn)}
+
{getDomain(service.fqdn) || ''}
{/if} {#if !service.type || !service.fqdn}
diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index f8891531d..ba4e6e9c5 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -62,7 +62,7 @@ {/if}
- {#if !sources || sources.length === 0} + {#if !sources || ownSources.length === 0}
No git sources found
@@ -86,7 +86,7 @@ Configuration missing
{:else} -
{getDomain(source.htmlUrl)}
+
{getDomain(source.htmlUrl) || ''}
{/if}
From 66af12f9b5be595841f19b2263744728eb9c5455 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 14:12:06 +0200 Subject: [PATCH 53/56] ui: fixes --- src/routes/applications/index.svelte | 9 +++++---- src/routes/databases/index.svelte | 29 ++++++++++++++-------------- src/routes/destinations/index.svelte | 25 ++++++++++++------------ src/routes/services/index.svelte | 29 ++++++++++++++-------------- src/routes/sources/index.svelte | 29 ++++++++++++++-------------- 5 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/routes/applications/index.svelte b/src/routes/applications/index.svelte index 3221f6634..99bb67175 100644 --- a/src/routes/applications/index.svelte +++ b/src/routes/applications/index.svelte @@ -62,9 +62,10 @@
No applications found
- {:else} + {/if} + {#if ownApplications.length > 0 || otherApplications.length > 0}
-
+
{#each ownApplications as application}
@@ -119,8 +120,8 @@ {/each}
{#if otherApplications.length > 0 && $session.teamId === '0'} -
Other Applications
-
+
Other Applications
+
{#each otherApplications as application}
diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 4ace17e27..29ef54965 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -50,12 +50,13 @@
No databases found
- {:else} + {/if} + {#if ownDatabases.length > 0 || otherDatabases.length > 0}
-
+
{#each ownDatabases as database} - -
+ +
{#if database.type === 'clickhouse'} {:else if database.type === 'couchdb'} @@ -69,14 +70,14 @@ {:else if database.type === 'redis'} {/if} -
+
{database.name}
{#if $session.teamId === '0' && otherDatabases.length > 0} -
{database.teams[0].name}
+
{database.teams[0].name}
{/if} {#if !database.type} -
+
Configuration missing
{/if} @@ -85,11 +86,11 @@ {/each}
{#if otherDatabases.length > 0 && $session.teamId === '0'} -
Other Databases
-
+
Other Databases
+
{#each otherDatabases as database} - -
+ +
{#if database.type === 'clickhouse'} {:else if database.type === 'couchdb'} @@ -103,14 +104,14 @@ {:else if database.type === 'redis'} {/if} -
+
{database.name}
{#if $session.teamId === '0'} -
{database.teams[0].name}
+
{database.teams[0].name}
{/if} {#if !database.type} -
+
Configuration missing
{:else} diff --git a/src/routes/destinations/index.svelte b/src/routes/destinations/index.svelte index 7c04f8aab..6921e4db4 100644 --- a/src/routes/destinations/index.svelte +++ b/src/routes/destinations/index.svelte @@ -61,33 +61,34 @@
No destination found
- {:else} + {/if} + {#if ownDestinations.length > 0 || otherDestinations.length > 0}
-
+ {#if otherDestinations.length > 0 && $session.teamId === '0'} -
Other Destinations
-
+
Other Destinations
+
{#each otherDestinations as destination} - +
-
{destination.name}
+
{destination.name}
{#if $session.teamId === '0'} -
{destination.teams[0].name}
+
{destination.teams[0].name}
{/if} -
{destination.network}
+
{destination.network}
{/each} diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index e829256c4..f8022f14f 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -56,12 +56,13 @@
No services found
- {:else} + {/if} + {#if ownServices.length > 0 || otherServices.length > 0}
-
+
{#each ownServices as service} - -
+ +
{#if service.type === 'plausibleanalytics'} {:else if service.type === 'nocodb'} @@ -85,17 +86,17 @@ {:else if service.type === 'meilisearch'} {/if} -
+
{service.name}
{#if $session.teamId === '0' && otherServices.length > 0} -
{service.teams[0].name}
+
{service.teams[0].name}
{/if} {#if service.fqdn}
{getDomain(service.fqdn) || ''}
{/if} {#if !service.type || !service.fqdn} -
+
Configuration missing
{/if} @@ -104,11 +105,11 @@ {/each}
{#if otherServices.length > 0 && $session.teamId === '0'} -
Other Services
-
+
Other Services
+
{#each otherServices as service} - -
+ +
{#if service.type === 'plausibleanalytics'} {:else if service.type === 'nocodb'} @@ -132,17 +133,17 @@ {:else if service.type === 'meilisearch'} {/if} -
+
{service.name}
{#if $session.teamId === '0'} -
{service.teams[0].name}
+
{service.teams[0].name}
{/if} {#if service.fqdn}
{getDomain(service.fqdn) || ''}
{/if} {#if !service.type || !service.fqdn} -
+
Configuration missing
{:else} diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index ba4e6e9c5..9bde85feb 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -66,23 +66,24 @@
No git sources found
- {:else} + {/if} + {#if ownSources.length > 0 || otherSources.length > 0}
-
+
{#each ownSources as source} - +
-
{source.name}
+
{source.name}
{#if $session.teamId === '0' && otherSources.length > 0} -
{source.teams[0].name}
+
{source.teams[0].name}
{/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)} -
+
Configuration missing
{:else} @@ -94,22 +95,22 @@
{#if otherSources.length > 0 && $session.teamId === '0'} -
Other Sources
-
+
Other Sources
+
{#each otherSources as source} - +
-
{source.name}
+
{source.name}
{#if $session.teamId === '0'} -
{source.teams[0].name}
+
{source.teams[0].name}
{/if} {#if (source.type === 'gitlab' && !source.gitlabAppId) || (source.type === 'github' && !source.githubAppId && !source.githubApp?.installationId)} -
+
Configuration missing
{:else} From 3449e0f8fc02ced1ce13f8b911f04d4a92bc2b1d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 14:16:14 +0200 Subject: [PATCH 54/56] ui: fix --- src/routes/sources/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index 9bde85feb..fe4063f3f 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -61,7 +61,7 @@ {/if}
-
+
{#if !sources || ownSources.length === 0}
No git sources found
From e3f78a1cf9d052ff37d870b30d4b5149d255a8c9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 15:02:48 +0200 Subject: [PATCH 55/56] ui: fixes --- src/routes/applications/index.svelte | 2 +- src/routes/databases/index.svelte | 2 +- src/routes/services/index.svelte | 2 +- src/routes/sources/index.svelte | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/applications/index.svelte b/src/routes/applications/index.svelte index 99bb67175..3cfcbf141 100644 --- a/src/routes/applications/index.svelte +++ b/src/routes/applications/index.svelte @@ -57,7 +57,7 @@
{/if}
-
+
{#if !applications || ownApplications.length === 0}
No applications found
diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 29ef54965..a47dbc66f 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -45,7 +45,7 @@
-
+
{#if !databases || ownDatabases.length === 0}
No databases found
diff --git a/src/routes/services/index.svelte b/src/routes/services/index.svelte index f8022f14f..998779a1f 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/index.svelte @@ -51,7 +51,7 @@
-
+
{#if !services || ownServices.length === 0}
No services found
diff --git a/src/routes/sources/index.svelte b/src/routes/sources/index.svelte index fe4063f3f..1e2d4d510 100644 --- a/src/routes/sources/index.svelte +++ b/src/routes/sources/index.svelte @@ -61,7 +61,7 @@ {/if}
-
+
{#if !sources || ownSources.length === 0}
No git sources found
From e8516bc83193a4b4fd439aa32e76cacc4c06c824 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 8 Apr 2022 15:12:10 +0200 Subject: [PATCH 56/56] ui: fixes --- .../[id]/configuration/destination.svelte | 35 ++++++++++++-- .../[id]/configuration/source.svelte | 46 +++++++++++++++++-- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/routes/applications/[id]/configuration/destination.svelte b/src/routes/applications/[id]/configuration/destination.svelte index 2c796b5ed..1b0c6df5c 100644 --- a/src/routes/applications/[id]/configuration/destination.svelte +++ b/src/routes/applications/[id]/configuration/destination.svelte @@ -29,7 +29,7 @@