From de9fe33194fb0642cde5fca68da97bd993730c9f Mon Sep 17 00:00:00 2001 From: charlesgauthereau Date: Wed, 16 Jul 2025 18:15:28 +0200 Subject: [PATCH] Finish migration prisma to drizzle. --- .../dashboard/(admin)/admin/page.tsx | 11 +- .../(admin)/agents/[agentId]/page.tsx | 66 +++++++---- .../dashboard/(admin)/agents/page.tsx | 1 - .../projects/[projectId]/edit/page.tsx | 2 +- .../projects/[projectId]/page.tsx | 2 +- .../(organization)/settings/edit/page.tsx | 13 +- .../(organization)/settings/page.tsx | 46 +------ .../(organization)/statistics/page.tsx | 10 +- app/api/agent/[agentId]/backup/route.ts | 112 ++++++++++-------- app/api/agent/[agentId]/restore/route.ts | 46 ++++--- app/api/agent/[agentId]/status/helpers.ts | 104 ++++++++-------- app/api/agent/[agentId]/status/route.ts | 33 +++--- .../dashboard/admin/columns-users.tsx | 71 +++++------ .../projects/ProjectCard/ProjectCard.tsx | 4 +- .../ProjectCard/ProjectDatabaseCard.tsx | 2 +- .../projects/ProjectsForm/ProjectForm.tsx | 2 +- .../dashboard/sideBar/app-sidebar.tsx | 7 -- .../dashboard/sideBar/sidebar-content.tsx | 25 +++- src/db/schema/06_database.ts | 5 +- src/db/schema/07_agent.ts | 7 ++ src/lib/auth/auth.ts | 2 +- 21 files changed, 278 insertions(+), 293 deletions(-) diff --git a/app/(customer)/dashboard/(admin)/admin/page.tsx b/app/(customer)/dashboard/(admin)/admin/page.tsx index 767f32d0..61efe771 100644 --- a/app/(customer)/dashboard/(admin)/admin/page.tsx +++ b/app/(customer)/dashboard/(admin)/admin/page.tsx @@ -1,16 +1,21 @@ import { PageParams } from "@/types/next"; +import * as drizzleDb from "@/db"; import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page"; import { AdminTabs } from "@/components/wrappers/dashboard/admin/admin-tabs"; import { currentUser } from "@/lib/auth/current-user"; import { db } from "@/db"; +import {eq, isNotNull, isNull} from "drizzle-orm"; + export default async function RoutePage(props: PageParams<{}>) { - const user = await currentUser()!; + const user = await currentUser(); const users = await db.query.user.findMany({ - where: (fields, { isNull, not }) => not(isNull(fields.deletedAt)), + where: (fields) => isNull(fields.deletedAt) }); + // const users = await db.query.user.findMany(); + console.log("users",users); const settings = await db.query.setting.findFirst({ where: (fields, { eq }) => eq(fields.name, "system"), @@ -22,7 +27,7 @@ export default async function RoutePage(props: PageParams<{}>) { Administration Panel - + ); diff --git a/app/(customer)/dashboard/(admin)/agents/[agentId]/page.tsx b/app/(customer)/dashboard/(admin)/agents/[agentId]/page.tsx index fa70c709..e56b6ead 100644 --- a/app/(customer)/dashboard/(admin)/agents/[agentId]/page.tsx +++ b/app/(customer)/dashboard/(admin)/agents/[agentId]/page.tsx @@ -1,6 +1,5 @@ import Link from "next/link"; import {GearIcon} from "@radix-ui/react-icons"; -import {prisma} from "@/prisma"; import {PageParams} from "@/types/next"; import {Page, PageContent, PageDescription, PageTitle} from "@/features/layout/page"; import {formatDateLastContact} from "@/utils/date-formatting"; @@ -9,38 +8,55 @@ import {Card, CardContent, CardHeader} from "@/components/ui/card"; import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination"; import {DatabaseCard} from "@/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard"; import {AgentCardKey} from "@/components/wrappers/dashboard/agent/AgentCardKey/AgentCardKey"; +import { db } from "@/db"; +import * as drizzleDb from "@/db"; +import {and, eq} from "drizzle-orm"; +import {notFound} from "next/navigation"; export default async function RoutePage(props: PageParams<{ agentId: string }>) { const {agentId} = await props.params - const agent = await prisma.agent.findUnique({ - where: { - id: agentId, - }, - include: { - databases: {} + const agent = await db.query.agent.findFirst({ + where: eq(drizzleDb.schemas.agent.id, agentId), + with: { + databases: true } }) + // + console.log(agent) - const databaseId = 'db-123'; - - const totalBackups = await prisma.backup.count({ - where: { - databaseId: databaseId, - }, - }); - - const successfulBackups = await prisma.backup.count({ - where: { - databaseId: databaseId, - status: 'success', - }, - }); - - const successRate = totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null - + if (!agent) { + notFound() + } + // + // const databaseId = 'db-123'; + // + // const totalBackupsResult = await db + // .select({ count: drizzleDb.schemas.backup.id }) + // .from(drizzleDb.schemas.backup) + // .where(eq(drizzleDb.schemas.backup.databaseId, databaseId)) + // .execute(); + // + // const totalBackups = totalBackupsResult.length; + // + // const successfulBackupsResult = await db + // .select({ count: drizzleDb.schemas.backup.id }) + // .from(drizzleDb.schemas.backup) + // .where( + // and( + // eq(drizzleDb.schemas.backup.databaseId, databaseId), + // eq(drizzleDb.schemas.backup.status, "success") + // ) + // ) + // .execute(); + // + // + // const successfulBackups = successfulBackupsResult.length; + // + // const successRate = + // totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null; return ( @@ -73,7 +89,7 @@ export default async function RoutePage(props: PageParams<{ agentId: string }>) Success rate - {successRate ?? "Unavailable for now."} + {/*{successRate ?? "Unavailable for now."}*/} diff --git a/app/(customer)/dashboard/(admin)/agents/page.tsx b/app/(customer)/dashboard/(admin)/agents/page.tsx index 0464ba00..26825a99 100644 --- a/app/(customer)/dashboard/(admin)/agents/page.tsx +++ b/app/(customer)/dashboard/(admin)/agents/page.tsx @@ -6,7 +6,6 @@ import Link from "next/link"; import { Page, PageActions, PageContent, PageHeader, PageTitle } from "@/features/layout/page"; import { notFound } from "next/navigation"; import { db } from "@/db"; -export const dynamic = "force-dynamic"; export default async function RoutePage(props: PageParams<{}>) { const agents = await db.query.agent.findMany(); diff --git a/app/(customer)/dashboard/(organization)/projects/[projectId]/edit/page.tsx b/app/(customer)/dashboard/(organization)/projects/[projectId]/edit/page.tsx index d9e9eea1..eaa308d8 100644 --- a/app/(customer)/dashboard/(organization)/projects/[projectId]/edit/page.tsx +++ b/app/(customer)/dashboard/(organization)/projects/[projectId]/edit/page.tsx @@ -22,7 +22,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }> notFound(); } - // + const org = await db.query.organization.findFirst({ where: eq(drizzleDb.schemas.organization.slug, "default"), }); diff --git a/app/(customer)/dashboard/(organization)/projects/[projectId]/page.tsx b/app/(customer)/dashboard/(organization)/projects/[projectId]/page.tsx index dd36ad31..2cd4d49b 100644 --- a/app/(customer)/dashboard/(organization)/projects/[projectId]/page.tsx +++ b/app/(customer)/dashboard/(organization)/projects/[projectId]/page.tsx @@ -46,7 +46,7 @@ export default async function RoutePage(props: PageParams<{
{proj.name} - + diff --git a/app/(customer)/dashboard/(organization)/settings/edit/page.tsx b/app/(customer)/dashboard/(organization)/settings/edit/page.tsx index b065c370..f9878fa2 100644 --- a/app/(customer)/dashboard/(organization)/settings/edit/page.tsx +++ b/app/(customer)/dashboard/(organization)/settings/edit/page.tsx @@ -1,26 +1,19 @@ import {PageParams} from "@/types/next"; import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page"; -import {getCurrentOrganizationSlug} from "@/features/dashboard/organization-cookie"; -import {prisma} from "@/prisma"; -import {requiredCurrentUser} from "@/auth/current-user"; import {notFound} from "next/navigation"; import {OrganizationForm} from "@/components/wrappers/dashboard/organization/OrganizationForm/OrganizationForm"; import {getOrganization} from "@/lib/auth/auth"; export default async function RoutePage(props: PageParams<{ - slug: string; + }>) { - - const {slug: organizationSlug} = await props.params; - - const organization = await getOrganization({organizationSlug}); + const organization = await getOrganization({}); if (!organization) { - notFound() + notFound(); } - return( diff --git a/app/(customer)/dashboard/(organization)/settings/page.tsx b/app/(customer)/dashboard/(organization)/settings/page.tsx index d8fab5e4..d8bc9d9c 100644 --- a/app/(customer)/dashboard/(organization)/settings/page.tsx +++ b/app/(customer)/dashboard/(organization)/settings/page.tsx @@ -3,9 +3,6 @@ import {Page, PageActions, PageContent, PageDescription, PageHeader, PageTitle} import {currentUser} from "@/lib/auth/current-user"; import {getOrganization} from "@/lib/auth/auth"; import {notFound} from "next/navigation"; -import {requiredCurrentUser} from "@/auth/current-user"; -import {SettingsTabs} from "@/components/wrappers/dashboard/settings/SettingsTabs/SettingsTabs"; -import {getCurrentOrganizationSlug} from "@/features/dashboard/organization-cookie"; import { DeleteOrganizationButton } from "@/components/wrappers/dashboard/organization/DeleteOrganization/DeleteOrganizationButton"; @@ -13,50 +10,13 @@ import {EditButtonSettings} from "@/components/wrappers/dashboard/settings/EditB export default async function RoutePage(props: PageParams<{ slug: string }>) { - const {slug: organizationSlug} = await props.params; - + const organization = await getOrganization({}); const user = await currentUser(); - const organization = await getOrganization({organizationSlug}); - - if (!organization || organization?.slug !== organizationSlug) { + if (!organization) { notFound(); } - - - // const organization = await prisma.organization.findUnique({ - // where: { - // slug: currentOrganizationSlug, - // }, - // include: { - // users:{ - // include:{ - // user: {} - // } - // } - // } - // }) - // - // const currentOrganizationUser = await prisma.userOrganization.findFirst({ - // where:{ - // userId: user.id, - // organization:{ - // slug: currentOrganizationSlug != "" ? currentOrganizationSlug : "default", - // } - // } - // }) - // if (currentOrganizationUser.role != "admin") { - // notFound() - // } - // - // - // const settings = await prisma.settings.findUnique({ - // where: { - // name: "system" - // } - // }) - return ( @@ -76,7 +36,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) { Manage your organization settings. - {/**/} + {/* TODO add the list of organisation members (add, remove, edit) */} ) diff --git a/app/(customer)/dashboard/(organization)/statistics/page.tsx b/app/(customer)/dashboard/(organization)/statistics/page.tsx index df3eae21..943c9e50 100644 --- a/app/(customer)/dashboard/(organization)/statistics/page.tsx +++ b/app/(customer)/dashboard/(organization)/statistics/page.tsx @@ -8,17 +8,17 @@ import { notFound } from "next/navigation"; import { db } from "@/db"; import { asc, count, eq, inArray } from "drizzle-orm"; import * as drizzleDb from "@/db"; +import {getOrganization} from "@/lib/auth/auth"; -export default async function RoutePage(props: PageParams<{ slug: string }>) { - const { slug: organizationSlug } = await props.params; +export default async function RoutePage(props: PageParams<{ }>) { + const organization = await getOrganization({}); - const currentOrganizationSlug = await getCurrentOrganizationSlug(); - if (currentOrganizationSlug !== organizationSlug) { + if (!organization) { notFound(); } const org = await db.query.organization.findFirst({ - where: eq(drizzleDb.schemas.organization.slug, currentOrganizationSlug), + where: eq(drizzleDb.schemas.organization.slug, organization.slug), }); if (!org) notFound(); diff --git a/app/api/agent/[agentId]/backup/route.ts b/app/api/agent/[agentId]/backup/route.ts index 71f809f4..74df5e0b 100644 --- a/app/api/agent/[agentId]/backup/route.ts +++ b/app/api/agent/[agentId]/backup/route.ts @@ -1,25 +1,27 @@ import {NextResponse} from "next/server"; -import {prisma} from "@/prisma"; import {isUuidv4} from "@/utils/verify-uuid"; import {uploadLocalPrivate} from "@/features/upload/private/upload.action"; import {v4 as uuidv4} from "uuid"; -import {Backup, Database} from "@prisma/client"; import {eventEmitter} from "../../../events/route"; +import {db} from "@/db"; +import {Backup} from "@/db/schema/06_database"; +import {and, eq} from "drizzle-orm"; +import * as drizzleDb from "@/db"; export async function POST( request: Request, - { params }: { params: Promise<{ agentId: string }> } + {params}: { params: Promise<{ agentId: string }> } ) { try { const contentType = request.headers.get("Content-Type"); if (!contentType || !contentType.includes("multipart/form-data")) { return NextResponse.json( - { error: "Unsupported or missing Content-Type" }, - { status: 400 } + {error: "Unsupported or missing Content-Type"}, + {status: 400} ); } - eventEmitter.emit('modification', { update: true }); + eventEmitter.emit('modification', {update: true}); const agentId = (await params).agentId; const formData = await request.formData(); @@ -28,61 +30,64 @@ export async function POST( if (!generatedId || !isUuidv4(generatedId)) { return NextResponse.json( - { error: "generatedId is not a valid UUID" }, - { status: 400 } + {error: "generatedId is not a valid UUID"}, + {status: 400} ); } - const agent = await prisma.agent.findFirst({ - where: { id: agentId }, + const agent = await db.query.agent.findFirst({ + where: eq(drizzleDb.schemas.agent.id, agentId), }); if (!agent) { return NextResponse.json( - { error: "Agent not found" }, - { status: 404 } + {error: "Agent not found"}, + {status: 404} ); } - const database = await prisma.database.findFirst({ - where: { generatedId }, + const database = await db.query.database.findFirst({ + where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId), }); if (!database) { return NextResponse.json( - { error: "Database associated with generatedId not found" }, - { status: 404 } + {error: "Database associated with generatedId not found"}, + {status: 404} ); } - let backup: Backup | null = null; + let backup: Backup | null | undefined = null; if (method === "automatic") { - backup = await prisma.backup.create({ - data: { - status: "ongoing", + [backup] = await db + .insert(drizzleDb.schemas.backup) + .values({ + status: 'ongoing', databaseId: database.id, - }, - }); + }) + .returning(); + if (!backup) { return NextResponse.json( - { error: "Unable to create an automatic backup" }, - { status: 500 } + {error: "Unable to create an automatic backup"}, + {status: 500} ); } } else { - backup = await prisma.backup.findFirst({ - where: { - status: "ongoing", - databaseId: database.id, - }, + backup = await db.query.backup.findFirst({ + where: and( + eq(drizzleDb.schemas.backup.status, 'ongoing'), + eq(drizzleDb.schemas.backup.databaseId, database.id), + ), }); + if (!backup) { return NextResponse.json( - { error: "Unable to find the corresponding backup" }, - { status: 404 } + {error: "Unable to find the corresponding backup"}, + {status: 404} ); } } @@ -94,8 +99,8 @@ export async function POST( if (!file) { return NextResponse.json( - { error: "File is required for successful backup" }, - { status: 400 } + {error: "File is required for successful backup"}, + {status: 400} ); } @@ -103,49 +108,52 @@ export async function POST( const fileName = `${uuid}.dump`; const buffer = Buffer.from(await file.arrayBuffer()); - const { success, message, filePath } = await uploadLocalPrivate(fileName, buffer); + const {success, message, filePath} = await uploadLocalPrivate(fileName, buffer); if (!success) { return NextResponse.json( - { error: message }, - { status: 500 } + {error: message}, + {status: 500} ); } - await prisma.backup.update({ - where: { id: backup.id }, - data: { + await db + .update(drizzleDb.schemas.backup) + .set({ file: fileName, - status: "success", - }, - }); - eventEmitter.emit('modification', { update: true }); + status: 'success', + }) + .where(eq(drizzleDb.schemas.backup.id, backup.id)); + + eventEmitter.emit('modification', {update: true}); return NextResponse.json( { message: "Backup successfully uploaded", }, - { status: 200 } + {status: 200} ); } else { - await prisma.backup.update({ - where: { id: backup.id }, - data: { status: "failed" }, - }); - eventEmitter.emit('modification', { update: true }); + + await db + .update(drizzleDb.schemas.backup) + .set({status: 'failed'}) + .where(eq(drizzleDb.schemas.backup.id, backup.id)); + + eventEmitter.emit('modification', {update: true}); return NextResponse.json( { message: "Backup successfully updated with status failed", }, - { status: 200 } + {status: 200} ); } } catch (error) { console.error("Error in POST handler:", error); return NextResponse.json( - { error: "Internal server error" }, - { status: 500 } + {error: "Internal server error"}, + {status: 500} ); } } \ No newline at end of file diff --git a/app/api/agent/[agentId]/restore/route.ts b/app/api/agent/[agentId]/restore/route.ts index d8f8412e..cc9528c6 100644 --- a/app/api/agent/[agentId]/restore/route.ts +++ b/app/api/agent/[agentId]/restore/route.ts @@ -1,14 +1,17 @@ import {NextResponse} from "next/server"; import {isUuidv4} from "@/utils/verify-uuid"; -import {prisma} from "@/prisma"; import {eventEmitter} from "../../../events/route"; - +import * as drizzleDb from "@/db"; +import {db} from "@/db"; +import {and, eq} from "drizzle-orm"; export type BodyResultRestore = { generatedId: string status: string } +type RestorationStatus = 'waiting' | 'ongoing' | 'failed' | 'success'; + export async function POST( @@ -17,7 +20,7 @@ export async function POST( ) { try { - eventEmitter.emit('modification', { update: true }); + eventEmitter.emit('modification', {update: true}); const agentId = (await params).agentId const body: BodyResultRestore = await request.json(); @@ -33,53 +36,44 @@ export async function POST( ); } - const agent = await prisma.agent.findFirst({ - where: { - id: agentId - } + const agent = await db.query.agent.findFirst({ + where: eq(drizzleDb.schemas.agent.id, agentId) }) if (!agent) { return NextResponse.json({error: "Agent not found"}, {status: 404}) } - const database = await prisma.database.findFirst({ - where: { - generatedId: body.generatedId - } + const database = await db.query.database.findFirst({ + where: eq(drizzleDb.schemas.database.agentDatabaseId, body.generatedId) + }) if (!database) { return NextResponse.json({error: "Database associated with generatedId provided not found"}, {status: 404}) } - const restoration = await prisma.restoration.findFirst({ - where: { - status : "ongoing", - databaseId: database.id - } + const restoration = await db.query.restoration.findFirst({ + where: and(eq(drizzleDb.schemas.restoration.status, "ongoing"), eq(drizzleDb.schemas.restoration.databaseId, database.id),) }) + if (!restoration) { return NextResponse.json({error: "Unable to fin the corresponding restoration"}, {status: 404}) } - await prisma.restoration.update({ - where:{ - id : restoration.id - }, - data: { - status: body.status - } - }) + await db + .update(drizzleDb.schemas.restoration) + .set({ status: body.status as RestorationStatus }) + .where(eq(drizzleDb.schemas.restoration.id, restoration.id)); const response = { message: true, details: "Restoration successfully updated" } - eventEmitter.emit('modification', { update: true }); + eventEmitter.emit('modification', {update: true}); - return Response.json(response , {status: 200}) + return Response.json(response, {status: 200}) } catch (error) { diff --git a/app/api/agent/[agentId]/status/helpers.ts b/app/api/agent/[agentId]/status/helpers.ts index 319089f4..80cd8b37 100644 --- a/app/api/agent/[agentId]/status/helpers.ts +++ b/app/api/agent/[agentId]/status/helpers.ts @@ -1,16 +1,18 @@ -import {Agent, Database} from "@prisma/client"; -import {prisma} from "@/prisma"; import {NextResponse} from "next/server"; import {Body} from "./route"; import {isUuidv4} from "@/utils/verify-uuid"; import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action"; - +import {Agent} from "@/db/schema/07_agent"; +import {Database} from "@/db/schema/06_database"; +import * as drizzleDb from "@/db"; +import {db as dbClient} from "@/db"; +import {and, eq} from "drizzle-orm"; export async function handleDatabases(body: Body, agent: Agent, lastContact: Date) { const databasesResponse = []; const formatDatabase = (database: Database, backupAction: boolean, restoreAction: boolean, UrlBackup: string) => ({ - generatedId: database.generatedId, + generatedId: database.agentDatabaseId, dbms: database.dbms, data: { backup: { @@ -25,15 +27,14 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat }); for (const db of body.databases) { - const existingDatabase = await prisma.database.findFirst({ - where: { - generatedId: db.generatedId, - }, + + const existingDatabase = await dbClient.query.database.findFirst({ + where: eq(drizzleDb.schemas.database.agentDatabaseId, db.generatedId) }); let backupAction: boolean = false let restoreAction: boolean = false - let UrlBackup: string = null + let UrlBackup: string = "" if (!existingDatabase) { if (!isUuidv4(db.generatedId)) { @@ -42,74 +43,69 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat { status: 500 } ); } - const databaseCreated = await prisma.database.create({ - data: { + + const [databaseCreated] = await dbClient + .insert(drizzleDb.schemas.database) + .values({ agentId: agent.id, name: db.name, dbms: db.dbms, - generatedId: db.generatedId, + agentDatabaseId: db.generatedId, lastContact: lastContact, - }, - }); + }) + .returning(); if (databaseCreated) { databasesResponse.push(formatDatabase(databaseCreated, backupAction,restoreAction, UrlBackup)); } } else { - const databaseUpdated = await prisma.database.update({ - where: { - id: existingDatabase.id, - }, - data: { - lastContact: lastContact, - }, - }); - const backup = await prisma.backup.findFirst({ - where: { - databaseId: databaseUpdated.id, - status: "waiting" - } + + + const [databaseUpdated] = await dbClient + .update(drizzleDb.schemas.database) + .set({ lastContact: lastContact }) + .where(eq(drizzleDb.schemas.database.id, existingDatabase.id)) + .returning(); + + + + const backup = await dbClient.query.backup.findFirst({ + where: and(eq(drizzleDb.schemas.backup.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.backup.status,"waiting")) }) - const restoration = await prisma.restoration.findFirst({ - where:{ - databaseId: databaseUpdated.id, - status: "waiting" - } + + const restoration = await dbClient.query.restoration.findFirst({ + where: and(eq(drizzleDb.schemas.restoration.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.restoration.status,"waiting")) }) if(backup){ backupAction = true - await prisma.backup.update({ - where:{ - id: backup.id - }, - data: { - status: "ongoing" - } - }) + + await dbClient + .update(drizzleDb.schemas.backup) + .set({ status: "ongoing" }) + .where(eq(drizzleDb.schemas.backup.id, backup.id)); } if(restoration){ restoreAction = true - const backupToRestore = await prisma.backup.findFirst({ - where:{ - id: restoration.backupId - } - }) - const fileName = backupToRestore.file - UrlBackup = await getFileUrlPresignedLocal(fileName) - await prisma.restoration.update({ - where: { - id: restoration.id - }, - data:{ - status: "ongoing" - } + + const backupToRestore = await dbClient.query.backup.findFirst({ + where: eq(drizzleDb.schemas.backup.id, restoration.backupId), }) + + + const fileName = backupToRestore?.file + UrlBackup = await getFileUrlPresignedLocal(fileName ?? "") + + await dbClient + .update(drizzleDb.schemas.restoration) + .set({ status: "ongoing" }) + .where(eq(drizzleDb.schemas.restoration.id, restoration.id)); + } diff --git a/app/api/agent/[agentId]/status/route.ts b/app/api/agent/[agentId]/status/route.ts index fbf73d3f..3f842d28 100644 --- a/app/api/agent/[agentId]/status/route.ts +++ b/app/api/agent/[agentId]/status/route.ts @@ -1,14 +1,15 @@ -import {prisma} from "@/prisma"; import {NextResponse} from "next/server"; -import {Dbms} from "@prisma/client"; import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action"; import {handleDatabases} from "./helpers"; import {eventEmitter} from "../../../events/route"; - +import * as drizzleDb from "@/db"; +import {db} from "@/db"; +import {EDbmsSchema} from "@/db/schema/types"; +import {eq} from "drizzle-orm"; export type databaseAgent = { name: string, - dbms: Dbms, + dbms: EDbmsSchema, generatedId: string } @@ -33,25 +34,23 @@ export async function POST( const body: Body = await request.json(); const lastContact = new Date(); - const agent = await prisma.agent.findFirst({ - where: { - id: agentId - } + + const agent = await db.query.agent.findFirst({ + where: eq(drizzleDb.schemas.agent.id, agentId), }) + if (!agent) { return NextResponse.json({error: "Agent not found"}, {status: 404}) } const databasesResponse = await handleDatabases(body, agent, lastContact) - await prisma.agent.update({ - where:{ - id: agentId, - }, - data:{ - lastContact: lastContact, - } - }) - eventEmitter.emit('modification', { update: true }); + + await db + .update(drizzleDb.schemas.agent) + .set({ lastContact: lastContact }) + .where(eq(drizzleDb.schemas.agent.id, agentId)); + + eventEmitter.emit('modification', {update: true}); const response = { agent: { diff --git a/src/components/wrappers/dashboard/admin/columns-users.tsx b/src/components/wrappers/dashboard/admin/columns-users.tsx index a9e09e0b..2de6cb6a 100644 --- a/src/components/wrappers/dashboard/admin/columns-users.tsx +++ b/src/components/wrappers/dashboard/admin/columns-users.tsx @@ -1,26 +1,26 @@ -"use client"; - -import { ColumnDef } from "@tanstack/react-table"; -import { Badge } from "@/components/ui/badge"; -import { User } from "@prisma/client"; -import { updateUserAction } from "@/components/wrappers/dashboard/profile/UserForm/user-form.action"; -import { useMutation } from "@tanstack/react-query"; -import { toast } from "sonner"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; -import { Trash2 } from "lucide-react"; -import { deleteUserAction } from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/delete-account.action"; -import { ButtonWithLoading } from "@/components/wrappers/common/button/button-with-loading"; +"use client" +import {ColumnDef} from "@tanstack/react-table"; +import {Badge} from "@/components/ui/badge"; +import {updateUserAction} from "@/components/wrappers/dashboard/profile/UserForm/user-form.action"; +import {useMutation} from "@tanstack/react-query"; +import {toast} from "sonner"; +import {useRouter} from "next/navigation"; +import {useState} from "react"; +import {Trash2} from "lucide-react"; +import {deleteUserAction} from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/delete-account.action"; +import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading"; +import {User} from "@/db/schema/01_user"; +import {useSession} from "@/lib/auth/auth-client"; export const usersColumnsAdmin: ColumnDef[] = [ { accessorKey: "role", header: "Role", - cell: ({ row }) => { + cell: ({row}) => { const [role, setRole] = useState(row.getValue("role")); const updateMutation = useMutation({ - mutationFn: () => updateUserAction({ id: row.original.id, data: { role: role } }), + mutationFn: () => updateUserAction({id: row.original.id, data: {role: role}}), onSuccess: () => { toast.success(`User updated successfully.`); }, @@ -53,22 +53,19 @@ export const usersColumnsAdmin: ColumnDef[] = [ { accessorKey: "updatedAt", header: "Updated At", - cell: ({ row }) => { - return new Date(row.getValue("updatedAt")).toLocaleString("fr-FR"); - }, - }, - { - accessorKey: "authMethod", - header: "Method", - cell: ({ row }) => { - return {row.getValue("authMethod")}; + cell: ({row}) => { + return new Date(row.getValue("updatedAt")).toLocaleString("fr-FR", { + timeZone: "Europe/Paris", + }); }, }, { header: "Action", id: "actions", - cell: ({ row }) => { + cell: ({row}) => { const router = useRouter(); + const {data: session, isPending} = useSession(); + const mutation = useMutation({ mutationFn: () => deleteUserAction(row.original.id), onSuccess: async () => { @@ -77,17 +74,23 @@ export const usersColumnsAdmin: ColumnDef[] = [ }, }); + + return (
- } - onClick={async () => { - await mutation.mutateAsync(); - }} - size="icon" - /> + {!session || session?.user.email === row.original.email ? null : + } + onClick={async () => { + await mutation.mutateAsync(); + }} + size="icon" + /> + + } +
); }, diff --git a/src/components/wrappers/dashboard/projects/ProjectCard/ProjectCard.tsx b/src/components/wrappers/dashboard/projects/ProjectCard/ProjectCard.tsx index 6b11cbbe..2a38d221 100644 --- a/src/components/wrappers/dashboard/projects/ProjectCard/ProjectCard.tsx +++ b/src/components/wrappers/dashboard/projects/ProjectCard/ProjectCard.tsx @@ -1,8 +1,8 @@ "use client"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { ProjectWith } from "@/db/schema"; import Link from "next/link"; +import {ProjectWith} from "@/db/schema/05_project"; export type projectCardProps = { data: ProjectWith; @@ -13,7 +13,7 @@ export const ProjectCard = (props: projectCardProps) => { const { data: project, organizationSlug } = props; return ( - +
{project.name} diff --git a/src/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard.tsx b/src/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard.tsx index 6b33de6d..d6ead6e3 100644 --- a/src/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard.tsx +++ b/src/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard.tsx @@ -17,7 +17,7 @@ export const ProjectDatabaseCard = (props: projectDatabaseCardProps) => { const { organizationSlug, data: database, extendedProps: extendedProps } = props; return ( - + ); diff --git a/src/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.tsx b/src/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.tsx index ff4a28e3..8a5570c8 100644 --- a/src/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.tsx +++ b/src/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.tsx @@ -66,7 +66,7 @@ export const ProjectForm = (props: projectFormProps) => { if (project && project.data) { if (project.data.success) { project.data.actionSuccess && toast.success(project.data.actionSuccess.message); - router.push(`/dashboard/${props.organization.slug}/projects/${project.data.value!.id}`); + router.push(`/dashboard/projects/${project.data.value!.id}`); router.refresh(); } else { project.data.actionError && toast.error(project.data.actionError.message || "Unknown error occurred."); diff --git a/src/components/wrappers/dashboard/sideBar/app-sidebar.tsx b/src/components/wrappers/dashboard/sideBar/app-sidebar.tsx index 37a8a25d..938af7e8 100644 --- a/src/components/wrappers/dashboard/sideBar/app-sidebar.tsx +++ b/src/components/wrappers/dashboard/sideBar/app-sidebar.tsx @@ -2,20 +2,14 @@ import { Sidebar, SidebarContent, SidebarFooter, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, SidebarHeader, SidebarMenu as SM, SidebarMenuItem, } from "@/components/ui/sidebar"; -import {SidebarItem, SidebarMenu} from "@/components/wrappers/dashboard/sideBar/SideBarMenu/SideBarMenu"; import {OrganizationCombobox} from "@/components/wrappers/dashboard/organization/organization-combobox"; import {SideBarLogo} from "@/components/wrappers/dashboard/sideBar/SideBarLogo/SideBarLogo"; import {SideBarFooterCredit} from "@/components/wrappers/dashboard/sideBar/SideBarFooterCredit/SideBarFooterCredit"; import {LoggedInButton} from "@/components/wrappers/dashboard/loggedInButton/LoggedInButton"; -import {Layers, ChartArea, Settings, ShieldHalf} from "lucide-react"; -import {authClient} from "@/lib/auth/auth-client"; import {SidebarContentA} from "./sidebar-content"; import {getActiveMember, getOrganization} from "@/lib/auth/auth"; import {notFound} from "next/navigation"; @@ -31,7 +25,6 @@ export async function AppSidebar() { const organization = await getOrganization({organizationId: member.organizationId}); - //todo: à revoir console.log("organization", organization); diff --git a/src/components/wrappers/dashboard/sideBar/sidebar-content.tsx b/src/components/wrappers/dashboard/sideBar/sidebar-content.tsx index f9157d8b..1b40eb76 100644 --- a/src/components/wrappers/dashboard/sideBar/sidebar-content.tsx +++ b/src/components/wrappers/dashboard/sideBar/sidebar-content.tsx @@ -41,6 +41,8 @@ export const SidebarContentA = () => { }); } + + const adminItems: SidebarItem[] = [ { type: "list", @@ -62,13 +64,24 @@ export const SidebarContentA = () => { return ( activeOrganization && ( + <> + + Application + + + + + {(session && (session.user.role === "admin" || session.user.role === "superadmin")) && ( + + Administration + + + + + )} + + - - Application - - - - ) ); }; diff --git a/src/db/schema/06_database.ts b/src/db/schema/06_database.ts index 80a80a51..bda7eb99 100644 --- a/src/db/schema/06_database.ts +++ b/src/db/schema/06_database.ts @@ -11,7 +11,7 @@ export const database = pgTable("databases", { agentDatabaseId: uuid("agent_database_id").notNull().defaultRandom(), name: text("name").notNull(), dbms: dbmsEnum("dbms").notNull(), - description: text("description").notNull(), + description: text("description"), backupPolicy: text("backup_policy"), isWaitingForBackup: boolean("is_waiting_for_backup").default(false).notNull(), backupToRestore: text("backup_to_restore"), @@ -23,8 +23,7 @@ export const database = pgTable("databases", { lastContact: timestamp("last_contact"), projectId: uuid("project_id") - .references(() => project.id) - .notNull(), + .references(() => project.id), }); export const backup = pgTable( diff --git a/src/db/schema/07_agent.ts b/src/db/schema/07_agent.ts index c29c2cd6..1ef8f279 100644 --- a/src/db/schema/07_agent.ts +++ b/src/db/schema/07_agent.ts @@ -1,6 +1,8 @@ import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; import { createSelectSchema } from "drizzle-zod"; import { z } from "zod"; +import {database} from "@/db/schema/06_database"; +import {relations} from "drizzle-orm"; export const agent = pgTable("agents", { id: uuid("id").primaryKey().defaultRandom(), @@ -14,3 +16,8 @@ export const agent = pgTable("agents", { export const agentSchema = createSelectSchema(agent); export type Agent = z.infer; + + +export const agentRelations = relations(agent, ({ many }) => ({ + databases: many(database), +})); \ No newline at end of file diff --git a/src/lib/auth/auth.ts b/src/lib/auth/auth.ts index 506c3400..9a46086c 100644 --- a/src/lib/auth/auth.ts +++ b/src/lib/auth/auth.ts @@ -97,7 +97,7 @@ export const auth = betterAuth({ await db.insert(drizzleDb.schemas.member).values({ userId: user.id, organizationId: defaultOrg.id, - role: "orgOwner", + role: "owner", }); } else { console.warn("Default organization not found. Cannot assign member.");