Compare commits

...

26 Commits

Author SHA1 Message Date
Mauricio Siu
8b71f963cc refactor: update logic 2025-02-15 19:35:22 -06:00
Mauricio Siu
1c5cc5a0db refactor: update roles 2025-02-15 19:23:08 -06:00
Mauricio Siu
d233f2c764 feat: adjust roles 2025-02-15 19:12:44 -06:00
Mauricio Siu
1bbb4c9b64 refactor: update migration 2025-02-15 18:13:20 -06:00
Mauricio Siu
6ec60b6bab refactor: update validation 2025-02-15 13:14:48 -06:00
Mauricio Siu
55abac3f2f refactor: migrate endpoints 2025-02-14 02:52:37 -06:00
Mauricio Siu
b6c29ccf05 refactor: update 2025-02-14 02:40:11 -06:00
Mauricio Siu
ca217affe6 feat: update references 2025-02-14 02:18:53 -06:00
Mauricio Siu
5c24281f72 refactor: return correct information 2025-02-13 02:45:33 -06:00
Mauricio Siu
bc901bcb25 refactor: update 2025-02-13 02:36:08 -06:00
Mauricio Siu
7c0d223e17 refactor: add fields 2025-02-13 01:42:58 -06:00
Mauricio Siu
74ee024cf9 refactor: update temps 2025-02-13 01:24:25 -06:00
Mauricio Siu
140a871275 refactor: update 2025-02-13 01:21:49 -06:00
Mauricio Siu
d1f72a2e20 refactor: update migration 2025-02-13 00:57:22 -06:00
Mauricio Siu
0d525398a8 feat: migrate rest schemas 2025-02-13 00:45:29 -06:00
Mauricio Siu
7c62408070 refactor: delete 2025-02-13 00:38:39 -06:00
Mauricio Siu
23f1ce17de refactor: add migration 2025-02-13 00:38:22 -06:00
Mauricio Siu
60eee55f2d refactor: test migrastion 2025-02-12 23:41:04 -06:00
Mauricio Siu
8f562eefc1 Merge branch 'canary' into feat/better-auth 2025-02-12 20:56:23 -06:00
Mauricio Siu
6179cef1ee refactor: update name 2025-02-10 02:13:52 -06:00
Mauricio Siu
b7112b89fd refactor: add migration 2025-02-10 00:39:46 -06:00
Mauricio Siu
1db6ba94f4 refactor: remove 2025-02-09 21:36:36 -06:00
Mauricio Siu
afd3d2eea3 refactor: lint 2025-02-09 20:53:14 -06:00
Mauricio Siu
8bd72a8a34 refactor: add organizations system 2025-02-09 20:53:06 -06:00
Mauricio Siu
fafc238e70 refactor: migration 2025-02-09 18:56:17 -06:00
Mauricio Siu
c04bf3c7e0 feat: add migration 2025-02-09 18:19:21 -06:00
132 changed files with 24380 additions and 893 deletions

View File

@@ -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}>

View File

@@ -57,7 +57,7 @@ export const ShowProjects = () => {
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
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 === "owner" || 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 === "owner" ||
user?.canDeleteProjects) && ( user?.canDeleteProjects) && (
<AlertDialog> <AlertDialog>
<AlertDialogTrigger className="w-full"> <AlertDialogTrigger className="w-full">

View File

@@ -18,6 +18,7 @@ import {
CommandList, CommandList,
CommandSeparator, CommandSeparator,
} from "@/components/ui/command"; } from "@/components/ui/command";
import { authClient } from "@/lib/auth";
import { import {
type Services, type Services,
extractServices, extractServices,
@@ -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(() => {

View File

@@ -15,7 +15,7 @@ export const ShowWelcomeDokploy = () => {
const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); const { data: isCloud, isLoading } = api.settings.isCloud.useQuery();
if (!isCloud || data?.rol !== "admin") { if (!isCloud || data?.role !== "admin") {
return null; return null;
} }
@@ -24,14 +24,14 @@ export const ShowWelcomeDokploy = () => {
!isLoading && !isLoading &&
isCloud && isCloud &&
!localStorage.getItem("hasSeenCloudWelcomeModal") && !localStorage.getItem("hasSeenCloudWelcomeModal") &&
data?.rol === "admin" data?.role === "owner"
) { ) {
setOpen(true); setOpen(true);
} }
}, [isCloud, isLoading]); }, [isCloud, isLoading]);
const handleClose = (isOpen: boolean) => { const handleClose = (isOpen: boolean) => {
if (data?.rol === "admin") { if (data?.role === "owner") {
setOpen(isOpen); setOpen(isOpen);
if (!isOpen) { if (!isOpen) {
localStorage.setItem("hasSeenCloudWelcomeModal", "true"); // Establece el flag al cerrar el modal localStorage.setItem("hasSeenCloudWelcomeModal", "true"); // Establece el flag al cerrar el modal

View File

@@ -51,7 +51,7 @@ export const GenerateToken = () => {
<Label>Token</Label> <Label>Token</Label>
<ToggleVisibilityInput <ToggleVisibilityInput
placeholder="Token" placeholder="Token"
value={data?.token || ""} value={data?.user?.token || ""}
disabled disabled
/> />
</div> </div>

View File

@@ -73,9 +73,9 @@ export const ProfileForm = () => {
const form = useForm<Profile>({ const form = useForm<Profile>({
defaultValues: { defaultValues: {
email: data?.email || "", email: data?.user?.email || "",
password: "", password: "",
image: data?.image || "", image: data?.user?.image || "",
currentPassword: "", currentPassword: "",
}, },
resolver: zodResolver(profileSchema), resolver: zodResolver(profileSchema),
@@ -84,14 +84,14 @@ export const ProfileForm = () => {
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
email: data?.email || "", email: data?.user?.email || "",
password: "", password: "",
image: data?.image || "", image: data?.user?.image || "",
currentPassword: "", currentPassword: "",
}); });
if (data.email) { if (data.user.email) {
generateSHA256Hash(data.email).then((hash) => { generateSHA256Hash(data.user.email).then((hash) => {
setGravatarHash(hash); setGravatarHash(hash);
}); });
} }

View File

@@ -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 === "owner" || 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 === "owner" || 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 === "owner" || 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 === "owner" || 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 === "owner" && !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 === "owner"),
}, },
{ {
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 === "owner"),
}, },
{ {
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 === "owner" || 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 === "owner" || 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 === "owner"),
}, },
{ {
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 === "owner"),
}, },
{ {
@@ -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 === "owner"),
}, },
{ {
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 === "owner" && !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 === "owner"),
}, },
{ {
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 === "owner" && 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 === "member",
}, },
); );
@@ -557,7 +557,7 @@ export default function Page({ children }: Props) {
// const showProjectsButton = // const showProjectsButton =
// currentPath === "/dashboard/projects" && // currentPath === "/dashboard/projects" &&
// (auth?.rol === "admin" || user?.canCreateProjects); // (auth?.rol === "owner" || user?.canCreateProjects);
return ( return (
<SidebarProvider <SidebarProvider
@@ -783,7 +783,7 @@ export default function Page({ children }: Props) {
</SidebarMenuButton> </SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
))} ))}
{!isCloud && auth?.rol === "admin" && ( {!isCloud && auth?.role === "owner" && (
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton asChild> <SidebarMenuButton asChild>
<UpdateServerButton /> <UpdateServerButton />

View File

@@ -15,6 +15,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { authClient } from "@/lib/auth";
import { Languages } from "@/lib/languages"; import { Languages } from "@/lib/languages";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import useLocale from "@/utils/hooks/use-locale"; import useLocale from "@/utils/hooks/use-locale";
@@ -36,11 +37,11 @@ export const UserNav = () => {
authId: data?.id || "", authId: data?.id || "",
}, },
{ {
enabled: !!data?.id && data?.rol === "user", enabled: !!data?.id && data?.role === "member",
}, },
); );
const { locale, setLocale } = useLocale(); const { locale, setLocale } = useLocale();
const { mutateAsync } = api.auth.logout.useMutation(); // const { mutateAsync } = api.auth.logout.useMutation();
return ( return (
<DropdownMenu> <DropdownMenu>
@@ -50,12 +51,15 @@ export const UserNav = () => {
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
> >
<Avatar className="h-8 w-8 rounded-lg"> <Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={data?.image || ""} alt={data?.image || ""} /> <AvatarImage
src={data?.user?.image || ""}
alt={data?.user?.image || ""}
/>
<AvatarFallback className="rounded-lg">CN</AvatarFallback> <AvatarFallback className="rounded-lg">CN</AvatarFallback>
</Avatar> </Avatar>
<div className="grid flex-1 text-left text-sm leading-tight"> <div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">Account</span> <span className="truncate font-semibold">Account</span>
<span className="truncate text-xs">{data?.email}</span> <span className="truncate text-xs">{data?.user?.email}</span>
</div> </div>
<ChevronsUpDown className="ml-auto size-4" /> <ChevronsUpDown className="ml-auto size-4" />
</SidebarMenuButton> </SidebarMenuButton>
@@ -70,7 +74,7 @@ export const UserNav = () => {
<DropdownMenuLabel className="flex flex-col"> <DropdownMenuLabel className="flex flex-col">
My Account My Account
<span className="text-xs font-normal text-muted-foreground"> <span className="text-xs font-normal text-muted-foreground">
{data?.email} {data?.user?.email}
</span> </span>
</DropdownMenuLabel> </DropdownMenuLabel>
<ModeToggle /> <ModeToggle />
@@ -95,7 +99,7 @@ export const UserNav = () => {
> >
Monitoring Monitoring
</DropdownMenuItem> </DropdownMenuItem>
{(data?.rol === "admin" || user?.canAccessToTraefikFiles) && ( {(data?.role === "owner" || user?.canAccessToTraefikFiles) && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -105,7 +109,7 @@ export const UserNav = () => {
Traefik Traefik
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{(data?.rol === "admin" || user?.canAccessToDocker) && ( {(data?.role === "owner" || user?.canAccessToDocker) && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -118,7 +122,7 @@ export const UserNav = () => {
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{data?.rol === "admin" && ( {data?.role === "owner" && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -139,7 +143,7 @@ export const UserNav = () => {
> >
Profile Profile
</DropdownMenuItem> </DropdownMenuItem>
{data?.rol === "admin" && ( {data?.role === "owner" && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -150,7 +154,7 @@ export const UserNav = () => {
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{data?.rol === "admin" && ( {data?.role === "owner" && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -163,7 +167,7 @@ export const UserNav = () => {
</> </>
)} )}
</DropdownMenuGroup> </DropdownMenuGroup>
{isCloud && data?.rol === "admin" && ( {isCloud && data?.role === "owner" && (
<DropdownMenuItem <DropdownMenuItem
className="cursor-pointer" className="cursor-pointer"
onClick={() => { onClick={() => {
@@ -178,9 +182,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

View File

@@ -0,0 +1,127 @@
CREATE TABLE "user_temp" (
"id" text PRIMARY KEY NOT NULL,
"name" text DEFAULT '' NOT NULL,
"token" text NOT NULL,
"isRegistered" boolean DEFAULT false NOT NULL,
"expirationDate" text NOT NULL,
"createdAt" text NOT NULL,
"canCreateProjects" boolean DEFAULT false NOT NULL,
"canAccessToSSHKeys" boolean DEFAULT false NOT NULL,
"canCreateServices" boolean DEFAULT false NOT NULL,
"canDeleteProjects" boolean DEFAULT false NOT NULL,
"canDeleteServices" boolean DEFAULT false NOT NULL,
"canAccessToDocker" boolean DEFAULT false NOT NULL,
"canAccessToAPI" boolean DEFAULT false NOT NULL,
"canAccessToGitProviders" boolean DEFAULT false NOT NULL,
"canAccessToTraefikFiles" boolean DEFAULT false NOT NULL,
"accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL,
"accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL,
"email" text NOT NULL,
"email_verified" boolean NOT NULL,
"image" text,
"banned" boolean,
"ban_reason" text,
"ban_expires" timestamp,
"updated_at" timestamp NOT NULL,
"serverIp" text,
"certificateType" "certificateType" DEFAULT 'none' NOT NULL,
"host" text,
"letsEncryptEmail" text,
"sshPrivateKey" text,
"enableDockerCleanup" boolean DEFAULT false NOT NULL,
"enableLogRotation" boolean DEFAULT false NOT NULL,
"enablePaidFeatures" boolean DEFAULT false NOT NULL,
"metricsConfig" jsonb DEFAULT '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'::jsonb NOT NULL,
"cleanupCacheApplications" boolean DEFAULT false NOT NULL,
"cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL,
"cleanupCacheOnCompose" boolean DEFAULT false NOT NULL,
"stripeCustomerId" text,
"stripeSubscriptionId" text,
"serversQuantity" integer DEFAULT 0 NOT NULL,
CONSTRAINT "user_temp_email_unique" UNIQUE("email")
);
--> statement-breakpoint
CREATE TABLE "session_temp" (
"id" text PRIMARY KEY NOT NULL,
"expires_at" timestamp NOT NULL,
"token" text NOT NULL,
"created_at" timestamp NOT NULL,
"updated_at" timestamp NOT NULL,
"ip_address" text,
"user_agent" text,
"user_id" text NOT NULL,
"impersonated_by" text,
"active_organization_id" text,
CONSTRAINT "session_temp_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "account" (
"id" text PRIMARY KEY NOT NULL,
"account_id" text NOT NULL,
"provider_id" text NOT NULL,
"user_id" text NOT NULL,
"access_token" text,
"refresh_token" text,
"id_token" text,
"access_token_expires_at" timestamp,
"refresh_token_expires_at" timestamp,
"scope" text,
"password" text,
"is2FAEnabled" boolean DEFAULT false NOT NULL,
"created_at" timestamp NOT NULL,
"updated_at" timestamp NOT NULL,
"resetPasswordToken" text,
"resetPasswordExpiresAt" text,
"confirmationToken" text,
"confirmationExpiresAt" text
);
--> statement-breakpoint
CREATE TABLE "invitation" (
"id" text PRIMARY KEY NOT NULL,
"organization_id" text NOT NULL,
"email" text NOT NULL,
"role" text,
"status" text NOT NULL,
"expires_at" timestamp NOT NULL,
"inviter_id" text NOT NULL
);
--> statement-breakpoint
CREATE TABLE "member" (
"id" text PRIMARY KEY NOT NULL,
"organization_id" text NOT NULL,
"user_id" text NOT NULL,
"role" text NOT NULL,
"created_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "organization" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"slug" text,
"logo" text,
"created_at" timestamp NOT NULL,
"metadata" text,
"owner_id" text NOT NULL,
CONSTRAINT "organization_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
CREATE TABLE "verification" (
"id" text PRIMARY KEY NOT NULL,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expires_at" timestamp NOT NULL,
"created_at" timestamp,
"updated_at" timestamp
);
--> statement-breakpoint
ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "ssh-key" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "git_provider" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "session_temp" ADD CONSTRAINT "session_temp_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;

View File

@@ -0,0 +1,211 @@
-- Custom SQL migration file, put your code below! --
WITH inserted_users AS (
-- Insertar usuarios desde admins
INSERT INTO user_temp (
id,
email,
token,
"email_verified",
"updated_at",
"serverIp",
image,
"certificateType",
host,
"letsEncryptEmail",
"sshPrivateKey",
"enableDockerCleanup",
"enableLogRotation",
"enablePaidFeatures",
"metricsConfig",
"cleanupCacheApplications",
"cleanupCacheOnPreviews",
"cleanupCacheOnCompose",
"stripeCustomerId",
"stripeSubscriptionId",
"serversQuantity",
"expirationDate",
"createdAt"
)
SELECT
a."adminId",
auth.email,
COALESCE(auth.token, ''),
true,
CURRENT_TIMESTAMP,
a."serverIp",
auth.image,
a."certificateType",
a.host,
a."letsEncryptEmail",
a."sshPrivateKey",
a."enableDockerCleanup",
a."enableLogRotation",
a."enablePaidFeatures",
a."metricsConfig",
a."cleanupCacheApplications",
a."cleanupCacheOnPreviews",
a."cleanupCacheOnCompose",
a."stripeCustomerId",
a."stripeSubscriptionId",
a."serversQuantity",
NOW() + INTERVAL '1 year',
NOW()
FROM admin a
JOIN auth ON auth.id = a."authId"
RETURNING *
),
inserted_accounts AS (
-- Insertar cuentas para los admins
INSERT INTO account (
id,
"account_id",
"provider_id",
"user_id",
password,
"is2FAEnabled",
"created_at",
"updated_at"
)
SELECT
gen_random_uuid(),
gen_random_uuid(),
'credential',
a."adminId",
auth.password,
COALESCE(auth."is2FAEnabled", false),
NOW(),
NOW()
FROM admin a
JOIN auth ON auth.id = a."authId"
RETURNING *
),
inserted_orgs AS (
-- Crear organizaciones para cada admin
INSERT INTO organization (
id,
name,
slug,
"owner_id",
"created_at"
)
SELECT
gen_random_uuid(),
'My Organization',
-- Generamos un slug único usando una función de hash
encode(sha256((a."adminId" || CURRENT_TIMESTAMP)::bytea), 'hex'),
a."adminId",
NOW()
FROM admin a
RETURNING *
),
inserted_members AS (
-- Insertar usuarios miembros
INSERT INTO user_temp (
id,
email,
token,
"email_verified",
"updated_at",
image,
"createdAt",
"canAccessToAPI",
"canAccessToDocker",
"canAccessToGitProviders",
"canAccessToSSHKeys",
"canAccessToTraefikFiles",
"canCreateProjects",
"canCreateServices",
"canDeleteProjects",
"canDeleteServices",
"accesedProjects",
"accesedServices",
"expirationDate"
)
SELECT
u."userId",
auth.email,
COALESCE(u.token, ''),
true,
CURRENT_TIMESTAMP,
auth.image,
NOW(),
COALESCE(u."canAccessToAPI", false),
COALESCE(u."canAccessToDocker", false),
COALESCE(u."canAccessToGitProviders", false),
COALESCE(u."canAccessToSSHKeys", false),
COALESCE(u."canAccessToTraefikFiles", false),
COALESCE(u."canCreateProjects", false),
COALESCE(u."canCreateServices", false),
COALESCE(u."canDeleteProjects", false),
COALESCE(u."canDeleteServices", false),
COALESCE(u."accesedProjects", '{}'),
COALESCE(u."accesedServices", '{}'),
NOW() + INTERVAL '1 year'
FROM "user" u
JOIN admin a ON u."adminId" = a."adminId"
JOIN auth ON auth.id = u."authId"
RETURNING *
),
inserted_member_accounts AS (
-- Insertar cuentas para los usuarios miembros
INSERT INTO account (
id,
"account_id",
"provider_id",
"user_id",
password,
"is2FAEnabled",
"created_at",
"updated_at"
)
SELECT
gen_random_uuid(),
gen_random_uuid(),
'credential',
u."userId",
auth.password,
COALESCE(auth."is2FAEnabled", false),
NOW(),
NOW()
FROM "user" u
JOIN admin a ON u."adminId" = a."adminId"
JOIN auth ON auth.id = u."authId"
RETURNING *
),
inserted_admin_members AS (
-- Insertar miembros en las organizaciones (admins como owners)
INSERT INTO member (
id,
"organization_id",
"user_id",
role,
"created_at"
)
SELECT
gen_random_uuid(),
o.id,
a."adminId",
'owner',
NOW()
FROM admin a
JOIN inserted_orgs o ON o."owner_id" = a."adminId"
RETURNING *
)
-- Insertar miembros regulares en las organizaciones
INSERT INTO member (
id,
"organization_id",
"user_id",
role,
"created_at"
)
SELECT
gen_random_uuid(),
o.id,
u."userId",
'member',
NOW()
FROM "user" u
JOIN admin a ON u."adminId" = a."adminId"
JOIN inserted_orgs o ON o."owner_id" = a."adminId";

View File

@@ -0,0 +1,32 @@
ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint
ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "ssh-key" DROP CONSTRAINT "ssh-key_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk";
--> statement-breakpoint
ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1,2 @@
ALTER TABLE "user_temp" ALTER COLUMN "token" SET DEFAULT '';--> statement-breakpoint
ALTER TABLE "user_temp" ADD COLUMN "created_at" timestamp DEFAULT now();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -463,6 +463,34 @@
"when": 1739087857244, "when": 1739087857244,
"tag": "0065_daily_zaladane", "tag": "0065_daily_zaladane",
"breakpoints": true "breakpoints": true
},
{
"idx": 66,
"version": "7",
"when": 1739426913392,
"tag": "0066_yielding_echo",
"breakpoints": true
},
{
"idx": 67,
"version": "7",
"when": 1739427057545,
"tag": "0067_migrate-data",
"breakpoints": true
},
{
"idx": 68,
"version": "7",
"when": 1739428942964,
"tag": "0068_sour_professor_monster",
"breakpoints": true
},
{
"idx": 69,
"version": "7",
"when": 1739664410814,
"tag": "0069_broad_ken_ellis",
"breakpoints": true
} }
] ]
} }

7
apps/dokploy/lib/auth.ts Normal file
View File

@@ -0,0 +1,7 @@
import { organizationClient } from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: "http://localhost:3000", // the base url of your auth server
plugins: [organizationClient()],
});

126
apps/dokploy/migrate.ts Normal file
View File

@@ -0,0 +1,126 @@
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import { nanoid } from "nanoid";
import postgres from "postgres";
import * as schema from "./server/db/schema";
const connectionString = process.env.DATABASE_URL!;
const sql = postgres(connectionString, { max: 1 });
const db = drizzle(sql, {
schema,
});
await db
.transaction(async (db) => {
const admins = await db.query.admins.findMany({
with: {
auth: true,
users: {
with: {
auth: true,
},
},
},
});
for (const admin of admins) {
const user = await db
.insert(schema.users_temp)
.values({
id: admin.adminId,
email: admin.auth.email,
token: admin.auth.token || "",
emailVerified: true,
updatedAt: new Date(),
role: "admin",
serverIp: admin.serverIp,
image: admin.auth.image,
certificateType: admin.certificateType,
host: admin.host,
letsEncryptEmail: admin.letsEncryptEmail,
sshPrivateKey: admin.sshPrivateKey,
enableDockerCleanup: admin.enableDockerCleanup,
enableLogRotation: admin.enableLogRotation,
enablePaidFeatures: admin.enablePaidFeatures,
metricsConfig: admin.metricsConfig,
cleanupCacheApplications: admin.cleanupCacheApplications,
cleanupCacheOnPreviews: admin.cleanupCacheOnPreviews,
cleanupCacheOnCompose: admin.cleanupCacheOnCompose,
stripeCustomerId: admin.stripeCustomerId,
stripeSubscriptionId: admin.stripeSubscriptionId,
serversQuantity: admin.serversQuantity,
})
.returning()
.then((user) => user[0]);
await db.insert(schema.account).values({
providerId: "credential",
userId: user?.id || "",
password: admin.auth.password,
is2FAEnabled: admin.auth.is2FAEnabled || false,
createdAt: new Date(admin.auth.createdAt) || new Date(),
updatedAt: new Date(admin.auth.createdAt) || new Date(),
});
const organization = await db
.insert(schema.organization)
.values({
name: "My Organization",
slug: nanoid(),
ownerId: user?.id || "",
createdAt: new Date(admin.createdAt) || new Date(),
})
.returning()
.then((organization) => organization[0]);
for (const member of admin.users) {
const userTemp = await db
.insert(schema.users_temp)
.values({
id: member.userId,
email: member.auth.email,
token: member.token || "",
emailVerified: true,
updatedAt: new Date(admin.createdAt) || new Date(),
role: "user",
image: member.auth.image,
createdAt: admin.createdAt,
canAccessToAPI: member.canAccessToAPI || false,
canAccessToDocker: member.canAccessToDocker || false,
canAccessToGitProviders: member.canAccessToGitProviders || false,
canAccessToSSHKeys: member.canAccessToSSHKeys || false,
canAccessToTraefikFiles: member.canAccessToTraefikFiles || false,
canCreateProjects: member.canCreateProjects || false,
canCreateServices: member.canCreateServices || false,
canDeleteProjects: member.canDeleteProjects || false,
canDeleteServices: member.canDeleteServices || false,
accessedProjects: member.accessedProjects || [],
accessedServices: member.accessedServices || [],
})
.returning()
.then((userTemp) => userTemp[0]);
await db.insert(schema.account).values({
providerId: "credential",
userId: member?.userId || "",
password: member.auth.password,
is2FAEnabled: member.auth.is2FAEnabled || false,
createdAt: new Date(member.auth.createdAt) || new Date(),
updatedAt: new Date(member.auth.createdAt) || new Date(),
});
await db.insert(schema.member).values({
organizationId: organization?.id || "",
userId: userTemp?.id || "",
role: "admin",
createdAt: new Date(member.createdAt) || new Date(),
});
}
}
})
.then(() => {
console.log("Migration finished");
})
.catch((error) => {
console.error(error);
});

View File

@@ -1,6 +1,6 @@
{ {
"name": "dokploy", "name": "dokploy",
"version": "v0.18.3", "version": "v0.18.2",
"private": true, "private": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module", "type": "module",
@@ -16,6 +16,7 @@
"studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts", "studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
"migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts", "migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts",
"migration:run": "tsx -r dotenv/config migration.ts", "migration:run": "tsx -r dotenv/config migration.ts",
"manual-migration:run": "tsx -r dotenv/config migrate.ts",
"migration:up": "drizzle-kit up --config ./server/db/drizzle.config.ts", "migration:up": "drizzle-kit up --config ./server/db/drizzle.config.ts",
"migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts", "migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts",
"db:push": "drizzle-kit push --config ./server/db/drizzle.config.ts", "db:push": "drizzle-kit push --config ./server/db/drizzle.config.ts",
@@ -35,6 +36,7 @@
"test": "vitest --config __test__/vitest.config.ts" "test": "vitest --config __test__/vitest.config.ts"
}, },
"dependencies": { "dependencies": {
"better-auth": "1.1.16",
"bl": "6.0.11", "bl": "6.0.11",
"rotating-file-stream": "3.2.3", "rotating-file-stream": "3.2.3",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",

View File

@@ -0,0 +1,7 @@
import { auth } from "@dokploy/server/index";
import { toNodeHandler } from "better-auth/node";
// Disallow body parsing, we will parse it manually
export const config = { api: { bodyParser: false } };
export default toNodeHandler(auth.handler);

View File

@@ -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 === "owner") {
const admin = await findAdminByAuthId(auth.id); const admin = await findAdminByAuthId(auth.id);
adminId = admin.adminId; adminId = admin.adminId;
} else { } else {

View File

@@ -1,7 +1,7 @@
import { buffer } from "node:stream/consumers"; import { buffer } from "node:stream/consumers";
import { db } from "@/server/db"; import { db } from "@/server/db";
import { admins, server } from "@/server/db/schema"; import { admins, server, users_temp } from "@/server/db/schema";
import { findAdminById } from "@dokploy/server"; import { findAdminById, findUserById } from "@dokploy/server";
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe"; import Stripe from "stripe";
@@ -64,33 +64,35 @@ export default async function handler(
session.subscription as string, session.subscription as string,
); );
await db await db
.update(admins) .update(users_temp)
.set({ .set({
stripeCustomerId: session.customer as string, stripeCustomerId: session.customer as string,
stripeSubscriptionId: session.subscription as string, stripeSubscriptionId: session.subscription as string,
serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0, serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0,
}) })
.where(eq(admins.adminId, adminId)) .where(eq(users_temp.id, adminId))
.returning(); .returning();
const admin = await findAdminById(adminId); const admin = await findUserById(adminId);
if (!admin) { if (!admin) {
return res.status(400).send("Webhook Error: Admin not found"); return res.status(400).send("Webhook Error: Admin not found");
} }
const newServersQuantity = admin.serversQuantity; const newServersQuantity = admin.serversQuantity;
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); await updateServersBasedOnQuantity(admin.id, newServersQuantity);
break; break;
} }
case "customer.subscription.created": { case "customer.subscription.created": {
const newSubscription = event.data.object as Stripe.Subscription; const newSubscription = event.data.object as Stripe.Subscription;
await db await db
.update(admins) .update(users_temp)
.set({ .set({
stripeSubscriptionId: newSubscription.id, stripeSubscriptionId: newSubscription.id,
stripeCustomerId: newSubscription.customer as string, stripeCustomerId: newSubscription.customer as string,
}) })
.where(eq(admins.stripeCustomerId, newSubscription.customer as string)) .where(
eq(users_temp.stripeCustomerId, newSubscription.customer as string),
)
.returning(); .returning();
break; break;
@@ -100,14 +102,16 @@ export default async function handler(
const newSubscription = event.data.object as Stripe.Subscription; const newSubscription = event.data.object as Stripe.Subscription;
await db await db
.update(admins) .update(users_temp)
.set({ .set({
stripeSubscriptionId: null, stripeSubscriptionId: null,
serversQuantity: 0, serversQuantity: 0,
}) })
.where(eq(admins.stripeCustomerId, newSubscription.customer as string)); .where(
eq(users_temp.stripeCustomerId, newSubscription.customer as string),
);
const admin = await findAdminByStripeCustomerId( const admin = await findUserByStripeCustomerId(
newSubscription.customer as string, newSubscription.customer as string,
); );
@@ -115,13 +119,13 @@ export default async function handler(
return res.status(400).send("Webhook Error: Admin not found"); return res.status(400).send("Webhook Error: Admin not found");
} }
await disableServers(admin.adminId); await disableServers(admin.id);
break; break;
} }
case "customer.subscription.updated": { case "customer.subscription.updated": {
const newSubscription = event.data.object as Stripe.Subscription; const newSubscription = event.data.object as Stripe.Subscription;
const admin = await findAdminByStripeCustomerId( const admin = await findUserByStripeCustomerId(
newSubscription.customer as string, newSubscription.customer as string,
); );
@@ -131,23 +135,23 @@ export default async function handler(
if (newSubscription.status === "active") { if (newSubscription.status === "active") {
await db await db
.update(admins) .update(users_temp)
.set({ .set({
serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0, serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0,
}) })
.where( .where(
eq(admins.stripeCustomerId, newSubscription.customer as string), eq(users_temp.stripeCustomerId, newSubscription.customer as string),
); );
const newServersQuantity = admin.serversQuantity; const newServersQuantity = admin.serversQuantity;
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); await updateServersBasedOnQuantity(admin.id, newServersQuantity);
} else { } else {
await disableServers(admin.adminId); await disableServers(admin.id);
await db await db
.update(admins) .update(users_temp)
.set({ serversQuantity: 0 }) .set({ serversQuantity: 0 })
.where( .where(
eq(admins.stripeCustomerId, newSubscription.customer as string), eq(users_temp.stripeCustomerId, newSubscription.customer as string),
); );
} }
@@ -174,7 +178,7 @@ export default async function handler(
}) })
.where(eq(admins.stripeCustomerId, suscription.customer as string)); .where(eq(admins.stripeCustomerId, suscription.customer as string));
const admin = await findAdminByStripeCustomerId( const admin = await findUserByStripeCustomerId(
suscription.customer as string, suscription.customer as string,
); );
@@ -182,7 +186,7 @@ export default async function handler(
return res.status(400).send("Webhook Error: Admin not found"); return res.status(400).send("Webhook Error: Admin not found");
} }
const newServersQuantity = admin.serversQuantity; const newServersQuantity = admin.serversQuantity;
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); await updateServersBasedOnQuantity(admin.id, newServersQuantity);
break; break;
} }
case "invoice.payment_failed": { case "invoice.payment_failed": {
@@ -193,7 +197,7 @@ export default async function handler(
); );
if (subscription.status !== "active") { if (subscription.status !== "active") {
const admin = await findAdminByStripeCustomerId( const admin = await findUserByStripeCustomerId(
newInvoice.customer as string, newInvoice.customer as string,
); );
@@ -207,7 +211,7 @@ export default async function handler(
}) })
.where(eq(admins.stripeCustomerId, newInvoice.customer as string)); .where(eq(admins.stripeCustomerId, newInvoice.customer as string));
await disableServers(admin.adminId); await disableServers(admin.id);
} }
break; break;
@@ -216,20 +220,20 @@ export default async function handler(
case "customer.deleted": { case "customer.deleted": {
const customer = event.data.object as Stripe.Customer; const customer = event.data.object as Stripe.Customer;
const admin = await findAdminByStripeCustomerId(customer.id); const admin = await findUserByStripeCustomerId(customer.id);
if (!admin) { if (!admin) {
return res.status(400).send("Webhook Error: Admin not found"); return res.status(400).send("Webhook Error: Admin not found");
} }
await disableServers(admin.adminId); await disableServers(admin.id);
await db await db
.update(admins) .update(users_temp)
.set({ .set({
stripeCustomerId: null, stripeCustomerId: null,
stripeSubscriptionId: null, stripeSubscriptionId: null,
serversQuantity: 0, serversQuantity: 0,
}) })
.where(eq(admins.stripeCustomerId, customer.id)); .where(eq(users_temp.stripeCustomerId, customer.id));
break; break;
} }
@@ -240,20 +244,20 @@ export default async function handler(
return res.status(200).json({ received: true }); return res.status(200).json({ received: true });
} }
const disableServers = async (adminId: string) => { const disableServers = async (userId: string) => {
await db await db
.update(server) .update(server)
.set({ .set({
serverStatus: "inactive", serverStatus: "inactive",
}) })
.where(eq(server.adminId, adminId)); .where(eq(server.userId, userId));
}; };
const findAdminByStripeCustomerId = async (stripeCustomerId: string) => { const findUserByStripeCustomerId = async (stripeCustomerId: string) => {
const admin = db.query.admins.findFirst({ const user = db.query.users_temp.findFirst({
where: eq(admins.stripeCustomerId, stripeCustomerId), where: eq(users_temp.stripeCustomerId, stripeCustomerId),
}); });
return admin; return user;
}; };
const activateServer = async (serverId: string) => { const activateServer = async (serverId: string) => {
@@ -270,19 +274,19 @@ const deactivateServer = async (serverId: string) => {
.where(eq(server.serverId, serverId)); .where(eq(server.serverId, serverId));
}; };
export const findServersByAdminIdSorted = async (adminId: string) => { export const findServersByUserIdSorted = async (userId: string) => {
const servers = await db.query.server.findMany({ const servers = await db.query.server.findMany({
where: eq(server.adminId, adminId), where: eq(server.userId, userId),
orderBy: asc(server.createdAt), orderBy: asc(server.createdAt),
}); });
return servers; return servers;
}; };
export const updateServersBasedOnQuantity = async ( export const updateServersBasedOnQuantity = async (
adminId: string, userId: string,
newServersQuantity: number, newServersQuantity: number,
) => { ) => {
const servers = await findServersByAdminIdSorted(adminId); const servers = await findServersByUserIdSorted(userId);
if (servers.length > newServersQuantity) { if (servers.length > newServersQuantity) {
for (const [index, server] of servers.entries()) { for (const [index, server] of servers.entries()) {

View File

@@ -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 === "member") {
const user = await helpers.user.byAuthId.fetch({ const user = await helpers.user.byAuthId.fetch({
authId: auth.id, authId: auth.id,
}); });

View File

@@ -70,9 +70,9 @@ import type {
} from "next"; } from "next";
import Head from "next/head"; import Head from "next/head";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useMemo, useState, type ReactElement } from "react"; import { type ReactElement, useMemo, useState } from "react";
import superjson from "superjson";
import { toast } from "sonner"; import { toast } from "sonner";
import superjson from "superjson";
export type Services = { export type Services = {
appName: string; appName: string;
@@ -206,7 +206,7 @@ const Project = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
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 === "owner" || 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>

View File

@@ -93,7 +93,7 @@ const Service = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
@@ -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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={applicationId} type="application" /> <DeleteService id={applicationId} type="application" />
)} )}
</div> </div>

View File

@@ -87,7 +87,7 @@ const Service = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
@@ -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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={composeId} type="compose" /> <DeleteService id={composeId} type="compose" />
)} )}
</div> </div>

View File

@@ -68,7 +68,7 @@ const Mariadb = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={mariadbId} type="mariadb" /> <DeleteService id={mariadbId} type="mariadb" />
)} )}
</div> </div>

View File

@@ -68,7 +68,7 @@ const Mongo = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
@@ -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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={mongoId} type="mongo" /> <DeleteService id={mongoId} type="mongo" />
)} )}
</div> </div>

View File

@@ -67,7 +67,7 @@ const MySql = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
@@ -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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={mysqlId} type="mysql" /> <DeleteService id={mysqlId} type="mysql" />
)} )}
</div> </div>

View File

@@ -66,7 +66,7 @@ const Postgresql = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={postgresId} type="postgres" /> <DeleteService id={postgresId} type="postgres" />
)} )}
</div> </div>

