diff --git a/apps/api/src/jobs/deployApplication.ts b/apps/api/src/jobs/deployApplication.ts index 5722dbcfb..23adbf608 100644 --- a/apps/api/src/jobs/deployApplication.ts +++ b/apps/api/src/jobs/deployApplication.ts @@ -357,7 +357,9 @@ import * as buildpacks from '../lib/buildPacks'; where: { id: buildId, status: { in: ['queued', 'running'] } }, data: { status: 'failed' } }); - await saveBuildLog({ line: error, buildId, applicationId: application.id }); + if (error !== 1) { + await saveBuildLog({ line: error, buildId, applicationId: application.id }); + } } }); } diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 5bb2aa134..337d27682 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -21,7 +21,7 @@ import { scheduler } from './scheduler'; import { supportedServiceTypesAndVersions } from './services/supportedVersions'; import { includeServices } from './services/common'; -export const version = '3.10.2'; +export const version = '3.10.3'; export const isDev = process.env.NODE_ENV === 'development'; const algorithm = 'aes-256-ctr'; @@ -96,7 +96,8 @@ export const asyncExecShellStream = async ({ const array = stdout.split('\n'); for (const line of array) { if (line !== '\n' && line !== '') { - await saveBuildLog({ + logs.push(line.replace('\n', '')) + debug && await saveBuildLog({ line: `${line.replace('\n', '')}`, buildId, applicationId @@ -109,11 +110,12 @@ export const asyncExecShellStream = async ({ const array = stderr.split('\n'); for (const line of array) { if (line !== '\n' && line !== '') { - await saveBuildLog({ + errorLogs.push(line.replace('\n', '')) + debug && await saveBuildLog({ line: `${line.replace('\n', '')}`, buildId, applicationId - }); + }); } } }); diff --git a/apps/api/src/lib/importers/gitlab.ts b/apps/api/src/lib/importers/gitlab.ts index 69f204155..35fa3d8ce 100644 --- a/apps/api/src/lib/importers/gitlab.ts +++ b/apps/api/src/lib/importers/gitlab.ts @@ -40,7 +40,7 @@ export default async function ({ if (forPublic) { await asyncExecShell( - `git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. ` + `git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. ` ); } else { await asyncExecShell( diff --git a/apps/api/src/lib/services/handlers.ts b/apps/api/src/lib/services/handlers.ts index 903f53035..6a5bfe91a 100644 --- a/apps/api/src/lib/services/handlers.ts +++ b/apps/api/src/lib/services/handlers.ts @@ -1006,79 +1006,136 @@ async function startUmamiService(request: FastifyRequest) { } const initDbSQL = ` - drop table if exists event; - drop table if exists pageview; - drop table if exists session; - drop table if exists website; - drop table if exists account; - - create table account ( - user_id serial primary key, - username varchar(255) unique not null, - password varchar(60) not null, - is_admin bool not null default false, - created_at timestamp with time zone default current_timestamp, - updated_at timestamp with time zone default current_timestamp - ); - - create table website ( - website_id serial primary key, - website_uuid uuid unique not null, - user_id int not null references account(user_id) on delete cascade, - name varchar(100) not null, - domain varchar(500), - share_id varchar(64) unique, - created_at timestamp with time zone default current_timestamp - ); - - create table session ( - session_id serial primary key, - session_uuid uuid unique not null, - website_id int not null references website(website_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - hostname varchar(100), - browser varchar(20), - os varchar(20), - device varchar(20), - screen varchar(11), - language varchar(35), - country char(2) - ); - - create table pageview ( - view_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - referrer varchar(500) - ); - - create table event ( - event_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - event_type varchar(50) not null, - event_value varchar(50) not null - ); - - create index website_user_id_idx on website(user_id); - - create index session_created_at_idx on session(created_at); - create index session_website_id_idx on session(website_id); - - create index pageview_created_at_idx on pageview(created_at); - create index pageview_website_id_idx on pageview(website_id); - create index pageview_session_id_idx on pageview(session_id); - create index pageview_website_id_created_at_idx on pageview(website_id, created_at); - create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); - - create index event_created_at_idx on event(created_at); - create index event_website_id_idx on event(website_id); - create index event_session_id_idx on event(session_id); - + -- CreateTable +CREATE TABLE "account" ( + "user_id" SERIAL NOT NULL, + "username" VARCHAR(255) NOT NULL, + "password" VARCHAR(60) NOT NULL, + "is_admin" BOOLEAN NOT NULL DEFAULT false, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + + PRIMARY KEY ("user_id") +); + +-- CreateTable +CREATE TABLE "event" ( + "event_id" SERIAL NOT NULL, + "website_id" INTEGER NOT NULL, + "session_id" INTEGER NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "url" VARCHAR(500) NOT NULL, + "event_type" VARCHAR(50) NOT NULL, + "event_value" VARCHAR(50) NOT NULL, + + PRIMARY KEY ("event_id") +); + +-- CreateTable +CREATE TABLE "pageview" ( + "view_id" SERIAL NOT NULL, + "website_id" INTEGER NOT NULL, + "session_id" INTEGER NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "url" VARCHAR(500) NOT NULL, + "referrer" VARCHAR(500), + + PRIMARY KEY ("view_id") +); + +-- CreateTable +CREATE TABLE "session" ( + "session_id" SERIAL NOT NULL, + "session_uuid" UUID NOT NULL, + "website_id" INTEGER NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "hostname" VARCHAR(100), + "browser" VARCHAR(20), + "os" VARCHAR(20), + "device" VARCHAR(20), + "screen" VARCHAR(11), + "language" VARCHAR(35), + "country" CHAR(2), + + PRIMARY KEY ("session_id") +); + +-- CreateTable +CREATE TABLE "website" ( + "website_id" SERIAL NOT NULL, + "website_uuid" UUID NOT NULL, + "user_id" INTEGER NOT NULL, + "name" VARCHAR(100) NOT NULL, + "domain" VARCHAR(500), + "share_id" VARCHAR(64), + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + + PRIMARY KEY ("website_id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "account.username_unique" ON "account"("username"); + +-- CreateIndex +CREATE INDEX "event_created_at_idx" ON "event"("created_at"); + +-- CreateIndex +CREATE INDEX "event_session_id_idx" ON "event"("session_id"); + +-- CreateIndex +CREATE INDEX "event_website_id_idx" ON "event"("website_id"); + +-- CreateIndex +CREATE INDEX "pageview_created_at_idx" ON "pageview"("created_at"); + +-- CreateIndex +CREATE INDEX "pageview_session_id_idx" ON "pageview"("session_id"); + +-- CreateIndex +CREATE INDEX "pageview_website_id_created_at_idx" ON "pageview"("website_id", "created_at"); + +-- CreateIndex +CREATE INDEX "pageview_website_id_idx" ON "pageview"("website_id"); + +-- CreateIndex +CREATE INDEX "pageview_website_id_session_id_created_at_idx" ON "pageview"("website_id", "session_id", "created_at"); + +-- CreateIndex +CREATE UNIQUE INDEX "session.session_uuid_unique" ON "session"("session_uuid"); + +-- CreateIndex +CREATE INDEX "session_created_at_idx" ON "session"("created_at"); + +-- CreateIndex +CREATE INDEX "session_website_id_idx" ON "session"("website_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "website.website_uuid_unique" ON "website"("website_uuid"); + +-- CreateIndex +CREATE UNIQUE INDEX "website.share_id_unique" ON "website"("share_id"); + +-- CreateIndex +CREATE INDEX "website_user_id_idx" ON "website"("user_id"); + +-- AddForeignKey +ALTER TABLE "event" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "event" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "pageview" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "pageview" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE; + insert into account (username, password, is_admin) values ('admin', '${bcrypt.hashSync( umamiAdminPassword, 10 diff --git a/apps/api/src/routes/api/v1/handlers.ts b/apps/api/src/routes/api/v1/handlers.ts index 3bdeeca0a..a0217c58a 100644 --- a/apps/api/src/routes/api/v1/handlers.ts +++ b/apps/api/src/routes/api/v1/handlers.ts @@ -3,15 +3,15 @@ import { compareVersions } from "compare-versions"; import cuid from "cuid"; import bcrypt from "bcryptjs"; import { - asyncExecShell, - asyncSleep, - cleanupDockerStorage, - errorHandler, - isDev, - listSettings, - prisma, - uniqueName, - version, + asyncExecShell, + asyncSleep, + cleanupDockerStorage, + errorHandler, + isDev, + listSettings, + prisma, + uniqueName, + version, } from "../../../lib/common"; import { supportedServiceTypesAndVersions } from "../../../lib/services/supportedVersions"; import { scheduler } from "../../../lib/scheduler"; @@ -20,321 +20,321 @@ import type { Login, Update } from "."; import type { GetCurrentUser } from "./types"; export async function hashPassword(password: string): Promise { - const saltRounds = 15; - return bcrypt.hash(password, saltRounds); + const saltRounds = 15; + return bcrypt.hash(password, saltRounds); } export async function cleanupManually(request: FastifyRequest) { - try { - const { serverId } = request.body; - const destination = await prisma.destinationDocker.findUnique({ - where: { id: serverId }, - }); - await cleanupDockerStorage(destination.id, true, true); - return {}; - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + try { + const { serverId } = request.body; + const destination = await prisma.destinationDocker.findUnique({ + where: { id: serverId }, + }); + await cleanupDockerStorage(destination.id, true, true); + return {}; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function checkUpdate(request: FastifyRequest) { - try { - const isStaging = - request.hostname === "staging.coolify.io" || - request.hostname === "arm.coolify.io"; - const currentVersion = version; - const { data: versions } = await axios.get( - `https://get.coollabs.io/versions.json?appId=${process.env["COOLIFY_APP_ID"]}&version=${currentVersion}` - ); - const latestVersion = versions["coolify"].main.version; - const isUpdateAvailable = compareVersions(latestVersion, currentVersion); - if (isStaging) { - return { - isUpdateAvailable: true, - latestVersion: "next", - }; - } - return { - isUpdateAvailable: isStaging ? true : isUpdateAvailable === 1, - latestVersion, - }; - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + try { + const isStaging = + request.hostname === "staging.coolify.io" || + request.hostname === "arm.coolify.io"; + const currentVersion = version; + const { data: versions } = await axios.get( + `https://get.coollabs.io/versions.json?appId=${process.env["COOLIFY_APP_ID"]}&version=${currentVersion}` + ); + const latestVersion = versions["coolify"].main.version; + const isUpdateAvailable = compareVersions(latestVersion, currentVersion); + if (isStaging) { + return { + isUpdateAvailable: true, + latestVersion: "next", + }; + } + return { + isUpdateAvailable: isStaging ? true : isUpdateAvailable === 1, + latestVersion, + }; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function update(request: FastifyRequest) { - const { latestVersion } = request.body; - try { - if (!isDev) { - const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); - await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`); - await asyncExecShell(`env | grep COOLIFY > .env`); - await asyncExecShell( - `sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` - ); - await asyncExecShell( - `docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify && docker rm coolify && docker compose up -d --force-recreate"` - ); - return {}; - } else { - await asyncSleep(2000); - return {}; - } - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + const { latestVersion } = request.body; + try { + if (!isDev) { + const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); + await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`); + await asyncExecShell(`env | grep COOLIFY > .env`); + await asyncExecShell( + `sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` + ); + await asyncExecShell( + `docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify && docker rm coolify && docker compose up -d --force-recreate"` + ); + return {}; + } else { + await asyncSleep(2000); + return {}; + } + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function resetQueue(request: FastifyRequest) { - try { - const teamId = request.user.teamId; - if (teamId === "0") { - await prisma.build.updateMany({ - where: { status: { in: ["queued", "running"] } }, - data: { status: "canceled" }, - }); - scheduler.workers.get("deployApplication").postMessage("cancel"); - } - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + try { + const teamId = request.user.teamId; + if (teamId === "0") { + await prisma.build.updateMany({ + where: { status: { in: ["queued", "running"] } }, + data: { status: "canceled" }, + }); + scheduler.workers.get("deployApplication").postMessage("cancel"); + } + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function restartCoolify(request: FastifyRequest) { - try { - const teamId = request.user.teamId; - if (teamId === "0") { - if (!isDev) { - asyncExecShell(`docker restart coolify`); - return {}; - } else { - return {}; - } - } - throw { - status: 500, - message: "You are not authorized to restart Coolify.", - }; - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + try { + const teamId = request.user.teamId; + if (teamId === "0") { + if (!isDev) { + asyncExecShell(`docker restart coolify`); + return {}; + } else { + return {}; + } + } + throw { + status: 500, + message: "You are not authorized to restart Coolify.", + }; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function showDashboard(request: FastifyRequest) { - try { - const userId = request.user.userId; - const teamId = request.user.teamId; - const applications = await prisma.application.findMany({ - where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, - include: { settings: true, destinationDocker: true, teams: true }, - }); - const databases = await prisma.database.findMany({ - where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, - include: { settings: true, destinationDocker: true, teams: true }, - }); - const services = await prisma.service.findMany({ - where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, - include: { destinationDocker: true, teams: true }, - }); - const gitSources = await prisma.gitSource.findMany({ - where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, - include: { teams: true }, - }); - const destinations = await prisma.destinationDocker.findMany({ - where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, - include: { teams: true }, - }); - const settings = await listSettings(); - return { - applications, - databases, - services, - gitSources, - destinations, - settings, - }; - } catch ({ status, message }) { - return errorHandler({ status, message }); - } + try { + const userId = request.user.userId; + const teamId = request.user.teamId; + const applications = await prisma.application.findMany({ + where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, + include: { settings: true, destinationDocker: true, teams: true }, + }); + const databases = await prisma.database.findMany({ + where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, + include: { settings: true, destinationDocker: true, teams: true }, + }); + const services = await prisma.service.findMany({ + where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, + include: { destinationDocker: true, teams: true }, + }); + const gitSources = await prisma.gitSource.findMany({ + where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, + include: { teams: true }, + }); + const destinations = await prisma.destinationDocker.findMany({ + where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } }, + include: { teams: true }, + }); + const settings = await listSettings(); + return { + applications, + databases, + services, + gitSources, + destinations, + settings, + }; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function login( - request: FastifyRequest, - reply: FastifyReply + request: FastifyRequest, + reply: FastifyReply ) { - if (request.user) { - return reply.redirect("/dashboard"); - } else { - const { email, password, isLogin } = request.body || {}; - if (!email || !password) { - throw { status: 500, message: "Email and password are required." }; - } - const users = await prisma.user.count(); - const userFound = await prisma.user.findUnique({ - where: { email }, - include: { teams: true, permission: true }, - rejectOnNotFound: false, - }); - if (!userFound && isLogin) { - throw { status: 500, message: "User not found." }; - } - const { isRegistrationEnabled, id } = await prisma.setting.findFirst(); - let uid = cuid(); - let permission = "read"; - let isAdmin = false; + if (request.user) { + return reply.redirect("/dashboard"); + } else { + const { email, password, isLogin } = request.body || {}; + if (!email || !password) { + throw { status: 500, message: "Email and password are required." }; + } + const users = await prisma.user.count(); + const userFound = await prisma.user.findUnique({ + where: { email }, + include: { teams: true, permission: true }, + rejectOnNotFound: false, + }); + if (!userFound && isLogin) { + throw { status: 500, message: "User not found." }; + } + const { isRegistrationEnabled, id } = await prisma.setting.findFirst(); + let uid = cuid(); + let permission = "read"; + let isAdmin = false; - if (users === 0) { - await prisma.setting.update({ - where: { id }, - data: { isRegistrationEnabled: false }, - }); - 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)) { - if (userFound.id === "0") { - await prisma.user.update({ - where: { email: userFound.email }, - data: { password: "RESETME" }, - }); - } else { - await prisma.user.update({ - where: { email: userFound.email }, - data: { password: "RESETTIMEOUT" }, - }); - } + if (users === 0) { + await prisma.setting.update({ + where: { id }, + data: { isRegistrationEnabled: false }, + }); + 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)) { + if (userFound.id === "0") { + await prisma.user.update({ + where: { email: userFound.email }, + data: { password: "RESETME" }, + }); + } else { + await prisma.user.update({ + where: { email: userFound.email }, + data: { password: "RESETTIMEOUT" }, + }); + } - throw { - status: 500, - message: - "Password reset link has expired. Please request a new one.", - }; - } else { - await prisma.user.update({ - where: { email: userFound.email }, - data: { password: hashedPassword }, - }); - return { - userId: userFound.id, - teamId: userFound.id, - permission: userFound.permission, - isAdmin: true, - }; - } - } + throw { + status: 500, + message: + "Password reset link has expired. Please request a new one.", + }; + } else { + await prisma.user.update({ + where: { email: userFound.email }, + data: { password: hashedPassword }, + }); + return { + userId: userFound.id, + teamId: userFound.id, + permission: userFound.permission, + isAdmin: true, + }; + } + } - const passwordMatch = await bcrypt.compare( - password, - userFound.password - ); - if (!passwordMatch) { - throw { - status: 500, - message: "Wrong password or email address.", - }; - } - uid = userFound.id; - isAdmin = true; - } - } else { - permission = "owner"; - isAdmin = true; - if (!isRegistrationEnabled) { - throw { - status: 404, - message: "Registration disabled by administrator.", - }; - } - const hashedPassword = await hashPassword(password); - if (users === 0) { - await prisma.user.create({ - data: { - id: uid, - email, - password: hashedPassword, - type: "email", - teams: { - create: { - id: uid, - name: uniqueName(), - destinationDocker: { connect: { network: "coolify" } }, - }, - }, - permission: { create: { teamId: uid, permission: "owner" } }, - }, - include: { teams: true }, - }); - } else { - await prisma.user.create({ - data: { - id: uid, - email, - password: hashedPassword, - type: "email", - teams: { - create: { - id: uid, - name: uniqueName(), - }, - }, - permission: { create: { teamId: uid, permission: "owner" } }, - }, - include: { teams: true }, - }); - } - } - return { - userId: uid, - teamId: uid, - permission, - isAdmin, - }; - } + const passwordMatch = await bcrypt.compare( + password, + userFound.password + ); + if (!passwordMatch) { + throw { + status: 500, + message: "Wrong password or email address.", + }; + } + uid = userFound.id; + isAdmin = true; + } + } else { + permission = "owner"; + isAdmin = true; + if (!isRegistrationEnabled) { + throw { + status: 404, + message: "Registration disabled by administrator.", + }; + } + const hashedPassword = await hashPassword(password); + if (users === 0) { + await prisma.user.create({ + data: { + id: uid, + email, + password: hashedPassword, + type: "email", + teams: { + create: { + id: uid, + name: uniqueName(), + destinationDocker: { connect: { network: "coolify" } }, + }, + }, + permission: { create: { teamId: uid, permission: "owner" } }, + }, + include: { teams: true }, + }); + } else { + await prisma.user.create({ + data: { + id: uid, + email, + password: hashedPassword, + type: "email", + teams: { + create: { + id: uid, + name: uniqueName(), + }, + }, + permission: { create: { teamId: uid, permission: "owner" } }, + }, + include: { teams: true }, + }); + } + } + return { + userId: uid, + teamId: uid, + permission, + isAdmin, + }; + } } export async function getCurrentUser( - request: FastifyRequest, - fastify + request: FastifyRequest, + fastify ) { - let token = null; - const { teamId } = request.query; - try { - const user = await prisma.user.findUnique({ - where: { id: request.user.userId }, - }); - if (!user) { - throw "User not found"; - } - } catch (error) { - throw { status: 401, message: error }; - } - if (teamId) { - try { - const user = await prisma.user.findFirst({ - where: { id: request.user.userId, teams: { some: { id: teamId } } }, - include: { teams: true, permission: true }, - }); - if (user) { - const permission = user.permission.find( - (p) => p.teamId === teamId - ).permission; - const payload = { - ...request.user, - teamId, - permission: permission || null, - isAdmin: permission === "owner" || permission === "admin", - }; - token = fastify.jwt.sign(payload); - } - } catch (error) { - // No new token -> not switching teams - } - } - return { - settings: await prisma.setting.findFirst(), - supportedServiceTypesAndVersions, - token, - ...request.user, - }; + let token = null; + const { teamId } = request.query; + try { + const user = await prisma.user.findUnique({ + where: { id: request.user.userId }, + }); + if (!user) { + throw "User not found"; + } + } catch (error) { + throw { status: 401, message: error }; + } + if (teamId) { + try { + const user = await prisma.user.findFirst({ + where: { id: request.user.userId, teams: { some: { id: teamId } } }, + include: { teams: true, permission: true }, + }); + if (user) { + const permission = user.permission.find( + (p) => p.teamId === teamId + ).permission; + const payload = { + ...request.user, + teamId, + permission: permission || null, + isAdmin: permission === "owner" || permission === "admin", + }; + token = fastify.jwt.sign(payload); + } + } catch (error) { + // No new token -> not switching teams + } + } + return { + settings: await prisma.setting.findFirst(), + supportedServiceTypesAndVersions, + token, + ...request.user, + }; } diff --git a/apps/ui/src/routes/applications/[id]/logs/build.svelte b/apps/ui/src/routes/applications/[id]/logs/build.svelte index 6999f53f0..de5d60c35 100644 --- a/apps/ui/src/routes/applications/[id]/logs/build.svelte +++ b/apps/ui/src/routes/applications/[id]/logs/build.svelte @@ -28,7 +28,7 @@ import {addToast} from '$lib/store'; import BuildLog from './_BuildLog.svelte'; import { get, post } from '$lib/api'; import { t } from '$lib/translations'; - import { changeQueryParams, dateOptions, errorNotification } from '$lib/common'; + import { changeQueryParams, dateOptions, errorNotification, asyncSleep } from '$lib/common'; import Tooltip from '$lib/components/Tooltip.svelte'; let buildId: any; @@ -85,7 +85,7 @@ import {addToast} from '$lib/store'; return changeQueryParams(buildId); } async function resetQueue() { - const sure = confirm('It will reset all build queues for all applications. If something is queued, it will be canceled automatically. Are you sure? '); + const sure = confirm('It will reset all build queues for all applications. If something is queued, it will be canceled automatically. Are you sure? '); if (sure) { try { @@ -94,6 +94,8 @@ import {addToast} from '$lib/store'; message: 'Queue reset done.', type: 'success' }); + await asyncSleep(500) + return window.location.reload() } catch (error) { return errorNotification(error); } @@ -162,12 +164,8 @@ import {addToast} from '$lib/store'; on:click={() => loadBuild(build.id)} class:rounded-tr={index === 0} class:rounded-br={index === builds.length - 1} - class="flex cursor-pointer items-center justify-center border-l-2 py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl" + class="flex cursor-pointer items-center justify-center py-4 no-underline transition-all duration-100 hover:bg-coolgray-400 hover:shadow-xl" class:bg-coolgray-400={buildId === build.id} - class:border-red-500={build.status === 'failed'} - class:border-orange-500={build.status === 'canceled'} - class:border-green-500={build.status === 'success'} - class:border-yellow-500={build.status === 'running'} >
@@ -176,6 +174,11 @@ import {addToast} from '$lib/store';
{build.type}
+
{build.status}
diff --git a/package.json b/package.json index 4d0c1ddaf..96dac690d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "3.10.2", + "version": "3.10.3", "license": "Apache-2.0", "repository": "github:coollabsio/coolify", "scripts": {