diff --git a/server/db/ensureActions.ts b/server/db/ensureActions.ts index 9d3286af..82968a84 100644 --- a/server/db/ensureActions.ts +++ b/server/db/ensureActions.ts @@ -54,13 +54,14 @@ export async function createSuperuserRole(orgId: number) { const roleId = insertedRole.roleId; - // Add all current actions to the new Default role - const actionIds = Object.values(ActionsEnum); + const actionIds = await db.select().from(actions).execute(); + + if (actionIds.length === 0) { + logger.info('No actions to assign to the Superuser role'); + return; + } + await db.insert(roleActions) - .values(actionIds.map(actionId => ({ - roleId, - actionId: actionId, - orgId - }))) + .values(actionIds.map(action => ({ roleId, actionId: action.actionId, orgId }))) .execute(); } \ No newline at end of file diff --git a/server/routers/resource/createResource.ts b/server/routers/resource/createResource.ts index 88f999df..1680a990 100644 --- a/server/routers/resource/createResource.ts +++ b/server/routers/resource/createResource.ts @@ -11,7 +11,7 @@ import { eq, and } from 'drizzle-orm'; const createResourceParamsSchema = z.object({ siteId: z.number().int().positive(), - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); // Define Zod schema for request body validation diff --git a/server/routers/site/createSite.ts b/server/routers/site/createSite.ts index 3f512955..75d94416 100644 --- a/server/routers/site/createSite.ts +++ b/server/routers/site/createSite.ts @@ -13,7 +13,7 @@ import { eq, and } from 'drizzle-orm'; const API_BASE_URL = "http://localhost:3000"; const createSiteParamsSchema = z.object({ - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); // Define Zod schema for request body validation diff --git a/server/routers/site/getSite.ts b/server/routers/site/getSite.ts index cb95bed5..4eb8ea9d 100644 --- a/server/routers/site/getSite.ts +++ b/server/routers/site/getSite.ts @@ -14,6 +14,14 @@ const getSiteSchema = z.object({ siteId: z.string().transform(Number).pipe(z.number().int().positive()) }); +export type GetSiteResponse = { + siteId: number; + name: string; + subdomain: string; + pubKey: string; + subnet: string; +} + export async function getSite(req: Request, res: Response, next: NextFunction): Promise { try { // Validate request parameters diff --git a/server/routers/user/addUserOrg.ts b/server/routers/user/addUserOrg.ts index 5c3e5148..0e3f07bd 100644 --- a/server/routers/user/addUserOrg.ts +++ b/server/routers/user/addUserOrg.ts @@ -11,7 +11,7 @@ import logger from '@server/logger'; const addUserParamsSchema = z.object({ userId: z.string().uuid(), - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); const addUserSchema = z.object({ diff --git a/server/routers/user/removeUserAction.ts b/server/routers/user/removeUserAction.ts index 3b58ff72..52f4050a 100644 --- a/server/routers/user/removeUserAction.ts +++ b/server/routers/user/removeUserAction.ts @@ -15,7 +15,7 @@ const removeUserActionParamsSchema = z.object({ const removeUserActionSchema = z.object({ actionId: z.string(), - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); export async function removeUserAction(req: Request, res: Response, next: NextFunction): Promise { diff --git a/server/routers/user/removeUserOrg.ts b/server/routers/user/removeUserOrg.ts index 3c8eda5c..24cd8b27 100644 --- a/server/routers/user/removeUserOrg.ts +++ b/server/routers/user/removeUserOrg.ts @@ -11,7 +11,7 @@ import logger from '@server/logger'; const removeUserSchema = z.object({ userId: z.string().uuid(), - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); export async function removeUserOrg(req: Request, res: Response, next: NextFunction): Promise { diff --git a/server/routers/user/setUserRole.ts b/server/routers/user/setUserRole.ts index 3bae1924..89e7a9fc 100644 --- a/server/routers/user/setUserRole.ts +++ b/server/routers/user/setUserRole.ts @@ -12,7 +12,7 @@ import logger from '@server/logger'; const addUserRoleSchema = z.object({ userId: z.string(), roleId: z.number().int().positive(), - orgId: z.number().int().positive(), + orgId: z.string().transform(Number).pipe(z.number().int().positive()) }); export async function addUserRole(req: Request, res: Response, next: NextFunction): Promise { diff --git a/src/app/[orgId]/layout.tsx b/src/app/[orgId]/layout.tsx index e8d7c4d8..c7716576 100644 --- a/src/app/[orgId]/layout.tsx +++ b/src/app/[orgId]/layout.tsx @@ -22,10 +22,10 @@ const sidebarNavItems = [ interface SettingsLayoutProps { children: React.ReactNode, - params: { siteId: string } + params: { siteId: string, orgId: string } } -export default function SettingsLayout({ children, params }: SettingsLayoutProps) { +export default async function SettingsLayout({ children, params }: SettingsLayoutProps) { return ( <>
@@ -56,7 +56,9 @@ export default function SettingsLayout({ children, params }: SettingsLayoutProps -
{children}
+
+ {children} +
diff --git a/src/app/[orgId]/sites/[siteId]/components/create-site.tsx b/src/app/[orgId]/sites/[siteId]/components/create-site.tsx index 435aa405..4777a793 100644 --- a/src/app/[orgId]/sites/[siteId]/components/create-site.tsx +++ b/src/app/[orgId]/sites/[siteId]/components/create-site.tsx @@ -35,6 +35,8 @@ import { generateKeypair } from "./wireguard-config"; import React, { useState, useEffect } from "react"; import { api } from "@/api"; import { AxiosResponse } from "axios" +import { useParams } from "next/navigation"; +import { useRouter } from "next/navigation"; const method = [ { label: "Wireguard", value: "wg" }, @@ -50,6 +52,16 @@ const accountFormSchema = z.object({ .max(30, { message: "Name must not be longer than 30 characters.", }), + subdomain: z + .string() + // cant be too long and cant have spaces or special characters + .regex(/^[a-zA-Z0-9-]+$/) + .min(2, { + message: "Subdomain must be at least 2 characters.", + }) + .max(30, { + message: "Subdomain must not be longer than 30 characters.", + }), method: z.string({ required_error: "Please select a method.", }), @@ -67,6 +79,10 @@ export function CreateSiteForm() { const [keypair, setKeypair] = useState<{ publicKey: string; privateKey: string } | null>(null); const [isLoading, setIsLoading] = useState(true); + const params = useParams(); + const orgId = params.orgId; + const router = useRouter(); + const form = useForm({ resolver: zodResolver(accountFormSchema), defaultValues, @@ -80,28 +96,30 @@ export function CreateSiteForm() { } }, []); - async function onSubmit(data: AccountFormValues) { - toast({ - title: "You submitted the following values:", - description: ( -
-                    {JSON.stringify(data, null, 2)}
-                
- ), - }); - // const res = await api - // .post>(`/org/:orgId/site/:siteId/resource`, { - // email, - // password, - // }) - // .catch((e) => { - // console.error(e); - // setError( - // e.response?.data?.message || - // "An error occurred while logging in", - // ); - // }); + const name = form.watch("name"); + useEffect(() => { + const subdomain = name.toLowerCase().replace(/\s+/g, "-"); + form.setValue("subdomain", subdomain, { shouldValidate: true }); + }, [name, form]); + async function onSubmit(data: AccountFormValues) { + const res = await api + .put(`/org/${orgId}/site/`, { + name: data.name, + subdomain: data.subdomain, + pubKey: keypair?.publicKey, + }) + .catch((e) => { + toast({ + title: "Error creating site..." + }); + }); + + if (res && res.status === 201) { + const siteId = res.data.data.siteId; + // navigate to the site page + router.push(`/${orgId}/sites/${siteId}`); + } } const wgConfig = keypair @@ -140,6 +158,22 @@ sh get-docker.sh`; )} /> + ( + + Subdomain + + + + + The subdomain of the site. This will be used to access resources on the site. + + + + )} + /> {field.value ? method.find( - (language) => language.value === field.value + (method) => method.value === field.value )?.label - : "Select language"} + : "Select method"} @@ -204,17 +238,17 @@ sh get-docker.sh`; )} /> - {methodValue === "wg" && !isLoading ? ( -
-                    {wgConfig}
-                
- ) : methodValue === "wg" && isLoading ? ( -

Loading WireGuard configuration...

- ) : ( -
-                {newtConfig}
-              
- )} + {methodValue === "wg" && !isLoading ? ( +
+                            {wgConfig}
+                        
+ ) : methodValue === "wg" && isLoading ? ( +

Loading WireGuard configuration...

+ ) : ( +
+                            {newtConfig}
+                        
+ )} diff --git a/src/app/[orgId]/sites/[siteId]/layout.tsx b/src/app/[orgId]/sites/[siteId]/layout.tsx index 74517b95..373b94ca 100644 --- a/src/app/[orgId]/sites/[siteId]/layout.tsx +++ b/src/app/[orgId]/sites/[siteId]/layout.tsx @@ -3,6 +3,8 @@ import Image from "next/image" import { Separator } from "@/components/ui/separator" import { SidebarNav } from "@/components/sidebar-nav" +import SiteProvider from "@app/providers/SiteProvider" +import api from "@app/api" export const metadata: Metadata = { title: "Forms", @@ -37,7 +39,22 @@ interface SettingsLayoutProps { params: { siteId: string } } -export default function SettingsLayout({ children, params }: SettingsLayoutProps) { +export default async function SettingsLayout({ children, params }: SettingsLayoutProps) { + const res = await api + .get(`/site/${params.siteId}`, {}) + .catch((e) => { + console.error("Failed to fetch site", e); + }); + + console.log(res); + + console.log(params.siteId); + + // const site = res!.data.data; + + // console.log(site); + const site: any = {}; + return ( <>
@@ -68,7 +85,11 @@ export default function SettingsLayout({ children, params }: SettingsLayoutProps -
{children}
+
+ + {children} + +
diff --git a/src/components/SiteForm.tsx b/src/components/SiteForm.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/contexts/siteContext.ts b/src/contexts/siteContext.ts new file mode 100644 index 00000000..e8e56120 --- /dev/null +++ b/src/contexts/siteContext.ts @@ -0,0 +1,4 @@ +import { GetSiteResponse } from "@server/routers/site/getSite"; +import { createContext } from "react"; + +export const SiteContext = createContext(null); diff --git a/src/providers/SiteProvider.tsx b/src/providers/SiteProvider.tsx new file mode 100644 index 00000000..b570c19f --- /dev/null +++ b/src/providers/SiteProvider.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { SiteContext } from "@app/contexts/siteContext"; +import { GetSiteResponse } from "@server/routers/site/getSite"; +import { ReactNode } from "react"; + +type LandingProviderProps = { + site: GetSiteResponse; + children: ReactNode; +}; + +export function SiteProvider({ site, children }: LandingProviderProps) { + return {children}; +} + +export default SiteProvider;