diff --git a/src/app.d.ts b/src/app.d.ts index a88bd7502..d432aef4a 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -15,6 +15,9 @@ declare namespace App { readOnly: boolean; source: string; settings: string; + database: Record; + versions: string; + privatePort: string; } } diff --git a/src/lib/components/common.ts b/src/lib/components/common.ts index 3e5568432..2bd962c4c 100644 --- a/src/lib/components/common.ts +++ b/src/lib/components/common.ts @@ -56,7 +56,7 @@ export const supportedDatabaseTypesAndVersions = [ name: 'postgresql', fancyName: 'PostgreSQL', baseImage: 'bitnami/postgresql', - versions: ['14.2', '13.6', '12.10', '11.15', '10.20'] + versions: ['14.2.0', '13.6.0', '12.10.0 ', '11.15.0', '10.20.0'] }, { name: 'redis', diff --git a/src/lib/database/databases.ts b/src/lib/database/databases.ts index 7fc237944..2179b5479 100644 --- a/src/lib/database/databases.ts +++ b/src/lib/database/databases.ts @@ -137,3 +137,37 @@ export async function stopDatabase(database) { } return everStarted; } + +export async function updatePasswordInDb(database, user, newPassword) { + const { + id, + type, + rootUser, + rootUserPassword, + dbUser, + dbUserPassword, + defaultDatabase, + destinationDockerId, + destinationDocker: { engine } + } = database; + if (destinationDockerId) { + const host = getEngine(engine); + if (type === 'mysql') { + await asyncExecShell( + `DOCKER_HOST=${host} docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';\"` + ); + } else if (type === 'postgresql') { + await asyncExecShell( + `DOCKER_HOST=${host} docker exec ${id} psql postgresql://${dbUser}:${dbUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role ${user} WITH PASSWORD '${newPassword}'"` + ); + } else if (type === 'mongodb') { + await asyncExecShell( + `DOCKER_HOST=${host} docker exec ${id} mongo 'mongodb://${rootUser}:${rootUserPassword}@${id}:27017/admin?readPreference=primary&ssl=false' --eval "db.changeUserPassword('${user}','${newPassword}')"` + ); + } else if (type === 'redis') { + await asyncExecShell( + `DOCKER_HOST=${host} docker exec ${id} redis-cli -u redis://${dbUserPassword}@${id}:6379 --raw CONFIG SET requirepass ${newPassword}` + ); + } + } +} diff --git a/src/lib/database/destinations.ts b/src/lib/database/destinations.ts index 5bd63c81b..7b2570d93 100644 --- a/src/lib/database/destinations.ts +++ b/src/lib/database/destinations.ts @@ -44,9 +44,7 @@ export async function configureDestinationForDatabase({ id, destinationId }) { const host = getEngine(engine); if (type && version) { const baseImage = getDatabaseImage(type); - asyncExecShell( - `DOCKER_HOST=${host} docker pull ${baseImage}:${version} && echo "FROM ${baseImage}:${version}" | docker build --label coolify.image="true" -t "${baseImage}:${version}" -` - ); + asyncExecShell(`DOCKER_HOST=${host} docker pull ${baseImage}:${version}`); } } } diff --git a/src/routes/databases/[id]/_Databases/_Databases.svelte b/src/routes/databases/[id]/_Databases/_Databases.svelte index 1820577bc..731dcd80e 100644 --- a/src/routes/databases/[id]/_Databases/_Databases.svelte +++ b/src/routes/databases/[id]/_Databases/_Databases.svelte @@ -2,6 +2,8 @@ export let database; export let privatePort; export let settings; + export let isRunning; + import { page, session } from '$app/stores'; import CopyPasswordField from '$lib/components/CopyPasswordField.svelte'; import Setting from '$lib/components/Setting.svelte'; @@ -15,24 +17,36 @@ import { browser } from '$app/env'; import { post } from '$lib/api'; import { getDomain } from '$lib/components/common'; + import { toast } from '@zerodevx/svelte-toast'; const { id } = $page.params; + let loading = false; + let publicLoading = false; + let isPublic = database.settings.isPublic || false; let appendOnly = database.settings.appendOnly; - let databaseDefault = database.defaultDatabase; - let databaseDbUser = database.dbUser; - let databaseDbUserPassword = database.dbUserPassword; - if (database.type === 'mongodb') { - databaseDefault = '?readPreference=primary&ssl=false'; - databaseDbUser = database.rootUser; - databaseDbUserPassword = database.rootUserPassword; - } else if (database.type === 'redis') { - databaseDefault = ''; - databaseDbUser = ''; + let databaseDefault; + let databaseDbUser; + let databaseDbUserPassword; + + generateDbDetails(); + + function generateDbDetails() { + databaseDefault = database.defaultDatabase; + databaseDbUser = database.dbUser; + databaseDbUserPassword = database.dbUserPassword; + if (database.type === 'mongodb') { + databaseDefault = '?readPreference=primary&ssl=false'; + databaseDbUser = database.rootUser; + databaseDbUserPassword = database.rootUserPassword; + } else if (database.type === 'redis') { + databaseDefault = ''; + databaseDbUser = ''; + } } - let databaseUrl = generateUrl(); + $: databaseUrl = generateUrl(); function generateUrl() { return browser @@ -49,28 +63,46 @@ } async function changeSettings(name) { + if (publicLoading || !isRunning) return; + publicLoading = true; + let data = { + isPublic, + appendOnly + }; if (name === 'isPublic') { - isPublic = !isPublic; + data.isPublic = !isPublic; } if (name === 'appendOnly') { - appendOnly = !appendOnly; + data.appendOnly = !appendOnly; } try { - const { publicPort } = await post(`/databases/${id}/settings.json`, { isPublic, appendOnly }); + const { publicPort } = await post(`/databases/${id}/settings.json`, { + isPublic: data.isPublic, + appendOnly: data.appendOnly + }); + isPublic = data.isPublic; + appendOnly = data.appendOnly; + databaseUrl = generateUrl(); if (isPublic) { database.publicPort = publicPort; } - databaseUrl = generateUrl(); } catch ({ error }) { return errorNotification(error); + } finally { + publicLoading = false; } } async function handleSubmit() { try { - await post(`/databases/${id}.json`, { ...database }); - return window.location.reload(); + loading = true; + await post(`/databases/${id}.json`, { ...database, isRunning }); + generateDbDetails(); + databaseUrl = generateUrl(); + toast.push('Settings saved.'); } catch ({ error }) { return errorNotification(error); + } finally { + loading = false; } } @@ -142,21 +174,21 @@ readonly disabled name="publicPort" - value={isPublic ? database.publicPort : privatePort} + value={publicLoading ? 'Loading...' : isPublic ? database.publicPort : privatePort} />
{#if database.type === 'mysql'} - + {:else if database.type === 'postgresql'} - + {:else if database.type === 'mongodb'} - + {:else if database.type === 'redis'} - + {:else if database.type === 'couchdb'} - + {/if}
@@ -168,7 +200,7 @@ name="url" readonly disabled - value={databaseUrl} + value={publicLoading || loading ? 'Loading...' : databaseUrl} />
@@ -179,10 +211,12 @@
changeSettings('isPublic')} title="Set it public" description="Your database will be reachable over the internet.
Take security seriously in this case!" + disabled={!isRunning} />
{#if database.type === 'redis'} diff --git a/src/routes/databases/[id]/_Databases/_MongoDB.svelte b/src/routes/databases/[id]/_Databases/_MongoDB.svelte index 7ec21edcd..fa73b870e 100644 --- a/src/routes/databases/[id]/_Databases/_MongoDB.svelte +++ b/src/routes/databases/[id]/_Databases/_MongoDB.svelte @@ -1,6 +1,8 @@
@@ -21,13 +23,14 @@
+
diff --git a/src/routes/databases/[id]/_Databases/_MySQL.svelte b/src/routes/databases/[id]/_Databases/_MySQL.svelte index f085b3320..27057049b 100644 --- a/src/routes/databases/[id]/_Databases/_MySQL.svelte +++ b/src/routes/databases/[id]/_Databases/_MySQL.svelte @@ -1,6 +1,8 @@
@@ -33,14 +35,15 @@
+
@@ -56,13 +59,14 @@
+
diff --git a/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte b/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte index 3f995cafc..d59f6bbbc 100644 --- a/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte +++ b/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte @@ -1,6 +1,8 @@
@@ -33,13 +35,14 @@
+
diff --git a/src/routes/databases/[id]/_Databases/_Redis.svelte b/src/routes/databases/[id]/_Databases/_Redis.svelte index fece7c837..fdd2ce5f1 100644 --- a/src/routes/databases/[id]/_Databases/_Redis.svelte +++ b/src/routes/databases/[id]/_Databases/_Redis.svelte @@ -1,6 +1,8 @@
@@ -10,40 +12,14 @@
+
-
diff --git a/src/routes/databases/[id]/__layout.svelte b/src/routes/databases/[id]/__layout.svelte index ae08d48f7..45016da69 100644 --- a/src/routes/databases/[id]/__layout.svelte +++ b/src/routes/databases/[id]/__layout.svelte @@ -15,7 +15,7 @@ const endpoint = `/databases/${params.id}.json`; const res = await fetch(endpoint); if (res.ok) { - const { database, state, versions, privatePort, settings } = await res.json(); + const { database, isRunning, versions, privatePort, settings } = await res.json(); if (!database || Object.entries(database).length === 0) { return { status: 302, @@ -35,13 +35,13 @@ return { props: { database, - state, + isRunning, versions, privatePort }, stuff: { database, - state, + isRunning, versions, privatePort, settings @@ -65,7 +65,7 @@ import { goto } from '$app/navigation'; export let database; - export let state; + export let isRunning; let loading = false; async function deleteDatabase() { @@ -91,8 +91,6 @@ return window.location.reload(); } catch ({ error }) { return errorNotification(error); - } finally { - loading = false; } } } @@ -103,8 +101,6 @@ return window.location.reload(); } catch ({ error }) { return errorNotification(error); - } finally { - loading = false; } } @@ -114,7 +110,7 @@ {:else} {#if database.type && database.destinationDockerId && database.version && database.defaultDatabase} - {#if state === 'running'} + {#if isRunning} - {:else if state === 'not started'} + {:else}