From 3bbbc2365cb98d6968327f33c593e6d21d9b7208 Mon Sep 17 00:00:00 2001 From: Owen Schwartz Date: Tue, 1 Oct 2024 21:53:49 -0400 Subject: [PATCH] Add basic CRUD --- server/routers/global/global.ts | 34 ++++---- server/routers/global/org/createOrg.ts | 50 ++++++++--- server/routers/global/org/deleteOrg.ts | 58 ++++++++++--- server/routers/global/org/getOrg.ts | 59 ++++++++++--- server/routers/global/org/updateOrg.ts | 77 +++++++++++++--- .../routers/global/resource/createResource.ts | 59 ++++++++++--- .../routers/global/resource/deleteResource.ts | 61 ++++++++++--- server/routers/global/resource/getResource.ts | 62 ++++++++++--- .../routers/global/resource/updateResource.ts | 82 ++++++++++++++--- server/routers/global/site/createSite.ts | 6 +- server/routers/global/site/deleteSite.ts | 63 +++++++++++--- server/routers/global/site/getSite.ts | 62 ++++++++++--- server/routers/global/site/updateSite.ts | 87 ++++++++++++++++--- server/routers/global/target/createTarget.ts | 51 ++++++++--- server/routers/global/target/deleteTarget.ts | 58 ++++++++++--- server/routers/global/target/getTarget.ts | 59 ++++++++++--- server/routers/global/target/updateTarget.ts | 80 ++++++++++++++--- server/routers/global/user/createUser.ts | 15 ---- server/routers/global/user/deleteUser.ts | 58 ++++++++++--- server/routers/global/user/getUser.ts | 62 ++++++++++--- server/routers/global/user/updateUser.ts | 15 ---- 21 files changed, 934 insertions(+), 224 deletions(-) delete mode 100644 server/routers/global/user/createUser.ts delete mode 100644 server/routers/global/user/updateUser.ts diff --git a/server/routers/global/global.ts b/server/routers/global/global.ts index 38ba9b3f..08c3bb19 100644 --- a/server/routers/global/global.ts +++ b/server/routers/global/global.ts @@ -28,26 +28,28 @@ global.get("/", (_, res) => { res.status(200).json({ message: "Healthy" }); }); -global.get("/site", getSite); global.put("/site", createSite); -global.post("/site", updateSite); -global.delete("/site", deleteSite); -global.get("/org", getOrg); +global.get("/site/:siteId", getSite); +global.post("/site/:siteId", updateSite); +global.delete("/site/:siteId", deleteSite); + global.put("/org", createOrg); -global.post("/org", updateOrg); -global.delete("/org", deleteOrg); -global.get("/resource", getResource); +global.get("/org/:orgId", getOrg); +global.post("/org/:orgId", updateOrg); +global.delete("/org/:orgId", deleteOrg); + global.put("/resource", createResource); -global.post("/resource", updateResource); -global.delete("/resource", deleteResource); -global.get("/target", getTarget); +global.get("/resource/resourceId", getResource); +global.post("/resource/resourceId", updateResource); +global.delete("/resource/resourceId", deleteResource); + global.put("/target", createTarget); -global.post("/target", updateTarget); -global.delete("/target", deleteTarget); -global.get("/user", getUser); -global.put("/user", createUser); -global.post("/user", updateUser); -global.delete("/user", deleteUser); +global.get("/target/:targetId", getTarget); +global.post("/target/:targetId", updateTarget); +global.delete("/target/:targetId", deleteTarget); + +global.get("/user/:userId", getUser); +global.delete("/user/:userId", deleteUser); // auth global.post("/signup", signup); diff --git a/server/routers/global/org/createOrg.ts b/server/routers/global/org/createOrg.ts index 9f8f5722..ed549d39 100644 --- a/server/routers/global/org/createOrg.ts +++ b/server/routers/global/org/createOrg.ts @@ -1,15 +1,45 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { orgs } from '@server/db/schema'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const createOrgSchema = z.object({ + name: z.string().min(1).max(255), + domain: z.string().min(1).max(255), +}); export async function createOrg(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedBody = createOrgSchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { name, domain } = parsedBody.data; + + const newOrg = await db.insert(orgs).values({ + name, + domain, + }).returning(); + + return res.status(HttpCode.CREATED).send( + response({ + data: newOrg[0], + success: true, + error: false, + message: "Organization created successfully", + status: HttpCode.CREATED, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/org/deleteOrg.ts b/server/routers/global/org/deleteOrg.ts index 6c05ff05..6187b5bd 100644 --- a/server/routers/global/org/deleteOrg.ts +++ b/server/routers/global/org/deleteOrg.ts @@ -1,15 +1,53 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { orgs } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const deleteOrgSchema = z.object({ + orgId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function deleteOrg(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = deleteOrgSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { orgId } = parsedParams.data; + + const deletedOrg = await db.delete(orgs) + .where(eq(orgs.orgId, orgId)) + .returning(); + + if (deletedOrg.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Organization with ID ${orgId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: null, + success: true, + error: false, + message: "Organization deleted successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/org/getOrg.ts b/server/routers/global/org/getOrg.ts index d521c048..e93b70c8 100644 --- a/server/routers/global/org/getOrg.ts +++ b/server/routers/global/org/getOrg.ts @@ -1,15 +1,54 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { orgs } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const getOrgSchema = z.object({ + orgId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function getOrg(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = getOrgSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { orgId } = parsedParams.data; + + const org = await db.select() + .from(orgs) + .where(eq(orgs.orgId, orgId)) + .limit(1); + + if (org.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Organization with ID ${orgId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: org[0], + success: true, + error: false, + message: "Organization retrieved successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/org/updateOrg.ts b/server/routers/global/org/updateOrg.ts index 53e722aa..49b3397e 100644 --- a/server/routers/global/org/updateOrg.ts +++ b/server/routers/global/org/updateOrg.ts @@ -1,15 +1,72 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { orgs } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const updateOrgParamsSchema = z.object({ + orgId: z.string().transform(Number).pipe(z.number().int().positive()) +}); + +const updateOrgBodySchema = z.object({ + name: z.string().min(1).max(255).optional(), + domain: z.string().min(1).max(255).optional(), +}).refine(data => Object.keys(data).length > 0, { + message: "At least one field must be provided for update" +}); export async function updateOrg(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = updateOrgParamsSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const parsedBody = updateOrgBodySchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { orgId } = parsedParams.data; + const updateData = parsedBody.data; + + const updatedOrg = await db.update(orgs) + .set(updateData) + .where(eq(orgs.orgId, orgId)) + .returning(); + + if (updatedOrg.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Organization with ID ${orgId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: updatedOrg[0], + success: true, + error: false, + message: "Organization updated successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/resource/createResource.ts b/server/routers/global/resource/createResource.ts index 6b96f12b..e3544520 100644 --- a/server/routers/global/resource/createResource.ts +++ b/server/routers/global/resource/createResource.ts @@ -1,15 +1,54 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { resources } from '@server/db/schema'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request body validation +const createResourceSchema = z.object({ + siteId: z.number().int().positive(), + name: z.string().min(1).max(255), + subdomain: z.string().min(1).max(255).optional(), +}); export async function createResource(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request body + const parsedBody = createResourceSchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { siteId, name, subdomain } = parsedBody.data; + + // Generate a unique resourceId + const resourceId = "subdomain" // TODO: create the subdomain here + + // Create new resource in the database + const newResource = await db.insert(resources).values({ + resourceId, + siteId, + name, + subdomain, + }).returning(); + + return res.status(HttpCode.CREATED).send( + response({ + data: newResource[0], + success: true, + error: false, + message: "Resource created successfully", + status: HttpCode.CREATED, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/resource/deleteResource.ts b/server/routers/global/resource/deleteResource.ts index 96f9d35c..186979a1 100644 --- a/server/routers/global/resource/deleteResource.ts +++ b/server/routers/global/resource/deleteResource.ts @@ -1,15 +1,56 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { resources } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request parameters validation +const deleteResourceSchema = z.object({ + resourceId: z.string().uuid() +}); export async function deleteResource(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = deleteResourceSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { resourceId } = parsedParams.data; + + // Delete the resource from the database + const deletedResource = await db.delete(resources) + .where(eq(resources.resourceId, resourceId)) + .returning(); + + if (deletedResource.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Resource with ID ${resourceId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: null, + success: true, + error: false, + message: "Resource deleted successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/resource/getResource.ts b/server/routers/global/resource/getResource.ts index 8b623848..3473a42c 100644 --- a/server/routers/global/resource/getResource.ts +++ b/server/routers/global/resource/getResource.ts @@ -1,15 +1,57 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { resources } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request parameters validation +const getResourceSchema = z.object({ + resourceId: z.string().uuid() +}); export async function getResource(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = getResourceSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { resourceId } = parsedParams.data; + + // Fetch the resource from the database + const resource = await db.select() + .from(resources) + .where(eq(resources.resourceId, resourceId)) + .limit(1); + + if (resource.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Resource with ID ${resourceId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: resource[0], + success: true, + error: false, + message: "Resource retrieved successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/resource/updateResource.ts b/server/routers/global/resource/updateResource.ts index a1da36eb..8c30c9da 100644 --- a/server/routers/global/resource/updateResource.ts +++ b/server/routers/global/resource/updateResource.ts @@ -1,15 +1,77 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { resources } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request parameters validation +const updateResourceParamsSchema = z.object({ + resourceId: z.string().uuid() +}); + +// Define Zod schema for request body validation +const updateResourceBodySchema = z.object({ + name: z.string().min(1).max(255).optional(), + subdomain: z.string().min(1).max(255).optional(), +}).refine(data => Object.keys(data).length > 0, { + message: "At least one field must be provided for update" +}); export async function updateResource(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = updateResourceParamsSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + // Validate request body + const parsedBody = updateResourceBodySchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { resourceId } = parsedParams.data; + const updateData = parsedBody.data; + + // Update the resource in the database + const updatedResource = await db.update(resources) + .set(updateData) + .where(eq(resources.resourceId, resourceId)) + .returning(); + + if (updatedResource.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Resource with ID ${resourceId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: updatedResource[0], + success: true, + error: false, + message: "Resource updated successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/site/createSite.ts b/server/routers/global/site/createSite.ts index 05efc25e..81a639f9 100644 --- a/server/routers/global/site/createSite.ts +++ b/server/routers/global/site/createSite.ts @@ -2,11 +2,7 @@ import { Request, Response, NextFunction } from 'express'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; -interface CreateSiteRequest { - publicKey: string; - name: string; - orgId: number; -} +// define zod type here export async function createSite(req: Request, res: Response, next: NextFunction) { return res.status(HttpCode.OK).send( diff --git a/server/routers/global/site/deleteSite.ts b/server/routers/global/site/deleteSite.ts index f46d78b2..61e6e3a4 100644 --- a/server/routers/global/site/deleteSite.ts +++ b/server/routers/global/site/deleteSite.ts @@ -1,19 +1,56 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { sites } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; -interface DeleteSiteRequest { - siteId: string; -} +// Define Zod schema for request parameters validation +const deleteSiteSchema = z.object({ + siteId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function deleteSite(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = deleteSiteSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { siteId } = parsedParams.data; + + // Delete the site from the database + const deletedSite = await db.delete(sites) + .where(eq(sites.siteId, siteId)) + .returning(); + + if (deletedSite.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Site with ID ${siteId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: null, + success: true, + error: false, + message: "Site deleted successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/site/getSite.ts b/server/routers/global/site/getSite.ts index bfeb5c5d..408a8794 100644 --- a/server/routers/global/site/getSite.ts +++ b/server/routers/global/site/getSite.ts @@ -1,15 +1,57 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { sites } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request parameters validation +const getSiteSchema = z.object({ + siteId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function getSite(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = getSiteSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { siteId } = parsedParams.data; + + // Fetch the site from the database + const site = await db.select() + .from(sites) + .where(eq(sites.siteId, siteId)) + .limit(1); + + if (site.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Site with ID ${siteId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: site[0], + success: true, + error: false, + message: "Site retrieved successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/site/updateSite.ts b/server/routers/global/site/updateSite.ts index a64200cc..c21e8af8 100644 --- a/server/routers/global/site/updateSite.ts +++ b/server/routers/global/site/updateSite.ts @@ -1,15 +1,82 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { sites } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +// Define Zod schema for request parameters validation +const updateSiteParamsSchema = z.object({ + siteId: z.string().transform(Number).pipe(z.number().int().positive()) +}); + +// Define Zod schema for request body validation +const updateSiteBodySchema = z.object({ + name: z.string().min(1).max(255).optional(), + subdomain: z.string().min(1).max(255).optional(), + pubKey: z.string().optional(), + subnet: z.string().optional(), + exitNode: z.number().int().positive().optional(), + megabytesIn: z.number().int().nonnegative().optional(), + megabytesOut: z.number().int().nonnegative().optional(), +}).refine(data => Object.keys(data).length > 0, { + message: "At least one field must be provided for update" +}); export async function updateSite(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + // Validate request parameters + const parsedParams = updateSiteParamsSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + // Validate request body + const parsedBody = updateSiteBodySchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { siteId } = parsedParams.data; + const updateData = parsedBody.data; + + // Update the site in the database + const updatedSite = await db.update(sites) + .set(updateData) + .where(eq(sites.siteId, siteId)) + .returning(); + + if (updatedSite.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Site with ID ${siteId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: updatedSite[0], + success: true, + error: false, + message: "Site updated successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/target/createTarget.ts b/server/routers/global/target/createTarget.ts index 2bcfa0aa..af6a68d8 100644 --- a/server/routers/global/target/createTarget.ts +++ b/server/routers/global/target/createTarget.ts @@ -1,15 +1,46 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { targets } from '@server/db/schema'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const createTargetSchema = z.object({ + resourceId: z.string().uuid(), + ip: z.string().ip(), + method: z.string().min(1).max(10), + port: z.number().int().min(1).max(65535), + protocol: z.string().optional(), + enabled: z.boolean().default(true), +}); export async function createTarget(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedBody = createTargetSchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const targetData = parsedBody.data; + + const newTarget = await db.insert(targets).values(targetData).returning(); + + return res.status(HttpCode.CREATED).send( + response({ + data: newTarget[0], + success: true, + error: false, + message: "Target created successfully", + status: HttpCode.CREATED, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/target/deleteTarget.ts b/server/routers/global/target/deleteTarget.ts index 259071ab..8150d60c 100644 --- a/server/routers/global/target/deleteTarget.ts +++ b/server/routers/global/target/deleteTarget.ts @@ -1,15 +1,53 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { targets } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const deleteTargetSchema = z.object({ + targetId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function deleteTarget(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = deleteTargetSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { targetId } = parsedParams.data; + + const deletedTarget = await db.delete(targets) + .where(eq(targets.targetId, targetId)) + .returning(); + + if (deletedTarget.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Target with ID ${targetId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: null, + success: true, + error: false, + message: "Target deleted successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/target/getTarget.ts b/server/routers/global/target/getTarget.ts index 34f5ae92..14a39a5b 100644 --- a/server/routers/global/target/getTarget.ts +++ b/server/routers/global/target/getTarget.ts @@ -1,15 +1,54 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { targets } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const getTargetSchema = z.object({ + targetId: z.string().transform(Number).pipe(z.number().int().positive()) +}); export async function getTarget(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = getTargetSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { targetId } = parsedParams.data; + + const target = await db.select() + .from(targets) + .where(eq(targets.targetId, targetId)) + .limit(1); + + if (target.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Target with ID ${targetId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: target[0], + success: true, + error: false, + message: "Target retrieved successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/target/updateTarget.ts b/server/routers/global/target/updateTarget.ts index fecbfdcd..5ca809be 100644 --- a/server/routers/global/target/updateTarget.ts +++ b/server/routers/global/target/updateTarget.ts @@ -1,15 +1,75 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { targets } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const updateTargetParamsSchema = z.object({ + targetId: z.string().transform(Number).pipe(z.number().int().positive()) +}); + +const updateTargetBodySchema = z.object({ + ip: z.string().ip().optional(), + method: z.string().min(1).max(10).optional(), + port: z.number().int().min(1).max(65535).optional(), + protocol: z.string().optional(), + enabled: z.boolean().optional(), +}).refine(data => Object.keys(data).length > 0, { + message: "At least one field must be provided for update" +}); export async function updateTarget(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = updateTargetParamsSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const parsedBody = updateTargetBodySchema.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedBody.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { targetId } = parsedParams.data; + const updateData = parsedBody.data; + + const updatedTarget = await db.update(targets) + .set(updateData) + .where(eq(targets.targetId, targetId)) + .returning(); + + if (updatedTarget.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Target with ID ${targetId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: updatedTarget[0], + success: true, + error: false, + message: "Target updated successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/user/createUser.ts b/server/routers/global/user/createUser.ts deleted file mode 100644 index a3a1bf4d..00000000 --- a/server/routers/global/user/createUser.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; -import response from "@server/utils/response"; -import HttpCode from '@server/types/HttpCode'; - -export async function createUser(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} diff --git a/server/routers/global/user/deleteUser.ts b/server/routers/global/user/deleteUser.ts index 7acff522..8a3b446d 100644 --- a/server/routers/global/user/deleteUser.ts +++ b/server/routers/global/user/deleteUser.ts @@ -1,15 +1,53 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { users } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const deleteUserSchema = z.object({ + userId: z.string().uuid() +}); export async function deleteUser(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = deleteUserSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { userId } = parsedParams.data; + + const deletedUser = await db.delete(users) + .where(eq(users.id, userId)) + .returning(); + + if (deletedUser.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `User with ID ${userId} not found` + ) + ); + } + + return res.status(HttpCode.OK).send( + response({ + data: null, + success: true, + error: false, + message: "User deleted successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/user/getUser.ts b/server/routers/global/user/getUser.ts index 417b5332..1b1b47b2 100644 --- a/server/routers/global/user/getUser.ts +++ b/server/routers/global/user/getUser.ts @@ -1,15 +1,57 @@ import { Request, Response, NextFunction } from 'express'; +import { z } from 'zod'; +import { db } from '@server/db'; +import { users } from '@server/db/schema'; +import { eq } from 'drizzle-orm'; import response from "@server/utils/response"; import HttpCode from '@server/types/HttpCode'; +import createHttpError from 'http-errors'; + +const getUserSchema = z.object({ + userId: z.string().uuid() +}); export async function getUser(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -} + try { + const parsedParams = getUserSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + parsedParams.error.errors.map(e => e.message).join(', ') + ) + ); + } + + const { userId } = parsedParams.data; + + const user = await db.select() + .from(users) + .where(eq(users.id, userId)) + .limit(1); + + if (user.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `User with ID ${userId} not found` + ) + ); + } + + // Remove passwordHash from the response + const { passwordHash: _, ...userWithoutPassword } = user[0]; + + return res.status(HttpCode.OK).send( + response({ + data: userWithoutPassword, + success: true, + error: false, + message: "User retrieved successfully", + status: HttpCode.OK, + }) + ); + } catch (error) { + next(error); + } +} \ No newline at end of file diff --git a/server/routers/global/user/updateUser.ts b/server/routers/global/user/updateUser.ts deleted file mode 100644 index bc314fac..00000000 --- a/server/routers/global/user/updateUser.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; -import response from "@server/utils/response"; -import HttpCode from '@server/types/HttpCode'; - -export async function updateUser(req: Request, res: Response, next: NextFunction) { - return res.status(HttpCode.OK).send( - response({ - data: null, - success: true, - error: false, - message: "Logged in successfully", - status: HttpCode.OK, - }), - ); -}