Working on the organization system.

This commit is contained in:
charlesgauthereau
2025-07-16 12:36:11 +02:00
parent 405de7b323
commit 385777535f
61 changed files with 514 additions and 366 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
import {PageParams} from "@/types/next"; import {PageParams} from "@/types/next";
import {RegisterForm} from "@/components/wrappers/auth/Register/register-form/RegisterForm"; import {RegisterForm} from "@/components/wrappers/auth/register/register-form/register-form";
export default async function RoutePage(props: PageParams<{}>) { export default async function RoutePage(props: PageParams<{}>) {
return ( return (
@@ -0,0 +1,41 @@
import {PageParams} from "@/types/next";
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
import {notFound} from "next/navigation";
import {RestoreForm} from "@/components/wrappers/dashboard/database/RestoreForm";
import {currentUser} from "@/lib/auth/current-user";
import {db} from "@/db";
import {eq} from "drizzle-orm";
import * as drizzleDb from "@/db";
export default async function RoutePage(
props: PageParams<{
databaseId: string;
}>
) {
const {databaseId} = await props.params;
const user = await currentUser();
if (!user) notFound();
const [dbToRestore] = await db.select().from(drizzleDb.schemas.database).where(eq(drizzleDb.schemas.database.id, databaseId));
if (!dbToRestore) {
notFound();
}
const dbsOfSameType = await db.select().from(drizzleDb.schemas.database).where(eq(drizzleDb.schemas.database.dbms!, dbToRestore.dbms!));
const successfulBackups = await db.select().from(drizzleDb.schemas.backup).where(eq(drizzleDb.schemas.backup.status, "success"));
return (
<Page>
<PageHeader>
<PageTitle>Restore {dbToRestore.name}</PageTitle>
</PageHeader>
<PageContent>
<RestoreForm databaseToRestore={dbToRestore} databases={dbsOfSameType} backups={successfulBackups}/>
</PageContent>
</Page>
);
}
@@ -4,14 +4,15 @@ import { notFound } from "next/navigation";
import { DatabaseForm } from "@/components/wrappers/dashboard/database/DatabaseForm/DatabaseForm"; import { DatabaseForm } from "@/components/wrappers/dashboard/database/DatabaseForm/DatabaseForm";
import { db } from "@/db"; import { db } from "@/db";
import { database } from "@/db/schema"; import * as drizzleDb from "@/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
export default async function RoutePage(props: PageParams<{ databaseId: string }>) { export default async function RoutePage(props: PageParams<{ databaseId: string }>) {
const { databaseId } = await props.params; const { databaseId } = await props.params;
const dbItem = await db.query.database.findFirst({ const dbItem = await db.query.database.findFirst({
where: eq(database.id, databaseId), where: eq(drizzleDb.schemas.database.id, databaseId),
}); });
if (!dbItem) { if (!dbItem) {
@@ -9,13 +9,13 @@ import { CronButton } from "@/components/wrappers/dashboard/database/CronButton/
import { db } from "@/db"; import { db } from "@/db";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import { backup as drizzleBackup, database as drizzleDatabase, restoration as drizzleRestoration } from "@/db/schema"; import * as drizzleDb from "@/db";
export default async function RoutePage(props: PageParams<{ databaseId: string }>) { export default async function RoutePage(props: PageParams<{ databaseId: string }>) {
const { databaseId } = await props.params; const { databaseId } = await props.params;
const dbItem = await db.query.database.findFirst({ const dbItem = await db.query.database.findFirst({
where: eq(drizzleDatabase.id, databaseId), where: eq(drizzleDb.schemas.database.id, databaseId),
}); });
if (!dbItem) { if (!dbItem) {
@@ -23,7 +23,7 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
} }
const backups = await db.query.backup.findMany({ const backups = await db.query.backup.findMany({
where: eq(drizzleBackup.databaseId, dbItem.id), where: eq(drizzleDb.schemas.backup.databaseId, dbItem.id),
with: { with: {
restorations: true, restorations: true,
}, },
@@ -31,7 +31,7 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
}); });
const restorations = await db.query.restoration.findMany({ const restorations = await db.query.restoration.findMany({
where: eq(drizzleRestoration.databaseId, dbItem.id), where: eq(drizzleDb.schemas.restoration.databaseId, dbItem.id),
orderBy: (r, { desc }) => [desc(r.createdAt)], orderBy: (r, { desc }) => [desc(r.createdAt)],
}); });
@@ -40,14 +40,14 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
const [totalBackups, successfulBackups] = await Promise.all([ const [totalBackups, successfulBackups] = await Promise.all([
db db
.select({ count: drizzleBackup.id }) .select({ count: drizzleDb.schemas.backup.id })
.from(drizzleBackup) .from(drizzleDb.schemas.backup)
.where(eq(drizzleBackup.databaseId, dbItem.id)) .where(eq(drizzleDb.schemas.backup.databaseId, dbItem.id))
.then((rows) => rows.length), .then((rows) => rows.length),
db db
.select({ count: drizzleBackup.id }) .select({ count: drizzleDb.schemas.backup.id })
.from(drizzleBackup) .from(drizzleDb.schemas.backup)
.where(and(eq(drizzleBackup.databaseId, dbItem.id), eq(drizzleBackup.status, "success"))) .where(and(eq(drizzleDb.schemas.backup.databaseId, dbItem.id), eq(drizzleDb.schemas.backup.status, "success")))
.then((rows) => rows.length), .then((rows) => rows.length),
]); ]);
@@ -1,17 +1,18 @@
import { notFound } from "next/navigation"; import {notFound} from "next/navigation";
import { PageParams } from "@/types/next"; import {PageParams} from "@/types/next";
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page"; import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
import { ProjectForm } from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm"; import {ProjectForm} from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm";
import * as drizzleDb from "@/db";
import { db } from "@/db"; import {db} from "@/db";
import { eq } from "drizzle-orm"; import {eq} from "drizzle-orm";
import { project as drizzleProject, organization as drizzleOrganization, DatabaseWith } from "@/db/schema"; import {DatabaseWith} from "@/db/schema/06_database";
export default async function RoutePage(props: PageParams<{ projectId: string }>) { export default async function RoutePage(props: PageParams<{ projectId: string }>) {
const { projectId } = await props.params; const {projectId} = await props.params;
const proj = await db.query.project.findFirst({ const proj = await db.query.project.findFirst({
where: eq(drizzleProject.id, projectId), where: eq(drizzleDb.schemas.project.id, projectId),
with: { with: {
databases: true, databases: true,
}, },
@@ -23,7 +24,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
// //
const org = await db.query.organization.findFirst({ const org = await db.query.organization.findFirst({
where: eq(drizzleOrganization.slug, "default"), where: eq(drizzleDb.schemas.organization.slug, "default"),
}); });
if (!org) { if (!org) {
@@ -32,14 +33,14 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
const availableDatabases = ( const availableDatabases = (
await db.query.database.findMany({ await db.query.database.findMany({
where: (db, { or, eq, isNull }) => or(isNull(db.projectId), eq(db.projectId, proj.id)), where: (db, {or, eq, isNull}) => or(isNull(db.projectId), eq(db.projectId, proj.id)),
with: { with: {
agent: true, agent: true,
project: true, project: true,
backups: true, backups: true,
restorations: true, restorations: true,
}, },
orderBy: (db, { desc }) => [desc(db.createdAt)], orderBy: (db, {desc}) => [desc(db.createdAt)],
}) })
).filter((db): db is DatabaseWith => db.project !== null); ).filter((db): db is DatabaseWith => db.project !== null);
@@ -52,7 +53,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
<ProjectForm <ProjectForm
organization={org} organization={org}
databases={availableDatabases} databases={availableDatabases}
defaultValues={{ name: proj.name, slug: proj.slug, databases: proj.databases.map((db) => db.id) }} defaultValues={{name: proj.name, slug: proj.slug, databases: proj.databases.map((db) => db.id)}}
projectId={proj.id} projectId={proj.id}
/> />
</PageContent> </PageContent>
@@ -10,19 +10,24 @@ import { notFound } from "next/navigation";
import { db } from "@/db"; import { db } from "@/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { organization as drizzleOrganization } from "@/db/schema";
import {getOrganization} from "@/lib/auth/auth"; import {getOrganization} from "@/lib/auth/auth";
import * as drizzleDb from "@/db";
export default async function RoutePage(props: PageParams<{ slug: string; projectId: string }>) { export default async function RoutePage(props: PageParams<{
const { slug: organizationSlug, projectId } = await props.params; // slug: string;
projectId: string
}>) {
const {
// slug: organizationSlug,
projectId } = await props.params;
const organization = await getOrganization({organizationSlug}); const organization = await getOrganization({});
if (!organization || organization?.slug !== organizationSlug) { if (!organization) {
notFound(); notFound();
} }
const org = await db.query.organization.findFirst({ const org = await db.query.organization.findFirst({
where: eq(drizzleOrganization.slug, organization.slug), where: eq(drizzleDb.schemas.organization.slug, organization.slug),
}); });
if (!org) notFound(); if (!org) notFound();
@@ -56,7 +61,7 @@ export default async function RoutePage(props: PageParams<{ slug: string; projec
{proj.databases.length > 0 ? ( {proj.databases.length > 0 ? (
<CardsWithPagination <CardsWithPagination
data={proj.databases} data={proj.databases}
organizationSlug={organizationSlug} organizationSlug={organization.slug}
cardItem={ProjectDatabaseCard} cardItem={ProjectDatabaseCard}
cardsPerPage={4} cardsPerPage={4}
numberOfColumns={1} numberOfColumns={1}
@@ -3,16 +3,16 @@ import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
import {ProjectForm} from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm"; import {ProjectForm} from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm";
import {notFound} from "next/navigation"; import {notFound} from "next/navigation";
import {db} from "@/db"; import {db} from "@/db";
import {DatabaseWith, organization as drizzleOrganization} from "@/db/schema";
import {eq} from "drizzle-orm"; import {eq} from "drizzle-orm";
import {getOrganization} from "@/lib/auth/auth"; import {getOrganization} from "@/lib/auth/auth";
import * as drizzleDb from "@/db";
import {DatabaseWith} from "@/db/schema/06_database";
export default async function RoutePage(props: PageParams<{ slug: string }>) { export default async function RoutePage(props: PageParams<{ }>) {
const {slug: organizationSlug} = await props.params;
const organization = await getOrganization({organizationSlug}); const organization = await getOrganization({});
if (!organization || organization?.slug !== organizationSlug) { if (!organization ) {
notFound(); notFound();
} }
@@ -30,7 +30,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
).filter((db) => db.project !== null) as DatabaseWith[]; ).filter((db) => db.project !== null) as DatabaseWith[];
const org = await db.query.organization.findFirst({ const org = await db.query.organization.findFirst({
where: eq(drizzleOrganization.slug, organization.slug), where: eq(drizzleDb.schemas.organization.slug, organization.slug),
}); });
if (!org) notFound(); if (!org) notFound();
@@ -9,12 +9,11 @@ import {db} from "@/db";
import {notFound} from "next/navigation"; import {notFound} from "next/navigation";
import {getOrganization} from "@/lib/auth/auth"; import {getOrganization} from "@/lib/auth/auth";
export default async function RoutePage(props: PageParams<{ slug: string }>) { export default async function RoutePage(props: PageParams<{ }>) {
const {slug: organizationSlug} = await props.params;
const organization = await getOrganization({organizationSlug}); const organization = await getOrganization({});
if (!organization || organization?.slug !== organizationSlug) { if (!organization) {
notFound(); notFound();
} }
@@ -35,7 +34,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
<PageTitle>Projects</PageTitle> <PageTitle>Projects</PageTitle>
{projects.length > 0 && ( {projects.length > 0 && (
<PageActions> <PageActions>
<Link href={`/dashboard/${organizationSlug}/projects/new`}> <Link href={`/dashboard/projects/new`}>
<Button>+ Create Project</Button> <Button>+ Create Project</Button>
</Link> </Link>
</PageActions> </PageActions>
@@ -44,11 +43,11 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
<PageContent className="mt-10"> <PageContent className="mt-10">
{projects.length > 0 ? ( {projects.length > 0 ? (
<CardsWithPagination organizationSlug={organizationSlug} data={projects} cardItem={ProjectCard} <CardsWithPagination organizationSlug={organization.slug} data={projects} cardItem={ProjectCard}
cardsPerPage={4} numberOfColumns={1}/> cardsPerPage={4} numberOfColumns={1}/>
) : ( ) : (
<Link <Link
href={`/dashboard/${organizationSlug}/projects/new`} href={`/dashboard/projects/new`}
className=" flex item-center justify-center border-2 border-dashed transition-colors border-primary p-8 lg:p-12 w-full rounded-md" className=" flex item-center justify-center border-2 border-dashed transition-colors border-primary p-8 lg:p-12 w-full rounded-md"
> >
Create new Project Create new Project
@@ -7,7 +7,7 @@ import { getCurrentOrganizationSlug } from "@/features/dashboard/organization-co
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { db } from "@/db"; import { db } from "@/db";
import { asc, count, eq, inArray } from "drizzle-orm"; import { asc, count, eq, inArray } from "drizzle-orm";
import { organization as drizzleOrganization, project as drizzleProject, backup as drizzleBackup } from "@/db/schema"; import * as drizzleDb from "@/db";
export default async function RoutePage(props: PageParams<{ slug: string }>) { export default async function RoutePage(props: PageParams<{ slug: string }>) {
const { slug: organizationSlug } = await props.params; const { slug: organizationSlug } = await props.params;
@@ -18,13 +18,13 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
} }
const org = await db.query.organization.findFirst({ const org = await db.query.organization.findFirst({
where: eq(drizzleOrganization.slug, currentOrganizationSlug), where: eq(drizzleDb.schemas.organization.slug, currentOrganizationSlug),
}); });
if (!org) notFound(); if (!org) notFound();
const projects = await db.query.project.findMany({ const projects = await db.query.project.findMany({
where: eq(drizzleProject.organizationId, org.id), where: eq(drizzleDb.schemas.project.organizationId, org.id),
}); });
const projectsCount = projects.length; const projectsCount = projects.length;
@@ -34,19 +34,19 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
id: true, id: true,
createdAt: true, createdAt: true,
}, },
orderBy: [asc(drizzleBackup.id)], orderBy: [asc(drizzleDb.schemas.backup.id)],
}); });
const backupsRate = await db const backupsRate = await db
.select({ .select({
createdAt: drizzleBackup.createdAt, createdAt: drizzleDb.schemas.backup.createdAt,
status: drizzleBackup.status, status: drizzleDb.schemas.backup.status,
_count: count(), _count: count(),
}) })
.from(drizzleBackup) .from(drizzleDb.schemas.backup)
.where(inArray(drizzleBackup.status, ["success", "failed"])) .where(inArray(drizzleDb.schemas.backup.status, ["success", "failed"]))
.groupBy(drizzleBackup.createdAt, drizzleBackup.status) .groupBy(drizzleDb.schemas.backup.createdAt, drizzleDb.schemas.backup.status)
.orderBy(drizzleBackup.createdAt); .orderBy(drizzleDb.schemas.backup.createdAt);
return ( return (
<Page> <Page>
@@ -1,41 +0,0 @@
import { PageParams } from "@/types/next";
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
import { notFound } from "next/navigation";
import { RestoreForm } from "@/components/wrappers/dashboard/database/RestoreForm";
import { currentUser } from "@/lib/auth/current-user";
import { db } from "@/db";
import { eq } from "drizzle-orm";
import { database, backup } from "@/db/schema";
export default async function RoutePage(
props: PageParams<{
databaseId: string;
}>
) {
const { databaseId } = await props.params;
const user = await currentUser();
if (!user) notFound();
const [dbToRestore] = await db.select().from(database).where(eq(database.id, databaseId));
if (!dbToRestore) {
notFound();
}
const dbsOfSameType = await db.select().from(database).where(eq(database.dbms!, dbToRestore.dbms!));
const successfulBackups = await db.select().from(backup).where(eq(backup.status, "success"));
return (
<Page>
<PageHeader>
<PageTitle>Restore {dbToRestore.name}</PageTitle>
</PageHeader>
<PageContent>
<RestoreForm databaseToRestore={dbToRestore} databases={dbsOfSameType} backups={successfulBackups} />
</PageContent>
</Page>
);
}
+8 -9
View File
@@ -1,23 +1,22 @@
import React from "react"; import React from "react";
import { redirect } from "next/navigation"; import {redirect} from "next/navigation";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; import {SidebarInset, SidebarProvider} from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/wrappers/dashboard/sideBar/app-sidebar"; import {AppSidebar} from "@/components/wrappers/dashboard/sideBar/app-sidebar";
import { Header } from "@/features/layout/Header"; import {Header} from "@/features/layout/Header";
import { currentUser } from "@/lib/auth/current-user"; import {currentUser} from "@/lib/auth/current-user";
export default async function Layout({ children }: { children: React.ReactNode }) { export default async function Layout({children}: { children: React.ReactNode }) {
const user = await currentUser(); const user = await currentUser();
if (!user) redirect("/login"); if (!user) redirect("/login");
return ( return (
<> <>
<SidebarProvider> <SidebarProvider>
<div className="flex flex-col lg:flex-row w-full"> <div className="flex flex-col lg:flex-row w-full">
<AppSidebar /> <AppSidebar/>
<SidebarInset> <SidebarInset>
<Header /> <Header/>
<main className="h-full">{children}</main> <main className="h-full">{children}</main>
</SidebarInset> </SidebarInset>
</div> </div>
+15 -13
View File
@@ -1,26 +1,28 @@
import { PageParams } from "@/types/next"; import {PageParams} from "@/types/next";
import { Page, PageActions, PageContent, PageHeader, PageTitle } from "@/features/layout/page"; import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
import { notFound } from "next/navigation"; import {notFound} from "next/navigation";
import { UserForm } from "@/components/wrappers/dashboard/profile/UserForm/UserForm"; import {UserForm} from "@/components/wrappers/dashboard/profile/UserForm/UserForm";
import { Badge } from "@/components/ui/badge"; import {Badge} from "@/components/ui/badge";
import { ButtonDeleteAccount } from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/ButtonDeleteAccount"; import {ButtonDeleteAccount} from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/ButtonDeleteAccount";
import { AvatarWithUpload } from "@/components/wrappers/dashboard/profile/Avatar/AvatarWithUpload"; import {AvatarWithUpload} from "@/components/wrappers/dashboard/profile/Avatar/AvatarWithUpload";
import { currentUser } from "@/lib/auth/current-user"; import {currentUser} from "@/lib/auth/current-user";
import {getAccounts, getSessions} from "@/lib/auth/auth";
//import { getAccounts, getSessions } from "@/lib/auth/auth"; //import { getAccounts, getSessions } from "@/lib/auth/auth";
export default async function RoutePage(props: PageParams<{}>) { export default async function RoutePage(props: PageParams<{}>) {
const user = await currentUser(); const user = await currentUser();
console.log("my user",user);
if (!user) { if (!user) {
return notFound(); return notFound();
} }
if (user.role !== "user" && user.role !== "admin" && user.role !== "superadmin") { if (user.role !== "user" && user.role !== "admin" && user.role !== "superadmin") {
return notFound(); return notFound();
} }
// const sessions = await getSessions(); // const sessions = await getSessions();
// const accounts = await getAccounts(); // const accounts = await getAccounts();
return ( return (
<Page> <Page>
@@ -41,7 +43,7 @@ export default async function RoutePage(props: PageParams<{}>) {
<Badge className="ml-3 hidden lg:block">{user.role}</Badge> <Badge className="ml-3 hidden lg:block">{user.role}</Badge>
</PageTitle> </PageTitle>
<PageActions className="mt-2 hidden sm:block"> <PageActions className="mt-2 hidden sm:block">
<ButtonDeleteAccount text="Delete my account" /> <ButtonDeleteAccount text="Delete my account"/>
</PageActions> </PageActions>
</div> </div>
<PageContent> <PageContent>
@@ -54,7 +56,7 @@ export default async function RoutePage(props: PageParams<{}>) {
}} }}
/> />
<div className="mt-4 sm:hidden"> <div className="mt-4 sm:hidden">
<ButtonDeleteAccount text="Delete my account" /> <ButtonDeleteAccount text="Delete my account"/>
</div> </div>
</PageContent> </PageContent>
</Page> </Page>
+6 -1
View File
@@ -1,5 +1,10 @@
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
export default async function NotFound() { export default async function NotFound() {
redirect("/dashboard/profile"); // redirect("/dashboard/profile");
return(
<>
Error
</>
)
} }
@@ -1,28 +0,0 @@
"use server";
import { RegisterSchema } from "@/components/wrappers/auth/Register/register-form/register-form.schema";
import { action } from "@/safe-actions";
import { signUp } from "@/lib/auth/auth-client";
import { db } from "@/db";
import { user as drizzleUser } from "@/db/schema/01_user";
import { eq } from "drizzle-orm";
export const registerUserAction = action.schema(RegisterSchema).action(async ({ parsedInput }: { parsedInput: typeof RegisterSchema._type }) => {
const [user] = await db.select().from(drizzleUser).where(eq(drizzleUser.email, parsedInput.email)).limit(1);
if (!user && parsedInput.password === parsedInput.confirmPassword) {
const { data, error } = await signUp.email({
email: parsedInput.email,
password: parsedInput.password,
name: parsedInput.name,
});
if (error) {
throw new Error(error.message);
}
return {
data: data?.user,
};
}
throw new Error("An error occured while creating user");
});
@@ -26,6 +26,7 @@ export const LoginForm = (props: loginFormProps) => {
const form = useZodForm({ const form = useZodForm({
schema: LoginSchema, schema: LoginSchema,
}); });
const mutation = useMutation({ const mutation = useMutation({
mutationFn: async (values: LoginType) => { mutationFn: async (values: LoginType) => {
const { error } = await signIn.email(values, { const { error } = await signIn.email(values, {
@@ -11,36 +11,37 @@ import { Input } from "@/components/ui/input";
import { Form } from "@/components/ui/form"; import { Form } from "@/components/ui/form";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { TooltipProvider, TooltipTrigger, Tooltip, TooltipContent } from "@/components/ui/tooltip"; import { TooltipProvider, TooltipTrigger, Tooltip, TooltipContent } from "@/components/ui/tooltip";
import { RegisterSchema, RegisterType } from "@/components/wrappers/auth/Register/register-form/register-form.schema"; import { RegisterSchema, RegisterType } from "@/components/wrappers/auth/register/register-form/register-form.schema";
import { registerUserAction } from "@/components/wrappers/auth/Register/register-form/register-form.action";
import { PasswordInput } from "@/components/wrappers/auth/PaswordInput/password-input"; import { PasswordInput } from "@/components/wrappers/auth/PaswordInput/password-input";
import {signUp} from "@/lib/auth/auth-client";
export type registerFormProps = { export type registerFormProps = {
defaultValues?: RegisterType; defaultValues?: RegisterType;
}; };
export const RegisterForm = (props: registerFormProps) => { export const RegisterForm = (props: registerFormProps) => {
const form = useZodForm({ const form = useZodForm({
schema: RegisterSchema, schema: RegisterSchema,
}); });
const router = useRouter(); const router = useRouter();
const mutation = useMutation({ const mutation = useMutation({
mutationFn: async (values: RegisterType) => { mutationFn: async (values: RegisterType) => {
console.log(values); await signUp.email(values, {
const createUser = await registerUserAction(values); onSuccess: () => {
console.log(createUser); toast.success(`Success`);
const data = createUser?.data?.data; router.push(`/login`);
if (createUser?.serverError || !data) { router.refresh();
console.log(createUser?.serverError); },
toast.error(createUser?.serverError); onError: (error) => {
return; console.log(error);
} toast.error(error.error.message);
toast.success(`Success`); },
router.push(`/login`); });
router.refresh();
}, },
}); });
return ( return (
<TooltipProvider> <TooltipProvider>
<Card> <Card>
@@ -2,9 +2,9 @@
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { EmailFormSchema } from "@/components/wrappers/dashboard/admin/AdminEmailTab/EmailForm/email-form.schema"; import { EmailFormSchema } from "@/components/wrappers/dashboard/admin/AdminEmailTab/EmailForm/email-form.schema";
import { setting as drizzleSetting } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "@/db"; import { db } from "@/db";
import * as drizzleDb from "@/db";
export const updateEmailSettingsAction = userAction export const updateEmailSettingsAction = userAction
.schema( .schema(
@@ -17,11 +17,11 @@ export const updateEmailSettingsAction = userAction
const { name, data } = parsedInput; const { name, data } = parsedInput;
const [updatedSettings] = await db const [updatedSettings] = await db
.update(drizzleSetting) .update(drizzleDb.schemas.setting)
.set({ .set({
...data, ...data,
}) })
.where(eq(drizzleSetting.name, name)) .where(eq(drizzleDb.schemas.setting.name, name))
.returning(); .returning();
return { return {
@@ -6,7 +6,7 @@ import { sendEmail } from "@/utils/email-helper";
import TestEmailSettings from "../../../../../../emails/TestEmailSettings"; import TestEmailSettings from "../../../../../../emails/TestEmailSettings";
import { render } from "@react-email/render"; import { render } from "@react-email/render";
import { toast } from "sonner"; import { toast } from "sonner";
import { Setting } from "@/db/schema"; import {Setting} from "@/db/schema/00_setting";
export type SettingsEmailTabProps = { export type SettingsEmailTabProps = {
settings: Setting; settings: Setting;
@@ -10,7 +10,7 @@ import { checkConnexionToS3 } from "@/features/upload/public/upload.action";
import { toast } from "sonner"; import { toast } from "sonner";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { updateStorageSettingsAction } from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action"; import { updateStorageSettingsAction } from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.action";
import { Setting } from "@/db/schema"; import {Setting} from "@/db/schema/00_setting";
export type SettingsStorageTabProps = { export type SettingsStorageTabProps = {
settings: Setting; settings: Setting;
@@ -3,9 +3,9 @@
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { db } from "@/db"; import { db } from "@/db";
import { setting as drizzleSetting } from "@/db/schema";
import { S3FormSchema, StorageSwitchSchema } from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema"; import { S3FormSchema, StorageSwitchSchema } from "@/components/wrappers/dashboard/admin/AdminStorageTab/StorageS3Form/s3-form.schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import * as drizzleDb from "@/db";
export const updateS3SettingsAction = userAction export const updateS3SettingsAction = userAction
.schema( .schema(
@@ -18,9 +18,9 @@ export const updateS3SettingsAction = userAction
const { name, data } = parsedInput; const { name, data } = parsedInput;
const [updatedSettings] = await db const [updatedSettings] = await db
.update(drizzleSetting) .update(drizzleDb.schemas.setting)
.set({ ...data }) .set({ ...data })
.where(eq(drizzleSetting.name, name)) .where(eq(drizzleDb.schemas.setting.name, name))
.returning(); .returning();
return { return {
@@ -39,9 +39,9 @@ export const updateStorageSettingsAction = userAction
const { name, data } = parsedInput; const { name, data } = parsedInput;
const [updatedSettings] = await db const [updatedSettings] = await db
.update(drizzleSetting) .update(drizzleDb.schemas.setting)
.set({ ...data }) .set({ ...data })
.where(eq(drizzleSetting.name, name)) .where(eq(drizzleDb.schemas.setting.name, name))
.returning(); .returning();
return { return {
@@ -4,8 +4,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { SettingsEmailTab } from "@/components/wrappers/dashboard/admin/AdminEmailTab/SettingsEmailTab"; import { SettingsEmailTab } from "@/components/wrappers/dashboard/admin/AdminEmailTab/SettingsEmailTab";
import { SettingsStorageTab } from "@/components/wrappers/dashboard/admin/AdminStorageTab/SettingsStorageTab"; import { SettingsStorageTab } from "@/components/wrappers/dashboard/admin/AdminStorageTab/SettingsStorageTab";
import { AdminUsersTable } from "@/components/wrappers/dashboard/admin/admin-user-table"; import { AdminUsersTable } from "@/components/wrappers/dashboard/admin/admin-user-table";
import { Setting } from "@/db/schema";
import { User } from "@/db/schema/01_user"; import { User } from "@/db/schema/01_user";
import {Setting} from "@/db/schema/00_setting";
export type AdminTabsProps = { export type AdminTabsProps = {
users: User[]; users: User[];
@@ -4,7 +4,7 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card";
import Link from "next/link"; import Link from "next/link";
import { formatDateLastContact } from "@/utils/date-formatting"; import { formatDateLastContact } from "@/utils/date-formatting";
import { ConnectionCircle } from "@/components/wrappers/common/connection-circle"; import { ConnectionCircle } from "@/components/wrappers/common/connection-circle";
import { Agent } from "@/db/schema"; import {Agent} from "@/db/schema/07_agent";
export type agentCardProps = { export type agentCardProps = {
data: Agent; data: Agent;
@@ -1,10 +1,10 @@
"use client"; "use client";
import { generateEdgeKey } from "@/utils/edge_key"; import {generateEdgeKey} from "@/utils/edge_key";
import { getServerUrl } from "@/utils/get-server-url"; import {getServerUrl} from "@/utils/get-server-url";
import { PasswordInput } from "@/components/wrappers/auth/PaswordInput/password-input"; import {PasswordInput} from "@/components/wrappers/auth/PaswordInput/password-input";
import { useState } from "react"; import {useState} from "react";
import { CopyButton } from "@/components/wrappers/common/button/copy-button"; import {CopyButton} from "@/components/wrappers/common/button/copy-button";
import { Agent } from "@/db/schema"; import {Agent} from "@/db/schema/07_agent";
export type AgentCardKeyProps = { export type AgentCardKeyProps = {
agent: Agent; agent: Agent;
@@ -22,7 +22,7 @@ export const AgentCardKey = (props: AgentCardKeyProps) => {
setCode(edge_key); setCode(edge_key);
}} }}
/> />
<CopyButton className="mt-5" value={code} /> <CopyButton className="mt-5" value={code}/>
</> </>
); );
}; };
@@ -4,12 +4,12 @@ import { AgentSchema } from "@/components/wrappers/dashboard/agent/AgentForm/age
import { z } from "zod"; import { z } from "zod";
import { eq, and, ne, count } from "drizzle-orm"; import { eq, and, ne, count } from "drizzle-orm";
import { db } from "@/db"; import { db } from "@/db";
import { agent } from "@/db/schema"; import * as drizzleDb from "@/db";
const verifySlugUniqueness = async (slug: string, agentId?: string) => { const verifySlugUniqueness = async (slug: string, agentId?: string) => {
const conditions = agentId ? and(eq(agent.slug, slug), ne(agent.id, agentId)) : eq(agent.slug, slug); const conditions = agentId ? and(eq(drizzleDb.schemas.agent.slug, slug), ne(drizzleDb.schemas.agent.id, agentId)) : eq(drizzleDb.schemas.agent.slug, slug);
const [countResult] = await db.select({ count: count() }).from(agent).where(conditions); const [countResult] = await db.select({ count: count() }).from(drizzleDb.schemas.agent).where(conditions);
if (countResult.count > 0) { if (countResult.count > 0) {
throw new ActionError("Slug already exists"); throw new ActionError("Slug already exists");
@@ -19,7 +19,7 @@ const verifySlugUniqueness = async (slug: string, agentId?: string) => {
export const createAgentAction = userAction.schema(AgentSchema).action(async ({ parsedInput }) => { export const createAgentAction = userAction.schema(AgentSchema).action(async ({ parsedInput }) => {
await verifySlugUniqueness(parsedInput.slug); await verifySlugUniqueness(parsedInput.slug);
const [createdAgent] = await db.insert(agent).values(parsedInput).returning(); const [createdAgent] = await db.insert(drizzleDb.schemas.agent).values(parsedInput).returning();
return { return {
data: createdAgent, data: createdAgent,
@@ -36,7 +36,7 @@ export const updateAgentAction = userAction
.action(async ({ parsedInput }) => { .action(async ({ parsedInput }) => {
await verifySlugUniqueness(parsedInput.data.slug, parsedInput.id); await verifySlugUniqueness(parsedInput.data.slug, parsedInput.id);
const [updatedAgent] = await db.update(agent).set(parsedInput.data).where(eq(agent.id, parsedInput.id)).returning(); const [updatedAgent] = await db.update(drizzleDb.schemas.agent).set(parsedInput.data).where(eq(drizzleDb.schemas.agent.id, parsedInput.id)).returning();
return { return {
data: updatedAgent, data: updatedAgent,
@@ -8,7 +8,7 @@ import { PropsWithChildren } from "react";
import { CopyButton } from "@/components/wrappers/common/button/copy-button"; import { CopyButton } from "@/components/wrappers/common/button/copy-button";
import { getServerUrl } from "@/utils/get-server-url"; import { getServerUrl } from "@/utils/get-server-url";
import { CodeSnippet } from "@/components/wrappers/code-snippet/CodeSnippet"; import { CodeSnippet } from "@/components/wrappers/code-snippet/CodeSnippet";
import { Agent } from "@/db/schema"; import {Agent} from "@/db/schema/07_agent";
export type agentRegistrationDialogProps = PropsWithChildren<{ export type agentRegistrationDialogProps = PropsWithChildren<{
agent: Agent; agent: Agent;
@@ -3,14 +3,14 @@
import { z } from "zod"; import { z } from "zod";
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { db } from "@/db"; import { db } from "@/db";
import { backup } from "@/db/schema";
import { ServerActionResult } from "@/types/action-type"; import { ServerActionResult } from "@/types/action-type";
import { Backup } from "@/db/schema"; import * as drizzleDb from "@/db";
import {Backup} from "@/db/schema/06_database";
export const backupButtonAction = userAction.schema(z.string()).action(async ({ parsedInput }): Promise<ServerActionResult<Backup>> => { export const backupButtonAction = userAction.schema(z.string()).action(async ({ parsedInput }): Promise<ServerActionResult<Backup>> => {
try { try {
const [createdBackup] = await db const [createdBackup] = await db
.insert(backup) .insert(drizzleDb.schemas.backup)
.values({ .values({
databaseId: parsedInput, databaseId: parsedInput,
status: "waiting", status: "waiting",
@@ -11,7 +11,7 @@ import { useMutation } from "@tanstack/react-query";
import { toast } from "sonner"; import { toast } from "sonner";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { updateDatabaseBackupPolicyAction } from "@/components/wrappers/dashboard/database/CronButton/cron.action"; import { updateDatabaseBackupPolicyAction } from "@/components/wrappers/dashboard/database/CronButton/cron.action";
import { Database } from "@/db/schema"; import {Database} from "@/db/schema/06_database";
export type CronButtonProps = { export type CronButtonProps = {
database: Database; database: Database;
@@ -6,7 +6,7 @@ import { useRouter } from "next/navigation";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { Database } from "@/db/schema"; import {Database} from "@/db/schema/06_database";
export type CronInputProps = { export type CronInputProps = {
database: Database; database: Database;
@@ -3,8 +3,8 @@
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { db } from "@/db"; import { db } from "@/db";
import { database } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import * as drizzleDb from "@/db";
export const updateDatabaseBackupPolicyAction = userAction export const updateDatabaseBackupPolicyAction = userAction
.schema( .schema(
@@ -17,11 +17,11 @@ export const updateDatabaseBackupPolicyAction = userAction
const cronPolicy = parsedInput.backupPolicy === "" ? null : parsedInput.backupPolicy; const cronPolicy = parsedInput.backupPolicy === "" ? null : parsedInput.backupPolicy;
const [updated] = await db const [updated] = await db
.update(database) .update(drizzleDb.schemas.database)
.set({ .set({
backupPolicy: cronPolicy, backupPolicy: cronPolicy,
}) })
.where(eq(database.id, parsedInput.databaseId)) .where(eq(drizzleDb.schemas.database.id, parsedInput.databaseId))
.returning() .returning()
.execute(); .execute();
@@ -3,9 +3,9 @@
import { z } from "zod"; import { z } from "zod";
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { db } from "@/db"; import { db } from "@/db";
import { database } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { DatabaseSchema } from "@/components/wrappers/dashboard/database/DatabaseForm/form-database.schema"; import { DatabaseSchema } from "@/components/wrappers/dashboard/database/DatabaseForm/form-database.schema";
import * as drizzleDb from "@/db";
export const updateDatabaseAction = userAction export const updateDatabaseAction = userAction
.schema( .schema(
@@ -15,7 +15,7 @@ export const updateDatabaseAction = userAction
}) })
) )
.action(async ({ parsedInput }) => { .action(async ({ parsedInput }) => {
const [updated] = await db.update(database).set(parsedInput.data).where(eq(database.id, parsedInput.id)).returning().execute(); const [updated] = await db.update(drizzleDb.schemas.database).set(parsedInput.data).where(eq(drizzleDb.schemas.database.id, parsedInput.id)).returning().execute();
return updated; return updated;
}); });
@@ -7,6 +7,7 @@ import { authClient } from "@/lib/auth/auth-client";
export function OrganizationCombobox() { export function OrganizationCombobox() {
const router = useRouter(); const router = useRouter();
const { state } = useSidebar();
const { data: organizations } = authClient.useListOrganizations(); const { data: organizations } = authClient.useListOrganizations();
const { data: activeOrganization } = authClient.useActiveOrganization(); const { data: activeOrganization } = authClient.useActiveOrganization();
@@ -27,10 +28,9 @@ export function OrganizationCombobox() {
await authClient.organization.setActive({ await authClient.organization.setActive({
organizationSlug: slug, organizationSlug: slug,
}); });
router.replace(`/dashboard/${slug}/home`); // router.replace(`/dashboard/${slug}/home`);
router.refresh(); router.refresh();
}; };
const { state } = useSidebar();
return <>{state === "expanded" && <ComboBox sideBar values={values} defaultValue={activeOrganization?.slug} onValueChange={onValueChange} />}</>; return <>{state === "expanded" && <ComboBox sideBar values={values} defaultValue={activeOrganization?.slug} onValueChange={onValueChange} />}</>;
} }
@@ -1,12 +1,13 @@
"use server"; "use server";
import { db } from "@/db"; import { db } from "@/db";
import { user as drizzleUser } from "@/db/schema";
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { z } from "zod"; import { z } from "zod";
import * as drizzleDb from "@/db";
export const updateImageUserAction = userAction.schema(z.string()).action(async ({ parsedInput, ctx }) => { export const updateImageUserAction = userAction.schema(z.string()).action(async ({ parsedInput, ctx }) => {
const [updatedUser] = await db.update(drizzleUser).set({ image: parsedInput }).where(eq(drizzleUser.id, ctx.user.id)).returning(); const [updatedUser] = await db.update(drizzleDb.schemas.user).set({ image: parsedInput }).where(eq(drizzleDb.schemas.user.id, ctx.user.id)).returning();
return { return {
data: updatedUser, data: updatedUser,
@@ -3,22 +3,23 @@ import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { db } from "@/db"; import { db } from "@/db";
import { user as drizzleUser } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import * as drizzleDb from "@/db";
export const deleteUserAction = userAction.schema(z.string()).action(async ({ parsedInput, ctx }) => { export const deleteUserAction = userAction.schema(z.string()).action(async ({ parsedInput, ctx }) => {
const userId = parsedInput.length > 0 ? parsedInput : ctx.user.id; const userId = parsedInput.length > 0 ? parsedInput : ctx.user.id;
const uuid = uuidv4(); const uuid = uuidv4();
const [updatedUser] = await db const [updatedUser] = await db
.update(drizzleUser) .update(drizzleDb.schemas.user)
.set({ .set({
email: `${uuid}@portabase.com`, email: `${uuid}@portabase.com`,
name: `${uuid}`, name: `${uuid}`,
//deleted: true, //deleted: true,
//todo: add deleted //todo: add deleted
}) })
.where(eq(drizzleUser.id, userId)) .where(eq(drizzleDb.schemas.user.id, userId))
.returning(); .returning();
return { return {
@@ -3,8 +3,8 @@ import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { UserSchema } from "@/components/wrappers/dashboard/profile/UserForm/user-form.schema"; import { UserSchema } from "@/components/wrappers/dashboard/profile/UserForm/user-form.schema";
import { db } from "@/db"; import { db } from "@/db";
import { user as drizzleUser } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import * as drizzleDb from "@/db";
export const updateUserAction = userAction export const updateUserAction = userAction
.schema( .schema(
@@ -14,8 +14,7 @@ export const updateUserAction = userAction
}) })
) )
.action(async ({ parsedInput }) => { .action(async ({ parsedInput }) => {
const [updatedUser] = await db.update(drizzleUser).set(parsedInput.data).where(eq(drizzleUser.id, parsedInput.id)).returning(); const [updatedUser] = await db.update(drizzleDb.schemas.user).set(parsedInput.data).where(eq(drizzleDb.schemas.user.id, parsedInput.id)).returning();
return { return {
data: updatedUser, data: updatedUser,
}; };
@@ -1,24 +1,24 @@
"use server"; "use server";
import { userAction } from "@/safe-actions"; import {userAction} from "@/safe-actions";
import { z } from "zod"; import {z} from "zod";
import { v4 as uuidv4 } from "uuid"; import {v4 as uuidv4} from "uuid";
import { ServerActionResult } from "@/types/action-type"; import {ServerActionResult} from "@/types/action-type";
import { eq } from "drizzle-orm"; import {eq} from "drizzle-orm";
import { db } from "@/db"; import {db} from "@/db";
import { project } from "@/db/schema"; import * as drizzleDb from "@/db";
export const deleteProjectAction = userAction.schema(z.string()).action(async ({ parsedInput }): Promise<ServerActionResult<typeof project.$inferSelect>> => { export const deleteProjectAction = userAction.schema(z.string()).action(async ({parsedInput}): Promise<ServerActionResult<typeof drizzleDb.schemas.project.$inferSelect>> => {
try { try {
const uuid = uuidv4(); const uuid = uuidv4();
const updatedProjects = await db const updatedProjects = await db
.update(project) .update(drizzleDb.schemas.project)
.set({ .set({
isArchived: true, isArchived: true,
slug: uuid, slug: uuid,
}) })
.where(eq(project.id, parsedInput)) .where(eq(drizzleDb.schemas.project.id, parsedInput))
.returning(); .returning();
const updatedProject = updatedProjects[0]; const updatedProject = updatedProjects[0];
@@ -32,7 +32,7 @@ export const deleteProjectAction = userAction.schema(z.string()).action(async ({
value: updatedProject, value: updatedProject,
actionSuccess: { actionSuccess: {
message: "Projects has been successfully archived.", message: "Projects has been successfully archived.",
messageParams: { projectId: parsedInput }, messageParams: {projectId: parsedInput},
}, },
}; };
} catch (error) { } catch (error) {
@@ -42,7 +42,7 @@ export const deleteProjectAction = userAction.schema(z.string()).action(async ({
message: "Failed to archive Projects.", message: "Failed to archive Projects.",
status: 500, status: 500,
cause: error instanceof Error ? error.message : "Unknown error", cause: error instanceof Error ? error.message : "Unknown error",
messageParams: { projectId: parsedInput }, messageParams: {projectId: parsedInput},
}, },
}; };
} }
@@ -7,7 +7,7 @@ import { eventUpdate } from "@/types/events";
import { backupColumns } from "@/features/dashboard/backup/columns"; import { backupColumns } from "@/features/dashboard/backup/columns";
import { restoreColumns } from "@/features/dashboard/restore/columns"; import { restoreColumns } from "@/features/dashboard/restore/columns";
import { DataTable } from "@/components/wrappers/common/table/data-table"; import { DataTable } from "@/components/wrappers/common/table/data-table";
import { Backup, Database, Restoration } from "@/db/schema"; import {Backup, Database, Restoration} from "@/db/schema/06_database";
export type DatabaseTabsProps = { export type DatabaseTabsProps = {
backups: Backup[]; backups: Backup[];
@@ -5,7 +5,7 @@ import Image from "next/image";
import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { ConnectionCircle } from "@/components/wrappers/common/connection-circle"; import { ConnectionCircle } from "@/components/wrappers/common/connection-circle";
import { formatDateLastContact } from "@/utils/date-formatting"; import { formatDateLastContact } from "@/utils/date-formatting";
import { Database } from "@/db/schema"; import {Database} from "@/db/schema/06_database";
export type projectDatabaseCardProps = { export type projectDatabaseCardProps = {
data: Database; data: Database;
@@ -11,7 +11,8 @@ import { createProjectAction, updateProjectAction } from "@/components/wrappers/
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { MultiSelect } from "@/components/wrappers/common/multiselect/multi-select"; import { MultiSelect } from "@/components/wrappers/common/multiselect/multi-select";
import { toast } from "sonner"; import { toast } from "sonner";
import { DatabaseWith, Organization } from "@/db/schema"; import {DatabaseWith} from "@/db/schema/06_database";
import {Organization} from "@/db/schema/02_organization";
export type projectFormProps = { export type projectFormProps = {
defaultValues?: ProjectType; defaultValues?: ProjectType;
@@ -4,9 +4,11 @@ import { userAction } from "@/safe-actions";
import { ProjectSchema } from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.schema"; import { ProjectSchema } from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm.schema";
import { z } from "zod"; import { z } from "zod";
import { ServerActionResult } from "@/types/action-type"; import { ServerActionResult } from "@/types/action-type";
import { Database, database as drizzleDatabase, project as drizzleProject, Project } from "@/db/schema";
import { db } from "@/db"; import { db } from "@/db";
import { eq, inArray } from "drizzle-orm"; import { eq, inArray } from "drizzle-orm";
import {Project} from "@/db/schema/05_project";
import * as drizzleDb from "@/db";
import {Database} from "@/db/schema/06_database";
export const createProjectAction = userAction export const createProjectAction = userAction
.schema( .schema(
@@ -18,7 +20,7 @@ export const createProjectAction = userAction
.action(async ({ parsedInput }): Promise<ServerActionResult<Project>> => { .action(async ({ parsedInput }): Promise<ServerActionResult<Project>> => {
try { try {
const [createdProject] = await db const [createdProject] = await db
.insert(drizzleProject) .insert(drizzleDb.schemas.project)
.values({ .values({
name: parsedInput.data.name, name: parsedInput.data.name,
slug: parsedInput.data.slug, slug: parsedInput.data.slug,
@@ -27,7 +29,7 @@ export const createProjectAction = userAction
.returning(); .returning();
if (parsedInput.data.databases.length > 0) { if (parsedInput.data.databases.length > 0) {
await db.update(drizzleDatabase).set({ projectId: createdProject.id }).where(inArray(drizzleDatabase.id, parsedInput.data.databases)); await db.update(drizzleDb.schemas.database).set({ projectId: createdProject.id }).where(inArray(drizzleDb.schemas.database.id, parsedInput.data.databases));
} }
return { return {
@@ -62,7 +64,7 @@ export const updateProjectAction = userAction
.action(async ({ parsedInput }): Promise<ServerActionResult<Project>> => { .action(async ({ parsedInput }): Promise<ServerActionResult<Project>> => {
try { try {
const existing = await db.query.project.findFirst({ const existing = await db.query.project.findFirst({
where: eq(drizzleProject.id, parsedInput.projectId), where: eq(drizzleDb.schemas.project.id, parsedInput.projectId),
with: { with: {
databases: true, databases: true,
}, },
@@ -79,20 +81,20 @@ export const updateProjectAction = userAction
const databasesToRemove = existingDbIds.filter((id: string) => !newDbIds.includes(id)); const databasesToRemove = existingDbIds.filter((id: string) => !newDbIds.includes(id));
if (databasesToAdd.length > 0) { if (databasesToAdd.length > 0) {
await db.update(drizzleDatabase).set({ projectId: parsedInput.projectId }).where(inArray(drizzleDatabase.id, databasesToAdd)); await db.update(drizzleDb.schemas.database).set({ projectId: parsedInput.projectId }).where(inArray(drizzleDb.schemas.database.id, databasesToAdd));
} }
if (databasesToRemove.length > 0) { if (databasesToRemove.length > 0) {
await db.update(drizzleDatabase).set({ projectId: null }).where(inArray(drizzleDatabase.id, databasesToRemove)); await db.update(drizzleDb.schemas.database).set({ projectId: null }).where(inArray(drizzleDb.schemas.database.id, databasesToRemove));
} }
const [updatedProject] = await db const [updatedProject] = await db
.update(drizzleProject) .update(drizzleDb.schemas.project)
.set({ .set({
name: parsedInput.data.name, name: parsedInput.data.name,
slug: parsedInput.data.slug, slug: parsedInput.data.slug,
}) })
.where(eq(drizzleProject.id, parsedInput.projectId)) .where(eq(drizzleDb.schemas.project.id, parsedInput.projectId))
.returning(); .returning();
return { return {
@@ -8,7 +8,7 @@ import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { updateUserOrganizationAction } from "@/components/wrappers/dashboard/settings/SettingsUsersTab/settings-user-tab.action"; import { updateUserOrganizationAction } from "@/components/wrappers/dashboard/settings/SettingsUsersTab/settings-user-tab.action";
import { OrganizationMember } from "@/db/schema/02_organization"; import {OrganizationMember} from "@/db/schema/03_member";
export const usersColumns: ColumnDef<OrganizationMember>[] = [ export const usersColumns: ColumnDef<OrganizationMember>[] = [
{ {
@@ -32,9 +32,8 @@ export async function AppSidebar() {
const organization = await getOrganization({organizationId: member.organizationId}); const organization = await getOrganization({organizationId: member.organizationId});
//todo: à revoir //todo: à revoir
console.log("organization", organization);
console.log("membrer", member);
console.log("aoaoaoaoaoa", organization);
return ( return (
<Sidebar collapsible="icon"> <Sidebar collapsible="icon">
+53 -6
View File
@@ -1,13 +1,60 @@
import "dotenv/config"; import {drizzle} from "drizzle-orm/node-postgres";
import { drizzle } from "drizzle-orm/node-postgres";
import * as settings from "./schema/00_setting";
import * as user from "./schema/01_user";
import * as organisation from "./schema/02_organization";
import * as invitation from "./schema/03_member";
import * as member from "./schema/04_invitation";
import * as project from "./schema/05_project";
import * as agent from "./schema/07_agent";
import * as database from "./schema/06_database";
import {Pool} from "pg";
// Do not delete
import dotenv from "dotenv"; import dotenv from "dotenv";
import { env } from "@/env.mjs"; import {migrate} from "drizzle-orm/node-postgres/migrator";
import * as schema from "./schema";
dotenv.config({ dotenv.config({
path: ".env", path: ".env",
}); });
export const db = drizzle(env.DATABASE_URL!, { const pool = new Pool({
schema, connectionString: process.env.DATABASE_URL!,
}); });
export const schemas = {
...settings,
...user,
...organisation,
...invitation,
...member,
...project,
...agent,
...database
};
export const db = drizzle({
client: pool,
logger: true,
schema: schemas,
});
export async function makeMigration() {
if (process.env.NODE_ENV != "development") {
const pool = new Pool({
connectionString: process.env.DATABASE_URL!,
});
const database = drizzle({client: pool});
console.log("Running migrations...");
try {
await migrate(database, {migrationsFolder: "./src/db/migrations"});
console.log("Migrations applied successfully.");
} catch (error) {
console.error("Error applying migrations:", error);
}
}
}
-7
View File
@@ -1,7 +0,0 @@
export * from "./schema/00_setting";
export { user, session, userRelations } from "./schema/01_user";
export type { Organization } from "./schema/02_organization";
export { organization, member as organizationMember, invitation as organizationInvitation } from "./schema/02_organization";
export * from "./schema/03_project";
export * from "./schema/04_agent";
export * from "./schema/05_database";
+4 -2
View File
@@ -2,8 +2,10 @@ import { relations } from "drizzle-orm";
import { boolean, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; import { boolean, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod"; import { createSelectSchema } from "drizzle-zod";
import { z } from "zod"; import { z } from "zod";
import { project } from "./03_project"; import { project } from "./05_project";
import { member, invitation, organization } from "./02_organization"; import {member} from "@/db/schema/03_member";
import {invitation} from "@/db/schema/04_invitation";
import {organization} from "@/db/schema/02_organization";
export const user = pgTable("user", { export const user = pgTable("user", {
id: uuid("id").defaultRandom().primaryKey(), id: uuid("id").defaultRandom().primaryKey(),
+3 -53
View File
@@ -1,9 +1,10 @@
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
import { user } from "./01_user";
import { relations } from "drizzle-orm"; import { relations } from "drizzle-orm";
import { project } from "./03_project"; import { project } from "./05_project";
import { createSelectSchema } from "drizzle-zod"; import { createSelectSchema } from "drizzle-zod";
import { z } from "zod"; import { z } from "zod";
import {invitation} from "@/db/schema/04_invitation";
import {member} from "@/db/schema/03_member";
export const organization = pgTable("organization", { export const organization = pgTable("organization", {
id: uuid("id").defaultRandom().primaryKey(), id: uuid("id").defaultRandom().primaryKey(),
@@ -15,32 +16,6 @@ export const organization = pgTable("organization", {
metadata: text("metadata"), metadata: text("metadata"),
}); });
export const member = pgTable("member", {
id: uuid("id").defaultRandom().primaryKey(),
organizationId: uuid("organization_id")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
userId: uuid("user_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
role: text("role").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at"),
});
export const invitation = pgTable("invitation", {
id: uuid("id").defaultRandom().primaryKey(),
organizationId: uuid("organization_id")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
email: text("email").notNull(),
role: text("role"),
status: text("status").notNull(),
expiresAt: timestamp("expires_at").notNull(),
inviterId: uuid("inviter_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
});
export const organizationRelations = relations(organization, ({ many }) => ({ export const organizationRelations = relations(organization, ({ many }) => ({
members: many(member), members: many(member),
@@ -48,33 +23,8 @@ export const organizationRelations = relations(organization, ({ many }) => ({
projects: many(project), projects: many(project),
})); }));
export const memberRelations = relations(member, ({ one }) => ({
user: one(user, {
fields: [member.userId],
references: [user.id],
}),
organization: one(organization, {
fields: [member.organizationId],
references: [organization.id],
}),
}));
export const invitationRelations = relations(invitation, ({ one }) => ({
organization: one(organization, {
fields: [invitation.organizationId],
references: [organization.id],
}),
inviter: one(user, {
fields: [invitation.inviterId],
references: [user.id],
}),
}));
export const organizationSchema = createSelectSchema(organization); export const organizationSchema = createSelectSchema(organization);
export type Organization = z.infer<typeof organizationSchema>; export type Organization = z.infer<typeof organizationSchema>;
export const organizationMemberSchema = createSelectSchema(member);
export type OrganizationMember = z.infer<typeof organizationMemberSchema>;
export const organizationInvitationSchema = createSelectSchema(invitation);
export type OrganizationInvitation = z.infer<typeof organizationInvitationSchema>;
+35
View File
@@ -0,0 +1,35 @@
import {pgTable, text, timestamp, uuid} from "drizzle-orm/pg-core";
import {user} from "@/db/schema/01_user";
import {organization} from "@/db/schema/02_organization";
import {relations} from "drizzle-orm";
import {createSelectSchema} from "drizzle-zod";
import {z} from "zod";
export const member = pgTable("member", {
id: uuid("id").defaultRandom().primaryKey(),
organizationId: uuid("organization_id")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
userId: uuid("user_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
role: text("role").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at"),
});
export const memberRelations = relations(member, ({ one }) => ({
user: one(user, {
fields: [member.userId],
references: [user.id],
}),
organization: one(organization, {
fields: [member.organizationId],
references: [organization.id],
}),
}));
export const organizationMemberSchema = createSelectSchema(member);
export type OrganizationMember = z.infer<typeof organizationMemberSchema>;
+39
View File
@@ -0,0 +1,39 @@
import {relations} from "drizzle-orm";
import {user} from "@/db/schema/01_user";
import {organization} from "@/db/schema/02_organization";
import {createSelectSchema} from "drizzle-zod";
import {z} from "zod";
import {pgTable, text, timestamp, uuid} from "drizzle-orm/pg-core";
export const invitation = pgTable("invitation", {
id: uuid("id").defaultRandom().primaryKey(),
organizationId: uuid("organization_id")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
email: text("email").notNull(),
role: text("role"),
status: text("status").notNull(),
expiresAt: timestamp("expires_at").notNull(),
inviterId: uuid("inviter_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
});
export const invitationRelations = relations(invitation, ({ one }) => ({
organization: one(organization, {
fields: [invitation.organizationId],
references: [organization.id],
}),
inviter: one(user, {
fields: [invitation.inviterId],
references: [user.id],
}),
}));
export const organizationInvitationSchema = createSelectSchema(invitation);
export type OrganizationInvitation = z.infer<typeof organizationInvitationSchema>;
@@ -3,7 +3,7 @@ import { relations } from "drizzle-orm";
import { Organization, organization } from "./02_organization"; import { Organization, organization } from "./02_organization";
import { createSelectSchema } from "drizzle-zod"; import { createSelectSchema } from "drizzle-zod";
import { z } from "zod"; import { z } from "zod";
import { Database, database } from "./05_database"; import { Database, database } from "./06_database";
export const project = pgTable("projects", { export const project = pgTable("projects", {
id: uuid("id").primaryKey().defaultRandom(), id: uuid("id").primaryKey().defaultRandom(),
@@ -1,6 +1,6 @@
import { pgTable, text, boolean, timestamp, uuid, integer, pgEnum, uniqueIndex } from "drizzle-orm/pg-core"; import { pgTable, text, boolean, timestamp, uuid, integer, pgEnum, uniqueIndex } from "drizzle-orm/pg-core";
import { Agent, agent } from "./04_agent"; import { Agent, agent } from "./07_agent";
import { Project, project } from "./03_project"; import { Project, project } from "./05_project";
import { relations } from "drizzle-orm"; import { relations } from "drizzle-orm";
import { dbmsEnum, statusEnum } from "./types"; import { dbmsEnum, statusEnum } from "./types";
import { createSelectSchema } from "drizzle-zod"; import { createSelectSchema } from "drizzle-zod";
+1 -1
View File
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button";
import { MoreHorizontal } from "lucide-react"; import { MoreHorizontal } from "lucide-react";
import { ReloadIcon } from "@radix-ui/react-icons"; import { ReloadIcon } from "@radix-ui/react-icons";
import { StatusBadge } from "@/components/wrappers/common/status-badge"; import { StatusBadge } from "@/components/wrappers/common/status-badge";
import { Restoration } from "@/db/schema"; import {Restoration} from "@/db/schema/06_database";
export const restoreColumns: ColumnDef<Restoration>[] = [ export const restoreColumns: ColumnDef<Restoration>[] = [
{ {
@@ -1,9 +1,11 @@
import { userAction } from "@/safe-actions"; import { userAction } from "@/safe-actions";
import { z } from "zod"; import { z } from "zod";
import { ServerActionResult } from "@/types/action-type"; import { ServerActionResult } from "@/types/action-type";
import { Backup, backup, Restoration, restoration } from "@/db/schema"; import * as drizzleDb from "@/db";
import { db } from "@/db"; import { db } from "@/db";
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import {Backup, Restoration} from "@/db/schema/06_database";
export const deleteBackupAction = userAction export const deleteBackupAction = userAction
.schema( .schema(
@@ -15,14 +17,14 @@ export const deleteBackupAction = userAction
.action(async ({ parsedInput }): Promise<ServerActionResult<Backup>> => { .action(async ({ parsedInput }): Promise<ServerActionResult<Backup>> => {
try { try {
await db await db
.delete(backup) .delete(drizzleDb.schemas.backup)
.where(and(eq(backup.id, parsedInput.backupId), eq(backup.databaseId, parsedInput.databaseId))) .where(and(eq(drizzleDb.schemas.backup.id, parsedInput.backupId), eq(drizzleDb.schemas.backup.databaseId, parsedInput.databaseId)))
.execute(); .execute();
const backupExists = await db const backupExists = await db
.select() .select()
.from(backup) .from(drizzleDb.schemas.backup)
.where(and(eq(backup.id, parsedInput.backupId), eq(backup.databaseId, parsedInput.databaseId))) .where(and(eq(drizzleDb.schemas.backup.id, parsedInput.backupId), eq(drizzleDb.schemas.backup.databaseId, parsedInput.databaseId)))
.execute(); .execute();
if (backupExists.length === 0) { if (backupExists.length === 0) {
@@ -68,7 +70,7 @@ export const createRestorationAction = userAction
try { try {
// Insert new restoration into the database // Insert new restoration into the database
const restorationData = await db const restorationData = await db
.insert(restoration) .insert(drizzleDb.schemas.restoration)
.values({ .values({
databaseId: parsedInput.databaseId, databaseId: parsedInput.databaseId,
backupId: parsedInput.backupId, backupId: parsedInput.backupId,
+3 -3
View File
@@ -9,9 +9,10 @@ import { checkMinioAlive, createPublicBucket, saveFileInBucket } from "@/utils/s
//@ts-ignore //@ts-ignore
import { UploadedObjectInfo } from "minio/src/internal/type"; import { UploadedObjectInfo } from "minio/src/internal/type";
import { getServerUrl } from "@/utils/get-server-url"; import { getServerUrl } from "@/utils/get-server-url";
import { setting as drizzleSetting, Setting } from "@/db/schema";
import { db } from "@/db"; import { db } from "@/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import {Setting} from "@/db/schema/00_setting";
import * as drizzleDb from "@/db";
export const uploadImageAction = userAction.schema(z.instanceof(FormData)).action(async ({ parsedInput: formData, ctx }) => { export const uploadImageAction = userAction.schema(z.instanceof(FormData)).action(async ({ parsedInput: formData, ctx }) => {
const file = formData.get("file") as File; const file = formData.get("file") as File;
@@ -21,8 +22,7 @@ export const uploadImageAction = userAction.schema(z.instanceof(FormData)).actio
const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer); const buffer = Buffer.from(arrayBuffer);
const [settings] = await db.select().from(drizzleSetting).where(eq(drizzleSetting.name, "system")).limit(1); const [settings] = await db.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1);
if (!settings) { if (!settings) {
throw new Error("System settings not found."); throw new Error("System settings not found.");
} }
+108 -22
View File
@@ -5,19 +5,14 @@ import {env} from "@/env.mjs";
import {nextCookies} from "better-auth/next-js"; import {nextCookies} from "better-auth/next-js";
import {admin as adminPlugin, openAPI, organization} from "better-auth/plugins"; import {admin as adminPlugin, openAPI, organization} from "better-auth/plugins";
import {ac, admin, orgAdmin, orgMember, orgOwner, pending, superadmin, user} from "@/lib/auth/permissions"; import {ac, admin, orgAdmin, orgMember, orgOwner, pending, superadmin, user} from "@/lib/auth/permissions";
import * as drizzleDb from "@/db";
import {headers} from "next/headers"; import {headers} from "next/headers";
import {count, eq} from "drizzle-orm"; import {count, eq} from "drizzle-orm";
import * as drizzleUser from "@/db/schema/01_user";
import * as drizzleOrganization from "@/db/schema/02_organization";
export const auth = betterAuth({ export const auth = betterAuth({
database: drizzleAdapter(db, { database: drizzleAdapter(db, {
provider: "pg", provider: "pg",
schema: { schema: drizzleDb.schemas,
...drizzleUser,
...drizzleOrganization,
},
}), }),
emailAndPassword: { emailAndPassword: {
enabled: true, enabled: true,
@@ -51,7 +46,7 @@ export const auth = betterAuth({
}), }),
adminPlugin({ adminPlugin({
adminRoles: ["admin", "superadmin"], adminRoles: ["admin", "superadmin"],
defaultRole: (await db.select({ count: count() }).from(drizzleUser["user"]))[0].count === 0 ? "superadmin" : "pending", defaultRole: "pending",
ac, ac,
roles: { roles: {
admin, admin,
@@ -75,6 +70,67 @@ export const auth = betterAuth({
}, },
}, },
}, },
databaseHooks: {
user: {
create: {
async before(user, context) {
const userCount = (await db.select({count: count()}).from(drizzleDb.schemas.user))[0].count;
const role = userCount === 0 ? "superadmin" : "pending";
return {
data: {
...user,
role,
},
};
},
async after(user, context) {
const userCount = (await db.select({count: count()}).from(drizzleDb.schemas.user))[0].count;
if (userCount === 1) {
const defaultOrgSlug = "default"; // change this if your default org has a different slug
const defaultOrg = await db.query.organization.findFirst({
where: eq(drizzleDb.schemas.organization.slug, defaultOrgSlug),
});
if (defaultOrg) {
await db.insert(drizzleDb.schemas.member).values({
userId: user.id,
organizationId: defaultOrg.id,
role: "orgOwner",
});
} else {
console.warn("Default organization not found. Cannot assign member.");
}
}
},
},
},
session: {
create: {
before: async (session, context) => {
const userId = session.userId;
const memberships = await db.query.member.findMany({
where: eq(drizzleDb.schemas.member.userId, userId),
});
if (!memberships.length) {
// Fail the login attempt explicitly
throw new Error("User is not part of any organization.");
}
const firstOrgId = memberships[0].organizationId;
return {
data: {
activeOrganizationId: firstOrgId,
},
};
},
},
},
},
session: { session: {
additionalFields: { additionalFields: {
activeOrganizationId: { activeOrganizationId: {
@@ -165,14 +221,15 @@ export const getSession = async () => {
export const revokeSession = async (e: string) => { export const revokeSession = async (e: string) => {
try { try {
const { status } = await auth.api.revokeSession({ const {status} = await auth.api.revokeSession({
body: { body: {
token: e, token: e,
}, },
headers: await headers(), headers: await headers(),
}); });
return status; return status;
} catch (e) {} } catch (e) {
}
}; };
export const getAccounts = async () => { export const getAccounts = async () => {
@@ -183,7 +240,7 @@ export const getAccounts = async () => {
export const unlinkAccount = async (provider: string, account: string) => { export const unlinkAccount = async (provider: string, account: string) => {
try { try {
const { status } = await auth.api.unlinkAccount({ const {status} = await auth.api.unlinkAccount({
body: { body: {
providerId: provider, providerId: provider,
accountId: account, accountId: account,
@@ -192,26 +249,53 @@ export const unlinkAccount = async (provider: string, account: string) => {
}); });
return status; return status;
} catch (e) {} } catch (e) {
}
}; };
//
// export const getOrganization = async ({
// organizationId,
// organizationSlug,
// }: {
// organizationId?: string;
// organizationSlug?: string;
// }) => {
// const query = organizationId
// ? {organizationId}
// : {organizationSlug};
//
// console.log(query);
//
// try {
// return await auth.api.getFullOrganization({
// headers: await headers(),
// // query,
// });
// } catch (e) {
// console.error(e);
// return null;
// }
// };
export const getOrganization = async ({ export const getOrganization = async ({
organizationId, organizationId,
organizationSlug, organizationSlug,
}: { }: {
organizationId?: string; organizationId?: string;
organizationSlug?: string; organizationSlug?: string;
}) => { } = {}) => {
const query = organizationId const query =
? { organizationId } organizationId != null
: { organizationSlug }; ? { organizationId }
: organizationSlug != null
? { organizationSlug }
: undefined;
console.log(query); console.log(query);
try { try {
return await auth.api.getFullOrganization({ return await auth.api.getFullOrganization({
headers: await headers(), headers: await headers(),
query, ...(query ? { query } : {}),
}); });
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@@ -224,13 +308,14 @@ export const listOrganizations = async () => {
return await auth.api.listOrganizations({ return await auth.api.listOrganizations({
headers: await headers(), headers: await headers(),
}); });
} catch (e) {} } catch (e) {
}
}; };
export const getLastOrganizationOrFirst = async (userId: string) => { export const getLastOrganizationOrFirst = async (userId: string) => {
try { try {
const organizations = await db.query.organizationMember.findMany({ const organizations = await db.query.organization.findMany({
where: eq(drizzleOrganization.member.userId, userId), where: eq(drizzleDb.schemas.member.userId, userId),
}); });
if (organizations.length > 0) { if (organizations.length > 0) {
@@ -260,7 +345,7 @@ export const createOrganization = async (name: string, slug: string) => {
export const checkSlugOrganization = async (slug: string) => { export const checkSlugOrganization = async (slug: string) => {
try { try {
const { status } = await auth.api.checkOrganizationSlug({ const {status} = await auth.api.checkOrganizationSlug({
headers: await headers(), headers: await headers(),
body: { body: {
slug, slug,
@@ -278,6 +363,7 @@ export const getActiveMember = async () => {
const member = await auth.api.getActiveMember({ const member = await auth.api.getActiveMember({
headers: await headers(), headers: await headers(),
}); });
console.log(member);
return member; return member;
} catch (e) { } catch (e) {
+3 -3
View File
@@ -1,9 +1,9 @@
"use server"; "use server";
import { db } from "@/db"; import { db } from "@/db";
import { setting as drizzleSetting } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import nodemailer from "nodemailer"; import nodemailer from "nodemailer";
import * as drizzleDb from "@/db";
type Payload = { type Payload = {
to: string; to: string;
@@ -33,8 +33,8 @@ type EmailMassProps = {
export const sendEmail = async (data: Payload) => { export const sendEmail = async (data: Payload) => {
const settings = await db const settings = await db
.select() .select()
.from(drizzleSetting) .from(drizzleDb.schemas.setting)
.where(eq(drizzleSetting.name, "system")) .where(eq(drizzleDb.schemas.setting.name, "system"))
.then((res) => res[0]); .then((res) => res[0]);
if (!settings) { if (!settings) {
+7 -6
View File
@@ -1,7 +1,8 @@
import { env } from "@/env.mjs"; import { env } from "@/env.mjs";
import { db } from "@/db"; import { db } from "@/db";
import { setting, organization } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import * as drizzleDb from "@/db";
export function init() { export function init() {
consoleAscii(); consoleAscii();
@@ -32,14 +33,14 @@ async function createSettingsIfNotExist() {
S3BucketName: env.S3_BUCKET_NAME ?? null, S3BucketName: env.S3_BUCKET_NAME ?? null,
}; };
const [existing] = await db.select().from(setting).where(eq(setting.name, "system")).limit(1); const [existing] = await db.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1);
if (!existing) { if (!existing) {
console.log("====Init Setting : Create ===="); console.log("====Init Setting : Create ====");
await db.insert(setting).values(configSettings); await db.insert(drizzleDb.schemas.setting).values(configSettings);
} else { } else {
console.log("====Init Setting : Update ===="); console.log("====Init Setting : Update ====");
await db.update(setting).set(configSettings).where(eq(setting.name, "system")); await db.update(drizzleDb.schemas.setting).set(configSettings).where(eq(drizzleDb.schemas.setting.name, "system"));
} }
} }
@@ -50,11 +51,11 @@ async function createDefaultOrganization() {
createdAt: new Date(), createdAt: new Date(),
}; };
const [existing] = await db.select().from(organization).where(eq(organization.slug, "default")).limit(1); const [existing] = await db.select().from(drizzleDb.schemas.organization).where(eq(drizzleDb.schemas.organization.slug, "default")).limit(1);
if (!existing) { if (!existing) {
console.log("==== Creating default Organization... ====\n"); console.log("==== Creating default Organization... ====\n");
await db.insert(organization).values(defaultOrganizationConf); await db.insert(drizzleDb.schemas.organization).values(defaultOrganizationConf);
} }
} }
+25 -21
View File
@@ -1,9 +1,9 @@
import * as Minio from "minio"; import * as Minio from "minio";
import { env } from "@/env.mjs"; import {env} from "@/env.mjs";
import internal from "node:stream"; import internal from "node:stream";
import { db } from "@/db"; import {db} from "@/db";
import { setting as drizzleSetting } from "@/db/schema"; import * as drizzleDb from "@/db";
import { eq } from "drizzle-orm"; import {eq} from "drizzle-orm";
// const settings = await prisma.settings.findUnique({ // const settings = await prisma.settings.findUnique({
// where:{ // where:{
@@ -40,8 +40,8 @@ import { eq } from "drizzle-orm";
async function getS3Client() { async function getS3Client() {
const settings = await db const settings = await db
.select() .select()
.from(drizzleSetting) .from(drizzleDb.schemas.setting)
.where(eq(drizzleSetting.name, "system")) .where(eq(drizzleDb.schemas.setting.name, "system"))
.then((res) => res[0]); .then((res) => res[0]);
if (!settings) { if (!settings) {
@@ -57,13 +57,13 @@ async function getS3Client() {
const s3Client = const s3Client =
env.NODE_ENV === "production" env.NODE_ENV === "production"
? new Minio.Client({ ? new Minio.Client({
...baseConfig, ...baseConfig,
}) })
: new Minio.Client({ : new Minio.Client({
...baseConfig, ...baseConfig,
port: Number(env.S3_PORT ?? 0), port: Number(env.S3_PORT ?? 0),
useSSL: env.S3_USE_SSL === "true", useSSL: env.S3_USE_SSL === "true",
}); });
return s3Client; return s3Client;
} }
@@ -75,10 +75,10 @@ export async function checkMinioAlive() {
// Try to list buckets to check connectivity // Try to list buckets to check connectivity
const buckets = await s3Client.listBuckets(); const buckets = await s3Client.listBuckets();
console.log("MinIO is up and running. Buckets:", buckets); console.log("MinIO is up and running. Buckets:", buckets);
return { message: true }; return {message: true};
} catch (error) { } catch (error) {
console.error("Error connecting to MinIO:", error); console.error("Error connecting to MinIO:", error);
return { error: error }; return {error: error};
} }
} }
@@ -98,7 +98,11 @@ export async function createBucketIfNotExists(bucketName: string) {
* @param fileName name of the file * @param fileName name of the file
* @param file file to save * @param file file to save
*/ */
export async function saveFileInBucket({ bucketName, fileName, file }: { bucketName: string; fileName: string; file: Buffer | internal.Readable }) { export async function saveFileInBucket({bucketName, fileName, file}: {
bucketName: string;
fileName: string;
file: Buffer | internal.Readable
}) {
// Check if Minio is Alive // Check if Minio is Alive
await checkMinioAlive(); await checkMinioAlive();
// Create bucket if it doesn't exist // Create bucket if it doesn't exist
@@ -128,7 +132,7 @@ export async function saveFileInBucket({ bucketName, fileName, file }: { bucketN
* @param fileName name of the file * @param fileName name of the file
* @returns true if file exists, false if not * @returns true if file exists, false if not
*/ */
export async function checkFileExistsInBucket({ bucketName, fileName }: { bucketName: string; fileName: string }) { export async function checkFileExistsInBucket({bucketName, fileName}: { bucketName: string; fileName: string }) {
const s3Client = await getS3Client(); const s3Client = await getS3Client();
try { try {
@@ -145,10 +149,10 @@ export async function checkFileExistsInBucket({ bucketName, fileName }: { bucket
* @returns promise with array of presigned urls * @returns promise with array of presigned urls
*/ */
export async function createPresignedUrlToUpload({ export async function createPresignedUrlToUpload({
bucketName, bucketName,
fileName, fileName,
expiry = 60 * 60, // 1 hour expiry = 60 * 60, // 1 hour
}: { }: {
bucketName: string; bucketName: string;
fileName: string; fileName: string;
expiry?: number; expiry?: number;
@@ -161,7 +165,7 @@ export async function createPresignedUrlToUpload({
} }
// Function to create a bucket and make it public // Function to create a bucket and make it public
export async function createPublicBucket({ bucketName }: { bucketName: string }) { export async function createPublicBucket({bucketName}: { bucketName: string }) {
const s3Client = await getS3Client(); const s3Client = await getS3Client();
try { try {