mirror of
https://github.com/LukeHagar/dokploy.git
synced 2025-12-09 20:37:45 +00:00
refactor: add organizations system
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
|||||||
|
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { authClient } from "@/lib/auth";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { PlusIcon, SquarePen } from "lucide-react";
|
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 (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
@@ -110,10 +123,26 @@ export const HandleProject = ({ projectId }: Props) => {
|
|||||||
<span>Update</span>
|
<span>Update</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
<Button>
|
<Button>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
Create Project
|
Create Project
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
const newUser = await authClient.admin.createUser({
|
||||||
|
name: "Test User",
|
||||||
|
email: "test4@example.com",
|
||||||
|
password: "password123",
|
||||||
|
role: "user",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(newUser);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create user
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="sm:m:max-w-lg ">
|
<DialogContent className="sm:m:max-w-lg ">
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const ShowProjects = () => {
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { mutateAsync } = api.project.remove.useMutation();
|
const { mutateAsync } = api.project.remove.useMutation();
|
||||||
@@ -91,7 +91,7 @@ export const ShowProjects = () => {
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
{(auth?.rol === "admin" || user?.canCreateProjects) && (
|
{(auth?.role === "admin" || user?.canCreateProjects) && (
|
||||||
<div className="">
|
<div className="">
|
||||||
<HandleProject />
|
<HandleProject />
|
||||||
</div>
|
</div>
|
||||||
@@ -293,7 +293,7 @@ export const ShowProjects = () => {
|
|||||||
<div
|
<div
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{(auth?.rol === "admin" ||
|
{(auth?.role === "admin" ||
|
||||||
user?.canDeleteProjects) && (
|
user?.canDeleteProjects) && (
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger className="w-full">
|
<AlertDialogTrigger className="w-full">
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { StatusTooltip } from "../shared/status-tooltip";
|
import { StatusTooltip } from "../shared/status-tooltip";
|
||||||
|
import { authClient } from "@/lib/auth";
|
||||||
|
|
||||||
type Project = Awaited<ReturnType<typeof findProjectById>>;
|
type Project = Awaited<ReturnType<typeof findProjectById>>;
|
||||||
|
|
||||||
@@ -35,8 +36,10 @@ export const SearchCommand = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const { data: session } = authClient.getSession();
|
||||||
const { data } = api.project.all.useQuery();
|
const { data } = api.project.all.useQuery(undefined, {
|
||||||
|
enabled: !!session,
|
||||||
|
});
|
||||||
const { data: isCloud, isLoading } = api.settings.isCloud.useQuery();
|
const { data: isCloud, isLoading } = api.settings.isCloud.useQuery();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ const MENU: Menu = {
|
|||||||
// Only enabled for admins and users with access to Traefik files in non-cloud environments
|
// Only enabled for admins and users with access to Traefik files in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!(
|
!!(
|
||||||
(auth?.rol === "admin" || user?.canAccessToTraefikFiles) &&
|
(auth?.role === "admin" || user?.canAccessToTraefikFiles) &&
|
||||||
!isCloud
|
!isCloud
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -166,7 +166,7 @@ const MENU: Menu = {
|
|||||||
icon: BlocksIcon,
|
icon: BlocksIcon,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud),
|
!!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -175,7 +175,7 @@ const MENU: Menu = {
|
|||||||
icon: PieChart,
|
icon: PieChart,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud),
|
!!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -184,7 +184,7 @@ const MENU: Menu = {
|
|||||||
icon: Forward,
|
icon: Forward,
|
||||||
// Only enabled for admins and users with access to Docker in non-cloud environments
|
// Only enabled for admins and users with access to Docker in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud),
|
!!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Legacy unused menu, adjusted to the new structure
|
// Legacy unused menu, adjusted to the new structure
|
||||||
@@ -252,7 +252,7 @@ const MENU: Menu = {
|
|||||||
icon: Activity,
|
icon: Activity,
|
||||||
// Only enabled for admins in non-cloud environments
|
// Only enabled for admins in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!(auth?.rol === "admin" && !isCloud),
|
!!(auth?.role === "admin" && !isCloud),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -266,7 +266,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/servers",
|
url: "/dashboard/settings/servers",
|
||||||
icon: Server,
|
icon: Server,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"),
|
isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -274,7 +274,7 @@ const MENU: Menu = {
|
|||||||
icon: Users,
|
icon: Users,
|
||||||
url: "/dashboard/settings/users",
|
url: "/dashboard/settings/users",
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"),
|
isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -283,7 +283,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/ssh-keys",
|
url: "/dashboard/settings/ssh-keys",
|
||||||
// Only enabled for admins and users with access to SSH keys
|
// Only enabled for admins and users with access to SSH keys
|
||||||
isEnabled: ({ auth, user }) =>
|
isEnabled: ({ auth, user }) =>
|
||||||
!!(auth?.rol === "admin" || user?.canAccessToSSHKeys),
|
!!(auth?.role === "admin" || user?.canAccessToSSHKeys),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -292,7 +292,7 @@ const MENU: Menu = {
|
|||||||
icon: GitBranch,
|
icon: GitBranch,
|
||||||
// Only enabled for admins and users with access to Git providers
|
// Only enabled for admins and users with access to Git providers
|
||||||
isEnabled: ({ auth, user }) =>
|
isEnabled: ({ auth, user }) =>
|
||||||
!!(auth?.rol === "admin" || user?.canAccessToGitProviders),
|
!!(auth?.role === "admin" || user?.canAccessToGitProviders),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -300,7 +300,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/registry",
|
url: "/dashboard/settings/registry",
|
||||||
icon: Package,
|
icon: Package,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"),
|
isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -308,7 +308,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/destinations",
|
url: "/dashboard/settings/destinations",
|
||||||
icon: Database,
|
icon: Database,
|
||||||
// Only enabled for admins
|
// 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",
|
url: "/dashboard/settings/certificates",
|
||||||
icon: ShieldCheck,
|
icon: ShieldCheck,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"),
|
isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -326,7 +326,7 @@ const MENU: Menu = {
|
|||||||
icon: Boxes,
|
icon: Boxes,
|
||||||
// Only enabled for admins in non-cloud environments
|
// Only enabled for admins in non-cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
isEnabled: ({ auth, user, isCloud }) =>
|
||||||
!!(auth?.rol === "admin" && !isCloud),
|
!!(auth?.role === "admin" && !isCloud),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -334,7 +334,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/notifications",
|
url: "/dashboard/settings/notifications",
|
||||||
icon: Bell,
|
icon: Bell,
|
||||||
// Only enabled for admins
|
// Only enabled for admins
|
||||||
isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"),
|
isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
@@ -343,7 +343,7 @@ const MENU: Menu = {
|
|||||||
icon: CreditCard,
|
icon: CreditCard,
|
||||||
// Only enabled for admins in cloud environments
|
// Only enabled for admins in cloud environments
|
||||||
isEnabled: ({ auth, user, isCloud }) =>
|
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 || "",
|
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) {
|
|||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
{!isCloud && auth?.rol === "admin" && (
|
{!isCloud && auth?.role === "admin" && (
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton asChild>
|
<SidebarMenuButton asChild>
|
||||||
<UpdateServerButton />
|
<UpdateServerButton />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { useRouter } from "next/router";
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { ModeToggle } from "../ui/modeToggle";
|
import { ModeToggle } from "../ui/modeToggle";
|
||||||
import { SidebarMenuButton } from "../ui/sidebar";
|
import { SidebarMenuButton } from "../ui/sidebar";
|
||||||
|
import { authClient } from "@/lib/auth";
|
||||||
|
|
||||||
const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7;
|
const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7;
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ export const UserNav = () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { locale, setLocale } = useLocale();
|
const { locale, setLocale } = useLocale();
|
||||||
const { mutateAsync } = api.auth.logout.useMutation();
|
// const { mutateAsync } = api.auth.logout.useMutation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@@ -178,9 +179,12 @@ export const UserNav = () => {
|
|||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await mutateAsync().then(() => {
|
await authClient.signOut().then(() => {
|
||||||
router.push("/");
|
router.push("/");
|
||||||
});
|
});
|
||||||
|
// await mutateAsync().then(() => {
|
||||||
|
// router.push("/");
|
||||||
|
// });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Log out
|
Log out
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { createAuthClient } from "better-auth/react";
|
import { createAuthClient } from "better-auth/react";
|
||||||
|
import { organizationClient } from "better-auth/client/plugins";
|
||||||
|
|
||||||
export const authClient = createAuthClient({
|
export const authClient = createAuthClient({
|
||||||
baseURL: "http://localhost:3000", // the base url of your auth server
|
baseURL: "http://localhost:3000", // the base url of your auth server
|
||||||
|
plugins: [organizationClient()],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default async function handler(
|
|||||||
const auth = await findAuthById(value as string);
|
const auth = await findAuthById(value as string);
|
||||||
|
|
||||||
let adminId = "";
|
let adminId = "";
|
||||||
if (auth.rol === "admin") {
|
if (auth.role === "admin") {
|
||||||
const admin = await findAdminByAuthId(auth.id);
|
const admin = await findAdminByAuthId(auth.id);
|
||||||
adminId = admin.adminId;
|
adminId = admin.adminId;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export async function getServerSideProps(
|
|||||||
await helpers.project.all.prefetch();
|
await helpers.project.all.prefetch();
|
||||||
const auth = await helpers.auth.get.fetch();
|
const auth = await helpers.auth.get.fetch();
|
||||||
|
|
||||||
if (auth.rol === "user") {
|
if (auth.role === "user") {
|
||||||
const user = await helpers.user.byAuthId.fetch({
|
const user = await helpers.user.byAuthId.fetch({
|
||||||
authId: auth.id,
|
authId: auth.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ const Project = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { data, isLoading, refetch } = api.project.one.useQuery({ projectId });
|
const { data, isLoading, refetch } = api.project.one.useQuery({ projectId });
|
||||||
@@ -335,7 +335,7 @@ const Project = (
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>{data?.description}</CardDescription>
|
<CardDescription>{data?.description}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
{(auth?.rol === "admin" || user?.canCreateServices) && (
|
{(auth?.role === "admin" || user?.canCreateServices) && (
|
||||||
<div className="flex flex-row gap-4 flex-wrap">
|
<div className="flex flex-row gap-4 flex-wrap">
|
||||||
<ProjectEnvironment projectId={projectId}>
|
<ProjectEnvironment projectId={projectId}>
|
||||||
<Button variant="outline">Project Environment</Button>
|
<Button variant="outline">Project Environment</Button>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ const Service = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ const Service = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateApplication applicationId={applicationId} />
|
<UpdateApplication applicationId={applicationId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={applicationId} type="application" />
|
<DeleteService id={applicationId} type="application" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const Service = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ const Service = (
|
|||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateCompose composeId={composeId} />
|
<UpdateCompose composeId={composeId} />
|
||||||
|
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={composeId} type="compose" />
|
<DeleteService id={composeId} type="compose" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const Mariadb = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { data: isCloud } = api.settings.isCloud.useQuery();
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||||
@@ -154,7 +154,7 @@ const Mariadb = (
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMariadb mariadbId={mariadbId} />
|
<UpdateMariadb mariadbId={mariadbId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={mariadbId} type="mariadb" />
|
<DeleteService id={mariadbId} type="mariadb" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const Mongo = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ const Mongo = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMongo mongoId={mongoId} />
|
<UpdateMongo mongoId={mongoId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={mongoId} type="mongo" />
|
<DeleteService id={mongoId} type="mongo" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const MySql = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ const MySql = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMysql mysqlId={mysqlId} />
|
<UpdateMysql mysqlId={mysqlId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={mysqlId} type="mysql" />
|
<DeleteService id={mysqlId} type="mysql" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ const Postgresql = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { data: monitoring } = api.admin.getMetricsToken.useQuery();
|
const { data: monitoring } = api.admin.getMetricsToken.useQuery();
|
||||||
@@ -154,7 +154,7 @@ const Postgresql = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdatePostgres postgresId={postgresId} />
|
<UpdatePostgres postgresId={postgresId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={postgresId} type="postgres" />
|
<DeleteService id={postgresId} type="postgres" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const Redis = (
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!auth?.id && auth?.rol === "user",
|
enabled: !!auth?.id && auth?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ const Redis = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateRedis redisId={redisId} />
|
<UpdateRedis redisId={redisId} />
|
||||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
{(auth?.role === "admin" || user?.canDeleteServices) && (
|
||||||
<DeleteService id={redisId} type="redis" />
|
<DeleteService id={redisId} type="redis" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export async function getServerSideProps(
|
|||||||
}
|
}
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export async function getServerSideProps(
|
|||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export async function getServerSideProps(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { user, session } = await validateRequest(ctx.req, ctx.res);
|
const { user, session } = await validateRequest(ctx.req, ctx.res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function getServerSideProps(
|
|||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export async function getServerSideProps(
|
|||||||
await helpers.settings.isCloud.prefetch();
|
await helpers.settings.isCloud.prefetch();
|
||||||
const auth = await helpers.auth.get.fetch();
|
const auth = await helpers.auth.get.fetch();
|
||||||
|
|
||||||
if (auth.rol === "user") {
|
if (auth.role === "user") {
|
||||||
const user = await helpers.user.byAuthId.fetch({
|
const user = await helpers.user.byAuthId.fetch({
|
||||||
authId: auth.id,
|
authId: auth.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export async function getServerSideProps(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (user.rol === "user") {
|
if (user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function getServerSideProps(
|
|||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const Page = () => {
|
|||||||
authId: data?.id || "",
|
authId: data?.id || "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !!data?.id && data?.rol === "user",
|
enabled: !!data?.id && data?.role === "user",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ const Page = () => {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
|
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
|
||||||
<ProfileForm />
|
<ProfileForm />
|
||||||
{(user?.canAccessToAPI || data?.rol === "admin") && <GenerateToken />}
|
{(user?.canAccessToAPI || data?.role === "admin") && <GenerateToken />}
|
||||||
|
|
||||||
{isCloud && <RemoveSelfAccount />}
|
{isCloud && <RemoveSelfAccount />}
|
||||||
</div>
|
</div>
|
||||||
@@ -62,7 +62,7 @@ export async function getServerSideProps(
|
|||||||
|
|
||||||
await helpers.settings.isCloud.prefetch();
|
await helpers.settings.isCloud.prefetch();
|
||||||
await helpers.auth.get.prefetch();
|
await helpers.auth.get.prefetch();
|
||||||
if (user?.rol === "user") {
|
if (user?.role === "user") {
|
||||||
await helpers.user.byAuthId.prefetch({
|
await helpers.user.byAuthId.prefetch({
|
||||||
authId: user.authId,
|
authId: user.authId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function getServerSideProps(
|
|||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export async function getServerSideProps(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (user.rol === "user") {
|
if (user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function getServerSideProps(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (user.rol === "user") {
|
if (user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export async function getServerSideProps(
|
|||||||
const auth = await helpers.auth.get.fetch();
|
const auth = await helpers.auth.get.fetch();
|
||||||
await helpers.settings.isCloud.prefetch();
|
await helpers.settings.isCloud.prefetch();
|
||||||
|
|
||||||
if (auth.rol === "user") {
|
if (auth.role === "user") {
|
||||||
const user = await helpers.user.byAuthId.fetch({
|
const user = await helpers.user.byAuthId.fetch({
|
||||||
authId: auth.id,
|
authId: auth.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export async function getServerSideProps(
|
|||||||
) {
|
) {
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
const { user, session } = await validateRequest(req, res);
|
const { user, session } = await validateRequest(req, res);
|
||||||
if (!user || user.rol === "user") {
|
if (!user || user.role === "user") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export async function getServerSideProps(
|
|||||||
await helpers.project.all.prefetch();
|
await helpers.project.all.prefetch();
|
||||||
const auth = await helpers.auth.get.fetch();
|
const auth = await helpers.auth.get.fetch();
|
||||||
|
|
||||||
if (auth.rol === "user") {
|
if (auth.role === "user") {
|
||||||
const user = await helpers.user.byAuthId.fetch({
|
const user = await helpers.user.byAuthId.fetch({
|
||||||
authId: auth.id,
|
authId: auth.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export async function getServerSideProps(
|
|||||||
await helpers.project.all.prefetch();
|
await helpers.project.all.prefetch();
|
||||||
const auth = await helpers.auth.get.fetch();
|
const auth = await helpers.auth.get.fetch();
|
||||||
|
|
||||||
if (auth.rol === "user") {
|
if (auth.role === "user") {
|
||||||
const user = await helpers.user.byAuthId.fetch({
|
const user = await helpers.user.byAuthId.fetch({
|
||||||
authId: auth.id,
|
authId: auth.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,8 +16,11 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { authClient } from "@/lib/auth";
|
import { authClient } from "@/lib/auth";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { api } from "@/utils/api";
|
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 { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { getSessionCookie, Session } from "better-auth";
|
||||||
|
import { betterFetch } from "better-auth/react";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@@ -66,7 +69,7 @@ export default function Home({ IS_CLOUD }: Props) {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const form = useForm<Login>({
|
const form = useForm<Login>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: "siumauricio@hotmail.com",
|
email: "user5@yopmail.com",
|
||||||
password: "Password1234",
|
password: "Password1234",
|
||||||
},
|
},
|
||||||
resolver: zodResolver(loginSchema),
|
resolver: zodResolver(loginSchema),
|
||||||
@@ -82,6 +85,17 @@ export default function Home({ IS_CLOUD }: Props) {
|
|||||||
password: values.password,
|
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);
|
console.log(data, error);
|
||||||
// await mutateAsync({
|
// await mutateAsync({
|
||||||
// email: values.email.toLowerCase(),
|
// email: values.email.toLowerCase(),
|
||||||
@@ -208,51 +222,51 @@ Home.getLayout = (page: ReactElement) => {
|
|||||||
return <OnboardingLayout>{page}</OnboardingLayout>;
|
return <OnboardingLayout>{page}</OnboardingLayout>;
|
||||||
};
|
};
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
// if (IS_CLOUD) {
|
if (IS_CLOUD) {
|
||||||
// try {
|
try {
|
||||||
// const { user } = await validateRequest(context.req, context.res);
|
const { user } = await validateRequest(context.req);
|
||||||
|
if (user) {
|
||||||
// if (user) {
|
|
||||||
// return {
|
|
||||||
// redirect: {
|
|
||||||
// permanent: true,
|
|
||||||
// destination: "/dashboard/projects",
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// } catch (error) {}
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// props: {
|
|
||||||
// IS_CLOUD: IS_CLOUD,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// const hasAdmin = await isAdminPresent();
|
|
||||||
|
|
||||||
// if (!hasAdmin) {
|
|
||||||
// return {
|
|
||||||
// redirect: {
|
|
||||||
// permanent: true,
|
|
||||||
// destination: "/register",
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const { user } = await validateRequest(context.req, context.res);
|
|
||||||
|
|
||||||
// if (user) {
|
|
||||||
// return {
|
|
||||||
// redirect: {
|
|
||||||
// permanent: true,
|
|
||||||
// destination: "/dashboard/projects",
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
redirect: {
|
||||||
// hasAdmin,
|
permanent: true,
|
||||||
|
destination: "/dashboard/projects",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
IS_CLOUD: IS_CLOUD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const hasAdmin = await isAdminPresent();
|
||||||
|
|
||||||
|
if (!hasAdmin) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
permanent: true,
|
||||||
|
destination: "/register",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { user } = await validateRequest(context.req);
|
||||||
|
console.log("Response", user);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
permanent: true,
|
||||||
|
destination: "/dashboard/projects",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
hasAdmin,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ import { z } from "zod";
|
|||||||
|
|
||||||
const registerSchema = z
|
const registerSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
name: z.string().min(1, {
|
||||||
|
message: "Name is required",
|
||||||
|
}),
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, {
|
.min(1, {
|
||||||
@@ -80,6 +83,7 @@ const Register = ({ isCloud }: Props) => {
|
|||||||
|
|
||||||
const form = useForm<Register>({
|
const form = useForm<Register>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
name: "Mauricio Siu",
|
||||||
email: "user5@yopmail.com",
|
email: "user5@yopmail.com",
|
||||||
password: "Password1234",
|
password: "Password1234",
|
||||||
confirmPassword: "Password1234",
|
confirmPassword: "Password1234",
|
||||||
@@ -95,8 +99,17 @@ const Register = ({ isCloud }: Props) => {
|
|||||||
const { data, error } = await authClient.signUp.email({
|
const { data, error } = await authClient.signUp.email({
|
||||||
email: values.email,
|
email: values.email,
|
||||||
password: values.password,
|
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({
|
// await mutateAsync({
|
||||||
// email: values.email.toLowerCase(),
|
// email: values.email.toLowerCase(),
|
||||||
// password: values.password,
|
// password: values.password,
|
||||||
@@ -153,6 +166,19 @@ const Register = ({ isCloud }: Props) => {
|
|||||||
className="grid gap-4"
|
className="grid gap-4"
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="name"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="name" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="email"
|
name="email"
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||||||
},
|
},
|
||||||
transformer: superjson,
|
transformer: superjson,
|
||||||
});
|
});
|
||||||
if (user.rol === "user") {
|
if (user.role === "user") {
|
||||||
const result = await helpers.user.byAuthId.fetch({
|
const result = await helpers.user.byAuthId.fetch({
|
||||||
authId: user.id,
|
authId: user.id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ export const authRouter = createTRPCRouter({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
get: protectedProcedure.query(async ({ ctx }) => {
|
get: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const auth = await findAuthById(ctx.user.authId);
|
console.log(ctx.user);
|
||||||
|
const auth = await findAuthById(ctx.user.id);
|
||||||
return auth;
|
return auth;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@@ -124,9 +124,10 @@ export const projectRouter = createTRPCRouter({
|
|||||||
return project;
|
return project;
|
||||||
}),
|
}),
|
||||||
all: protectedProcedure.query(async ({ ctx }) => {
|
all: protectedProcedure.query(async ({ ctx }) => {
|
||||||
|
// console.log(ctx.user);
|
||||||
if (ctx.user.rol === "user") {
|
if (ctx.user.rol === "user") {
|
||||||
const { accessedProjects, accessedServices } = await findUserByAuthId(
|
const { accessedProjects, accessedServices } = await findUserByAuthId(
|
||||||
ctx.user.authId,
|
ctx.user.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (accessedProjects.length === 0) {
|
if (accessedProjects.length === 0) {
|
||||||
@@ -139,7 +140,7 @@ export const projectRouter = createTRPCRouter({
|
|||||||
accessedProjects.map((projectId) => sql`${projectId}`),
|
accessedProjects.map((projectId) => sql`${projectId}`),
|
||||||
sql`, `,
|
sql`, `,
|
||||||
)})`,
|
)})`,
|
||||||
eq(projects.adminId, ctx.user.adminId),
|
eq(projects.userId, ctx.user.id),
|
||||||
),
|
),
|
||||||
with: {
|
with: {
|
||||||
applications: {
|
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),
|
orderBy: desc(projects.createdAt),
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ export const settingsRouter = createTRPCRouter({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
isCloud: protectedProcedure.query(async () => {
|
isCloud: publicProcedure.query(async () => {
|
||||||
return IS_CLOUD;
|
return IS_CLOUD;
|
||||||
}),
|
}),
|
||||||
health: publicProcedure.query(async () => {
|
health: publicProcedure.query(async () => {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
// import { getServerAuthSession } from "@/server/auth";
|
// import { getServerAuthSession } from "@/server/auth";
|
||||||
import { db } from "@/server/db";
|
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 type { OpenApiMeta } from "@dokploy/trpc-openapi";
|
||||||
import { TRPCError, initTRPC } from "@trpc/server";
|
import { TRPCError, initTRPC } from "@trpc/server";
|
||||||
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
|
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
|
||||||
@@ -18,7 +19,7 @@ import {
|
|||||||
experimental_isMultipartFormDataRequest,
|
experimental_isMultipartFormDataRequest,
|
||||||
experimental_parseMultipartFormData,
|
experimental_parseMultipartFormData,
|
||||||
} from "@trpc/server/adapters/node-http/content-type/form-data";
|
} 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 superjson from "superjson";
|
||||||
import { ZodError } from "zod";
|
import { ZodError } from "zod";
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +31,7 @@ import { ZodError } from "zod";
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
interface CreateContextOptions {
|
interface CreateContextOptions {
|
||||||
user: (User & { authId: string; adminId: string }) | null;
|
user: (User & { authId: string; rol: "admin" | "user" }) | null;
|
||||||
session: Session | null;
|
session: Session | null;
|
||||||
req: CreateNextContextOptions["req"];
|
req: CreateNextContextOptions["req"];
|
||||||
res: CreateNextContextOptions["res"];
|
res: CreateNextContextOptions["res"];
|
||||||
@@ -65,10 +66,11 @@ const createInnerTRPCContext = (opts: CreateContextOptions) => {
|
|||||||
export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
||||||
const { req, res } = opts;
|
const { req, res } = opts;
|
||||||
|
|
||||||
let { session, user } = await validateBearerToken(req);
|
// Get from the request
|
||||||
|
let { session, user } = await validateRequest(req);
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
const cookieResult = await validateRequest(req, res);
|
const cookieResult = await validateRequest(req);
|
||||||
session = cookieResult.session;
|
session = cookieResult.session;
|
||||||
user = cookieResult.user;
|
user = cookieResult.user;
|
||||||
}
|
}
|
||||||
@@ -79,12 +81,10 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
|||||||
session: session,
|
session: session,
|
||||||
...((user && {
|
...((user && {
|
||||||
user: {
|
user: {
|
||||||
authId: user.id,
|
authId: "Null",
|
||||||
email: user.email,
|
email: user.email,
|
||||||
rol: user.rol,
|
rol: user.role,
|
||||||
id: user.id,
|
id: user.id,
|
||||||
secret: user.secret,
|
|
||||||
adminId: user.adminId,
|
|
||||||
},
|
},
|
||||||
}) || {
|
}) || {
|
||||||
user: null,
|
user: null,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
boolean,
|
|
||||||
integer,
|
|
||||||
pgTable,
|
pgTable,
|
||||||
text,
|
text,
|
||||||
|
integer,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
boolean,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const user = pgTable("user", {
|
export const user = pgTable("user", {
|
||||||
@@ -14,10 +14,6 @@ export const user = pgTable("user", {
|
|||||||
image: text("image"),
|
image: text("image"),
|
||||||
createdAt: timestamp("created_at").notNull(),
|
createdAt: timestamp("created_at").notNull(),
|
||||||
updatedAt: timestamp("updated_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", {
|
export const session = pgTable("session", {
|
||||||
@@ -31,32 +27,67 @@ export const session = pgTable("session", {
|
|||||||
userId: text("user_id")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => user.id),
|
.references(() => user.id),
|
||||||
impersonatedBy: text("impersonated_by"),
|
activeOrganizationId: text("active_organization_id"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// export const account = pgTable("account", {
|
export const account = pgTable("account", {
|
||||||
// id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
// accountId: text("account_id").notNull(),
|
accountId: text("account_id").notNull(),
|
||||||
// providerId: text("provider_id").notNull(),
|
providerId: text("provider_id").notNull(),
|
||||||
// userId: text("user_id")
|
userId: text("user_id")
|
||||||
// .notNull()
|
.notNull()
|
||||||
// .references(() => user.id),
|
.references(() => user.id),
|
||||||
// accessToken: text("access_token"),
|
accessToken: text("access_token"),
|
||||||
// refreshToken: text("refresh_token"),
|
refreshToken: text("refresh_token"),
|
||||||
// idToken: text("id_token"),
|
idToken: text("id_token"),
|
||||||
// accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||||
// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||||
// scope: text("scope"),
|
scope: text("scope"),
|
||||||
// password: text("password"),
|
password: text("password"),
|
||||||
// createdAt: timestamp("created_at").notNull(),
|
createdAt: timestamp("created_at").notNull(),
|
||||||
// updatedAt: timestamp("updated_at").notNull(),
|
updatedAt: timestamp("updated_at").notNull(),
|
||||||
// });
|
});
|
||||||
|
|
||||||
// export const verification = pgTable("verification", {
|
export const verification = pgTable("verification", {
|
||||||
// id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
// identifier: text("identifier").notNull(),
|
identifier: text("identifier").notNull(),
|
||||||
// value: text("value").notNull(),
|
value: text("value").notNull(),
|
||||||
// expiresAt: timestamp("expires_at").notNull(),
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
// createdAt: timestamp("created_at"),
|
createdAt: timestamp("created_at"),
|
||||||
// updatedAt: timestamp("updated_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),
|
||||||
|
});
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { TimeSpan } from "lucia";
|
|||||||
import { Lucia } from "lucia/dist/core.js";
|
import { Lucia } from "lucia/dist/core.js";
|
||||||
import type { Session, User } from "lucia/dist/core.js";
|
import type { Session, User } from "lucia/dist/core.js";
|
||||||
import { db } from "../db";
|
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, {
|
export const lucia = new Lucia(adapter, {
|
||||||
sessionCookie: {
|
sessionCookie: {
|
||||||
@@ -46,6 +46,7 @@ export async function validateRequest(
|
|||||||
req: IncomingMessage,
|
req: IncomingMessage,
|
||||||
res: ServerResponse,
|
res: ServerResponse,
|
||||||
): ReturnValidateToken {
|
): ReturnValidateToken {
|
||||||
|
console.log(session);
|
||||||
const sessionId = lucia.readSessionCookie(req.headers.cookie ?? "");
|
const sessionId = lucia.readSessionCookie(req.headers.cookie ?? "");
|
||||||
|
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
|
|||||||
@@ -32,3 +32,38 @@ export const verification = pgTable("verification", {
|
|||||||
createdAt: timestamp("created_at"),
|
createdAt: timestamp("created_at"),
|
||||||
updatedAt: timestamp("updated_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),
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|||||||
import { user } from "./user";
|
import { user } from "./user";
|
||||||
|
|
||||||
// OLD TABLE
|
// OLD TABLE
|
||||||
export const sessionTable = pgTable("session", {
|
export const session = pgTable("session", {
|
||||||
id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
expiresAt: timestamp("expires_at").notNull(),
|
expiresAt: timestamp("expires_at").notNull(),
|
||||||
token: text("token").notNull().unique(),
|
token: text("token").notNull().unique(),
|
||||||
@@ -14,4 +14,5 @@ export const sessionTable = pgTable("session", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.references(() => user.id),
|
.references(() => user.id),
|
||||||
impersonatedBy: text("impersonated_by"),
|
impersonatedBy: text("impersonated_by"),
|
||||||
|
activeOrganizationId: text("active_organization_id"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,11 +24,16 @@ export const user = pgTable("user", {
|
|||||||
isRegistered: boolean("isRegistered").notNull().default(false),
|
isRegistered: boolean("isRegistered").notNull().default(false),
|
||||||
expirationDate: timestamp("expirationDate", {
|
expirationDate: timestamp("expirationDate", {
|
||||||
precision: 3,
|
precision: 3,
|
||||||
mode: "string",
|
mode: "date",
|
||||||
}).notNull(),
|
})
|
||||||
createdAt: text("createdAt")
|
|
||||||
.notNull()
|
.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),
|
canCreateProjects: boolean("canCreateProjects").notNull().default(false),
|
||||||
canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
|
canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
|
||||||
canCreateServices: boolean("canCreateServices").notNull().default(false),
|
canCreateServices: boolean("canCreateServices").notNull().default(false),
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
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 { db } from "../db";
|
||||||
import * as schema from "../db/schema";
|
import * as schema from "../db/schema";
|
||||||
|
import type { IncomingMessage } from "node:http";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
database: drizzleAdapter(db, {
|
database: drizzleAdapter(db, {
|
||||||
provider: "pg",
|
provider: "pg",
|
||||||
@@ -11,5 +13,38 @@ export const auth = betterAuth({
|
|||||||
emailAndPassword: {
|
emailAndPassword: {
|
||||||
enabled: true,
|
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;
|
||||||
|
};
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ export const updateAdminById = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isAdminPresent = async () => {
|
export const isAdminPresent = async () => {
|
||||||
const admin = await db.query.users.findFirst({
|
const admin = await db.query.user.findFirst({
|
||||||
where: eq(users.role, "admin"),
|
where: eq(user.role, "admin"),
|
||||||
});
|
});
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -100,10 +100,11 @@ export const findAuthByEmail = async (email: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const findAuthById = async (authId: string) => {
|
export const findAuthById = async (authId: string) => {
|
||||||
const result = await db.query.auth.findFirst({
|
const result = await db.query.user.findFirst({
|
||||||
where: eq(auth.id, authId),
|
where: eq(user.id, authId),
|
||||||
columns: {
|
columns: {
|
||||||
password: false,
|
createdAt: false,
|
||||||
|
updatedAt: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
|||||||
@@ -20,18 +20,16 @@ export const findUserById = async (userId: string) => {
|
|||||||
|
|
||||||
export const findUserByAuthId = async (authId: string) => {
|
export const findUserByAuthId = async (authId: string) => {
|
||||||
const userR = await db.query.user.findFirst({
|
const userR = await db.query.user.findFirst({
|
||||||
where: eq(user.authId, authId),
|
where: eq(user.id, authId),
|
||||||
with: {
|
with: {},
|
||||||
auth: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
if (!user) {
|
if (!userR) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
message: "User not found",
|
message: "User not found",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return user;
|
return userR;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const findUsers = async (adminId: string) => {
|
export const findUsers = async (adminId: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user