View File

@@ -67,7 +67,7 @@ const Redis = (
authId: auth?.id || "", authId: auth?.id || "",
}, },
{ {
enabled: !!auth?.id && auth?.rol === "user", enabled: !!auth?.id && auth?.role === "member",
}, },
); );
@@ -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 === "owner" || user?.canDeleteServices) && (
<DeleteService id={redisId} type="redis" /> <DeleteService id={redisId} type="redis" />
)} )}
</div> </div>

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
const user = await helpers.user.byAuthId.fetch({ const user = await helpers.user.byAuthId.fetch({
authId: auth.id, authId: auth.id,
}); });

View File

@@ -190,7 +190,7 @@ export async function getServerSideProps(
}, },
}; };
} }
if (user.rol === "user") { if (user.role === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "owner") && <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,
}); });

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -107,7 +107,7 @@ export async function getServerSideProps(
}, },
}; };
} }
if (user.rol === "user") { if (user.role === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -36,7 +36,7 @@ export async function getServerSideProps(
}, },
}; };
} }
if (user.rol === "user") { if (user.role === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
const user = await helpers.user.byAuthId.fetch({ const user = await helpers.user.byAuthId.fetch({
authId: auth.id, authId: auth.id,
}); });

View File

@@ -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 === "member") {
return { return {
redirect: { redirect: {
permanent: true, permanent: true,

View File

@@ -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 === "member") {
const user = await helpers.user.byAuthId.fetch({ const user = await helpers.user.byAuthId.fetch({
authId: auth.id, authId: auth.id,
}); });

View File

@@ -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 === "member") {
const user = await helpers.user.byAuthId.fetch({ const user = await helpers.user.byAuthId.fetch({
authId: auth.id, authId: auth.id,
}); });

View File

@@ -13,10 +13,14 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
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 { IS_CLOUD, auth, isAdminPresent } from "@dokploy/server";
import { validateRequest } from "@dokploy/server/lib/auth";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { Session, getSessionCookie } 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";
@@ -56,17 +60,18 @@ interface Props {
IS_CLOUD: boolean; IS_CLOUD: boolean;
} }
export default function Home({ IS_CLOUD }: Props) { export default function Home({ IS_CLOUD }: Props) {
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [error, setError] = useState<string | null>(null);
const [temp, setTemp] = useState<AuthResponse>({ const [temp, setTemp] = useState<AuthResponse>({
is2FAEnabled: false, is2FAEnabled: false,
authId: "", authId: "",
}); });
const { mutateAsync, isLoading, error, isError } =
api.auth.login.useMutation();
const router = useRouter(); const router = useRouter();
const form = useForm<Login>({ const form = useForm<Login>({
defaultValues: { defaultValues: {
email: "", email: "siumauricio@hotmail.com",
password: "", password: "Password123",
}, },
resolver: zodResolver(loginSchema), resolver: zodResolver(loginSchema),
}); });
@@ -76,25 +81,49 @@ export default function Home({ IS_CLOUD }: Props) {
}, [form, form.reset, form.formState.isSubmitSuccessful]); }, [form, form.reset, form.formState.isSubmitSuccessful]);
const onSubmit = async (values: Login) => { const onSubmit = async (values: Login) => {
await mutateAsync({ setIsLoading(true);
email: values.email.toLowerCase(), const { data, error } = await authClient.signIn.email({
email: values.email,
password: values.password, password: values.password,
}) });
.then((data) => {
if (data.is2FAEnabled) { if (!error) {
setTemp(data); // if (data) {
} else { // setTemp(data);
toast.success("Successfully signed in", { // } else {
duration: 2000, toast.success("Successfully signed in", {
}); duration: 2000,
router.push("/dashboard/projects");
}
})
.catch(() => {
toast.error("Signin failed", {
duration: 2000,
});
}); });
router.push("/dashboard/projects");
// }
} else {
setIsError(true);
setError(error.message ?? "Error to signup");
toast.error("Error to sign up", {
description: error.message,
});
}
setIsLoading(false);
// await mutateAsync({
// email: values.email.toLowerCase(),
// password: values.password,
// })
// .then((data) => {
// if (data.is2FAEnabled) {
// setTemp(data);
// } else {
// toast.success("Successfully signed in", {
// duration: 2000,
// });
// router.push("/dashboard/projects");
// }
// })
// .catch(() => {
// toast.error("Signin failed", {
// duration: 2000,
// });
// });
}; };
return ( return (
<> <>
@@ -111,7 +140,7 @@ export default function Home({ IS_CLOUD }: Props) {
</div> </div>
{isError && ( {isError && (
<AlertBlock type="error" className="my-2"> <AlertBlock type="error" className="my-2">
<span>{error?.message}</span> <span>{error}</span>
</AlertBlock> </AlertBlock>
)} )}
<CardContent className="p-0"> <CardContent className="p-0">
@@ -203,8 +232,7 @@ Home.getLayout = (page: ReactElement) => {
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 { return {
redirect: { redirect: {
@@ -232,7 +260,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}; };
} }
const { user } = await validateRequest(context.req, context.res); const { user } = await validateRequest(context.req);
if (user) { if (user) {
return { return {

View File

@@ -17,6 +17,7 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { authClient } from "@/lib/auth";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
@@ -31,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, {
@@ -79,9 +83,10 @@ const Register = ({ isCloud }: Props) => {
const form = useForm<Register>({ const form = useForm<Register>({
defaultValues: { defaultValues: {
email: "", name: "Mauricio Siu",
password: "", email: "user5@yopmail.com",
confirmPassword: "", password: "Password1234",
confirmPassword: "Password1234",
}, },
resolver: zodResolver(registerSchema), resolver: zodResolver(registerSchema),
}); });
@@ -91,19 +96,33 @@ const Register = ({ isCloud }: Props) => {
}, [form, form.reset, form.formState.isSubmitSuccessful]); }, [form, form.reset, form.formState.isSubmitSuccessful]);
const onSubmit = async (values: Register) => { const onSubmit = async (values: Register) => {
await mutateAsync({ const { data, error } = await authClient.signUp.email({
email: values.email.toLowerCase(), email: values.email,
password: values.password, password: values.password,
}) name: values.name,
.then(() => { });
toast.success("User registered successfuly", {
duration: 2000, // const { data, error } = await authClient.admin.createUser({
}); // name: values.name,
if (!isCloud) { // email: values.email,
router.push("/"); // password: values.password,
} // role: "superAdmin",
}) // });
.catch((e) => e);
// consol/e.log(data, error);
// await mutateAsync({
// email: values.email.toLowerCase(),
// password: values.password,
// })
// .then(() => {
// toast.success("User registered successfuly", {
// duration: 2000,
// });
// if (!isCloud) {
// router.push("/");
// }
// })
// .catch((e) => e);
}; };
return ( return (
<div className=""> <div className="">
@@ -147,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"

View File

@@ -58,7 +58,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}, },
transformer: superjson, transformer: superjson,
}); });
if (user.rol === "user") { if (user.role === "member") {
const result = await helpers.user.byAuthId.fetch({ const result = await helpers.user.byAuthId.fetch({
authId: user.id, authId: user.id,
}); });

View File

@@ -6,19 +6,17 @@ import {
apiRemoveUser, apiRemoveUser,
apiUpdateAdmin, apiUpdateAdmin,
apiUpdateWebServerMonitoring, apiUpdateWebServerMonitoring,
users,
} from "@/server/db/schema"; } from "@/server/db/schema";
import { import {
IS_CLOUD, IS_CLOUD,
createInvitation, createInvitation,
findAdminById,
findUserByAuthId, findUserByAuthId,
findUserById, findUserById,
getUserByToken, getUserByToken,
removeUserByAuthId, removeUserById,
setupWebMonitoring, setupWebMonitoring,
updateAdmin,
updateAdminById, updateAdminById,
updateUser,
} from "@dokploy/server"; } from "@dokploy/server";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@@ -32,7 +30,7 @@ import {
export const adminRouter = createTRPCRouter({ export const adminRouter = createTRPCRouter({
one: adminProcedure.query(async ({ ctx }) => { one: adminProcedure.query(async ({ ctx }) => {
const { sshPrivateKey, ...rest } = await findAdminById(ctx.user.adminId); const { sshPrivateKey, ...rest } = await findUserById(ctx.user.id);
return { return {
haveSSH: !!sshPrivateKey, haveSSH: !!sshPrivateKey,
...rest, ...rest,
@@ -41,21 +39,21 @@ export const adminRouter = createTRPCRouter({
update: adminProcedure update: adminProcedure
.input(apiUpdateAdmin) .input(apiUpdateAdmin)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to update this admin", message: "You are not allowed to update this admin",
}); });
} }
const { authId } = await findAdminById(ctx.user.adminId); const { id } = await findUserById(ctx.user.id);
// @ts-ignore // @ts-ignore
return updateAdmin(authId, input); return updateAdmin(id, input);
}), }),
createUserInvitation: adminProcedure createUserInvitation: adminProcedure
.input(apiCreateUserInvitation) .input(apiCreateUserInvitation)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
await createInvitation(input, ctx.user.adminId); await createInvitation(input, ctx.user.id);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -69,15 +67,16 @@ export const adminRouter = createTRPCRouter({
.input(apiRemoveUser) .input(apiRemoveUser)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const user = await findUserByAuthId(input.authId); const user = await findUserById(input.id);
if (user.adminId !== ctx.user.adminId) { if (user.id !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to delete this user", message: "You are not allowed to delete this user",
}); });
} }
return await removeUserByAuthId(input.authId);
return await removeUserById(input.id);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -95,20 +94,23 @@ export const adminRouter = createTRPCRouter({
.input(apiAssignPermissions) .input(apiAssignPermissions)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const user = await findUserById(input.userId); const user = await findUserById(input.id);
if (user.adminId !== ctx.user.adminId) { if (user.id !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to assign permissions", message: "You are not allowed to assign permissions",
}); });
} }
await db await updateUser(user.id, {
.update(users) ...input,
.set({ });
...input, // await db
}) // .update(users)
.where(eq(users.userId, input.userId)); // .set({
// ...input,
// })
// .where(eq(users.userId, input.userId));
} catch (error) { } catch (error) {
throw error; throw error;
} }
@@ -124,15 +126,15 @@ export const adminRouter = createTRPCRouter({
message: "Feature disabled on cloud", message: "Feature disabled on cloud",
}); });
} }
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
if (admin.adminId !== ctx.user.adminId) { if (user.id !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to setup this server", message: "You are not authorized to setup this server",
}); });
} }
await updateAdminById(admin.adminId, { await updateUser(user.id, {
metricsConfig: { metricsConfig: {
server: { server: {
type: "Dokploy", type: "Dokploy",
@@ -156,18 +158,19 @@ export const adminRouter = createTRPCRouter({
}, },
}, },
}); });
const currentServer = await setupWebMonitoring(admin.adminId);
const currentServer = await setupWebMonitoring(user.id);
return currentServer; return currentServer;
} catch (error) { } catch (error) {
throw error; throw error;
} }
}), }),
getMetricsToken: protectedProcedure.query(async ({ ctx }) => { getMetricsToken: protectedProcedure.query(async ({ ctx }) => {
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
return { return {
serverIp: admin.serverIp, serverIp: user.serverIp,
enabledFeatures: admin.enablePaidFeatures, enabledFeatures: user.enablePaidFeatures,
metricsConfig: admin?.metricsConfig, metricsConfig: user?.metricsConfig,
}; };
}), }),

