diff --git a/apps/dokploy/components/dashboard/projects/handle-project.tsx b/apps/dokploy/components/dashboard/projects/handle-project.tsx index 08e3e0a8..5b077771 100644 --- a/apps/dokploy/components/dashboard/projects/handle-project.tsx +++ b/apps/dokploy/components/dashboard/projects/handle-project.tsx @@ -21,6 +21,7 @@ import { import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; +import { authClient } from "@/lib/auth"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon, SquarePen } from "lucide-react"; @@ -97,6 +98,18 @@ export const HandleProject = ({ projectId }: Props) => { ); }); }; + // useEffect(() => { + // const getUsers = async () => { + // const users = await authClient.admin.listUsers({ + // query: { + // limit: 100, + // }, + // }); + // console.log(users); + // }; + + // getUsers(); + // }); return ( @@ -110,10 +123,26 @@ export const HandleProject = ({ projectId }: Props) => { Update ) : ( - + <> + + + )} diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index 8d058b6c..98ef14a4 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -57,7 +57,7 @@ export const ShowProjects = () => { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { mutateAsync } = api.project.remove.useMutation(); @@ -91,7 +91,7 @@ export const ShowProjects = () => { - {(auth?.rol === "admin" || user?.canCreateProjects) && ( + {(auth?.role === "admin" || user?.canCreateProjects) && (
@@ -293,7 +293,7 @@ export const ShowProjects = () => {
e.stopPropagation()} > - {(auth?.rol === "admin" || + {(auth?.role === "admin" || user?.canDeleteProjects) && ( diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 4d3c75f9..f52fd14f 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -28,6 +28,7 @@ import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; import { useRouter } from "next/router"; import React from "react"; import { StatusTooltip } from "../shared/status-tooltip"; +import { authClient } from "@/lib/auth"; type Project = Awaited>; @@ -35,8 +36,10 @@ export const SearchCommand = () => { const router = useRouter(); const [open, setOpen] = React.useState(false); const [search, setSearch] = React.useState(""); - - const { data } = api.project.all.useQuery(); + const { data: session } = authClient.getSession(); + const { data } = api.project.all.useQuery(undefined, { + enabled: !!session, + }); const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); React.useEffect(() => { diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 44a4b0ed..88740054 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -155,7 +155,7 @@ const MENU: Menu = { // Only enabled for admins and users with access to Traefik files in non-cloud environments isEnabled: ({ auth, user, isCloud }) => !!( - (auth?.rol === "admin" || user?.canAccessToTraefikFiles) && + (auth?.role === "admin" || user?.canAccessToTraefikFiles) && !isCloud ), }, @@ -166,7 +166,7 @@ const MENU: Menu = { icon: BlocksIcon, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -175,7 +175,7 @@ const MENU: Menu = { icon: PieChart, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -184,7 +184,7 @@ const MENU: Menu = { icon: Forward, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, // Legacy unused menu, adjusted to the new structure @@ -252,7 +252,7 @@ const MENU: Menu = { icon: Activity, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && !isCloud), + !!(auth?.role === "admin" && !isCloud), }, { isSingle: true, @@ -266,7 +266,7 @@ const MENU: Menu = { url: "/dashboard/settings/servers", icon: Server, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -274,7 +274,7 @@ const MENU: Menu = { icon: Users, url: "/dashboard/settings/users", // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -283,7 +283,7 @@ const MENU: Menu = { url: "/dashboard/settings/ssh-keys", // Only enabled for admins and users with access to SSH keys isEnabled: ({ auth, user }) => - !!(auth?.rol === "admin" || user?.canAccessToSSHKeys), + !!(auth?.role === "admin" || user?.canAccessToSSHKeys), }, { isSingle: true, @@ -292,7 +292,7 @@ const MENU: Menu = { icon: GitBranch, // Only enabled for admins and users with access to Git providers isEnabled: ({ auth, user }) => - !!(auth?.rol === "admin" || user?.canAccessToGitProviders), + !!(auth?.role === "admin" || user?.canAccessToGitProviders), }, { isSingle: true, @@ -300,7 +300,7 @@ const MENU: Menu = { url: "/dashboard/settings/registry", icon: Package, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -308,7 +308,7 @@ const MENU: Menu = { url: "/dashboard/settings/destinations", icon: Database, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { @@ -317,7 +317,7 @@ const MENU: Menu = { url: "/dashboard/settings/certificates", icon: ShieldCheck, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -326,7 +326,7 @@ const MENU: Menu = { icon: Boxes, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && !isCloud), + !!(auth?.role === "admin" && !isCloud), }, { isSingle: true, @@ -334,7 +334,7 @@ const MENU: Menu = { url: "/dashboard/settings/notifications", icon: Bell, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -343,7 +343,7 @@ const MENU: Menu = { icon: CreditCard, // Only enabled for admins in cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && isCloud), + !!(auth?.role === "admin" && isCloud), }, ], @@ -537,7 +537,7 @@ export default function Page({ children }: Props) { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -783,7 +783,7 @@ export default function Page({ children }: Props) { ))} - {!isCloud && auth?.rol === "admin" && ( + {!isCloud && auth?.role === "admin" && ( diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 67c5cbfd..d2ad153b 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -24,6 +24,7 @@ import { useRouter } from "next/router"; import { useEffect, useRef, useState } from "react"; import { ModeToggle } from "../ui/modeToggle"; import { SidebarMenuButton } from "../ui/sidebar"; +import { authClient } from "@/lib/auth"; const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; @@ -40,7 +41,7 @@ export const UserNav = () => { }, ); const { locale, setLocale } = useLocale(); - const { mutateAsync } = api.auth.logout.useMutation(); + // const { mutateAsync } = api.auth.logout.useMutation(); return ( @@ -178,9 +179,12 @@ export const UserNav = () => { { - await mutateAsync().then(() => { + await authClient.signOut().then(() => { router.push("/"); }); + // await mutateAsync().then(() => { + // router.push("/"); + // }); }} > Log out diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth.ts index d0b50c7e..d050b360 100644 --- a/apps/dokploy/lib/auth.ts +++ b/apps/dokploy/lib/auth.ts @@ -1,4 +1,7 @@ import { createAuthClient } from "better-auth/react"; +import { organizationClient } from "better-auth/client/plugins"; + export const authClient = createAuthClient({ baseURL: "http://localhost:3000", // the base url of your auth server + plugins: [organizationClient()], }); diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index a1ce98d4..38a281b1 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -42,7 +42,7 @@ export default async function handler( const auth = await findAuthById(value as string); let adminId = ""; - if (auth.rol === "admin") { + if (auth.role === "admin") { const admin = await findAdminByAuthId(auth.id); adminId = admin.adminId; } else { diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 96387c07..5449b9bd 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index ea23ad3a..f8c39a3a 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -206,7 +206,7 @@ const Project = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data, isLoading, refetch } = api.project.one.useQuery({ projectId }); @@ -335,7 +335,7 @@ const Project = ( {data?.description} - {(auth?.rol === "admin" || user?.canCreateServices) && ( + {(auth?.role === "admin" || user?.canCreateServices) && (
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 9d3ffe4f..e2bf8455 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -93,7 +93,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -186,7 +186,7 @@ const Service = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index c6840214..ddc613e5 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -87,7 +87,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -181,7 +181,7 @@ const Service = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index a2ee9051..813ea729 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -68,7 +68,7 @@ const Mariadb = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -154,7 +154,7 @@ const Mariadb = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 4f3947c2..0361b7e2 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -68,7 +68,7 @@ const Mongo = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -156,7 +156,7 @@ const Mongo = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index baf7e6f8..eff9cfe7 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -67,7 +67,7 @@ const MySql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -156,7 +156,7 @@ const MySql = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index e3fd8b44..808c7aee 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -66,7 +66,7 @@ const Postgresql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); @@ -154,7 +154,7 @@ const Postgresql = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 3421e759..82180401 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -67,7 +67,7 @@ const Redis = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -155,7 +155,7 @@ const Redis = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index 5c58e25a..dd70c22a 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -30,7 +30,7 @@ export async function getServerSideProps( } const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index 732b6622..d5bbf033 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index a6605c57..9affb9ee 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -34,7 +34,7 @@ export async function getServerSideProps( }; } const { user, session } = await validateRequest(ctx.req, ctx.res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index c5c6f2f8..671087fe 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index dc37522a..6e8bf587 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index bf76607b..9b4c8048 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -190,7 +190,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index 0b75fc67..054f92e5 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 44e007f1..00f10ec7 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -19,7 +19,7 @@ const Page = () => { authId: data?.id || "", }, { - enabled: !!data?.id && data?.rol === "user", + enabled: !!data?.id && data?.role === "user", }, ); @@ -28,7 +28,7 @@ const Page = () => {
- {(user?.canAccessToAPI || data?.rol === "admin") && } + {(user?.canAccessToAPI || data?.role === "admin") && } {isCloud && }
@@ -62,7 +62,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); - if (user?.rol === "user") { + if (user?.role === "user") { await helpers.user.byAuthId.prefetch({ authId: user.authId, }); diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 49c9ec20..441bee39 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index a229d0bc..98710d06 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -107,7 +107,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 36fde983..27f88be2 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -36,7 +36,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 239edac6..fcb11666 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( const auth = await helpers.auth.get.fetch(); await helpers.settings.isCloud.prefetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index e7072890..ace43969 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 3a8a60b2..524b464a 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 9cd7eefc..b8ff13f3 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 2691fc5c..7877e65c 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -16,8 +16,11 @@ import { Input } from "@/components/ui/input"; import { authClient } from "@/lib/auth"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; -import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; +import { auth, IS_CLOUD, isAdminPresent } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; +import { getSessionCookie, Session } from "better-auth"; +import { betterFetch } from "better-auth/react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -66,7 +69,7 @@ export default function Home({ IS_CLOUD }: Props) { const router = useRouter(); const form = useForm({ defaultValues: { - email: "siumauricio@hotmail.com", + email: "user5@yopmail.com", password: "Password1234", }, resolver: zodResolver(loginSchema), @@ -82,6 +85,17 @@ export default function Home({ IS_CLOUD }: Props) { password: values.password, }); + if (!error) { + // if (data) { + // setTemp(data); + // } else { + toast.success("Successfully signed in", { + duration: 2000, + }); + // router.push("/dashboard/projects"); + // } + } + console.log(data, error); // await mutateAsync({ // email: values.email.toLowerCase(), @@ -208,51 +222,51 @@ Home.getLayout = (page: ReactElement) => { return {page}; }; export async function getServerSideProps(context: GetServerSidePropsContext) { - // if (IS_CLOUD) { - // try { - // const { user } = await validateRequest(context.req, context.res); + if (IS_CLOUD) { + try { + const { user } = await validateRequest(context.req); + if (user) { + return { + redirect: { + permanent: true, + destination: "/dashboard/projects", + }, + }; + } + } catch (error) {} - // if (user) { - // return { - // redirect: { - // permanent: true, - // destination: "/dashboard/projects", - // }, - // }; - // } - // } catch (error) {} + return { + props: { + IS_CLOUD: IS_CLOUD, + }, + }; + } + const hasAdmin = await isAdminPresent(); - // return { - // props: { - // IS_CLOUD: IS_CLOUD, - // }, - // }; - // } - // const hasAdmin = await isAdminPresent(); + if (!hasAdmin) { + return { + redirect: { + permanent: true, + destination: "/register", + }, + }; + } - // if (!hasAdmin) { - // return { - // redirect: { - // permanent: true, - // destination: "/register", - // }, - // }; - // } + const { user } = await validateRequest(context.req); + console.log("Response", user); - // const { user } = await validateRequest(context.req, context.res); - - // if (user) { - // return { - // redirect: { - // permanent: true, - // destination: "/dashboard/projects", - // }, - // }; - // } + if (user) { + return { + redirect: { + permanent: true, + destination: "/dashboard/projects", + }, + }; + } return { props: { - // hasAdmin, + hasAdmin, }, }; } diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index 4ff3d4da..f7902478 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -32,6 +32,9 @@ import { z } from "zod"; const registerSchema = z .object({ + name: z.string().min(1, { + message: "Name is required", + }), email: z .string() .min(1, { @@ -80,6 +83,7 @@ const Register = ({ isCloud }: Props) => { const form = useForm({ defaultValues: { + name: "Mauricio Siu", email: "user5@yopmail.com", password: "Password1234", confirmPassword: "Password1234", @@ -95,8 +99,17 @@ const Register = ({ isCloud }: Props) => { const { data, error } = await authClient.signUp.email({ email: values.email, password: values.password, - name: "Mauricio Siu", + name: values.name, }); + + // const { data, error } = await authClient.admin.createUser({ + // name: values.name, + // email: values.email, + // password: values.password, + // role: "superAdmin", + // }); + + // consol/e.log(data, error); // await mutateAsync({ // email: values.email.toLowerCase(), // password: values.password, @@ -153,6 +166,19 @@ const Register = ({ isCloud }: Props) => { className="grid gap-4" >
+ ( + + Name + + + + + + )} + /> { - const auth = await findAuthById(ctx.user.authId); + console.log(ctx.user); + const auth = await findAuthById(ctx.user.id); return auth; }), diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 35b2669b..c2852ff6 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -124,9 +124,10 @@ export const projectRouter = createTRPCRouter({ return project; }), all: protectedProcedure.query(async ({ ctx }) => { + // console.log(ctx.user); if (ctx.user.rol === "user") { const { accessedProjects, accessedServices } = await findUserByAuthId( - ctx.user.authId, + ctx.user.id, ); if (accessedProjects.length === 0) { @@ -139,7 +140,7 @@ export const projectRouter = createTRPCRouter({ accessedProjects.map((projectId) => sql`${projectId}`), sql`, `, )})`, - eq(projects.adminId, ctx.user.adminId), + eq(projects.userId, ctx.user.id), ), with: { applications: { @@ -193,7 +194,7 @@ export const projectRouter = createTRPCRouter({ }, }, }, - where: eq(projects.adminId, ctx.user.adminId), + where: eq(projects.userId, ctx.user.id), orderBy: desc(projects.createdAt), }); }), diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index cb0e32d9..116de6ad 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -655,7 +655,7 @@ export const settingsRouter = createTRPCRouter({ return true; }), - isCloud: protectedProcedure.query(async () => { + isCloud: publicProcedure.query(async () => { return IS_CLOUD; }), health: publicProcedure.query(async () => { diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index db4f7adf..9579407b 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -9,7 +9,8 @@ // import { getServerAuthSession } from "@/server/auth"; import { db } from "@/server/db"; -import { validateBearerToken, validateRequest } from "@dokploy/server"; +import { validateBearerToken } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import type { OpenApiMeta } from "@dokploy/trpc-openapi"; import { TRPCError, initTRPC } from "@trpc/server"; import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; @@ -18,7 +19,7 @@ import { experimental_isMultipartFormDataRequest, experimental_parseMultipartFormData, } from "@trpc/server/adapters/node-http/content-type/form-data"; -import type { Session, User } from "lucia"; +import type { Session, User } from "better-auth"; import superjson from "superjson"; import { ZodError } from "zod"; /** @@ -30,7 +31,7 @@ import { ZodError } from "zod"; */ interface CreateContextOptions { - user: (User & { authId: string; adminId: string }) | null; + user: (User & { authId: string; rol: "admin" | "user" }) | null; session: Session | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; @@ -65,10 +66,11 @@ const createInnerTRPCContext = (opts: CreateContextOptions) => { export const createTRPCContext = async (opts: CreateNextContextOptions) => { const { req, res } = opts; - let { session, user } = await validateBearerToken(req); + // Get from the request + let { session, user } = await validateRequest(req); if (!session) { - const cookieResult = await validateRequest(req, res); + const cookieResult = await validateRequest(req); session = cookieResult.session; user = cookieResult.user; } @@ -79,12 +81,10 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { session: session, ...((user && { user: { - authId: user.id, + authId: "Null", email: user.email, - rol: user.rol, + rol: user.role, id: user.id, - secret: user.secret, - adminId: user.adminId, }, }) || { user: null, diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 8865078b..0bd91141 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { - boolean, - integer, pgTable, text, + integer, timestamp, + boolean, } from "drizzle-orm/pg-core"; export const user = pgTable("user", { @@ -14,10 +14,6 @@ export const user = pgTable("user", { image: text("image"), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), - role: text("role"), - banned: boolean("banned"), - banReason: text("ban_reason"), - banExpires: timestamp("ban_expires"), }); export const session = pgTable("session", { @@ -31,32 +27,67 @@ export const session = pgTable("session", { userId: text("user_id") .notNull() .references(() => user.id), - impersonatedBy: text("impersonated_by"), + activeOrganizationId: text("active_organization_id"), }); -// export const account = pgTable("account", { -// id: text("id").primaryKey(), -// accountId: text("account_id").notNull(), -// providerId: text("provider_id").notNull(), -// userId: text("user_id") -// .notNull() -// .references(() => user.id), -// accessToken: text("access_token"), -// refreshToken: text("refresh_token"), -// idToken: text("id_token"), -// accessTokenExpiresAt: timestamp("access_token_expires_at"), -// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), -// scope: text("scope"), -// password: text("password"), -// createdAt: timestamp("created_at").notNull(), -// updatedAt: timestamp("updated_at").notNull(), -// }); +export const account = pgTable("account", { + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), +}); -// export const verification = pgTable("verification", { -// id: text("id").primaryKey(), -// identifier: text("identifier").notNull(), -// value: text("value").notNull(), -// expiresAt: timestamp("expires_at").notNull(), -// createdAt: timestamp("created_at"), -// updatedAt: timestamp("updated_at"), -// }); +export const verification = pgTable("verification", { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at"), + updatedAt: timestamp("updated_at"), +}); + +export const organization = pgTable("organization", { + id: text("id").primaryKey(), + name: text("name").notNull(), + slug: text("slug").unique(), + logo: text("logo"), + createdAt: timestamp("created_at").notNull(), + metadata: text("metadata"), +}); + +export const member = pgTable("member", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + userId: text("user_id") + .notNull() + .references(() => user.id), + role: text("role").notNull(), + createdAt: timestamp("created_at").notNull(), +}); + +export const invitation = pgTable("invitation", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + email: text("email").notNull(), + role: text("role"), + status: text("status").notNull(), + expiresAt: timestamp("expires_at").notNull(), + inviterId: text("inviter_id") + .notNull() + .references(() => user.id), +}); diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index ab340d0a..423c4333 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -6,9 +6,9 @@ import { TimeSpan } from "lucia"; import { Lucia } from "lucia/dist/core.js"; import type { Session, User } from "lucia/dist/core.js"; import { db } from "../db"; -import { type DatabaseUser, auth, sessionTable } from "../db/schema"; +import { type DatabaseUser, auth, session } from "../db/schema"; -export const adapter = new DrizzlePostgreSQLAdapter(db, sessionTable, auth); +export const adapter = new DrizzlePostgreSQLAdapter(db, session, auth); export const lucia = new Lucia(adapter, { sessionCookie: { @@ -46,6 +46,7 @@ export async function validateRequest( req: IncomingMessage, res: ServerResponse, ): ReturnValidateToken { + console.log(session); const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ""); if (!sessionId) { diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index a332ec92..38c63027 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -32,3 +32,38 @@ export const verification = pgTable("verification", { createdAt: timestamp("created_at"), updatedAt: timestamp("updated_at"), }); + +export const organization = pgTable("organization", { + id: text("id").primaryKey(), + name: text("name").notNull(), + slug: text("slug").unique(), + logo: text("logo"), + createdAt: timestamp("created_at").notNull(), + metadata: text("metadata"), +}); + +export const member = pgTable("member", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + userId: text("user_id") + .notNull() + .references(() => user.id), + role: text("role").notNull(), + createdAt: timestamp("created_at").notNull(), +}); + +export const invitation = pgTable("invitation", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + email: text("email").notNull(), + role: text("role"), + status: text("status").notNull(), + expiresAt: timestamp("expires_at").notNull(), + inviterId: text("inviter_id") + .notNull() + .references(() => user.id), +}); diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index e7d579fb..66a410b3 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -2,7 +2,7 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { user } from "./user"; // OLD TABLE -export const sessionTable = pgTable("session", { +export const session = pgTable("session", { id: text("id").primaryKey(), expiresAt: timestamp("expires_at").notNull(), token: text("token").notNull().unique(), @@ -14,4 +14,5 @@ export const sessionTable = pgTable("session", { .notNull() .references(() => user.id), impersonatedBy: text("impersonated_by"), + activeOrganizationId: text("active_organization_id"), }); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 372b79f8..bb06f8bc 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -24,11 +24,16 @@ export const user = pgTable("user", { isRegistered: boolean("isRegistered").notNull().default(false), expirationDate: timestamp("expirationDate", { precision: 3, - mode: "string", - }).notNull(), - createdAt: text("createdAt") + mode: "date", + }) .notNull() - .$defaultFn(() => new Date().toISOString()), + .$defaultFn(() => new Date()), + createdAt: timestamp("createdAt", { + precision: 3, + mode: "date", + }) + .notNull() + .$defaultFn(() => new Date()), canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), canCreateServices: boolean("canCreateServices").notNull().default(false), diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 93eed4ca..082176b2 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -1,8 +1,10 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { admin } from "better-auth/plugins"; +import { admin, createAuthMiddleware, organization } from "better-auth/plugins"; import { db } from "../db"; import * as schema from "../db/schema"; +import type { IncomingMessage } from "node:http"; +import { eq } from "drizzle-orm"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", @@ -11,5 +13,38 @@ export const auth = betterAuth({ emailAndPassword: { enabled: true, }, - plugins: [admin()], + hooks: { + after: createAuthMiddleware(async (ctx) => { + if (ctx.path.startsWith("/sign-up")) { + const newSession = ctx.context.newSession; + await db + .update(schema.user) + .set({ + role: "admin", + }) + .where(eq(schema.user.id, newSession?.user?.id || "")); + } + }), + }, + user: { + additionalFields: {}, + }, + plugins: [organization()], }); + +export const validateRequest = async (request: IncomingMessage) => { + const session = await auth.api.getSession({ + headers: new Headers({ + cookie: request.headers.cookie || "", + }), + }); + + if (!session?.session || !session.user) { + return { + session: null, + user: null, + }; + } + + return session; +}; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index ea0df9b0..21c8f13e 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -94,8 +94,8 @@ export const updateAdminById = async ( }; export const isAdminPresent = async () => { - const admin = await db.query.users.findFirst({ - where: eq(users.role, "admin"), + const admin = await db.query.user.findFirst({ + where: eq(user.role, "admin"), }); if (!admin) { return false; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 376f10e9..f391d011 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -100,10 +100,11 @@ export const findAuthByEmail = async (email: string) => { }; export const findAuthById = async (authId: string) => { - const result = await db.query.auth.findFirst({ - where: eq(auth.id, authId), + const result = await db.query.user.findFirst({ + where: eq(user.id, authId), columns: { - password: false, + createdAt: false, + updatedAt: false, }, }); if (!result) { diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index f50e678a..afc3ec00 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -20,18 +20,16 @@ export const findUserById = async (userId: string) => { export const findUserByAuthId = async (authId: string) => { const userR = await db.query.user.findFirst({ - where: eq(user.authId, authId), - with: { - auth: true, - }, + where: eq(user.id, authId), + with: {}, }); - if (!user) { + if (!userR) { throw new TRPCError({ code: "NOT_FOUND", message: "User not found", }); } - return user; + return userR; }; export const findUsers = async (adminId: string) => {