View File

@@ -60,8 +60,8 @@ export const applicationRouter = createTRPCRouter({
.input(apiCreateApplication) .input(apiCreateApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -72,7 +72,7 @@ export const applicationRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
@@ -80,8 +80,8 @@ export const applicationRouter = createTRPCRouter({
} }
const newApplication = await createApplication(input); const newApplication = await createApplication(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newApplication.applicationId); await addNewService(ctx.user.id, newApplication.applicationId);
} }
return newApplication; return newApplication;
} catch (error: unknown) { } catch (error: unknown) {
@@ -98,15 +98,11 @@ export const applicationRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneApplication) .input(apiFindOneApplication)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess( await checkServiceAccess(ctx.user.id, input.applicationId, "access");
ctx.user.authId,
input.applicationId,
"access",
);
} }
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -119,7 +115,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiReloadApplication) .input(apiReloadApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this application", message: "You are not authorized to reload this application",
@@ -144,16 +140,12 @@ export const applicationRouter = createTRPCRouter({
delete: protectedProcedure delete: protectedProcedure
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess( await checkServiceAccess(ctx.user.id, input.applicationId, "delete");
ctx.user.authId,
input.applicationId,
"delete",
);
} }
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this application", message: "You are not authorized to delete this application",
@@ -194,7 +186,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findApplicationById(input.applicationId); const service = await findApplicationById(input.applicationId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this application", message: "You are not authorized to stop this application",
@@ -214,7 +206,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findApplicationById(input.applicationId); const service = await findApplicationById(input.applicationId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this application", message: "You are not authorized to start this application",
@@ -235,7 +227,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to redeploy this application", message: "You are not authorized to redeploy this application",
@@ -268,7 +260,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariables) .input(apiSaveEnvironmentVariables)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",
@@ -284,7 +276,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveBuildType) .input(apiSaveBuildType)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this build type", message: "You are not authorized to save this build type",
@@ -305,7 +297,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGithubProvider) .input(apiSaveGithubProvider)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this github provider", message: "You are not authorized to save this github provider",
@@ -327,7 +319,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGitlabProvider) .input(apiSaveGitlabProvider)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this gitlab provider", message: "You are not authorized to save this gitlab provider",
@@ -351,7 +343,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveBitbucketProvider) .input(apiSaveBitbucketProvider)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this bitbucket provider", message: "You are not authorized to save this bitbucket provider",
@@ -373,7 +365,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveDockerProvider) .input(apiSaveDockerProvider)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this docker provider", message: "You are not authorized to save this docker provider",
@@ -394,7 +386,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGitProvider) .input(apiSaveGitProvider)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this git provider", message: "You are not authorized to save this git provider",
@@ -415,7 +407,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to mark this application as running", message: "You are not authorized to mark this application as running",
@@ -427,7 +419,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiUpdateApplication) .input(apiUpdateApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this application", message: "You are not authorized to update this application",
@@ -451,7 +443,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to refresh this application", message: "You are not authorized to refresh this application",
@@ -466,7 +458,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this application", message: "You are not authorized to deploy this application",
@@ -500,7 +492,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to clean this application", message: "You are not authorized to clean this application",
@@ -513,7 +505,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to read this application", message: "You are not authorized to read this application",
@@ -548,7 +540,7 @@ export const applicationRouter = createTRPCRouter({
const app = await findApplicationById(input.applicationId as string); const app = await findApplicationById(input.applicationId as string);
if (app.project.adminId !== ctx.user.adminId) { if (app.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this application", message: "You are not authorized to deploy this application",
@@ -590,7 +582,7 @@ export const applicationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this application", message: "You are not authorized to update this application",

View File

@@ -7,6 +7,7 @@ import {
apiVerify2FA, apiVerify2FA,
apiVerifyLogin2FA, apiVerifyLogin2FA,
auth, auth,
member,
} from "@/server/db/schema"; } from "@/server/db/schema";
import { WEBSITE_URL } from "@/server/utils/stripe"; import { WEBSITE_URL } from "@/server/utils/stripe";
import { import {
@@ -16,22 +17,23 @@ import {
createUser, createUser,
findAuthByEmail, findAuthByEmail,
findAuthById, findAuthById,
findUserById,
generate2FASecret, generate2FASecret,
getUserByToken, getUserByToken,
lucia, lucia,
luciaToken, luciaToken,
removeAdminByAuthId, removeAdminByAuthId,
removeUserByAuthId,
sendDiscordNotification, sendDiscordNotification,
sendEmailNotification, sendEmailNotification,
updateAuthById, updateAuthById,
updateUser,
validateRequest, validateRequest,
verify2FA, verify2FA,
} from "@dokploy/server"; } from "@dokploy/server";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import * as bcrypt from "bcrypt"; import * as bcrypt from "bcrypt";
import { isBefore } from "date-fns"; import { isBefore } from "date-fns";
import { eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { db } from "../../db"; import { db } from "../../db";
@@ -169,8 +171,17 @@ export const authRouter = createTRPCRouter({
}), }),
get: protectedProcedure.query(async ({ ctx }) => { get: protectedProcedure.query(async ({ ctx }) => {
const auth = await findAuthById(ctx.user.authId); const memberResult = await db.query.member.findFirst({
return auth; where: and(
eq(member.userId, ctx.user.id),
eq(member.organizationId, ctx.session?.activeOrganizationId || ""),
),
with: {
user: true,
},
});
return memberResult;
}), }),
logout: protectedProcedure.mutation(async ({ ctx }) => { logout: protectedProcedure.mutation(async ({ ctx }) => {
@@ -243,7 +254,7 @@ export const authRouter = createTRPCRouter({
await lucia.invalidateSession(session.id); await lucia.invalidateSession(session.id);
res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
if (ctx.user.rol === "admin") { if (ctx.user.rol === "owner") {
await removeAdminByAuthId(ctx.user.authId); await removeAdminByAuthId(ctx.user.authId);
} else { } else {
await removeUserByAuthId(ctx.user.authId); await removeUserByAuthId(ctx.user.authId);
@@ -253,19 +264,18 @@ export const authRouter = createTRPCRouter({
}), }),
generateToken: protectedProcedure.mutation(async ({ ctx, input }) => { generateToken: protectedProcedure.mutation(async ({ ctx, input }) => {
const auth = await findAuthById(ctx.user.authId); const auth = await findUserById(ctx.user.id);
console.log(auth);
if (auth.token) { if (auth.token) {
await luciaToken.invalidateSession(auth.token); await luciaToken.invalidateSession(auth.token);
} }
const session = await luciaToken.createSession(auth?.id || "", { // const session = await luciaToken.createSession(auth?.id || "", {
expiresIn: 60 * 60 * 24 * 30, // expiresIn: 60 * 60 * 24 * 30,
}); // });
// await updateUser(auth.id, {
await updateAuthById(auth.id, { // token: session.id,
token: session.id, // });
});
return auth; return auth;
}), }),
verifyToken: protectedProcedure.mutation(async () => { verifyToken: protectedProcedure.mutation(async () => {
@@ -277,7 +287,7 @@ export const authRouter = createTRPCRouter({
}), }),
generate2FASecret: protectedProcedure.query(async ({ ctx }) => { generate2FASecret: protectedProcedure.query(async ({ ctx }) => {
return await generate2FASecret(ctx.user.authId); return await generate2FASecret(ctx.user.id);
}), }),
verify2FASetup: protectedProcedure verify2FASetup: protectedProcedure
.input(apiVerify2FA) .input(apiVerify2FA)

View File

@@ -23,7 +23,7 @@ export const bitbucketRouter = createTRPCRouter({
.input(apiCreateBitbucket) .input(apiCreateBitbucket)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createBitbucket(input, ctx.user.adminId); return await createBitbucket(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -38,7 +38,7 @@ export const bitbucketRouter = createTRPCRouter({
const bitbucketProvider = await findBitbucketById(input.bitbucketId); const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if ( if (
IS_CLOUD && IS_CLOUD &&
bitbucketProvider.gitProvider.adminId !== ctx.user.adminId bitbucketProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -61,7 +61,7 @@ export const bitbucketRouter = createTRPCRouter({
if (IS_CLOUD) { if (IS_CLOUD) {
// TODO: mAyBe a rEfaCtoR 🤫 // TODO: mAyBe a rEfaCtoR 🤫
result = result.filter( result = result.filter(
(provider) => provider.gitProvider.adminId === ctx.user.adminId, (provider) => provider.gitProvider.userId === ctx.user.ownerId,
); );
} }
return result; return result;
@@ -73,7 +73,7 @@ export const bitbucketRouter = createTRPCRouter({
const bitbucketProvider = await findBitbucketById(input.bitbucketId); const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if ( if (
IS_CLOUD && IS_CLOUD &&
bitbucketProvider.gitProvider.adminId !== ctx.user.adminId bitbucketProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -91,7 +91,7 @@ export const bitbucketRouter = createTRPCRouter({
); );
if ( if (
IS_CLOUD && IS_CLOUD &&
bitbucketProvider.gitProvider.adminId !== ctx.user.adminId bitbucketProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -108,7 +108,7 @@ export const bitbucketRouter = createTRPCRouter({
const bitbucketProvider = await findBitbucketById(input.bitbucketId); const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if ( if (
IS_CLOUD && IS_CLOUD &&
bitbucketProvider.gitProvider.adminId !== ctx.user.adminId bitbucketProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -132,7 +132,7 @@ export const bitbucketRouter = createTRPCRouter({
const bitbucketProvider = await findBitbucketById(input.bitbucketId); const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if ( if (
IS_CLOUD && IS_CLOUD &&
bitbucketProvider.gitProvider.adminId !== ctx.user.adminId bitbucketProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -142,7 +142,7 @@ export const bitbucketRouter = createTRPCRouter({
} }
return await updateBitbucket(input.bitbucketId, { return await updateBitbucket(input.bitbucketId, {
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
}), }),
}); });

View File

@@ -25,14 +25,14 @@ export const certificateRouter = createTRPCRouter({
message: "Please set a server to create a certificate", message: "Please set a server to create a certificate",
}); });
} }
return await createCertificate(input, ctx.user.adminId); return await createCertificate(input, ctx.user.ownerId);
}), }),
one: adminProcedure one: adminProcedure
.input(apiFindCertificate) .input(apiFindCertificate)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const certificates = await findCertificateById(input.certificateId); const certificates = await findCertificateById(input.certificateId);
if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) { if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to access this certificate", message: "You are not allowed to access this certificate",
@@ -44,7 +44,7 @@ export const certificateRouter = createTRPCRouter({
.input(apiFindCertificate) .input(apiFindCertificate)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const certificates = await findCertificateById(input.certificateId); const certificates = await findCertificateById(input.certificateId);
if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) { if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to delete this certificate", message: "You are not allowed to delete this certificate",
@@ -56,7 +56,7 @@ export const certificateRouter = createTRPCRouter({
all: adminProcedure.query(async ({ ctx }) => { all: adminProcedure.query(async ({ ctx }) => {
return await db.query.certificates.findMany({ return await db.query.certificates.findMany({
// TODO: Remove this line when the cloud version is ready // TODO: Remove this line when the cloud version is ready
...(IS_CLOUD && { where: eq(certificates.adminId, ctx.user.adminId) }), ...(IS_CLOUD && { where: eq(certificates.userId, ctx.user.ownerId) }),
}); });
}), }),
}); });

View File

@@ -44,6 +44,7 @@ import {
findDomainsByComposeId, findDomainsByComposeId,
findProjectById, findProjectById,
findServerById, findServerById,
findUserById,
loadServices, loadServices,
randomizeComposeFile, randomizeComposeFile,
randomizeIsolatedDeploymentComposeFile, randomizeIsolatedDeploymentComposeFile,
@@ -60,8 +61,8 @@ export const composeRouter = createTRPCRouter({
.input(apiCreateCompose) .input(apiCreateCompose)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -71,7 +72,7 @@ export const composeRouter = createTRPCRouter({
}); });
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
@@ -79,8 +80,8 @@ export const composeRouter = createTRPCRouter({
} }
const newService = await createCompose(input); const newService = await createCompose(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newService.composeId); await addNewService(ctx.user.id, newService.composeId);
} }
return newService; return newService;
@@ -92,12 +93,12 @@ export const composeRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindCompose) .input(apiFindCompose)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.composeId, "access"); await checkServiceAccess(ctx.user.id, input.composeId, "access");
} }
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -110,7 +111,7 @@ export const composeRouter = createTRPCRouter({
.input(apiUpdateCompose) .input(apiUpdateCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this compose", message: "You are not authorized to update this compose",
@@ -121,12 +122,12 @@ export const composeRouter = createTRPCRouter({
delete: protectedProcedure delete: protectedProcedure
.input(apiDeleteCompose) .input(apiDeleteCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); await checkServiceAccess(ctx.user.id, input.composeId, "delete");
} }
const composeResult = await findComposeById(input.composeId); const composeResult = await findComposeById(input.composeId);
if (composeResult.project.adminId !== ctx.user.adminId) { if (composeResult.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this compose", message: "You are not authorized to delete this compose",
@@ -157,7 +158,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to clean this compose", message: "You are not authorized to clean this compose",
@@ -170,7 +171,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFetchServices) .input(apiFetchServices)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to load this compose", message: "You are not authorized to load this compose",
@@ -184,7 +185,7 @@ export const composeRouter = createTRPCRouter({
try { try {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to fetch this compose", message: "You are not authorized to fetch this compose",
@@ -209,7 +210,7 @@ export const composeRouter = createTRPCRouter({
.input(apiRandomizeCompose) .input(apiRandomizeCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to randomize this compose", message: "You are not authorized to randomize this compose",
@@ -221,7 +222,7 @@ export const composeRouter = createTRPCRouter({
.input(apiRandomizeCompose) .input(apiRandomizeCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to randomize this compose", message: "You are not authorized to randomize this compose",
@@ -236,7 +237,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to get this compose", message: "You are not authorized to get this compose",
@@ -254,7 +255,7 @@ export const composeRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this compose", message: "You are not authorized to deploy this compose",
@@ -287,7 +288,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to redeploy this compose", message: "You are not authorized to redeploy this compose",
@@ -319,7 +320,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this compose", message: "You are not authorized to stop this compose",
@@ -333,7 +334,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this compose", message: "You are not authorized to stop this compose",
@@ -348,7 +349,7 @@ export const composeRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to get this compose", message: "You are not authorized to get this compose",
@@ -361,7 +362,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to refresh this compose", message: "You are not authorized to refresh this compose",
@@ -375,8 +376,8 @@ export const composeRouter = createTRPCRouter({
deployTemplate: protectedProcedure deployTemplate: protectedProcedure
.input(apiCreateComposeByTemplate) .input(apiCreateComposeByTemplate)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -390,7 +391,7 @@ export const composeRouter = createTRPCRouter({
const generate = await loadTemplateModule(input.id as TemplatesKeys); const generate = await loadTemplateModule(input.id as TemplatesKeys);
const admin = await findAdminById(ctx.user.adminId); const admin = await findUserById(ctx.user.ownerId);
let serverIp = admin.serverIp || "127.0.0.1"; let serverIp = admin.serverIp || "127.0.0.1";
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
@@ -418,8 +419,8 @@ export const composeRouter = createTRPCRouter({
isolatedDeployment: true, isolatedDeployment: true,
}); });
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, compose.composeId); await addNewService(ctx.user.id, compose.composeId);
} }
if (mounts && mounts?.length > 0) { if (mounts && mounts?.length > 0) {

View File

@@ -19,7 +19,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByApplication) .input(apiFindAllByApplication)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -32,7 +32,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByCompose) .input(apiFindAllByCompose)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -44,7 +44,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByServer) .input(apiFindAllByServer)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this server", message: "You are not authorized to access this server",

View File

@@ -28,7 +28,7 @@ export const destinationRouter = createTRPCRouter({
.input(apiCreateDestination) .input(apiCreateDestination)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createDestintation(input, ctx.user.adminId); return await createDestintation(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -84,7 +84,7 @@ export const destinationRouter = createTRPCRouter({
.input(apiFindOneDestination) .input(apiFindOneDestination)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const destination = await findDestinationById(input.destinationId); const destination = await findDestinationById(input.destinationId);
if (destination.adminId !== ctx.user.adminId) { if (destination.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to access this destination", message: "You are not allowed to access this destination",
@@ -94,7 +94,7 @@ export const destinationRouter = createTRPCRouter({
}), }),
all: protectedProcedure.query(async ({ ctx }) => { all: protectedProcedure.query(async ({ ctx }) => {
return await db.query.destinations.findMany({ return await db.query.destinations.findMany({
where: eq(destinations.adminId, ctx.user.adminId), where: eq(destinations.userId, ctx.user.ownerId),
}); });
}), }),
remove: adminProcedure remove: adminProcedure
@@ -103,7 +103,7 @@ export const destinationRouter = createTRPCRouter({
try { try {
const destination = await findDestinationById(input.destinationId); const destination = await findDestinationById(input.destinationId);
if (destination.adminId !== ctx.user.adminId) { if (destination.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to delete this destination", message: "You are not allowed to delete this destination",
@@ -111,7 +111,7 @@ export const destinationRouter = createTRPCRouter({
} }
return await removeDestinationById( return await removeDestinationById(
input.destinationId, input.destinationId,
ctx.user.adminId, ctx.user.ownerId,
); );
} catch (error) { } catch (error) {
throw error; throw error;
@@ -122,7 +122,7 @@ export const destinationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const destination = await findDestinationById(input.destinationId); const destination = await findDestinationById(input.destinationId);
if (destination.adminId !== ctx.user.adminId) { if (destination.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to update this destination", message: "You are not allowed to update this destination",
@@ -130,7 +130,7 @@ export const destinationRouter = createTRPCRouter({
} }
return await updateDestinationById(input.destinationId, { return await updateDestinationById(input.destinationId, {
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw error; throw error;

View File

@@ -30,7 +30,7 @@ export const domainRouter = createTRPCRouter({
try { try {
if (input.domainType === "compose" && input.composeId) { if (input.domainType === "compose" && input.composeId) {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -38,7 +38,7 @@ export const domainRouter = createTRPCRouter({
} }
} else if (input.domainType === "application" && input.applicationId) { } else if (input.domainType === "application" && input.applicationId) {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -58,7 +58,7 @@ export const domainRouter = createTRPCRouter({
.input(apiFindOneApplication) .input(apiFindOneApplication)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -70,7 +70,7 @@ export const domainRouter = createTRPCRouter({
.input(apiFindCompose) .input(apiFindCompose)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -83,7 +83,7 @@ export const domainRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
return generateTraefikMeDomain( return generateTraefikMeDomain(
input.appName, input.appName,
ctx.user.adminId, ctx.user.ownerId,
input.serverId, input.serverId,
); );
}), }),
@@ -95,7 +95,7 @@ export const domainRouter = createTRPCRouter({
if (currentDomain.applicationId) { if (currentDomain.applicationId) {
const newApp = await findApplicationById(currentDomain.applicationId); const newApp = await findApplicationById(currentDomain.applicationId);
if (newApp.project.adminId !== ctx.user.adminId) { if (newApp.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -103,7 +103,7 @@ export const domainRouter = createTRPCRouter({
} }
} else if (currentDomain.composeId) { } else if (currentDomain.composeId) {
const newCompose = await findComposeById(currentDomain.composeId); const newCompose = await findComposeById(currentDomain.composeId);
if (newCompose.project.adminId !== ctx.user.adminId) { if (newCompose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -114,7 +114,7 @@ export const domainRouter = createTRPCRouter({
currentDomain.previewDeploymentId, currentDomain.previewDeploymentId,
); );
if ( if (
newPreviewDeployment.application.project.adminId !== ctx.user.adminId newPreviewDeployment.application.project.userId !== ctx.user.ownerId
) { ) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -143,7 +143,7 @@ export const domainRouter = createTRPCRouter({
const domain = await findDomainById(input.domainId); const domain = await findDomainById(input.domainId);
if (domain.applicationId) { if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId); const application = await findApplicationById(domain.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -151,7 +151,7 @@ export const domainRouter = createTRPCRouter({
} }
} else if (domain.composeId) { } else if (domain.composeId) {
const compose = await findComposeById(domain.composeId); const compose = await findComposeById(domain.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",
@@ -166,7 +166,7 @@ export const domainRouter = createTRPCRouter({
const domain = await findDomainById(input.domainId); const domain = await findDomainById(input.domainId);
if (domain.applicationId) { if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId); const application = await findApplicationById(domain.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -174,7 +174,7 @@ export const domainRouter = createTRPCRouter({
} }
} else if (domain.composeId) { } else if (domain.composeId) {
const compose = await findComposeById(domain.composeId); const compose = await findComposeById(domain.composeId);
if (compose.project.adminId !== ctx.user.adminId) { if (compose.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this compose", message: "You are not authorized to access this compose",

View File

@@ -18,7 +18,7 @@ export const gitProviderRouter = createTRPCRouter({
github: true, github: true,
}, },
orderBy: desc(gitProvider.createdAt), orderBy: desc(gitProvider.createdAt),
...(IS_CLOUD && { where: eq(gitProvider.adminId, ctx.user.adminId) }), ...(IS_CLOUD && { where: eq(gitProvider.userId, ctx.user.ownerId) }),
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
}); });
}), }),
@@ -28,7 +28,7 @@ export const gitProviderRouter = createTRPCRouter({
try { try {
const gitProvider = await findGitProviderById(input.gitProviderId); const gitProvider = await findGitProviderById(input.gitProviderId);
if (IS_CLOUD && gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && gitProvider.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",

View File

@@ -20,7 +20,7 @@ export const githubRouter = createTRPCRouter({
.input(apiFindOneGithub) .input(apiFindOneGithub)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId); const githubProvider = await findGithubById(input.githubId);
if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -33,7 +33,7 @@ export const githubRouter = createTRPCRouter({
.input(apiFindOneGithub) .input(apiFindOneGithub)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId); const githubProvider = await findGithubById(input.githubId);
if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -46,7 +46,7 @@ export const githubRouter = createTRPCRouter({
.input(apiFindGithubBranches) .input(apiFindGithubBranches)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId || ""); const githubProvider = await findGithubById(input.githubId || "");
if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -65,7 +65,7 @@ export const githubRouter = createTRPCRouter({
if (IS_CLOUD) { if (IS_CLOUD) {
// TODO: mAyBe a rEfaCtoR 🤫 // TODO: mAyBe a rEfaCtoR 🤫
result = result.filter( result = result.filter(
(provider) => provider.gitProvider.adminId === ctx.user.adminId, (provider) => provider.gitProvider.userId === ctx.user.ownerId,
); );
} }
@@ -90,7 +90,7 @@ export const githubRouter = createTRPCRouter({
const githubProvider = await findGithubById(input.githubId); const githubProvider = await findGithubById(input.githubId);
if ( if (
IS_CLOUD && IS_CLOUD &&
githubProvider.gitProvider.adminId !== ctx.user.adminId githubProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -111,7 +111,7 @@ export const githubRouter = createTRPCRouter({
.input(apiUpdateGithub) .input(apiUpdateGithub)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId); const githubProvider = await findGithubById(input.githubId);
if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -120,7 +120,7 @@ export const githubRouter = createTRPCRouter({
} }
await updateGitProvider(input.gitProviderId, { await updateGitProvider(input.gitProviderId, {
name: input.name, name: input.name,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
}), }),
}); });

View File

@@ -26,7 +26,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiCreateGitlab) .input(apiCreateGitlab)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createGitlab(input, ctx.user.adminId); return await createGitlab(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -39,7 +39,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindOneGitlab) .input(apiFindOneGitlab)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId); const gitlabProvider = await findGitlabById(input.gitlabId);
if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -58,7 +58,7 @@ export const gitlabRouter = createTRPCRouter({
if (IS_CLOUD) { if (IS_CLOUD) {
// TODO: mAyBe a rEfaCtoR 🤫 // TODO: mAyBe a rEfaCtoR 🤫
result = result.filter( result = result.filter(
(provider) => provider.gitProvider.adminId === ctx.user.adminId, (provider) => provider.gitProvider.userId === ctx.user.ownerId,
); );
} }
const filtered = result const filtered = result
@@ -78,7 +78,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindOneGitlab) .input(apiFindOneGitlab)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId); const gitlabProvider = await findGitlabById(input.gitlabId);
if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -92,7 +92,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindGitlabBranches) .input(apiFindGitlabBranches)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId || ""); const gitlabProvider = await findGitlabById(input.gitlabId || "");
if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -108,7 +108,7 @@ export const gitlabRouter = createTRPCRouter({
const gitlabProvider = await findGitlabById(input.gitlabId || ""); const gitlabProvider = await findGitlabById(input.gitlabId || "");
if ( if (
IS_CLOUD && IS_CLOUD &&
gitlabProvider.gitProvider.adminId !== ctx.user.adminId gitlabProvider.gitProvider.userId !== ctx.user.ownerId
) { ) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
@@ -130,7 +130,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiUpdateGitlab) .input(apiUpdateGitlab)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId); const gitlabProvider = await findGitlabById(input.gitlabId);
if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) {
//TODO: Remove this line when the cloud version is ready //TODO: Remove this line when the cloud version is ready
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -140,7 +140,7 @@ export const gitlabRouter = createTRPCRouter({
if (input.name) { if (input.name) {
await updateGitProvider(input.gitProviderId, { await updateGitProvider(input.gitProviderId, {
name: input.name, name: input.name,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
await updateGitlab(input.gitlabId, { await updateGitlab(input.gitlabId, {

View File

@@ -37,8 +37,8 @@ export const mariadbRouter = createTRPCRouter({
.input(apiCreateMariaDB) .input(apiCreateMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -49,15 +49,15 @@ export const mariadbRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
}); });
} }
const newMariadb = await createMariadb(input); const newMariadb = await createMariadb(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newMariadb.mariadbId); await addNewService(ctx.user.id, newMariadb.mariadbId);
} }
await createMount({ await createMount({
@@ -79,11 +79,11 @@ export const mariadbRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneMariaDB) .input(apiFindOneMariaDB)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mariadbId, "access"); await checkServiceAccess(ctx.user.id, input.mariadbId, "access");
} }
const mariadb = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this Mariadb", message: "You are not authorized to access this Mariadb",
@@ -96,7 +96,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiFindOneMariaDB) .input(apiFindOneMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findMariadbById(input.mariadbId); const service = await findMariadbById(input.mariadbId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this Mariadb", message: "You are not authorized to start this Mariadb",
@@ -133,7 +133,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiSaveExternalPortMariaDB) .input(apiSaveExternalPortMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMariadbById(input.mariadbId); const mongo = await findMariadbById(input.mariadbId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
@@ -149,7 +149,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiDeployMariaDB) .input(apiDeployMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Mariadb", message: "You are not authorized to deploy this Mariadb",
@@ -170,7 +170,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiDeployMariaDB) .input(apiDeployMariaDB)
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Mariadb", message: "You are not authorized to deploy this Mariadb",
@@ -187,7 +187,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiChangeMariaDBStatus) .input(apiChangeMariaDBStatus)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMariadbById(input.mariadbId); const mongo = await findMariadbById(input.mariadbId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to change this Mariadb status", message: "You are not authorized to change this Mariadb status",
@@ -201,12 +201,12 @@ export const mariadbRouter = createTRPCRouter({
remove: protectedProcedure remove: protectedProcedure
.input(apiFindOneMariaDB) .input(apiFindOneMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mariadbId, "delete"); await checkServiceAccess(ctx.user.id, input.mariadbId, "delete");
} }
const mongo = await findMariadbById(input.mariadbId); const mongo = await findMariadbById(input.mariadbId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this Mariadb", message: "You are not authorized to delete this Mariadb",
@@ -232,7 +232,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMariaDB) .input(apiSaveEnvironmentVariablesMariaDB)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",
@@ -255,7 +255,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiResetMariadb) .input(apiResetMariadb)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId); const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this Mariadb", message: "You are not authorized to reload this Mariadb",
@@ -285,7 +285,7 @@ export const mariadbRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { mariadbId, ...rest } = input; const { mariadbId, ...rest } = input;
const mariadb = await findMariadbById(mariadbId); const mariadb = await findMariadbById(mariadbId);
if (mariadb.project.adminId !== ctx.user.adminId) { if (mariadb.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this Mariadb", message: "You are not authorized to update this Mariadb",

View File

@@ -36,8 +36,8 @@ export const mongoRouter = createTRPCRouter({
.input(apiCreateMongo) .input(apiCreateMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -48,15 +48,15 @@ export const mongoRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
}); });
} }
const newMongo = await createMongo(input); const newMongo = await createMongo(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newMongo.mongoId); await addNewService(ctx.user.id, newMongo.mongoId);
} }
await createMount({ await createMount({
@@ -82,12 +82,12 @@ export const mongoRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneMongo) .input(apiFindOneMongo)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mongoId, "access"); await checkServiceAccess(ctx.user.id, input.mongoId, "access");
} }
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this mongo", message: "You are not authorized to access this mongo",
@@ -101,7 +101,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findMongoById(input.mongoId); const service = await findMongoById(input.mongoId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this mongo", message: "You are not authorized to start this mongo",
@@ -124,7 +124,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this mongo", message: "You are not authorized to stop this mongo",
@@ -146,7 +146,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiSaveExternalPortMongo) .input(apiSaveExternalPortMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
@@ -162,7 +162,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiDeployMongo) .input(apiDeployMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this mongo", message: "You are not authorized to deploy this mongo",
@@ -182,7 +182,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiDeployMongo) .input(apiDeployMongo)
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this mongo", message: "You are not authorized to deploy this mongo",
@@ -199,7 +199,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiChangeMongoStatus) .input(apiChangeMongoStatus)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to change this mongo status", message: "You are not authorized to change this mongo status",
@@ -214,7 +214,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiResetMongo) .input(apiResetMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this mongo", message: "You are not authorized to reload this mongo",
@@ -242,13 +242,13 @@ export const mongoRouter = createTRPCRouter({
remove: protectedProcedure remove: protectedProcedure
.input(apiFindOneMongo) .input(apiFindOneMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mongoId, "delete"); await checkServiceAccess(ctx.user.id, input.mongoId, "delete");
} }
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this mongo", message: "You are not authorized to delete this mongo",
@@ -274,7 +274,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMongo) .input(apiSaveEnvironmentVariablesMongo)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId); const mongo = await findMongoById(input.mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",
@@ -298,7 +298,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { mongoId, ...rest } = input; const { mongoId, ...rest } = input;
const mongo = await findMongoById(mongoId); const mongo = await findMongoById(mongoId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this mongo", message: "You are not authorized to update this mongo",

View File

@@ -38,8 +38,8 @@ export const mysqlRouter = createTRPCRouter({
.input(apiCreateMySql) .input(apiCreateMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -50,7 +50,7 @@ export const mysqlRouter = createTRPCRouter({
} }
1; 1;
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
@@ -58,8 +58,8 @@ export const mysqlRouter = createTRPCRouter({
} }
const newMysql = await createMysql(input); const newMysql = await createMysql(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newMysql.mysqlId); await addNewService(ctx.user.id, newMysql.mysqlId);
} }
await createMount({ await createMount({
@@ -85,11 +85,11 @@ export const mysqlRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneMySql) .input(apiFindOneMySql)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mysqlId, "access"); await checkServiceAccess(ctx.user.id, input.mysqlId, "access");
} }
const mysql = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this MySQL", message: "You are not authorized to access this MySQL",
@@ -102,7 +102,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiFindOneMySql) .input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findMySqlById(input.mysqlId); const service = await findMySqlById(input.mysqlId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this MySQL", message: "You are not authorized to start this MySQL",
@@ -124,7 +124,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiFindOneMySql) .input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId); const mongo = await findMySqlById(input.mysqlId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this MySQL", message: "You are not authorized to stop this MySQL",
@@ -145,7 +145,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiSaveExternalPortMySql) .input(apiSaveExternalPortMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId); const mongo = await findMySqlById(input.mysqlId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
@@ -161,7 +161,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiDeployMySql) .input(apiDeployMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this MySQL", message: "You are not authorized to deploy this MySQL",
@@ -181,7 +181,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiDeployMySql) .input(apiDeployMySql)
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this MySQL", message: "You are not authorized to deploy this MySQL",
@@ -198,7 +198,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiChangeMySqlStatus) .input(apiChangeMySqlStatus)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId); const mongo = await findMySqlById(input.mysqlId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to change this MySQL status", message: "You are not authorized to change this MySQL status",
@@ -213,7 +213,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiResetMysql) .input(apiResetMysql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this MySQL", message: "You are not authorized to reload this MySQL",
@@ -240,11 +240,11 @@ export const mysqlRouter = createTRPCRouter({
remove: protectedProcedure remove: protectedProcedure
.input(apiFindOneMySql) .input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.mysqlId, "delete"); await checkServiceAccess(ctx.user.id, input.mysqlId, "delete");
} }
const mongo = await findMySqlById(input.mysqlId); const mongo = await findMySqlById(input.mysqlId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this MySQL", message: "You are not authorized to delete this MySQL",
@@ -270,7 +270,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMySql) .input(apiSaveEnvironmentVariablesMySql)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId); const mysql = await findMySqlById(input.mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",
@@ -294,7 +294,7 @@ export const mysqlRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { mysqlId, ...rest } = input; const { mysqlId, ...rest } = input;
const mysql = await findMySqlById(mysqlId); const mysql = await findMySqlById(mysqlId);
if (mysql.project.adminId !== ctx.user.adminId) { if (mysql.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this MySQL", message: "You are not authorized to update this MySQL",

View File

@@ -6,7 +6,6 @@ import {
} from "@/server/api/trpc"; } from "@/server/api/trpc";
import { db } from "@/server/db"; import { db } from "@/server/db";
import { import {
admins,
apiCreateDiscord, apiCreateDiscord,
apiCreateEmail, apiCreateEmail,
apiCreateGotify, apiCreateGotify,
@@ -25,6 +24,7 @@ import {
apiUpdateTelegram, apiUpdateTelegram,
notifications, notifications,
server, server,
users_temp,
} from "@/server/db/schema"; } from "@/server/db/schema";
import { import {
IS_CLOUD, IS_CLOUD,
@@ -57,7 +57,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateSlack) .input(apiCreateSlack)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createSlackNotification(input, ctx.user.adminId); return await createSlackNotification(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -71,7 +71,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -80,7 +80,7 @@ export const notificationRouter = createTRPCRouter({
} }
return await updateSlackNotification({ return await updateSlackNotification({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw error; throw error;
@@ -107,7 +107,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateTelegram) .input(apiCreateTelegram)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createTelegramNotification(input, ctx.user.adminId); return await createTelegramNotification(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -122,7 +122,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -131,7 +131,7 @@ export const notificationRouter = createTRPCRouter({
} }
return await updateTelegramNotification({ return await updateTelegramNotification({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -159,7 +159,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateDiscord) .input(apiCreateDiscord)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createDiscordNotification(input, ctx.user.adminId); return await createDiscordNotification(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -174,7 +174,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -183,7 +183,7 @@ export const notificationRouter = createTRPCRouter({
} }
return await updateDiscordNotification({ return await updateDiscordNotification({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -220,7 +220,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateEmail) .input(apiCreateEmail)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createEmailNotification(input, ctx.user.adminId); return await createEmailNotification(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -234,7 +234,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -243,7 +243,7 @@ export const notificationRouter = createTRPCRouter({
} }
return await updateEmailNotification({ return await updateEmailNotification({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -276,7 +276,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -295,7 +295,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiFindOneNotification) .input(apiFindOneNotification)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -314,7 +314,7 @@ export const notificationRouter = createTRPCRouter({
gotify: true, gotify: true,
}, },
orderBy: desc(notifications.createdAt), orderBy: desc(notifications.createdAt),
...(IS_CLOUD && { where: eq(notifications.adminId, ctx.user.adminId) }), ...(IS_CLOUD && { where: eq(notifications.userId, ctx.user.ownerId) }),
// TODO: Remove this line when the cloud version is ready // TODO: Remove this line when the cloud version is ready
}); });
}), }),
@@ -332,24 +332,24 @@ export const notificationRouter = createTRPCRouter({
) )
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
try { try {
let adminId = ""; let userId = "";
let ServerName = ""; let ServerName = "";
if (input.ServerType === "Dokploy") { if (input.ServerType === "Dokploy") {
const result = await db const result = await db
.select() .select()
.from(admins) .from(users_temp)
.where( .where(
sql`${admins.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, sql`${users_temp.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
); );
if (!result?.[0]?.adminId) { if (!result?.[0]?.id) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Token not found", message: "Token not found",
}); });
} }
adminId = result?.[0]?.adminId; userId = result?.[0]?.id;
ServerName = "Dokploy"; ServerName = "Dokploy";
} else { } else {
const result = await db const result = await db
@@ -359,18 +359,18 @@ export const notificationRouter = createTRPCRouter({
sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
); );
if (!result?.[0]?.adminId) { if (!result?.[0]?.userId) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Token not found", message: "Token not found",
}); });
} }
adminId = result?.[0]?.adminId; userId = result?.[0]?.userId;
ServerName = "Remote"; ServerName = "Remote";
} }
await sendServerThresholdNotifications(adminId, { await sendServerThresholdNotifications(userId, {
...input, ...input,
ServerName, ServerName,
}); });
@@ -386,7 +386,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateGotify) .input(apiCreateGotify)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
return await createGotifyNotification(input, ctx.user.adminId); return await createGotifyNotification(input, ctx.user.ownerId);
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
@@ -400,7 +400,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const notification = await findNotificationById(input.notificationId); const notification = await findNotificationById(input.notificationId);
if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { if (IS_CLOUD && notification.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this notification", message: "You are not authorized to update this notification",
@@ -408,7 +408,7 @@ export const notificationRouter = createTRPCRouter({
} }
return await updateGotifyNotification({ return await updateGotifyNotification({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw error; throw error;

View File

@@ -44,8 +44,8 @@ export const postgresRouter = createTRPCRouter({
.input(apiCreatePostgres) .input(apiCreatePostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -56,15 +56,15 @@ export const postgresRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
}); });
} }
const newPostgres = await createPostgres(input); const newPostgres = await createPostgres(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newPostgres.postgresId); await addNewService(ctx.user.id, newPostgres.postgresId);
} }
await createMount({ await createMount({
@@ -90,12 +90,12 @@ export const postgresRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOnePostgres) .input(apiFindOnePostgres)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.postgresId, "access"); await checkServiceAccess(ctx.user.id, input.postgresId, "access");
} }
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this Postgres", message: "You are not authorized to access this Postgres",
@@ -109,7 +109,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const service = await findPostgresById(input.postgresId); const service = await findPostgresById(input.postgresId);
if (service.project.adminId !== ctx.user.adminId) { if (service.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this Postgres", message: "You are not authorized to start this Postgres",
@@ -131,7 +131,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiFindOnePostgres) .input(apiFindOnePostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this Postgres", message: "You are not authorized to stop this Postgres",
@@ -153,7 +153,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
@@ -169,7 +169,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiDeployPostgres) .input(apiDeployPostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Postgres", message: "You are not authorized to deploy this Postgres",
@@ -190,7 +190,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiDeployPostgres) .input(apiDeployPostgres)
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Postgres", message: "You are not authorized to deploy this Postgres",
@@ -207,7 +207,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiChangePostgresStatus) .input(apiChangePostgresStatus)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to change this Postgres status", message: "You are not authorized to change this Postgres status",
@@ -221,12 +221,12 @@ export const postgresRouter = createTRPCRouter({
remove: protectedProcedure remove: protectedProcedure
.input(apiFindOnePostgres) .input(apiFindOnePostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.postgresId, "delete"); await checkServiceAccess(ctx.user.id, input.postgresId, "delete");
} }
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this Postgres", message: "You are not authorized to delete this Postgres",
@@ -249,7 +249,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesPostgres) .input(apiSaveEnvironmentVariablesPostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",
@@ -272,7 +272,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiResetPostgres) .input(apiResetPostgres)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId); const postgres = await findPostgresById(input.postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this Postgres", message: "You are not authorized to reload this Postgres",
@@ -302,7 +302,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { postgresId, ...rest } = input; const { postgresId, ...rest } = input;
const postgres = await findPostgresById(postgresId); const postgres = await findPostgresById(postgresId);
if (postgres.project.adminId !== ctx.user.adminId) { if (postgres.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this Postgres", message: "You are not authorized to update this Postgres",

View File

@@ -14,7 +14,7 @@ export const previewDeploymentRouter = createTRPCRouter({
.input(apiFindAllByApplication) .input(apiFindAllByApplication)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -28,7 +28,7 @@ export const previewDeploymentRouter = createTRPCRouter({
const previewDeployment = await findPreviewDeploymentById( const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId, input.previewDeploymentId,
); );
if (previewDeployment.application.project.adminId !== ctx.user.adminId) { if (previewDeployment.application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this preview deployment", message: "You are not authorized to delete this preview deployment",
@@ -43,7 +43,7 @@ export const previewDeploymentRouter = createTRPCRouter({
const previewDeployment = await findPreviewDeploymentById( const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId, input.previewDeploymentId,
); );
if (previewDeployment.application.project.adminId !== ctx.user.adminId) { if (previewDeployment.application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this preview deployment", message: "You are not authorized to access this preview deployment",

View File

@@ -25,9 +25,9 @@ import {
checkProjectAccess, checkProjectAccess,
createProject, createProject,
deleteProject, deleteProject,
findAdminById,
findProjectById, findProjectById,
findUserByAuthId, findUserByAuthId,
findUserById,
updateProjectById, updateProjectById,
} from "@dokploy/server"; } from "@dokploy/server";
@@ -36,11 +36,11 @@ export const projectRouter = createTRPCRouter({
.input(apiCreateProject) .input(apiCreateProject)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkProjectAccess(ctx.user.authId, "create"); await checkProjectAccess(ctx.user.id, "create");
} }
const admin = await findAdminById(ctx.user.adminId); const admin = await findUserById(ctx.user.ownerId);
if (admin.serversQuantity === 0 && IS_CLOUD) { if (admin.serversQuantity === 0 && IS_CLOUD) {
throw new TRPCError({ throw new TRPCError({
@@ -49,9 +49,9 @@ export const projectRouter = createTRPCRouter({
}); });
} }
const project = await createProject(input, ctx.user.adminId); const project = await createProject(input, ctx.user.ownerId);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewProject(ctx.user.authId, project.projectId); await addNewProject(ctx.user.id, project.projectId);
} }
return project; return project;
@@ -67,15 +67,15 @@ export const projectRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneProject) .input(apiFindOneProject)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
const { accessedServices } = await findUserByAuthId(ctx.user.authId); const { accessedServices } = await findUserByAuthId(ctx.user.id);
await checkProjectAccess(ctx.user.authId, "access", input.projectId); await checkProjectAccess(ctx.user.id, "access", input.projectId);
const project = await db.query.projects.findFirst({ const project = await db.query.projects.findFirst({
where: and( where: and(
eq(projects.projectId, input.projectId), eq(projects.projectId, input.projectId),
eq(projects.adminId, ctx.user.adminId), eq(projects.userId, ctx.user.ownerId),
), ),
with: { with: {
compose: { compose: {
@@ -115,7 +115,7 @@ export const projectRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
@@ -124,9 +124,10 @@ export const projectRouter = createTRPCRouter({
return project; return project;
}), }),
all: protectedProcedure.query(async ({ ctx }) => { all: protectedProcedure.query(async ({ ctx }) => {
if (ctx.user.rol === "user") { // console.log(ctx.user);
const { accessedProjects, accessedServices } = await findUserByAuthId( if (ctx.user.rol === "member") {
ctx.user.authId, const { accessedProjects, accessedServices } = await findUserById(
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),
}); });
}), }),
@@ -202,11 +203,11 @@ export const projectRouter = createTRPCRouter({
.input(apiRemoveProject) .input(apiRemoveProject)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkProjectAccess(ctx.user.authId, "delete"); await checkProjectAccess(ctx.user.id, "delete");
} }
const currentProject = await findProjectById(input.projectId); const currentProject = await findProjectById(input.projectId);
if (currentProject.adminId !== ctx.user.adminId) { if (currentProject.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this project", message: "You are not authorized to delete this project",
@@ -224,7 +225,7 @@ export const projectRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const currentProject = await findProjectById(input.projectId); const currentProject = await findProjectById(input.projectId);
if (currentProject.adminId !== ctx.user.adminId) { if (currentProject.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this project", message: "You are not authorized to update this project",

View File

@@ -18,7 +18,7 @@ export const redirectsRouter = createTRPCRouter({
.input(apiCreateRedirect) .input(apiCreateRedirect)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -31,7 +31,7 @@ export const redirectsRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId); const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId); const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -44,7 +44,7 @@ export const redirectsRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId); const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId); const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -57,7 +57,7 @@ export const redirectsRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId); const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId); const application = await findApplicationById(redirect.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",

View File

@@ -36,8 +36,8 @@ export const redisRouter = createTRPCRouter({
.input(apiCreateRedis) .input(apiCreateRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.projectId, "create"); await checkServiceAccess(ctx.user.id, input.projectId, "create");
} }
if (IS_CLOUD && !input.serverId) { if (IS_CLOUD && !input.serverId) {
@@ -48,15 +48,15 @@ export const redisRouter = createTRPCRouter({
} }
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
if (project.adminId !== ctx.user.adminId) { if (project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this project", message: "You are not authorized to access this project",
}); });
} }
const newRedis = await createRedis(input); const newRedis = await createRedis(input);
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await addNewService(ctx.user.authId, newRedis.redisId); await addNewService(ctx.user.id, newRedis.redisId);
} }
await createMount({ await createMount({
@@ -75,12 +75,12 @@ export const redisRouter = createTRPCRouter({
one: protectedProcedure one: protectedProcedure
.input(apiFindOneRedis) .input(apiFindOneRedis)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.redisId, "access"); await checkServiceAccess(ctx.user.id, input.redisId, "access");
} }
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this Redis", message: "You are not authorized to access this Redis",
@@ -93,7 +93,7 @@ export const redisRouter = createTRPCRouter({
.input(apiFindOneRedis) .input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to start this Redis", message: "You are not authorized to start this Redis",
@@ -115,7 +115,7 @@ export const redisRouter = createTRPCRouter({
.input(apiResetRedis) .input(apiResetRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to reload this Redis", message: "You are not authorized to reload this Redis",
@@ -145,7 +145,7 @@ export const redisRouter = createTRPCRouter({
.input(apiFindOneRedis) .input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to stop this Redis", message: "You are not authorized to stop this Redis",
@@ -166,7 +166,7 @@ export const redisRouter = createTRPCRouter({
.input(apiSaveExternalPortRedis) .input(apiSaveExternalPortRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findRedisById(input.redisId); const mongo = await findRedisById(input.redisId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this external port", message: "You are not authorized to save this external port",
@@ -182,7 +182,7 @@ export const redisRouter = createTRPCRouter({
.input(apiDeployRedis) .input(apiDeployRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Redis", message: "You are not authorized to deploy this Redis",
@@ -202,7 +202,7 @@ export const redisRouter = createTRPCRouter({
.input(apiDeployRedis) .input(apiDeployRedis)
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Redis", message: "You are not authorized to deploy this Redis",
@@ -218,7 +218,7 @@ export const redisRouter = createTRPCRouter({
.input(apiChangeRedisStatus) .input(apiChangeRedisStatus)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const mongo = await findRedisById(input.redisId); const mongo = await findRedisById(input.redisId);
if (mongo.project.adminId !== ctx.user.adminId) { if (mongo.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to change this Redis status", message: "You are not authorized to change this Redis status",
@@ -232,13 +232,13 @@ export const redisRouter = createTRPCRouter({
remove: protectedProcedure remove: protectedProcedure
.input(apiFindOneRedis) .input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
await checkServiceAccess(ctx.user.authId, input.redisId, "delete"); await checkServiceAccess(ctx.user.id, input.redisId, "delete");
} }
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this Redis", message: "You are not authorized to delete this Redis",
@@ -261,7 +261,7 @@ export const redisRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesRedis) .input(apiSaveEnvironmentVariablesRedis)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId); const redis = await findRedisById(input.redisId);
if (redis.project.adminId !== ctx.user.adminId) { if (redis.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to save this environment", message: "You are not authorized to save this environment",

View File

@@ -10,7 +10,7 @@ import {
createRegistry, createRegistry,
execAsync, execAsync,
execAsyncRemote, execAsyncRemote,
findAllRegistryByAdminId, findAllRegistryByUserId,
findRegistryById, findRegistryById,
removeRegistry, removeRegistry,
updateRegistry, updateRegistry,
@@ -22,13 +22,13 @@ export const registryRouter = createTRPCRouter({
create: adminProcedure create: adminProcedure
.input(apiCreateRegistry) .input(apiCreateRegistry)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
return await createRegistry(input, ctx.user.adminId); return await createRegistry(input, ctx.user.ownerId);
}), }),
remove: adminProcedure remove: adminProcedure
.input(apiRemoveRegistry) .input(apiRemoveRegistry)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const registry = await findRegistryById(input.registryId); const registry = await findRegistryById(input.registryId);
if (registry.adminId !== ctx.user.adminId) { if (registry.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to delete this registry", message: "You are not allowed to delete this registry",
@@ -41,7 +41,7 @@ export const registryRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const { registryId, ...rest } = input; const { registryId, ...rest } = input;
const registry = await findRegistryById(registryId); const registry = await findRegistryById(registryId);
if (registry.adminId !== ctx.user.adminId) { if (registry.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to update this registry", message: "You are not allowed to update this registry",
@@ -61,13 +61,13 @@ export const registryRouter = createTRPCRouter({
return true; return true;
}), }),
all: protectedProcedure.query(async ({ ctx }) => { all: protectedProcedure.query(async ({ ctx }) => {
return await findAllRegistryByAdminId(ctx.user.adminId); return await findAllRegistryByUserId(ctx.user.ownerId);
}), }),
one: adminProcedure one: adminProcedure
.input(apiFindOneRegistry) .input(apiFindOneRegistry)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const registry = await findRegistryById(input.registryId); const registry = await findRegistryById(input.registryId);
if (registry.adminId !== ctx.user.adminId) { if (registry.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to access this registry", message: "You are not allowed to access this registry",

View File

@@ -18,7 +18,7 @@ export const securityRouter = createTRPCRouter({
.input(apiCreateSecurity) .input(apiCreateSecurity)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -31,7 +31,7 @@ export const securityRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId); const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId); const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -44,7 +44,7 @@ export const securityRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId); const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId); const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",
@@ -57,7 +57,7 @@ export const securityRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId); const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId); const application = await findApplicationById(security.applicationId);
if (application.project.adminId !== ctx.user.adminId) { if (application.project.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this application", message: "You are not authorized to access this application",

View File

@@ -21,9 +21,9 @@ import {
createServer, createServer,
defaultCommand, defaultCommand,
deleteServer, deleteServer,
findAdminById,
findServerById, findServerById,
findServersByAdminId, findServersByUserId,
findUserById,
getPublicIpWithFallback, getPublicIpWithFallback,
haveActiveServices, haveActiveServices,
removeDeploymentsByServerId, removeDeploymentsByServerId,
@@ -42,15 +42,15 @@ export const serverRouter = createTRPCRouter({
.input(apiCreateServer) .input(apiCreateServer)
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
try { try {
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
const servers = await findServersByAdminId(admin.adminId); const servers = await findServersByUserId(user.id);
if (IS_CLOUD && servers.length >= admin.serversQuantity) { if (IS_CLOUD && servers.length >= user.serversQuantity) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "You cannot create more servers", message: "You cannot create more servers",
}); });
} }
const project = await createServer(input, ctx.user.adminId); const project = await createServer(input, ctx.user.ownerId);
return project; return project;
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -65,7 +65,7 @@ export const serverRouter = createTRPCRouter({
.input(apiFindOneServer) .input(apiFindOneServer)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to access this server", message: "You are not authorized to access this server",
@@ -93,7 +93,7 @@ export const serverRouter = createTRPCRouter({
.leftJoin(mongo, eq(mongo.serverId, server.serverId)) .leftJoin(mongo, eq(mongo.serverId, server.serverId))
.leftJoin(mysql, eq(mysql.serverId, server.serverId)) .leftJoin(mysql, eq(mysql.serverId, server.serverId))
.leftJoin(postgres, eq(postgres.serverId, server.serverId)) .leftJoin(postgres, eq(postgres.serverId, server.serverId))
.where(eq(server.adminId, ctx.user.adminId)) .where(eq(server.userId, ctx.user.ownerId))
.orderBy(desc(server.createdAt)) .orderBy(desc(server.createdAt))
.groupBy(server.serverId); .groupBy(server.serverId);
@@ -105,10 +105,10 @@ export const serverRouter = createTRPCRouter({
where: IS_CLOUD where: IS_CLOUD
? and( ? and(
isNotNull(server.sshKeyId), isNotNull(server.sshKeyId),
eq(server.adminId, ctx.user.adminId), eq(server.userId, ctx.user.ownerId),
eq(server.serverStatus, "active"), eq(server.serverStatus, "active"),
) )
: and(isNotNull(server.sshKeyId), eq(server.adminId, ctx.user.adminId)), : and(isNotNull(server.sshKeyId), eq(server.userId, ctx.user.ownerId)),
}); });
return result; return result;
}), }),
@@ -117,7 +117,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to setup this server", message: "You are not authorized to setup this server",
@@ -142,7 +142,7 @@ export const serverRouter = createTRPCRouter({
.subscription(async ({ input, ctx }) => { .subscription(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to setup this server", message: "You are not authorized to setup this server",
@@ -162,7 +162,7 @@ export const serverRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to validate this server", message: "You are not authorized to validate this server",
@@ -204,7 +204,7 @@ export const serverRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to validate this server", message: "You are not authorized to validate this server",
@@ -254,7 +254,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to setup this server", message: "You are not authorized to setup this server",
@@ -296,7 +296,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to delete this server", message: "You are not authorized to delete this server",
@@ -315,12 +315,9 @@ export const serverRouter = createTRPCRouter({
await deleteServer(input.serverId); await deleteServer(input.serverId);
if (IS_CLOUD) { if (IS_CLOUD) {
const admin = await findAdminById(ctx.user.adminId); const admin = await findUserById(ctx.user.ownerId);
await updateServersBasedOnQuantity( await updateServersBasedOnQuantity(admin.id, admin.serversQuantity);
admin.adminId,
admin.serversQuantity,
);
} }
return currentServer; return currentServer;
@@ -333,7 +330,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const server = await findServerById(input.serverId); const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) { if (server.userId !== ctx.user.ownerId) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not authorized to update this server", message: "You are not authorized to update this server",

View File

@@ -47,7 +47,6 @@ import {
startServiceRemote, startServiceRemote,
stopService, stopService,
stopServiceRemote, stopServiceRemote,
updateAdmin,
updateLetsEncryptEmail, updateLetsEncryptEmail,
updateServerById, updateServerById,
updateServerTraefik, updateServerTraefik,
@@ -383,7 +382,7 @@ export const settingsRouter = createTRPCRouter({
.input(apiServerSchema) .input(apiServerSchema)
.query(async ({ ctx, input }) => { .query(async ({ ctx, input }) => {
try { try {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
const canAccess = await canAccessToTraefikFiles(ctx.user.authId); const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) { if (!canAccess) {
@@ -401,7 +400,7 @@ export const settingsRouter = createTRPCRouter({
updateTraefikFile: protectedProcedure updateTraefikFile: protectedProcedure
.input(apiModifyTraefikConfig) .input(apiModifyTraefikConfig)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
const canAccess = await canAccessToTraefikFiles(ctx.user.authId); const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) { if (!canAccess) {
@@ -419,7 +418,7 @@ export const settingsRouter = createTRPCRouter({
readTraefikFile: protectedProcedure readTraefikFile: protectedProcedure
.input(apiReadTraefikConfig) .input(apiReadTraefikConfig)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
if (ctx.user.rol === "user") { if (ctx.user.rol === "member") {
const canAccess = await canAccessToTraefikFiles(ctx.user.authId); const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) { if (!canAccess) {
@@ -655,7 +654,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 () => {

View File

@@ -24,9 +24,10 @@ export const sshRouter = createTRPCRouter({
.input(apiCreateSshKey) .input(apiCreateSshKey)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
console.log(ctx.user.ownerId);
await createSshKey({ await createSshKey({
...input, ...input,
adminId: ctx.user.adminId, userId: ctx.user.ownerId,
}); });
} catch (error) { } catch (error) {
throw new TRPCError({ throw new TRPCError({
@@ -41,7 +42,7 @@ export const sshRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const sshKey = await findSSHKeyById(input.sshKeyId); const sshKey = await findSSHKeyById(input.sshKeyId);
if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -59,7 +60,7 @@ export const sshRouter = createTRPCRouter({
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const sshKey = await findSSHKeyById(input.sshKeyId); const sshKey = await findSSHKeyById(input.sshKeyId);
if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -70,7 +71,7 @@ export const sshRouter = createTRPCRouter({
}), }),
all: protectedProcedure.query(async ({ ctx }) => { all: protectedProcedure.query(async ({ ctx }) => {
return await db.query.sshKeys.findMany({ return await db.query.sshKeys.findMany({
...(IS_CLOUD && { where: eq(sshKeys.adminId, ctx.user.adminId) }), ...(IS_CLOUD && { where: eq(sshKeys.userId, ctx.user.ownerId) }),
orderBy: desc(sshKeys.createdAt), orderBy: desc(sshKeys.createdAt),
}); });
// TODO: Remove this line when the cloud version is ready // TODO: Remove this line when the cloud version is ready
@@ -85,7 +86,7 @@ export const sshRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
const sshKey = await findSSHKeyById(input.sshKeyId); const sshKey = await findSSHKeyById(input.sshKeyId);
if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) {
// TODO: Remove isCloud in the next versions of dokploy // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",

View File

@@ -1,9 +1,9 @@
import { WEBSITE_URL, getStripeItems } from "@/server/utils/stripe"; import { WEBSITE_URL, getStripeItems } from "@/server/utils/stripe";
import { import {
IS_CLOUD, IS_CLOUD,
findAdminById, findServersByUserId,
findServersByAdminId, findUserById,
updateAdmin, updateUser,
} from "@dokploy/server"; } from "@dokploy/server";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import Stripe from "stripe"; import Stripe from "stripe";
@@ -12,8 +12,8 @@ import { adminProcedure, createTRPCRouter } from "../trpc";
export const stripeRouter = createTRPCRouter({ export const stripeRouter = createTRPCRouter({
getProducts: adminProcedure.query(async ({ ctx }) => { getProducts: adminProcedure.query(async ({ ctx }) => {
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
const stripeCustomerId = admin.stripeCustomerId; const stripeCustomerId = user.stripeCustomerId;
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-09-30.acacia", apiVersion: "2024-09-30.acacia",
@@ -56,15 +56,15 @@ export const stripeRouter = createTRPCRouter({
}); });
const items = getStripeItems(input.serverQuantity, input.isAnnual); const items = getStripeItems(input.serverQuantity, input.isAnnual);
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
let stripeCustomerId = admin.stripeCustomerId; let stripeCustomerId = user.stripeCustomerId;
if (stripeCustomerId) { if (stripeCustomerId) {
const customer = await stripe.customers.retrieve(stripeCustomerId); const customer = await stripe.customers.retrieve(stripeCustomerId);
if (customer.deleted) { if (customer.deleted) {
await updateAdmin(admin.authId, { await updateUser(user.id, {
stripeCustomerId: null, stripeCustomerId: null,
}); });
stripeCustomerId = null; stripeCustomerId = null;
@@ -78,7 +78,7 @@ export const stripeRouter = createTRPCRouter({
customer: stripeCustomerId, customer: stripeCustomerId,
}), }),
metadata: { metadata: {
adminId: admin.adminId, ownerId: user.id,
}, },
allow_promotion_codes: true, allow_promotion_codes: true,
success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`, success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`,
@@ -89,15 +89,15 @@ export const stripeRouter = createTRPCRouter({
}), }),
createCustomerPortalSession: adminProcedure.mutation( createCustomerPortalSession: adminProcedure.mutation(
async ({ ctx, input }) => { async ({ ctx, input }) => {
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
if (!admin.stripeCustomerId) { if (!user.stripeCustomerId) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Stripe Customer ID not found", message: "Stripe Customer ID not found",
}); });
} }
const stripeCustomerId = admin.stripeCustomerId; const stripeCustomerId = user.stripeCustomerId;
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-09-30.acacia", apiVersion: "2024-09-30.acacia",
@@ -119,13 +119,13 @@ export const stripeRouter = createTRPCRouter({
), ),
canCreateMoreServers: adminProcedure.query(async ({ ctx }) => { canCreateMoreServers: adminProcedure.query(async ({ ctx }) => {
const admin = await findAdminById(ctx.user.adminId); const user = await findUserById(ctx.user.ownerId);
const servers = await findServersByAdminId(admin.adminId); const servers = await findServersByUserId(user.id);
if (!IS_CLOUD) { if (!IS_CLOUD) {
return true; return true;
} }
return servers.length < admin.serversQuantity; return servers.length < user.serversQuantity;
}), }),
}); });

View File

@@ -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,8 +31,8 @@ import { ZodError } from "zod";
*/ */
interface CreateContextOptions { interface CreateContextOptions {
user: (User & { authId: string; adminId: string }) | null; user: (User & { rol: "member" | "admin" | "owner"; ownerId: string }) | null;
session: Session | null; session: (Session & { activeOrganizationId?: string }) | null;
req: CreateNextContextOptions["req"]; req: CreateNextContextOptions["req"];
res: CreateNextContextOptions["res"]; res: CreateNextContextOptions["res"];
} }
@@ -65,30 +66,36 @@ 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
const { 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;
} // }
console.log("session", session);
console.log("user", user);
return createInnerTRPCContext({ return createInnerTRPCContext({
req, req,
res, res,
session: session, session: session
...((user && { ? {
user: { ...session,
authId: user.id, activeOrganizationId: session.activeOrganizationId ?? undefined,
email: user.email, }
rol: user.rol, : null,
id: user.id, user: user
secret: user.secret, ? {
adminId: user.adminId, ...user,
}, email: user.email,
}) || { rol: user.role as "owner" | "member" | "admin",
user: null, id: user.id,
}), ownerId: user.ownerId,
}
: null,
}); });
}; };
@@ -181,7 +188,7 @@ export const uploadProcedure = async (opts: any) => {
}; };
export const cliProcedure = t.procedure.use(({ ctx, next }) => { export const cliProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") { if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") {
throw new TRPCError({ code: "UNAUTHORIZED" }); throw new TRPCError({ code: "UNAUTHORIZED" });
} }
return next({ return next({
@@ -195,7 +202,7 @@ export const cliProcedure = t.procedure.use(({ ctx, next }) => {
}); });
export const adminProcedure = t.procedure.use(({ ctx, next }) => { export const adminProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") { if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") {
throw new TRPCError({ code: "UNAUTHORIZED" }); throw new TRPCError({ code: "UNAUTHORIZED" });
} }
return next({ return next({

View File

@@ -34,14 +34,14 @@ void app.prepare().then(async () => {
}); });
// WEBSOCKET // WEBSOCKET
setupDrawerLogsWebSocketServer(server); // setupDrawerLogsWebSocketServer(server);
setupDeploymentLogsWebSocketServer(server); // setupDeploymentLogsWebSocketServer(server);
setupDockerContainerLogsWebSocketServer(server); // setupDockerContainerLogsWebSocketServer(server);
setupDockerContainerTerminalWebSocketServer(server); // setupDockerContainerTerminalWebSocketServer(server);
setupTerminalWebSocketServer(server); // setupTerminalWebSocketServer(server);
if (!IS_CLOUD) { // if (!IS_CLOUD) {
setupDockerStatsMonitoringSocketServer(server); // setupDockerStatsMonitoringSocketServer(server);
} // }
if (process.env.NODE_ENV === "production" && !IS_CLOUD) { if (process.env.NODE_ENV === "production" && !IS_CLOUD) {
setupDirectories(); setupDirectories();

View File

@@ -0,0 +1,96 @@
import {
boolean,
integer,
pgTable,
text,
timestamp,
} from "drizzle-orm/pg-core";
export const user = pgTable("user", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").notNull(),
image: text("image"),
createdAt: timestamp("created_at").notNull(),
updatedAt: timestamp("updated_at").notNull(),
});
export const session = pgTable("session", {
id: text("id").primaryKey(),
expiresAt: timestamp("expires_at").notNull(),
token: text("token").notNull().unique(),
createdAt: timestamp("created_at").notNull(),
updatedAt: timestamp("updated_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
userId: text("user_id")
.notNull()
.references(() => user.id),
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 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"),
ownerId: text("owner_id")
.notNull()
.references(() => user.userId),
});
export const member = pgTable("member", {
id: text("id").primaryKey(),
organizationId: text("organization_id")
.notNull()
.references(() => organization.id),
userId: text("user_id")
.notNull()
.references(() => user.userId),
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.userId),
});

View File

@@ -28,6 +28,10 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@oslojs/encoding":"1.1.0",
"@oslojs/crypto":"1.0.1",
"drizzle-dbml-generator":"0.10.0",
"better-auth":"1.1.16",
"rotating-file-stream": "3.2.3", "rotating-file-stream": "3.2.3",
"@faker-js/faker": "^8.4.1", "@faker-js/faker": "^8.4.1",
"@lucia-auth/adapter-drizzle": "1.0.7", "@lucia-auth/adapter-drizzle": "1.0.7",

View File

@@ -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: {
@@ -16,6 +16,7 @@ export const lucia = new Lucia(adapter, {
secure: false, secure: false,
}, },
}, },
sessionExpiresIn: new TimeSpan(1, "d"), sessionExpiresIn: new TimeSpan(1, "d"),
getUserAttributes: (attributes) => { getUserAttributes: (attributes) => {
return { return {
@@ -46,6 +47,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) {
@@ -69,10 +71,10 @@ export async function validateRequest(
} }
if (result.user) { if (result.user) {
try { try {
if (result.user?.rol === "admin") { if (result.user?.rol === "owner") {
const admin = await findAdminByAuthId(result.user.id); const admin = await findAdminByAuthId(result.user.id);
result.user.adminId = admin.adminId; result.user.adminId = admin.adminId;
} else if (result.user?.rol === "user") { } else if (result.user?.rol === "member") {
const userResult = await findUserByAuthId(result.user.id); const userResult = await findUserByAuthId(result.user.id);
result.user.adminId = userResult.adminId; result.user.adminId = userResult.adminId;
} }

View File

@@ -35,10 +35,10 @@ export const validateBearerToken = async (
const result = await luciaToken.validateSession(sessionId); const result = await luciaToken.validateSession(sessionId);
if (result.user) { if (result.user) {
if (result.user?.rol === "admin") { if (result.user?.rol === "owner") {
const admin = await findAdminByAuthId(result.user.id); const admin = await findAdminByAuthId(result.user.id);
result.user.adminId = admin.adminId; result.user.adminId = admin.adminId;
} else if (result.user?.rol === "user") { } else if (result.user?.rol === "member") {
const userResult = await findUserByAuthId(result.user.id); const userResult = await findUserByAuthId(result.user.id);
result.user.adminId = userResult.adminId; result.user.adminId = userResult.adminId;
} }
@@ -73,10 +73,10 @@ export const validateBearerTokenAPI = async (
const result = await luciaToken.validateSession(sessionId); const result = await luciaToken.validateSession(sessionId);
if (result.user) { if (result.user) {
if (result.user?.rol === "admin") { if (result.user?.rol === "owner") {
const admin = await findAdminByAuthId(result.user.id); const admin = await findAdminByAuthId(result.user.id);
result.user.adminId = admin.adminId; result.user.adminId = admin.adminId;
} else if (result.user?.rol === "user") { } else if (result.user?.rol === "member") {
const userResult = await findUserByAuthId(result.user.id); const userResult = await findUserByAuthId(result.user.id);
result.user.adminId = userResult.adminId; result.user.adminId = userResult.adminId;
} }

View File

@@ -0,0 +1,114 @@
import { relations } from "drizzle-orm";
import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { nanoid } from "nanoid";
import { users_temp } from "./user";
export const account = pgTable("account", {
id: text("id")
.primaryKey()
.$defaultFn(() => nanoid()),
accountId: text("account_id")
.notNull()
.$defaultFn(() => nanoid()),
providerId: text("provider_id").notNull(),
userId: text("user_id")
.notNull()
.references(() => users_temp.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"),
is2FAEnabled: boolean("is2FAEnabled").notNull().default(false),
createdAt: timestamp("created_at").notNull(),
updatedAt: timestamp("updated_at").notNull(),
resetPasswordToken: text("resetPasswordToken"),
resetPasswordExpiresAt: text("resetPasswordExpiresAt"),
confirmationToken: text("confirmationToken"),
confirmationExpiresAt: text("confirmationExpiresAt"),
});
export const accountRelations = relations(account, ({ one }) => ({
user: one(users_temp, {
fields: [account.userId],
references: [users_temp.id],
}),
}));
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()
.$defaultFn(() => nanoid()),
name: text("name").notNull(),
slug: text("slug").unique(),
logo: text("logo"),
createdAt: timestamp("created_at").notNull(),
metadata: text("metadata"),
ownerId: text("owner_id")
.notNull()
.references(() => users_temp.id),
});
export const organizationRelations = relations(organization, ({ one }) => ({
owner: one(users_temp, {
fields: [organization.ownerId],
references: [users_temp.id],
}),
}));
export const member = pgTable("member", {
id: text("id")
.primaryKey()
.$defaultFn(() => nanoid()),
organizationId: text("organization_id")
.notNull()
.references(() => organization.id),
userId: text("user_id")
.notNull()
.references(() => users_temp.id),
role: text("role").notNull().$type<"owner" | "member" | "admin">(),
createdAt: timestamp("created_at").notNull(),
});
export const memberRelations = relations(member, ({ one }) => ({
organization: one(organization, {
fields: [member.organizationId],
references: [organization.id],
}),
user: one(users_temp, {
fields: [member.userId],
references: [users_temp.id],
}),
}));
export const invitation = pgTable("invitation", {
id: text("id").primaryKey(),
organizationId: text("organization_id")
.notNull()
.references(() => organization.id),
email: text("email").notNull(),
role: text("role").$type<"owner" | "member" | "admin">(),
status: text("status").notNull(),
expiresAt: timestamp("expires_at").notNull(),
inviterId: text("inviter_id")
.notNull()
.references(() => users_temp.id),
});
export const invitationRelations = relations(invitation, ({ one }) => ({
organization: one(organization, {
fields: [invitation.organizationId],
references: [organization.id],
}),
}));

View File

@@ -4,7 +4,7 @@ import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod"; import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; // import { admins } from "./admin";
import { users } from "./user"; import { users } from "./user";
const randomImages = [ const randomImages = [
@@ -55,7 +55,7 @@ export const auth = pgTable("auth", {
}); });
export const authRelations = relations(auth, ({ many }) => ({ export const authRelations = relations(auth, ({ many }) => ({
admins: many(admins), // admins: many(admins),
users: many(users), users: many(users),
})); }));
const createSchema = createInsertSchema(auth, { const createSchema = createInsertSchema(auth, {

View File

@@ -61,5 +61,5 @@ export const apiUpdateBitbucket = createSchema.extend({
name: z.string().min(1), name: z.string().min(1),
bitbucketUsername: z.string().optional(), bitbucketUsername: z.string().optional(),
bitbucketWorkspaceName: z.string().optional(), bitbucketWorkspaceName: z.string().optional(),
adminId: z.string().optional(), userId: z.string().optional(),
}); });

View File

@@ -5,6 +5,8 @@ import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; import { admins } from "./admin";
import { server } from "./server"; import { server } from "./server";
import { users_temp } from "./user";
// import { user } from "./user";
import { generateAppName } from "./utils"; import { generateAppName } from "./utils";
export const certificates = pgTable("certificate", { export const certificates = pgTable("certificate", {
@@ -20,9 +22,12 @@ export const certificates = pgTable("certificate", {
.$defaultFn(() => generateAppName("certificate")) .$defaultFn(() => generateAppName("certificate"))
.unique(), .unique(),
autoRenew: boolean("autoRenew"), autoRenew: boolean("autoRenew"),
adminId: text("adminId").references(() => admins.adminId, { // userId: text("userId").references(() => user.userId, {
onDelete: "cascade", // onDelete: "cascade",
}), // }),
userId: text("userId")
.notNull()
.references(() => users_temp.id, { onDelete: "cascade" }),
serverId: text("serverId").references(() => server.serverId, { serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade", onDelete: "cascade",
}), }),
@@ -35,9 +40,9 @@ export const certificatesRelations = relations(
fields: [certificates.serverId], fields: [certificates.serverId],
references: [server.serverId], references: [server.serverId],
}), }),
admin: one(admins, { user: one(users_temp, {
fields: [certificates.adminId], fields: [certificates.userId],
references: [admins.adminId], references: [users_temp.id],
}), }),
}), }),
); );

View File

@@ -0,0 +1,7 @@
import { pgGenerate } from "drizzle-dbml-generator"; // Using Postgres for this example
import * as schema from "./index";
const out = "./schema.dbml";
const relational = true;
pgGenerate({ schema, out, relational });

View File

@@ -5,6 +5,8 @@ import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; import { admins } from "./admin";
import { backups } from "./backups"; import { backups } from "./backups";
import { users_temp } from "./user";
// import { user } from "./user";
export const destinations = pgTable("destination", { export const destinations = pgTable("destination", {
destinationId: text("destinationId") destinationId: text("destinationId")
@@ -19,19 +21,22 @@ export const destinations = pgTable("destination", {
region: text("region").notNull(), region: text("region").notNull(),
// maybe it can be null // maybe it can be null
endpoint: text("endpoint").notNull(), endpoint: text("endpoint").notNull(),
adminId: text("adminId") // userId: text("userId")
// .notNull()
// .references(() => user.userId, { onDelete: "cascade" }),
userId: text("userId")
.notNull() .notNull()
.references(() => admins.adminId, { onDelete: "cascade" }), .references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const destinationsRelations = relations( export const destinationsRelations = relations(
destinations, destinations,
({ many, one }) => ({ ({ many, one }) => ({
backups: many(backups), backups: many(backups),
admin: one(admins, { // user: one(user, {
fields: [destinations.adminId], // fields: [destinations.userId],
references: [admins.adminId], // references: [user.id],
}), // }),
}), }),
); );

View File

@@ -7,6 +7,8 @@ import { admins } from "./admin";
import { bitbucket } from "./bitbucket"; import { bitbucket } from "./bitbucket";
import { github } from "./github"; import { github } from "./github";
import { gitlab } from "./gitlab"; import { gitlab } from "./gitlab";
import { users_temp } from "./user";
// import { user } from "./user";
export const gitProviderType = pgEnum("gitProviderType", [ export const gitProviderType = pgEnum("gitProviderType", [
"github", "github",
@@ -24,9 +26,12 @@ export const gitProvider = pgTable("git_provider", {
createdAt: text("createdAt") createdAt: text("createdAt")
.notNull() .notNull()
.$defaultFn(() => new Date().toISOString()), .$defaultFn(() => new Date().toISOString()),
adminId: text("adminId").references(() => admins.adminId, { // userId: text("userId").references(() => user.userId, {
onDelete: "cascade", // onDelete: "cascade",
}), // }),
userId: text("userId")
.notNull()
.references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({
@@ -42,9 +47,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({
fields: [gitProvider.gitProviderId], fields: [gitProvider.gitProviderId],
references: [bitbucket.gitProviderId], references: [bitbucket.gitProviderId],
}), }),
admin: one(admins, { user: one(users_temp, {
fields: [gitProvider.adminId], fields: [gitProvider.userId],
references: [admins.adminId], references: [users_temp.id],
}), }),
})); }));

View File

@@ -30,3 +30,4 @@ export * from "./gitlab";
export * from "./server"; export * from "./server";
export * from "./utils"; export * from "./utils";
export * from "./preview-deployments"; export * from "./preview-deployments";
export * from "./account";

View File

@@ -3,7 +3,8 @@ import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod"; import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; import { users_temp } from "./user";
// import { user } from "./user";
export const notificationType = pgEnum("notificationType", [ export const notificationType = pgEnum("notificationType", [
"slack", "slack",
@@ -44,9 +45,12 @@ export const notifications = pgTable("notification", {
gotifyId: text("gotifyId").references(() => gotify.gotifyId, { gotifyId: text("gotifyId").references(() => gotify.gotifyId, {
onDelete: "cascade", onDelete: "cascade",
}), }),
adminId: text("adminId").references(() => admins.adminId, { // userId: text("userId").references(() => user.userId, {
onDelete: "cascade", // onDelete: "cascade",
}), // }),
userId: text("userId")
.notNull()
.references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const slack = pgTable("slack", { export const slack = pgTable("slack", {
@@ -121,9 +125,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({
fields: [notifications.gotifyId], fields: [notifications.gotifyId],
references: [gotify.gotifyId], references: [gotify.gotifyId],
}), }),
admin: one(admins, { user: one(users_temp, {
fields: [notifications.adminId], fields: [notifications.userId],
references: [admins.adminId], references: [users_temp.id],
}), }),
})); }));
@@ -148,7 +152,7 @@ export const apiCreateSlack = notificationsSchema
export const apiUpdateSlack = apiCreateSlack.partial().extend({ export const apiUpdateSlack = apiCreateSlack.partial().extend({
notificationId: z.string().min(1), notificationId: z.string().min(1),
slackId: z.string(), slackId: z.string(),
adminId: z.string().optional(), userId: z.string().optional(),
}); });
export const apiTestSlackConnection = apiCreateSlack.pick({ export const apiTestSlackConnection = apiCreateSlack.pick({
@@ -175,7 +179,7 @@ export const apiCreateTelegram = notificationsSchema
export const apiUpdateTelegram = apiCreateTelegram.partial().extend({ export const apiUpdateTelegram = apiCreateTelegram.partial().extend({
notificationId: z.string().min(1), notificationId: z.string().min(1),
telegramId: z.string().min(1), telegramId: z.string().min(1),
adminId: z.string().optional(), userId: z.string().optional(),
}); });
export const apiTestTelegramConnection = apiCreateTelegram.pick({ export const apiTestTelegramConnection = apiCreateTelegram.pick({
@@ -202,7 +206,7 @@ export const apiCreateDiscord = notificationsSchema
export const apiUpdateDiscord = apiCreateDiscord.partial().extend({ export const apiUpdateDiscord = apiCreateDiscord.partial().extend({
notificationId: z.string().min(1), notificationId: z.string().min(1),
discordId: z.string().min(1), discordId: z.string().min(1),
adminId: z.string().optional(), userId: z.string().optional(),
}); });
export const apiTestDiscordConnection = apiCreateDiscord export const apiTestDiscordConnection = apiCreateDiscord
@@ -236,7 +240,7 @@ export const apiCreateEmail = notificationsSchema
export const apiUpdateEmail = apiCreateEmail.partial().extend({ export const apiUpdateEmail = apiCreateEmail.partial().extend({
notificationId: z.string().min(1), notificationId: z.string().min(1),
emailId: z.string().min(1), emailId: z.string().min(1),
adminId: z.string().optional(), userId: z.string().optional(),
}); });
export const apiTestEmailConnection = apiCreateEmail.pick({ export const apiTestEmailConnection = apiCreateEmail.pick({
@@ -268,7 +272,7 @@ export const apiCreateGotify = notificationsSchema
export const apiUpdateGotify = apiCreateGotify.partial().extend({ export const apiUpdateGotify = apiCreateGotify.partial().extend({
notificationId: z.string().min(1), notificationId: z.string().min(1),
gotifyId: z.string().min(1), gotifyId: z.string().min(1),
adminId: z.string().optional(), userId: z.string().optional(),
}); });
export const apiTestGotifyConnection = apiCreateGotify export const apiTestGotifyConnection = apiCreateGotify

View File

@@ -5,6 +5,7 @@ import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; import { admins } from "./admin";
// import { admins } from "./admin";
import { applications } from "./application"; import { applications } from "./application";
import { compose } from "./compose"; import { compose } from "./compose";
import { mariadb } from "./mariadb"; import { mariadb } from "./mariadb";
@@ -12,6 +13,7 @@ import { mongo } from "./mongo";
import { mysql } from "./mysql"; import { mysql } from "./mysql";
import { postgres } from "./postgres"; import { postgres } from "./postgres";
import { redis } from "./redis"; import { redis } from "./redis";
import { users, users_temp } from "./user";
export const projects = pgTable("project", { export const projects = pgTable("project", {
projectId: text("projectId") projectId: text("projectId")
@@ -23,9 +25,12 @@ export const projects = pgTable("project", {
createdAt: text("createdAt") createdAt: text("createdAt")
.notNull() .notNull()
.$defaultFn(() => new Date().toISOString()), .$defaultFn(() => new Date().toISOString()),
adminId: text("adminId") // userId: text("userId")
// .notNull()
// .references(() => user.userId, { onDelete: "cascade" }),
userId: text("userId")
.notNull() .notNull()
.references(() => admins.adminId, { onDelete: "cascade" }), .references(() => users_temp.id, { onDelete: "cascade" }),
env: text("env").notNull().default(""), env: text("env").notNull().default(""),
}); });
@@ -37,10 +42,10 @@ export const projectRelations = relations(projects, ({ many, one }) => ({
mongo: many(mongo), mongo: many(mongo),
redis: many(redis), redis: many(redis),
compose: many(compose), compose: many(compose),
admin: one(admins, { // user: one(user, {
fields: [projects.adminId], // fields: [projects.userId],
references: [admins.adminId], // references: [user.id],
}), // }),
})); }));
const createSchema = createInsertSchema(projects, { const createSchema = createInsertSchema(projects, {

View File

@@ -5,6 +5,8 @@ import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { admins } from "./admin"; import { admins } from "./admin";
import { applications } from "./application"; import { applications } from "./application";
import { users_temp } from "./user";
// import { user } from "./user";
/** /**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
* database instance for multiple projects. * database instance for multiple projects.
@@ -27,16 +29,19 @@ export const registry = pgTable("registry", {
.notNull() .notNull()
.$defaultFn(() => new Date().toISOString()), .$defaultFn(() => new Date().toISOString()),
registryType: registryType("selfHosted").notNull().default("cloud"), registryType: registryType("selfHosted").notNull().default("cloud"),
adminId: text("adminId") // userId: text("userId")
// .notNull()
// .references(() => user.userId, { onDelete: "cascade" }),
userId: text("userId")
.notNull() .notNull()
.references(() => admins.adminId, { onDelete: "cascade" }), .references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const registryRelations = relations(registry, ({ one, many }) => ({ export const registryRelations = relations(registry, ({ one, many }) => ({
admin: one(admins, { // user: one(user, {
fields: [registry.adminId], // fields: [registry.userId],
references: [admins.adminId], // references: [user.id],
}), // }),
applications: many(applications), applications: many(applications),
})); }));
@@ -45,7 +50,7 @@ const createSchema = createInsertSchema(registry, {
username: z.string().min(1), username: z.string().min(1),
password: z.string().min(1), password: z.string().min(1),
registryUrl: z.string(), registryUrl: z.string(),
adminId: z.string().min(1), userId: z.string().min(1),
registryId: z.string().min(1), registryId: z.string().min(1),
registryType: z.enum(["cloud"]), registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(), imagePrefix: z.string().nullable().optional(),

View File

@@ -0,0 +1,872 @@
enum applicationStatus {
idle
running
done
error
}
enum buildType {
dockerfile
heroku_buildpacks
paketo_buildpacks
nixpacks
static
}
enum certificateType {
letsencrypt
none
}
enum composeType {
"docker-compose"
stack
}
enum databaseType {
postgres
mariadb
mysql
mongo
}
enum deploymentStatus {
running
done
error
}
enum domainType {
compose
application
preview
}
enum gitProviderType {
github
gitlab
bitbucket
}
enum mountType {
bind
volume
file
}
enum notificationType {
slack
telegram
discord
email
gotify
}
enum protocolType {
tcp
udp
}
enum RegistryType {
selfHosted
cloud
}
enum Roles {
admin
user
}
enum serverStatus {
active
inactive
}
enum serviceType {
application
postgres
mysql
mariadb
mongo
redis
compose
}
enum sourceType {
docker
git
github
gitlab
bitbucket
drop
}
enum sourceTypeCompose {
git
github
gitlab
bitbucket
raw
}
table account {
id text [pk, not null]
account_id text [not null]
provider_id text [not null]
user_id text [not null]
access_token text
refresh_token text
id_token text
access_token_expires_at timestamp
refresh_token_expires_at timestamp
scope text
password text
is2FAEnabled boolean [not null, default: false]
created_at timestamp [not null]
updated_at timestamp [not null]
resetPasswordToken text
resetPasswordExpiresAt text
confirmationToken text
confirmationExpiresAt text
}
table admin {
}
table application {
applicationId text [pk, not null]
name text [not null]
appName text [not null, unique]
description text
env text
previewEnv text
previewBuildArgs text
previewWildcard text
previewPort integer [default: 3000]
previewHttps boolean [not null, default: false]
previewPath text [default: '/']
certificateType certificateType [not null, default: 'none']
previewLimit integer [default: 3]
isPreviewDeploymentsActive boolean [default: false]
buildArgs text
memoryReservation text
memoryLimit text
cpuReservation text
cpuLimit text
title text
enabled boolean
subtitle text
command text
refreshToken text
sourceType sourceType [not null, default: 'github']
repository text
owner text
branch text
buildPath text [default: '/']
autoDeploy boolean
gitlabProjectId integer
gitlabRepository text
gitlabOwner text
gitlabBranch text
gitlabBuildPath text [default: '/']
gitlabPathNamespace text
bitbucketRepository text
bitbucketOwner text
bitbucketBranch text
bitbucketBuildPath text [default: '/']
username text
password text
dockerImage text
registryUrl text
customGitUrl text
customGitBranch text
customGitBuildPath text
customGitSSHKeyId text
dockerfile text
dockerContextPath text
dockerBuildStage text
dropBuildPath text
healthCheckSwarm json
restartPolicySwarm json
placementSwarm json
updateConfigSwarm json
rollbackConfigSwarm json
modeSwarm json
labelsSwarm json
networkSwarm json
replicas integer [not null, default: 1]
applicationStatus applicationStatus [not null, default: 'idle']
buildType buildType [not null, default: 'nixpacks']
herokuVersion text [default: '24']
publishDirectory text
createdAt text [not null]
registryId text
projectId text [not null]
githubId text
gitlabId text
bitbucketId text
serverId text
}
table auth {
id text [pk, not null]
email text [not null, unique]
password text [not null]
rol Roles [not null]
image text
secret text
token text
is2FAEnabled boolean [not null, default: false]
createdAt text [not null]
resetPasswordToken text
resetPasswordExpiresAt text
confirmationToken text
confirmationExpiresAt text
}
table backup {
backupId text [pk, not null]
schedule text [not null]
enabled boolean
database text [not null]
prefix text [not null]
destinationId text [not null]
databaseType databaseType [not null]
postgresId text
mariadbId text
mysqlId text
mongoId text
}
table bitbucket {
bitbucketId text [pk, not null]
bitbucketUsername text
appPassword text
bitbucketWorkspaceName text
gitProviderId text [not null]
}
table certificate {
certificateId text [pk, not null]
name text [not null]
certificateData text [not null]
privateKey text [not null]
certificatePath text [not null, unique]
autoRenew boolean
userId text
serverId text
}
table compose {
composeId text [pk, not null]
name text [not null]
appName text [not null]
description text
env text
composeFile text [not null, default: '']
refreshToken text
sourceType sourceTypeCompose [not null, default: 'github']
composeType composeType [not null, default: 'docker-compose']
repository text
owner text
branch text
autoDeploy boolean
gitlabProjectId integer
gitlabRepository text
gitlabOwner text
gitlabBranch text
gitlabPathNamespace text
bitbucketRepository text
bitbucketOwner text
bitbucketBranch text
customGitUrl text
customGitBranch text
customGitSSHKeyId text
command text [not null, default: '']
composePath text [not null, default: './docker-compose.yml']
suffix text [not null, default: '']
randomize boolean [not null, default: false]
isolatedDeployment boolean [not null, default: false]
composeStatus applicationStatus [not null, default: 'idle']
projectId text [not null]
createdAt text [not null]
githubId text
gitlabId text
bitbucketId text
serverId text
}
table deployment {
deploymentId text [pk, not null]
title text [not null]
description text
status deploymentStatus [default: 'running']
logPath text [not null]
applicationId text
composeId text
serverId text
isPreviewDeployment boolean [default: false]
previewDeploymentId text
createdAt text [not null]
errorMessage text
}
table destination {
destinationId text [pk, not null]
name text [not null]
provider text
accessKey text [not null]
secretAccessKey text [not null]
bucket text [not null]
region text [not null]
endpoint text [not null]
userId text [not null]
}
table discord {
discordId text [pk, not null]
webhookUrl text [not null]
decoration boolean
}
table domain {
domainId text [pk, not null]
host text [not null]
https boolean [not null, default: false]
port integer [default: 3000]
path text [default: '/']
serviceName text
domainType domainType [default: 'application']
uniqueConfigKey serial [not null, increment]
createdAt text [not null]
composeId text
applicationId text
previewDeploymentId text
certificateType certificateType [not null, default: 'none']
}
table email {
emailId text [pk, not null]
smtpServer text [not null]
smtpPort integer [not null]
username text [not null]
password text [not null]
fromAddress text [not null]
toAddress text[] [not null]
}
table git_provider {
gitProviderId text [pk, not null]
name text [not null]
providerType gitProviderType [not null, default: 'github']
createdAt text [not null]
userId text
}
table github {
githubId text [pk, not null]
githubAppName text
githubAppId integer
githubClientId text
githubClientSecret text
githubInstallationId text
githubPrivateKey text
githubWebhookSecret text
gitProviderId text [not null]
}
table gitlab {
gitlabId text [pk, not null]
gitlabUrl text [not null, default: 'https://gitlab.com']
application_id text
redirect_uri text
secret text
access_token text
refresh_token text
group_name text
expires_at integer
gitProviderId text [not null]
}
table gotify {
gotifyId text [pk, not null]
serverUrl text [not null]
appToken text [not null]
priority integer [not null, default: 5]
decoration boolean
}
table invitation {
id text [pk, not null]
organization_id text [not null]
email text [not null]
role text
status text [not null]
expires_at timestamp [not null]
inviter_id text [not null]
}
table mariadb {
mariadbId text [pk, not null]
name text [not null]
appName text [not null, unique]
description text
databaseName text [not null]
databaseUser text [not null]
databasePassword text [not null]
rootPassword text [not null]
dockerImage text [not null]
command text
env text
memoryReservation text
memoryLimit text
cpuReservation text
cpuLimit text
externalPort integer
applicationStatus applicationStatus [not null, default: 'idle']
createdAt text [not null]
projectId text [not null]
serverId text
}
table member {
id text [pk, not null]
organization_id text [not null]
user_id text [not null]
role text [not null]
created_at timestamp [not null]
}
table mongo {
mongoId text [pk, not null]
name text [not null]
appName text [not null, unique]
description text
databaseUser text [not null]
databasePassword text [not null]
dockerImage text [not null]
command text
env text
memoryReservation text
memoryLimit text
cpuReservation text
cpuLimit text
externalPort integer
applicationStatus applicationStatus [not null, default: 'idle']
createdAt text [not null]
projectId text [not null]
serverId text
replicaSets boolean [default: false]
}
table mount {
mountId text [pk, not null]
type mountType [not null]
hostPath text
volumeName text
filePath text
content text
serviceType serviceType [not null, default: 'application']
mountPath text [not null]
applicationId text
postgresId text
mariadbId text
mongoId text
mysqlId text
redisId text
composeId text
}
table mysql {
mysqlId text [pk, not null]
name text [not null]
appName text [not null, unique]
description text
databaseName text [not null]
databaseUser text [not null]
databasePassword text [not null]
rootPassword text [not null]
dockerImage text [not null]
command text
env text
memoryReservation text
memoryLimit text
cpuReservation text
cpuLimit text
externalPort integer
applicationStatus applicationStatus [not null, default: 'idle']
createdAt text [not null]
projectId text [not null]
serverId text
}
table notification {
notificationId text [pk, not null]
name text [not null]
appDeploy boolean [not null, default: false]
appBuildError boolean [not null, default: false]
databaseBackup boolean [not null, default: false]
dokployRestart boolean [not null, default: false]
dockerCleanup boolean [not null, default: false]
serverThreshold boolean [not null, default: false]
notificationType notificationType [not null]
createdAt text [not null]
slackId text
telegramId text
discordId text
emailId text
gotifyId text
userId text
}
table organization {
id text [pk, not null]
name text [not null]
slug text [unique]
logo text
created_at timestamp [not null]
metadata text
owner_id text [not null]
}
table port {
portId text [pk, not null]
publishedPort integer [not null]
targetPort integer [not null]
protocol protocolType [not null]
applicationId text [not null]
}
table postgres {
postgresId text [pk, not null]
name text [not null]
appName text [not null, unique]
databaseName text [not null]
databaseUser text [not null]
databasePassword text [not null]
description text
dockerImage text [not null]
command text
env text
memoryReservation text
externalPort integer
memoryLimit text
cpuReservation text
cpuLimit text
applicationStatus applicationStatus [not null, default: 'idle']
createdAt text [not null]
projectId text [not null]
serverId text
}
table preview_deployments {
previewDeploymentId text [pk, not null]
branch text [not null]
pullRequestId text [not null]
pullRequestNumber text [not null]
pullRequestURL text [not null]
pullRequestTitle text [not null]
pullRequestCommentId text [not null]
previewStatus applicationStatus [not null, default: 'idle']
appName text [not null, unique]
applicationId text [not null]
domainId text
createdAt text [not null]
expiresAt text
}
table project {
projectId text [pk, not null]
name text [not null]
description text
createdAt text [not null]
userId text [not null]
env text [not null, default: '']
}
table redirect {
redirectId text [pk, not null]
regex text [not null]
replacement text [not null]
permanent boolean [not null, default: false]
uniqueConfigKey serial [not null, increment]
createdAt text [not null]
applicationId text [not null]
}
table redis {
redisId text [pk, not null]
name text [not null]
appName text [not null, unique]
description text
password text [not null]
dockerImage text [not null]
command text
env text
memoryReservation text
memoryLimit text
cpuReservation text
cpuLimit text
externalPort integer
createdAt text [not null]
applicationStatus applicationStatus [not null, default: 'idle']
projectId text [not null]
serverId text
}
table registry {
registryId text [pk, not null]
registryName text [not null]
imagePrefix text
username text [not null]
password text [not null]
registryUrl text [not null, default: '']
createdAt text [not null]
selfHosted RegistryType [not null, default: 'cloud']
userId text [not null]
}
table security {
securityId text [pk, not null]
username text [not null]
password text [not null]
createdAt text [not null]
applicationId text [not null]
indexes {
(username, applicationId) [name: 'security_username_applicationId_unique', unique]
}
}
table server {
serverId text [pk, not null]
name text [not null]
description text
ipAddress text [not null]
port integer [not null]
username text [not null, default: 'root']
appName text [not null]
enableDockerCleanup boolean [not null, default: false]
createdAt text [not null]
userId text [not null]
serverStatus serverStatus [not null, default: 'active']
command text [not null, default: '']
sshKeyId text
metricsConfig jsonb [not null, default: `{"server":{"type":"Remote","refreshRate":60,"port":4500,"token":"","urlCallback":"","cronJob":"","retentionDays":2,"thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`]
}
table session {
id text [pk, not null]
expires_at timestamp [not null]
token text [not null, unique]
created_at timestamp [not null]
updated_at timestamp [not null]
ip_address text
user_agent text
user_id text [not null]
impersonated_by text
active_organization_id text
}
table slack {
slackId text [pk, not null]
webhookUrl text [not null]
channel text
}
table "ssh-key" {
sshKeyId text [pk, not null]
privateKey text [not null, default: '']
publicKey text [not null]
name text [not null]
description text
createdAt text [not null]
lastUsedAt text
userId text
}
table telegram {
telegramId text [pk, not null]
botToken text [not null]
chatId text [not null]
}
table user {
id text [pk, not null]
name text [not null, default: '']
token text [not null]
isRegistered boolean [not null, default: false]
expirationDate text [not null]
createdAt text [not null]
canCreateProjects boolean [not null, default: false]
canAccessToSSHKeys boolean [not null, default: false]
canCreateServices boolean [not null, default: false]
canDeleteProjects boolean [not null, default: false]
canDeleteServices boolean [not null, default: false]
canAccessToDocker boolean [not null, default: false]
canAccessToAPI boolean [not null, default: false]
canAccessToGitProviders boolean [not null, default: false]
canAccessToTraefikFiles boolean [not null, default: false]
accesedProjects text[] [not null, default: `ARRAY[]::text[]`]
accesedServices text[] [not null, default: `ARRAY[]::text[]`]
email text [not null, unique]
email_verified boolean [not null]
image text
role text
banned boolean
ban_reason text
ban_expires timestamp
updated_at timestamp [not null]
serverIp text
certificateType certificateType [not null, default: 'none']
host text
letsEncryptEmail text
sshPrivateKey text
enableDockerCleanup boolean [not null, default: false]
enableLogRotation boolean [not null, default: false]
enablePaidFeatures boolean [not null, default: false]
metricsConfig jsonb [not null, default: `{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`]
cleanupCacheApplications boolean [not null, default: false]
cleanupCacheOnPreviews boolean [not null, default: false]
cleanupCacheOnCompose boolean [not null, default: false]
stripeCustomerId text
stripeSubscriptionId text
serversQuantity integer [not null, default: 0]
}
table verification {
id text [pk, not null]
identifier text [not null]
value text [not null]
expires_at timestamp [not null]
created_at timestamp
updated_at timestamp
}
ref: mount.applicationId > application.applicationId
ref: mount.postgresId > postgres.postgresId
ref: mount.mariadbId > mariadb.mariadbId
ref: mount.mongoId > mongo.mongoId
ref: mount.mysqlId > mysql.mysqlId
ref: mount.redisId > redis.redisId
ref: mount.composeId > compose.composeId
ref: application.projectId > project.projectId
ref: application.customGitSSHKeyId > "ssh-key".sshKeyId
ref: application.registryId > registry.registryId
ref: application.githubId - github.githubId
ref: application.gitlabId - gitlab.gitlabId
ref: application.bitbucketId - bitbucket.bitbucketId
ref: application.serverId > server.serverId
ref: backup.destinationId > destination.destinationId
ref: backup.postgresId > postgres.postgresId
ref: backup.mariadbId > mariadb.mariadbId
ref: backup.mysqlId > mysql.mysqlId
ref: backup.mongoId > mongo.mongoId
ref: git_provider.gitProviderId - bitbucket.gitProviderId
ref: certificate.serverId > server.serverId
ref: certificate.userId - user.id
ref: compose.projectId > project.projectId
ref: compose.customGitSSHKeyId > "ssh-key".sshKeyId
ref: compose.githubId - github.githubId
ref: compose.gitlabId - gitlab.gitlabId
ref: compose.bitbucketId - bitbucket.bitbucketId
ref: compose.serverId > server.serverId
ref: deployment.applicationId > application.applicationId
ref: deployment.composeId > compose.composeId
ref: deployment.serverId > server.serverId
ref: deployment.previewDeploymentId > preview_deployments.previewDeploymentId
ref: destination.userId - user.id
ref: domain.applicationId > application.applicationId
ref: domain.composeId > compose.composeId
ref: preview_deployments.domainId - domain.domainId
ref: github.gitProviderId - git_provider.gitProviderId
ref: gitlab.gitProviderId - git_provider.gitProviderId
ref: git_provider.userId - user.id
ref: mariadb.projectId > project.projectId
ref: mariadb.serverId > server.serverId
ref: mongo.projectId > project.projectId
ref: mongo.serverId > server.serverId
ref: mysql.projectId > project.projectId
ref: mysql.serverId > server.serverId
ref: notification.slackId - slack.slackId
ref: notification.telegramId - telegram.telegramId
ref: notification.discordId - discord.discordId
ref: notification.emailId - email.emailId
ref: notification.gotifyId - gotify.gotifyId
ref: notification.userId - user.id
ref: port.applicationId > application.applicationId
ref: postgres.projectId > project.projectId
ref: postgres.serverId > server.serverId
ref: preview_deployments.applicationId > application.applicationId
ref: project.userId - user.id
ref: redirect.applicationId > application.applicationId
ref: redis.projectId > project.projectId
ref: redis.serverId > server.serverId
ref: registry.userId - user.id
ref: security.applicationId > application.applicationId
ref: server.userId - user.id
ref: server.sshKeyId > "ssh-key".sshKeyId
ref: "ssh-key".userId - user.id

View File

@@ -22,6 +22,8 @@ import { mysql } from "./mysql";
import { postgres } from "./postgres"; import { postgres } from "./postgres";
import { redis } from "./redis"; import { redis } from "./redis";
import { sshKeys } from "./ssh-key"; import { sshKeys } from "./ssh-key";
import { users_temp } from "./user";
// import { user } from "./user";
import { generateAppName } from "./utils"; import { generateAppName } from "./utils";
export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]);
@@ -40,12 +42,14 @@ export const server = pgTable("server", {
.notNull() .notNull()
.$defaultFn(() => generateAppName("server")), .$defaultFn(() => generateAppName("server")),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
createdAt: text("createdAt") createdAt: text("createdAt").notNull(),
// .$defaultFn(() => new Date().toISOString()),
// userId: text("userId")
// .notNull()
// .references(() => user.userId, { onDelete: "cascade" }),
userId: text("userId")
.notNull() .notNull()
.$defaultFn(() => new Date().toISOString()), .references(() => users_temp.id, { onDelete: "cascade" }),
adminId: text("adminId")
.notNull()
.references(() => admins.adminId, { onDelete: "cascade" }),
serverStatus: serverStatus("serverStatus").notNull().default("active"), serverStatus: serverStatus("serverStatus").notNull().default("active"),
command: text("command").notNull().default(""), command: text("command").notNull().default(""),
sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, {
@@ -100,10 +104,10 @@ export const server = pgTable("server", {
}); });
export const serverRelations = relations(server, ({ one, many }) => ({ export const serverRelations = relations(server, ({ one, many }) => ({
admin: one(admins, { // user: one(user, {
fields: [server.adminId], // fields: [server.userId],
references: [admins.adminId], // references: [user.id],
}), // }),
deployments: many(deployments), deployments: many(deployments),
sshKey: one(sshKeys, { sshKey: one(sshKeys, {
fields: [server.sshKeyId], fields: [server.sshKeyId],

View File

@@ -1,5 +1,23 @@
import { sql } from "drizzle-orm";
import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { auth } from "./auth"; import { auth } from "./auth";
import { users_temp } from "./user";
// OLD TABLE
export const session = pgTable("session_temp", {
id: text("id").primaryKey(),
expiresAt: timestamp("expires_at").notNull(),
token: text("token").notNull().unique(),
createdAt: timestamp("created_at").notNull(),
updatedAt: timestamp("updated_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
userId: text("user_id")
.notNull()
.references(() => users_temp.id),
impersonatedBy: text("impersonated_by"),
activeOrganizationId: text("active_organization_id"),
});
export const sessionTable = pgTable("session", { export const sessionTable = pgTable("session", {
id: text("id").primaryKey(), id: text("id").primaryKey(),

View File

@@ -7,6 +7,8 @@ import { admins } from "./admin";
import { applications } from "./application"; import { applications } from "./application";
import { compose } from "./compose"; import { compose } from "./compose";
import { server } from "./server"; import { server } from "./server";
import { users_temp } from "./user";
// import { user } from "./user";
export const sshKeys = pgTable("ssh-key", { export const sshKeys = pgTable("ssh-key", {
sshKeyId: text("sshKeyId") sshKeyId: text("sshKeyId")
@@ -21,18 +23,21 @@ export const sshKeys = pgTable("ssh-key", {
.notNull() .notNull()
.$defaultFn(() => new Date().toISOString()), .$defaultFn(() => new Date().toISOString()),
lastUsedAt: text("lastUsedAt"), lastUsedAt: text("lastUsedAt"),
adminId: text("adminId").references(() => admins.adminId, { // userId: text("userId").references(() => user.userId, {
onDelete: "cascade", // onDelete: "cascade",
}), // }),
userId: text("userId")
.notNull()
.references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({
applications: many(applications), applications: many(applications),
compose: many(compose), compose: many(compose),
servers: many(server), servers: many(server),
admin: one(admins, { user: one(users_temp, {
fields: [sshKeys.adminId], fields: [sshKeys.userId],
references: [admins.adminId], references: [users_temp.id],
}), }),
})); }));
@@ -48,7 +53,7 @@ export const apiCreateSshKey = createSchema
description: true, description: true,
privateKey: true, privateKey: true,
publicKey: true, publicKey: true,
adminId: true, userId: true,
}) })
.merge(sshKeyCreate.pick({ privateKey: true })); .merge(sshKeyCreate.pick({ privateKey: true }));

View File

@@ -1,10 +1,19 @@
import { relations, sql } from "drizzle-orm"; import { relations, sql } from "drizzle-orm";
import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import {
boolean,
integer,
jsonb,
pgTable,
text,
timestamp,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod"; import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { account, organization } from "./account";
import { admins } from "./admin"; import { admins } from "./admin";
import { auth } from "./auth"; import { auth } from "./auth";
import { certificateType } from "./shared";
/** /**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
* database instance for multiple projects. * database instance for multiple projects.
@@ -12,6 +21,8 @@ import { auth } from "./auth";
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema * @see https://orm.drizzle.team/docs/goodies#multi-project-schema
*/ */
// OLD TABLE
export const users = pgTable("user", { export const users = pgTable("user", {
userId: text("userId") userId: text("userId")
.notNull() .notNull()
@@ -56,23 +67,146 @@ export const users = pgTable("user", {
.references(() => auth.id, { onDelete: "cascade" }), .references(() => auth.id, { onDelete: "cascade" }),
}); });
export const usersRelations = relations(users, ({ one }) => ({ // TEMP
auth: one(auth, { export const users_temp = pgTable("user_temp", {
fields: [users.authId], id: text("id")
references: [auth.id], .notNull()
}), .primaryKey()
admin: one(admins, { .$defaultFn(() => nanoid()),
fields: [users.adminId], name: text("name").notNull().default(""),
references: [admins.adminId], token: text("token").notNull().default(""),
isRegistered: boolean("isRegistered").notNull().default(false),
expirationDate: text("expirationDate")
.notNull()
.$defaultFn(() => new Date().toISOString()),
createdAt2: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
createdAt: timestamp("created_at").defaultNow(),
canCreateProjects: boolean("canCreateProjects").notNull().default(false),
canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
canCreateServices: boolean("canCreateServices").notNull().default(false),
canDeleteProjects: boolean("canDeleteProjects").notNull().default(false),
canDeleteServices: boolean("canDeleteServices").notNull().default(false),
canAccessToDocker: boolean("canAccessToDocker").notNull().default(false),
canAccessToAPI: boolean("canAccessToAPI").notNull().default(false),
canAccessToGitProviders: boolean("canAccessToGitProviders")
.notNull()
.default(false),
canAccessToTraefikFiles: boolean("canAccessToTraefikFiles")
.notNull()
.default(false),
accessedProjects: text("accesedProjects")
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
accessedServices: text("accesedServices")
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
// authId: text("authId")
// .notNull()
// .references(() => auth.id, { onDelete: "cascade" }),
// Auth
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").notNull(),
image: text("image"),
banned: boolean("banned"),
banReason: text("ban_reason"),
banExpires: timestamp("ban_expires"),
updatedAt: timestamp("updated_at").notNull(),
// Admin
serverIp: text("serverIp"),
certificateType: certificateType("certificateType").notNull().default("none"),
host: text("host"),
letsEncryptEmail: text("letsEncryptEmail"),
sshPrivateKey: text("sshPrivateKey"),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
enableLogRotation: boolean("enableLogRotation").notNull().default(false),
// Metrics
enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false),
metricsConfig: jsonb("metricsConfig")
.$type<{
server: {
type: "Dokploy" | "Remote";
refreshRate: number;
port: number;
token: string;
urlCallback: string;
retentionDays: number;
cronJob: string;
thresholds: {
cpu: number;
memory: number;
};
};
containers: {
refreshRate: number;
services: {
include: string[];
exclude: string[];
};
};
}>()
.notNull()
.default({
server: {
type: "Dokploy",
refreshRate: 60,
port: 4500,
token: "",
retentionDays: 2,
cronJob: "",
urlCallback: "",
thresholds: {
cpu: 0,
memory: 0,
},
},
containers: {
refreshRate: 60,
services: {
include: [],
exclude: [],
},
},
}),
cleanupCacheApplications: boolean("cleanupCacheApplications")
.notNull()
.default(false),
cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews")
.notNull()
.default(false),
cleanupCacheOnCompose: boolean("cleanupCacheOnCompose")
.notNull()
.default(false),
stripeCustomerId: text("stripeCustomerId"),
stripeSubscriptionId: text("stripeSubscriptionId"),
serversQuantity: integer("serversQuantity").notNull().default(0),
});
export const usersRelations = relations(users_temp, ({ one, many }) => ({
// auth: one(auth, {
// fields: [users.authId],
// references: [auth.id],
// }),
account: one(account, {
fields: [users_temp.id],
references: [account.userId],
}), }),
organizations: many(organization),
// admin: one(admins, {
// fields: [users.adminId],
// references: [admins.adminId],
// }),
})); }));
const createSchema = createInsertSchema(users, { const createSchema = createInsertSchema(users_temp, {
userId: z.string().min(1), id: z.string().min(1),
authId: z.string().min(1), // authId: z.string().min(1),
token: z.string().min(1), token: z.string().min(1),
isRegistered: z.boolean().optional(), isRegistered: z.boolean().optional(),
adminId: z.string(), // adminId: z.string(),
accessedProjects: z.array(z.string()).optional(), accessedProjects: z.array(z.string()).optional(),
accessedServices: z.array(z.string()).optional(), accessedServices: z.array(z.string()).optional(),
canCreateProjects: z.boolean().optional(), canCreateProjects: z.boolean().optional(),
@@ -89,7 +223,7 @@ export const apiCreateUserInvitation = createSchema.pick({}).extend({
export const apiRemoveUser = createSchema export const apiRemoveUser = createSchema
.pick({ .pick({
authId: true, id: true,
}) })
.required(); .required();
@@ -101,7 +235,7 @@ export const apiFindOneToken = createSchema
export const apiAssignPermissions = createSchema export const apiAssignPermissions = createSchema
.pick({ .pick({
userId: true, id: true,
canCreateProjects: true, canCreateProjects: true,
canCreateServices: true, canCreateServices: true,
canDeleteProjects: true, canDeleteProjects: true,
@@ -118,12 +252,12 @@ export const apiAssignPermissions = createSchema
export const apiFindOneUser = createSchema export const apiFindOneUser = createSchema
.pick({ .pick({
userId: true, id: true,
}) })
.required(); .required();
export const apiFindOneUserByAuth = createSchema export const apiFindOneUserByAuth = createSchema
.pick({ .pick({
authId: true, // authId: true,
}) })
.required(); .required();

View File

@@ -118,3 +118,5 @@ export * from "./monitoring/utils";
export * from "./db/validations/domain"; export * from "./db/validations/domain";
export * from "./db/validations/index"; export * from "./db/validations/index";
export * from "./utils/gpu-setup"; export * from "./utils/gpu-setup";
export * from "./lib/auth";

Some files were not shown because too many files have changed in this diff Show More