refactor contexts, format zod errors, and more refactoring

This commit is contained in:
Milo Schwartz 2024-11-03 13:57:51 -05:00
parent 2635443105
commit 2852d62258
No known key found for this signature in database
83 changed files with 2150 additions and 1264 deletions

View file

@ -120,7 +120,8 @@ if (!parsedConfig.success) {
throw new Error(`Invalid configuration file: ${errors}`);
}
process.env.SERVER_EXTERNAL_PORT = parsedConfig.data.server.external_port.toString();
process.env.SERVER_EXTERNAL_PORT =
parsedConfig.data.server.external_port.toString();
process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED = parsedConfig.data.flags
?.require_email_verification
? "true"

View file

@ -47,7 +47,7 @@ authenticated.get("/org/:orgId/sites", verifyOrgAccess, site.listSites);
authenticated.get("/org/:orgId/site/:niceId", verifyOrgAccess, site.getSite);
authenticated.get(
"/org/:orgId/pickSiteDefaults",
"/org/:orgId/pick-site-defaults",
verifyOrgAccess,
site.pickSiteDefaults
);
@ -118,12 +118,12 @@ authenticated.delete(
target.deleteTarget
);
authenticated.put(
"/org/:orgId/role",
verifyOrgAccess,
verifySuperuser,
role.createRole
);
// authenticated.put(
// "/org/:orgId/role",
// verifyOrgAccess,
// verifySuperuser,
// role.createRole
// );
authenticated.get("/org/:orgId/roles", verifyOrgAccess, role.listRoles);
authenticated.get(
"/role/:roleId",
@ -131,18 +131,18 @@ authenticated.get(
verifyUserInRole,
role.getRole
);
authenticated.post(
"/role/:roleId",
verifyRoleAccess,
verifySuperuser,
role.updateRole
);
authenticated.delete(
"/role/:roleId",
verifyRoleAccess,
verifySuperuser,
role.deleteRole
);
// authenticated.post(
// "/role/:roleId",
// verifyRoleAccess,
// verifySuperuser,
// role.updateRole
// );
// authenticated.delete(
// "/role/:roleId",
// verifyRoleAccess,
// verifySuperuser,
// role.deleteRole
// );
authenticated.put(
"/role/:roleId/site",
@ -210,12 +210,6 @@ authenticated.delete(
verifyUserAccess,
user.removeUserOrg
);
authenticated.put(
"/org/:orgId/user/:userId",
verifyOrgAccess,
verifyUserAccess,
user.addUserOrg
);
authenticated.put(
"/user/:userId/site",

View file

@ -10,6 +10,7 @@ import logger from '@server/logger';
import config from "@server/config";
import { getUniqueExitNodeEndpointName } from '@server/db/names';
import { findNextAvailableCidr } from "@server/utils/ip";
import { fromError } from 'zod-validation-error';
// Define Zod schema for request validation
const getConfigSchema = z.object({
publicKey: z.string(),
@ -33,7 +34,7 @@ export async function getConfig(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}

View file

@ -1,32 +1,38 @@
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 { 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';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const getOrgSchema = z.object({
orgId: z.string()
orgId: z.string(),
});
export async function checkId(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function checkId(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedQuery = getOrgSchema.safeParse(req.query);
if (!parsedQuery.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedQuery.error.errors.map(e => e.message).join(', ')
fromError(parsedQuery.error).toString()
)
);
}
const { orgId } = parsedQuery.data;
const org = await db.select()
const org = await db
.select()
.from(orgs)
.where(eq(orgs.orgId, orgId))
.limit(1);
@ -50,6 +56,11 @@ export async function checkId(req: Request, res: Response, next: NextFunction):
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -10,6 +10,7 @@ import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { createSuperuserRole } from '@server/db/ensureActions';
import config, { APP_PATH } from "@server/config";
import { fromError } from 'zod-validation-error';
const createOrgSchema = z.object({
orgId: z.string(),
@ -26,7 +27,7 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}

View file

@ -8,6 +8,7 @@ import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { fromError } from 'zod-validation-error';
const deleteOrgSchema = z.object({
orgId: z.string()
@ -20,7 +21,7 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}

View file

@ -8,6 +8,7 @@ import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { fromError } from 'zod-validation-error';
const updateOrgParamsSchema = z.object({
orgId: z.string()
@ -27,7 +28,7 @@ export async function updateOrg(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -37,7 +38,7 @@ export async function updateOrg(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}

View file

@ -9,6 +9,7 @@ import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq, and } from 'drizzle-orm';
import stoi from '@server/utils/stoi';
import { fromError } from 'zod-validation-error';
const createResourceParamsSchema = z.object({
siteId: z.string().optional().transform(stoi).pipe(z.number().int().positive().optional()),
@ -29,7 +30,7 @@ export async function createResource(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -42,7 +43,7 @@ export async function createResource(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}

View file

@ -1,20 +1,25 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
// Define Zod schema for request parameters validation
const deleteResourceSchema = z.object({
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function deleteResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function deleteResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = deleteResourceSchema.safeParse(req.params);
@ -22,7 +27,7 @@ export async function deleteResource(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -30,13 +35,22 @@ export async function deleteResource(req: Request, res: Response, next: NextFunc
const { resourceId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.deleteResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Delete the resource from the database
const deletedResource = await db.delete(resources)
const deletedResource = await db
.delete(resources)
.where(eq(resources.resourceId, resourceId))
.returning();
@ -58,6 +72,11 @@ export async function deleteResource(req: Request, res: Response, next: NextFunc
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,13 +1,14 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
// Define Zod schema for request parameters validation
const getResourceSchema = z.object({
@ -19,9 +20,13 @@ export type GetResourceResponse = {
siteId: number;
orgId: string;
name: string;
}
};
export async function getResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function getResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = getResourceSchema.safeParse(req.params);
@ -29,7 +34,7 @@ export async function getResource(req: Request, res: Response, next: NextFunctio
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -37,13 +42,22 @@ export async function getResource(req: Request, res: Response, next: NextFunctio
const { resourceId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.getResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.getResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Fetch the resource from the database
const resource = await db.select()
const resource = await db
.select()
.from(resources)
.where(eq(resources.resourceId, resourceId))
.limit(1);
@ -62,7 +76,7 @@ export async function getResource(req: Request, res: Response, next: NextFunctio
resourceId: resource[0].resourceId,
siteId: resource[0].siteId,
orgId: resource[0].orgId,
name: resource[0].name
name: resource[0].name,
},
success: true,
error: false,
@ -71,6 +85,11 @@ export async function getResource(req: Request, res: Response, next: NextFunctio
});
} catch (error) {
throw error;
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleResources, roles } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleResources, roles } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listResourceRolesSchema = z.object({
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function listResourceRoles(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listResourceRoles(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = listResourceRolesSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,9 +33,17 @@ export async function listResourceRoles(req: Request, res: Response, next: NextF
const { resourceId } = parsedParams.data;
// Check if the user has permission to list resource roles
const hasPermission = await checkUserActionPermission(ActionsEnum.listResourceRoles, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listResourceRoles,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const resourceRolesList = await db
@ -53,6 +66,11 @@ export async function listResourceRoles(req: Request, res: Response, next: NextF
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
// Define Zod schema for request parameters validation
const updateResourceParamsSchema = z.object({
@ -15,14 +16,20 @@ const updateResourceParamsSchema = z.object({
});
// 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"
});
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): Promise<any> {
export async function updateResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = updateResourceParamsSchema.safeParse(req.params);
@ -30,7 +37,7 @@ export async function updateResource(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -41,7 +48,7 @@ export async function updateResource(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -50,13 +57,22 @@ export async function updateResource(req: Request, res: Response, next: NextFunc
const updateData = parsedBody.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.updateResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.updateResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Update the resource in the database
const updatedResource = await db.update(resources)
const updatedResource = await db
.update(resources)
.set(updateData)
.where(eq(resources.resourceId, resourceId))
.returning();
@ -79,6 +95,11 @@ export async function updateResource(req: Request, res: Response, next: NextFunc
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleActions, roles } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleActions, roles } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq } from 'drizzle-orm';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { eq } from "drizzle-orm";
import { fromError } from "zod-validation-error";
const addRoleActionParamSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -17,14 +18,18 @@ const addRoleActionSchema = z.object({
actionId: z.string(),
});
export async function addRoleAction(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addRoleAction(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addRoleActionSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function addRoleAction(req: Request, res: Response, next: NextFunct
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -44,22 +49,42 @@ export async function addRoleAction(req: Request, res: Response, next: NextFunct
const { roleId } = parsedParams.data;
// Check if the user has permission to add role actions
const hasPermission = await checkUserActionPermission(ActionsEnum.addRoleAction, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addRoleAction,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Get the orgId for the role
const role = await db.select({ orgId: roles.orgId }).from(roles).where(eq(roles.roleId, roleId)).limit(1);
const role = await db
.select({ orgId: roles.orgId })
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
if (role.length === 0) {
return next(createHttpError(HttpCode.NOT_FOUND, `Role with ID ${roleId} not found`));
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Role with ID ${roleId} not found`
)
);
}
const newRoleAction = await db.insert(roleActions).values({
roleId,
actionId,
orgId: role[0].orgId!,
}).returning();
const newRoleAction = await db
.insert(roleActions)
.values({
roleId,
actionId,
orgId: role[0].orgId!,
})
.returning();
return response(res, {
data: newRoleAction[0],
@ -70,6 +95,11 @@ export async function addRoleAction(req: Request, res: Response, next: NextFunct
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,12 +1,13 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleResources } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleResources } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const addRoleResourceParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -16,14 +17,18 @@ const addRoleResourceSchema = z.object({
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function addRoleResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addRoleResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addRoleResourceSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -35,7 +40,7 @@ export async function addRoleResource(req: Request, res: Response, next: NextFun
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -43,15 +48,26 @@ export async function addRoleResource(req: Request, res: Response, next: NextFun
const { roleId } = parsedParams.data;
// Check if the user has permission to add role resources
const hasPermission = await checkUserActionPermission(ActionsEnum.addRoleResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addRoleResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const newRoleResource = await db.insert(roleResources).values({
roleId,
resourceId,
}).returning();
const newRoleResource = await db
.insert(roleResources)
.values({
roleId,
resourceId,
})
.returning();
return response(res, {
data: newRoleResource[0],
@ -62,6 +78,11 @@ export async function addRoleResource(req: Request, res: Response, next: NextFun
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, roleResources, roleSites } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, roleResources, roleSites } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq } from 'drizzle-orm';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { eq } from "drizzle-orm";
import { fromError } from "zod-validation-error";
const addRoleSiteParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -17,14 +18,18 @@ const addRoleSiteSchema = z.object({
siteId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function addRoleSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addRoleSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addRoleSiteSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function addRoleSite(req: Request, res: Response, next: NextFunctio
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -44,17 +49,29 @@ export async function addRoleSite(req: Request, res: Response, next: NextFunctio
const { roleId } = parsedParams.data;
// Check if the user has permission to add role sites
const hasPermission = await checkUserActionPermission(ActionsEnum.addRoleSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addRoleSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const newRoleSite = await db.insert(roleSites).values({
roleId,
siteId,
}).returning();
const newRoleSite = await db
.insert(roleSites)
.values({
roleId,
siteId,
})
.returning();
const siteResources = await db.select()
const siteResources = await db
.select()
.from(resources)
.where(eq(resources.siteId, siteId));
@ -74,6 +91,11 @@ export async function addRoleSite(req: Request, res: Response, next: NextFunctio
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,15 +1,16 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roles } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const createRoleParamsSchema = z.object({
orgId: z.string()
orgId: z.string(),
});
const createRoleSchema = z.object({
@ -17,14 +18,18 @@ const createRoleSchema = z.object({
description: z.string().optional(),
});
export async function createRole(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function createRole(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = createRoleSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function createRole(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -44,15 +49,26 @@ export async function createRole(req: Request, res: Response, next: NextFunction
const { orgId } = parsedParams.data;
// Check if the user has permission to create roles
const hasPermission = await checkUserActionPermission(ActionsEnum.createRole, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.createRole,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const newRole = await db.insert(roles).values({
...roleData,
orgId,
}).returning();
const newRole = await db
.insert(roles)
.values({
...roleData,
orgId,
})
.returning();
return response(res, {
data: newRole[0],
@ -63,6 +79,11 @@ export async function createRole(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roles } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const deleteRoleSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive())
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function deleteRole(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function deleteRole(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = deleteRoleSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,15 +33,24 @@ export async function deleteRole(req: Request, res: Response, next: NextFunction
const { roleId } = parsedParams.data;
// Check if the user has permission to delete roles
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteRole, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.deleteRole,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const role = await db.select()
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
const role = await db
.select()
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
if (role.length === 0) {
return next(
@ -56,7 +70,8 @@ export async function deleteRole(req: Request, res: Response, next: NextFunction
);
}
const deletedRole = await db.delete(roles)
const deletedRole = await db
.delete(roles)
.where(eq(roles.roleId, roleId))
.returning();
@ -78,6 +93,11 @@ export async function deleteRole(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roles } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const getRoleSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive())
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function getRole(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function getRole(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = getRoleSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,12 +33,21 @@ export async function getRole(req: Request, res: Response, next: NextFunction):
const { roleId } = parsedParams.data;
// Check if the user has permission to get roles
const hasPermission = await checkUserActionPermission(ActionsEnum.getRole, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.getRole,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const role = await db.select()
const role = await db
.select()
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
@ -56,6 +70,11 @@ export async function getRole(req: Request, res: Response, next: NextFunction):
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleActions, actions } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleActions, actions } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listRoleActionsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function listRoleActions(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listRoleActions(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = listRoleActionsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,9 +33,17 @@ export async function listRoleActions(req: Request, res: Response, next: NextFun
const { roleId } = parsedParams.data;
// Check if the user has permission to list role actions
const hasPermission = await checkUserActionPermission(ActionsEnum.listRoleActions, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listRoleActions,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const roleActionsList = await db
@ -43,7 +56,7 @@ export async function listRoleActions(req: Request, res: Response, next: NextFun
.innerJoin(actions, eq(roleActions.actionId, actions.actionId))
.where(eq(roleActions.roleId, roleId));
// TODO: Do we need to filter out what the user can see?
// TODO: Do we need to filter out what the user can see?
return response(res, {
data: roleActionsList,
@ -54,6 +67,11 @@ export async function listRoleActions(req: Request, res: Response, next: NextFun
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleResources, resources } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleResources, 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listRoleResourcesSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function listRoleResources(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listRoleResources(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = listRoleResourcesSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,9 +33,17 @@ export async function listRoleResources(req: Request, res: Response, next: NextF
const { roleId } = parsedParams.data;
// Check if the user has permission to list role resources
const hasPermission = await checkUserActionPermission(ActionsEnum.listRoleResources, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listRoleResources,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const roleResourcesList = await db
@ -40,10 +53,13 @@ export async function listRoleResources(req: Request, res: Response, next: NextF
subdomain: resources.subdomain,
})
.from(roleResources)
.innerJoin(resources, eq(roleResources.resourceId, resources.resourceId))
.innerJoin(
resources,
eq(roleResources.resourceId, resources.resourceId)
)
.where(eq(roleResources.roleId, roleId));
// TODO: Do we need to filter out what the user can see?
// TODO: Do we need to filter out what the user can see?
return response(res, {
data: roleResourcesList,
@ -54,6 +70,11 @@ export async function listRoleResources(req: Request, res: Response, next: NextF
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleSites, sites } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleSites, 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listRoleSitesSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function listRoleSites(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listRoleSites(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = listRoleSitesSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,9 +33,17 @@ export async function listRoleSites(req: Request, res: Response, next: NextFunct
const { roleId } = parsedParams.data;
// Check if the user has permission to list role sites
const hasPermission = await checkUserActionPermission(ActionsEnum.listRoleSites, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listRoleSites,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const roleSitesList = await db
@ -42,7 +55,7 @@ export async function listRoleSites(req: Request, res: Response, next: NextFunct
.innerJoin(sites, eq(roleSites.siteId, sites.siteId))
.where(eq(roleSites.roleId, roleId));
// TODO: Do we need to filter out what the user can see?
// TODO: Do we need to filter out what the user can see?
return response(res, {
data: roleSitesList,
@ -53,6 +66,11 @@ export async function listRoleSites(req: Request, res: Response, next: NextFunct
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,32 +1,49 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles, orgs } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roles, orgs } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { sql, eq } from 'drizzle-orm';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { sql, eq } from "drizzle-orm";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listRolesParamsSchema = z.object({
orgId: z.string()
orgId: z.string(),
});
const listRolesSchema = z.object({
limit: z.string().optional().transform(Number).pipe(z.number().int().positive().default(10)),
offset: z.string().optional().transform(Number).pipe(z.number().int().nonnegative().default(0)),
orgId: z.string().optional().transform(Number).pipe(z.number().int().positive()),
limit: z
.string()
.optional()
.transform(Number)
.pipe(z.number().int().positive().default(10)),
offset: z
.string()
.optional()
.transform(Number)
.pipe(z.number().int().nonnegative().default(0)),
orgId: z
.string()
.optional()
.transform(Number)
.pipe(z.number().int().positive()),
});
export async function listRoles(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listRoles(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedQuery = listRolesSchema.safeParse(req.query);
if (!parsedQuery.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedQuery.error.errors.map(e => e.message).join(', ')
fromError(parsedQuery.error).toString()
)
);
}
@ -38,7 +55,7 @@ export async function listRoles(req: Request, res: Response, next: NextFunction)
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -46,9 +63,17 @@ export async function listRoles(req: Request, res: Response, next: NextFunction)
const { orgId } = parsedParams.data;
// Check if the user has permission to list roles
const hasPermission = await checkUserActionPermission(ActionsEnum.listRoles, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listRoles,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
let baseQuery: any = db
@ -64,8 +89,10 @@ export async function listRoles(req: Request, res: Response, next: NextFunction)
.leftJoin(orgs, eq(roles.orgId, orgs.orgId))
.where(eq(roles.orgId, orgId));
let countQuery: any = db.select({ count: sql<number>`cast(count(*) as integer)` }).from(roles)
.where(eq(roles.orgId, orgId));
let countQuery: any = db
.select({ count: sql<number>`cast(count(*) as integer)` })
.from(roles)
.where(eq(roles.orgId, orgId));
const rolesList = await baseQuery.limit(limit).offset(offset);
const totalCountResult = await countQuery;
@ -87,6 +114,11 @@ export async function listRoles(req: Request, res: Response, next: NextFunction)
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleActions } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleActions } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeRoleActionParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -17,14 +18,18 @@ const removeRoleActionSchema = z.object({
actionId: z.string(),
});
export async function removeRoleAction(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeRoleAction(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeRoleActionSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function removeRoleAction(req: Request, res: Response, next: NextFu
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -44,13 +49,27 @@ export async function removeRoleAction(req: Request, res: Response, next: NextFu
const { roleId } = parsedBody.data;
// Check if the user has permission to remove role actions
const hasPermission = await checkUserActionPermission(ActionsEnum.removeRoleAction, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeRoleAction,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedRoleAction = await db.delete(roleActions)
.where(and(eq(roleActions.roleId, roleId), eq(roleActions.actionId, actionId)))
const deletedRoleAction = await db
.delete(roleActions)
.where(
and(
eq(roleActions.roleId, roleId),
eq(roleActions.actionId, actionId)
)
)
.returning();
if (deletedRoleAction.length === 0) {
@ -71,6 +90,11 @@ export async function removeRoleAction(req: Request, res: Response, next: NextFu
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleResources } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleResources } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeRoleResourceParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -17,14 +18,18 @@ const removeRoleResourceSchema = z.object({
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function removeRoleResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeRoleResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeRoleResourceSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function removeRoleResource(req: Request, res: Response, next: Next
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -44,13 +49,27 @@ export async function removeRoleResource(req: Request, res: Response, next: Next
const { roleId } = parsedBody.data;
// Check if the user has permission to remove role resources
const hasPermission = await checkUserActionPermission(ActionsEnum.removeRoleResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeRoleResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedRoleResource = await db.delete(roleResources)
.where(and(eq(roleResources.roleId, roleId), eq(roleResources.resourceId, resourceId)))
const deletedRoleResource = await db
.delete(roleResources)
.where(
and(
eq(roleResources.roleId, roleId),
eq(roleResources.resourceId, resourceId)
)
)
.returning();
if (deletedRoleResource.length === 0) {
@ -71,6 +90,11 @@ export async function removeRoleResource(req: Request, res: Response, next: Next
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, roleResources, roleSites } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, roleResources, roleSites } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeRoleSiteParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -17,14 +18,18 @@ const removeRoleSiteSchema = z.object({
siteId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function removeRoleSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeRoleSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeRoleSiteSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function removeRoleSite(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -44,13 +49,24 @@ export async function removeRoleSite(req: Request, res: Response, next: NextFunc
const { roleId } = parsedBody.data;
// Check if the user has permission to remove role sites
const hasPermission = await checkUserActionPermission(ActionsEnum.removeRoleSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeRoleSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedRoleSite = await db.delete(roleSites)
.where(and(eq(roleSites.roleId, roleId), eq(roleSites.siteId, siteId)))
const deletedRoleSite = await db
.delete(roleSites)
.where(
and(eq(roleSites.roleId, roleId), eq(roleSites.siteId, siteId))
)
.returning();
if (deletedRoleSite.length === 0) {
@ -62,13 +78,20 @@ export async function removeRoleSite(req: Request, res: Response, next: NextFunc
);
}
const siteResources = await db.select()
.from(resources)
.where(eq(resources.siteId, siteId));
const siteResources = await db
.select()
.from(resources)
.where(eq(resources.siteId, siteId));
for (const resource of siteResources) {
await db.delete(roleResources)
.where(and(eq(roleResources.roleId, roleId), eq(roleResources.resourceId, resource.resourceId)))
await db
.delete(roleResources)
.where(
and(
eq(roleResources.roleId, roleId),
eq(roleResources.resourceId, resource.resourceId)
)
)
.returning();
}
@ -81,6 +104,11 @@ export async function removeRoleSite(req: Request, res: Response, next: NextFunc
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,33 +1,40 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roles } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const updateRoleParamsSchema = z.object({
roleId: z.string().transform(Number).pipe(z.number().int().positive())
roleId: z.string().transform(Number).pipe(z.number().int().positive()),
});
const updateRoleBodySchema = z.object({
name: z.string().min(1).max(255).optional(),
description: z.string().optional(),
}).refine(data => Object.keys(data).length > 0, {
message: "At least one field must be provided for update"
});
const updateRoleBodySchema = z
.object({
name: z.string().min(1).max(255).optional(),
description: z.string().optional(),
})
.refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided for update",
});
export async function updateRole(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function updateRole(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = updateRoleParamsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -37,7 +44,7 @@ export async function updateRole(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -46,15 +53,24 @@ export async function updateRole(req: Request, res: Response, next: NextFunction
const updateData = parsedBody.data;
// Check if the user has permission to update roles
const hasPermission = await checkUserActionPermission(ActionsEnum.updateRole, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.updateRole,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const role = await db.select()
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
const role = await db
.select()
.from(roles)
.where(eq(roles.roleId, roleId))
.limit(1);
if (role.length === 0) {
return next(
@ -74,7 +90,8 @@ export async function updateRole(req: Request, res: Response, next: NextFunction
);
}
const updatedRole = await db.update(roles)
const updatedRole = await db
.update(roles)
.set(updateData)
.where(eq(roles.roleId, roleId))
.returning();
@ -97,6 +114,11 @@ export async function updateRole(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,20 +1,25 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roles, userSites, sites, roleSites, exitNodes } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import {
roles,
userSites,
sites,
roleSites,
exitNodes,
} from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq, and } from 'drizzle-orm';
import { getUniqueSiteName } from '@server/db/names';
import { addPeer } from '../gerbil/peers';
const API_BASE_URL = "http://localhost:3000";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { eq, and } from "drizzle-orm";
import { getUniqueSiteName } from "@server/db/names";
import { addPeer } from "../gerbil/peers";
import { fromError } from "zod-validation-error";
const createSiteParamsSchema = z.object({
orgId: z.string()
orgId: z.string(),
});
// Define Zod schema for request body validation
@ -36,7 +41,11 @@ export type CreateSiteResponse = {
// subnet: string;
};
export async function createSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function createSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request body
const parsedBody = createSiteSchema.safeParse(req.body);
@ -44,7 +53,7 @@ export async function createSite(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -57,7 +66,7 @@ export async function createSite(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -65,38 +74,49 @@ export async function createSite(req: Request, res: Response, next: NextFunction
const { orgId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.createSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.createSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission perform this action"
)
);
}
if (!req.userOrgRoleId) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have a role'));
return next(
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
);
}
const niceId = await getUniqueSiteName(orgId);
// Create new site in the database
const [newSite] = await db.insert(sites).values({
orgId,
exitNodeId,
name,
niceId,
pubKey,
subnet,
}).returning();
const [newSite] = await db
.insert(sites)
.values({
orgId,
exitNodeId,
name,
niceId,
pubKey,
subnet,
})
.returning();
// find the superuser roleId and also add the resource to the superuser role
const superuserRole = await db.select()
.from(roles)
.where(and(eq(roles.isSuperuserRole, true), eq(roles.orgId, orgId)))
.limit(1);
const superuserRole = await db
.select()
.from(roles)
.where(and(eq(roles.isSuperuserRole, true), eq(roles.orgId, orgId)))
.limit(1);
if (superuserRole.length === 0) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Superuser role not found`
)
createHttpError(HttpCode.NOT_FOUND, `Superuser role not found`)
);
}
@ -135,6 +155,11 @@ export async function createSite(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,23 +1,28 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { deletePeer } from '../gerbil/peers';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { deletePeer } from "../gerbil/peers";
import { fromError } from "zod-validation-error";
const API_BASE_URL = "http://localhost:3000";
// Define Zod schema for request parameters validation
const deleteSiteSchema = z.object({
siteId: z.string().transform(Number).pipe(z.number().int().positive())
siteId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function deleteSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function deleteSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = deleteSiteSchema.safeParse(req.params);
@ -25,7 +30,7 @@ export async function deleteSite(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -33,13 +38,22 @@ export async function deleteSite(req: Request, res: Response, next: NextFunction
const { siteId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.deleteSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Delete the site from the database
const [deletedSite] = await db.delete(sites)
const [deletedSite] = await db
.delete(sites)
.where(eq(sites.siteId, siteId))
.returning();
@ -63,26 +77,33 @@ export async function deleteSite(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
async function removePeer(publicKey: string) {
try {
const response = await fetch(`${API_BASE_URL}/peer?public_key=${encodeURIComponent(publicKey)}`, {
method: 'DELETE',
});
const response = await fetch(
`${API_BASE_URL}/peer?public_key=${encodeURIComponent(publicKey)}`,
{
method: "DELETE",
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Peer removed successfully:', data.status);
console.log("Peer removed successfully:", data.status);
return data;
} catch (error: any) {
console.error('Error removing peer:', error.message);
console.error("Error removing peer:", error.message);
throw error;
}
}

View file

@ -1,18 +1,24 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { sites } from '@server/db/schema';
import { eq, and } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { sites } from "@server/db/schema";
import { eq, and } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import stoi from '@server/utils/stoi';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import stoi from "@server/utils/stoi";
import { fromError } from "zod-validation-error";
// Define Zod schema for request parameters validation
const getSiteSchema = z.object({
siteId: z.string().optional().transform(stoi).pipe(z.number().int().positive().optional()).optional(),
siteId: z
.string()
.optional()
.transform(stoi)
.pipe(z.number().int().positive().optional())
.optional(),
niceId: z.string().optional(),
orgId: z.string().optional(),
});
@ -22,9 +28,13 @@ export type GetSiteResponse = {
name: string;
subdomain: string;
subnet: string;
}
};
export async function getSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function getSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = getSiteSchema.safeParse(req.params);
@ -32,7 +42,7 @@ export async function getSite(req: Request, res: Response, next: NextFunction):
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -40,27 +50,37 @@ export async function getSite(req: Request, res: Response, next: NextFunction):
const { siteId, niceId, orgId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.updateSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.updateSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
let site;
// Fetch the site from the database
if (siteId) {
site = await db.select()
site = await db
.select()
.from(sites)
.where(eq(sites.siteId, siteId))
.limit(1);
} else if (niceId && orgId) {
site = await db.select()
site = await db
.select()
.from(sites)
.where(and(eq(sites.niceId, niceId), eq(sites.orgId, orgId)))
.limit(1);
}
if (!site) {
return next(createHttpError(HttpCode.NOT_FOUND, 'Site not found'));
return next(createHttpError(HttpCode.NOT_FOUND, "Site not found"));
}
if (site.length === 0) {
@ -86,6 +106,11 @@ export async function getSite(req: Request, res: Response, next: NextFunction):
});
} catch (error) {
logger.error("Error from getSite: ", error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { roleSites, roles } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { roleSites, roles } 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const listSiteRolesSchema = z.object({
siteId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function listSiteRoles(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function listSiteRoles(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = listSiteRolesSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,9 +33,17 @@ export async function listSiteRoles(req: Request, res: Response, next: NextFunct
const { siteId } = parsedParams.data;
// Check if the user has permission to list site roles
const hasPermission = await checkUserActionPermission(ActionsEnum.listSiteRoles, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.listSiteRoles,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const siteRolesList = await db
@ -53,6 +66,11 @@ export async function listSiteRoles(req: Request, res: Response, next: NextFunct
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -18,26 +18,25 @@ export type PickSiteDefaultsResponse = {
listenPort: number;
endpoint: string;
subnet: string;
}
};
export async function pickSiteDefaults(
req: Request,
res: Response,
next: NextFunction,
next: NextFunction
): Promise<any> {
try {
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(
ActionsEnum.createSite,
req,
req
);
if (!hasPermission) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action",
),
"User does not have permission to perform this action"
)
);
}
@ -47,10 +46,7 @@ export async function pickSiteDefaults(
const nodes = await db.select().from(exitNodes);
if (nodes.length === 0) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
"No exit nodes available",
),
createHttpError(HttpCode.NOT_FOUND, "No exit nodes available")
);
}
@ -59,9 +55,10 @@ export async function pickSiteDefaults(
// TODO: this probably can be optimized...
// list all of the sites on that exit node
const sitesQuery = await db.select({
subnet: sites.subnet
})
const sitesQuery = await db
.select({
subnet: sites.subnet,
})
.from(sites)
.where(eq(sites.exitNodeId, exitNode.exitNodeId));
@ -74,8 +71,8 @@ export async function pickSiteDefaults(
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"No available subnets",
),
"No available subnets"
)
);
}
@ -97,11 +94,7 @@ export async function pickSiteDefaults(
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred...",
),
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}

View file

@ -1,33 +1,40 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
// Define Zod schema for request parameters validation
const updateSiteParamsSchema = z.object({
siteId: z.string().transform(Number).pipe(z.number().int().positive())
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"
});
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): Promise<any> {
export async function updateSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
// Validate request parameters
const parsedParams = updateSiteParamsSchema.safeParse(req.params);
@ -35,7 +42,7 @@ export async function updateSite(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -46,7 +53,7 @@ export async function updateSite(req: Request, res: Response, next: NextFunction
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -55,13 +62,22 @@ export async function updateSite(req: Request, res: Response, next: NextFunction
const updateData = parsedBody.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.updateSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.updateSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Update the site in the database
const updatedSite = await db.update(sites)
const updatedSite = await db
.update(sites)
.set(updateData)
.where(eq(sites.siteId, siteId))
.returning();
@ -84,6 +100,11 @@ export async function updateSite(req: Request, res: Response, next: NextFunction
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,15 +1,16 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, sites, targets } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, sites, targets } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { addPeer } from '../gerbil/peers';
import { eq, and } from 'drizzle-orm';
import { isIpInCidr } from '@server/utils/ip';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { addPeer } from "../gerbil/peers";
import { eq, and } from "drizzle-orm";
import { isIpInCidr } from "@server/utils/ip";
import { fromError } from "zod-validation-error";
const createTargetParamsSchema = z.object({
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
@ -23,14 +24,18 @@ const createTargetSchema = z.object({
enabled: z.boolean().default(true),
});
export async function createTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function createTarget(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = createTargetSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -42,7 +47,7 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -50,15 +55,24 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
const { resourceId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.createTarget, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.createTarget,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// get the resource
const [resource] = await db.select({
siteId: resources.siteId,
})
const [resource] = await db
.select({
siteId: resources.siteId,
})
.from(resources)
.where(eq(resources.resourceId, resourceId));
@ -72,9 +86,10 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
}
// TODO: is this all inefficient?
// get the site
const [site] = await db.select()
const [site] = await db
.select()
.from(sites)
.where(eq(sites.siteId, resource.siteId!))
.limit(1);
@ -98,10 +113,13 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
);
}
const newTarget = await db.insert(targets).values({
resourceId,
...targetData
}).returning();
const newTarget = await db
.insert(targets)
.values({
resourceId,
...targetData,
})
.returning();
// Fetch resources for this site
const resourcesRes = await db.query.resources.findMany({
@ -109,16 +127,18 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
});
// Fetch targets for all resources of this site
const targetIps = await Promise.all(resourcesRes.map(async (resource) => {
const targetsRes = await db.query.targets.findMany({
where: eq(targets.resourceId, resource.resourceId),
});
return targetsRes.map(target => `${target.ip}/32`);
}));
const targetIps = await Promise.all(
resourcesRes.map(async (resource) => {
const targetsRes = await db.query.targets.findMany({
where: eq(targets.resourceId, resource.resourceId),
});
return targetsRes.map((target) => `${target.ip}/32`);
})
);
await addPeer(site.exitNodeId!, {
publicKey: site.pubKey,
allowedIps: targetIps.flat()
allowedIps: targetIps.flat(),
});
return response(res, {
@ -130,6 +150,11 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,27 +1,32 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, sites, targets } from '@server/db/schema';
import { eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, sites, 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { addPeer } from '../gerbil/peers';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { addPeer } from "../gerbil/peers";
import { fromError } from "zod-validation-error";
const deleteTargetSchema = z.object({
targetId: z.string().transform(Number).pipe(z.number().int().positive())
targetId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function deleteTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function deleteTarget(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = deleteTargetSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -29,13 +34,21 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
const { targetId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.deleteTarget, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.deleteTarget,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const [deletedTarget] = await db.delete(targets)
const [deletedTarget] = await db
.delete(targets)
.where(eq(targets.targetId, targetId))
.returning();
@ -48,9 +61,10 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
);
}
// get the resource
const [resource] = await db.select({
siteId: resources.siteId,
})
const [resource] = await db
.select({
siteId: resources.siteId,
})
.from(resources)
.where(eq(resources.resourceId, deletedTarget.resourceId!));
@ -66,7 +80,8 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
// TODO: is this all inefficient?
// get the site
const [site] = await db.select()
const [site] = await db
.select()
.from(sites)
.where(eq(sites.siteId, resource.siteId!))
.limit(1);
@ -86,16 +101,18 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
});
// Fetch targets for all resources of this site
const targetIps = await Promise.all(resourcesRes.map(async (resource) => {
const targetsRes = await db.query.targets.findMany({
where: eq(targets.resourceId, resource.resourceId),
});
return targetsRes.map(target => `${target.ip}/32`);
}));
const targetIps = await Promise.all(
resourcesRes.map(async (resource) => {
const targetsRes = await db.query.targets.findMany({
where: eq(targets.resourceId, resource.resourceId),
});
return targetsRes.map((target) => `${target.ip}/32`);
})
);
await addPeer(site.exitNodeId!, {
publicKey: site.pubKey,
allowedIps: targetIps.flat()
allowedIps: targetIps.flat(),
});
return response(res, {
@ -107,6 +124,11 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,26 +1,31 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const getTargetSchema = z.object({
targetId: z.string().transform(Number).pipe(z.number().int().positive())
targetId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function getTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function getTarget(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = getTargetSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -28,12 +33,21 @@ export async function getTarget(req: Request, res: Response, next: NextFunction)
const { targetId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.getTarget, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.getTarget,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const target = await db.select()
const target = await db
.select()
.from(targets)
.where(eq(targets.targetId, targetId))
.limit(1);
@ -56,6 +70,11 @@ export async function getTarget(req: Request, res: Response, next: NextFunction)
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,36 +1,43 @@
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 { 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';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const updateTargetParamsSchema = z.object({
targetId: z.string().transform(Number).pipe(z.number().int().positive())
targetId: z.string().transform(Number).pipe(z.number().int().positive()),
});
const updateTargetBodySchema = z.object({
// ip: z.string().ip().optional(), // for now we cant update the ip; you will have to delete
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"
});
const updateTargetBodySchema = z
.object({
// ip: z.string().ip().optional(), // for now we cant update the ip; you will have to delete
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): Promise<any> {
export async function updateTarget(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = updateTargetParamsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -40,7 +47,7 @@ export async function updateTarget(req: Request, res: Response, next: NextFuncti
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -49,12 +56,21 @@ export async function updateTarget(req: Request, res: Response, next: NextFuncti
const updateData = parsedBody.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.updateTarget, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.updateTarget,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const updatedTarget = await db.update(targets)
const updatedTarget = await db
.update(targets)
.set(updateData)
.where(eq(targets.targetId, targetId))
.returning();
@ -77,6 +93,11 @@ export async function updateTarget(req: Request, res: Response, next: NextFuncti
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userActions, users } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userActions, users } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq } from 'drizzle-orm';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { eq } from "drizzle-orm";
import { fromError } from "zod-validation-error";
const addUserActionSchema = z.object({
userId: z.string(),
@ -15,14 +16,18 @@ const addUserActionSchema = z.object({
orgId: z.string(),
});
export async function addUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addUserAction(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addUserActionSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -30,22 +35,42 @@ export async function addUserAction(req: Request, res: Response, next: NextFunct
const { userId, actionId, orgId } = parsedBody.data;
// Check if the user has permission to add user actions
const hasPermission = await checkUserActionPermission(ActionsEnum.addUserAction, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addUserAction,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Check if the user exists
const user = await db.select().from(users).where(eq(users.userId, userId)).limit(1);
const user = await db
.select()
.from(users)
.where(eq(users.userId, userId))
.limit(1);
if (user.length === 0) {
return next(createHttpError(HttpCode.NOT_FOUND, `User with ID ${userId} not found`));
return next(
createHttpError(
HttpCode.NOT_FOUND,
`User with ID ${userId} not found`
)
);
}
const newUserAction = await db.insert(userActions).values({
userId,
actionId,
orgId,
}).returning();
const newUserAction = await db
.insert(userActions)
.values({
userId,
actionId,
orgId,
})
.returning();
return response(res, {
data: newUserAction[0],
@ -56,6 +81,11 @@ export async function addUserAction(req: Request, res: Response, next: NextFunct
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,87 +0,0 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userOrgs, users, roles } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
const addUserParamsSchema = z.object({
userId: z.string().uuid(),
orgId: z.string()
});
const addUserSchema = z.object({
roleId: z.number().int().positive(),
});
export async function addUserOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
try {
const parsedParams = addUserParamsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
)
);
}
const { userId, orgId } = parsedParams.data;
const parsedBody = addUserSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
)
);
}
const { roleId } = parsedBody.data;
// Check if the user has permission to add users
const hasPermission = await checkUserActionPermission(ActionsEnum.addUser, req);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
}
// Check if the user exists
const user = await db.select().from(users).where(eq(users.userId, userId)).limit(1);
if (user.length === 0) {
return next(createHttpError(HttpCode.NOT_FOUND, `User with ID ${userId} not found`));
}
// Check if the user is already in the organization
const existingUserOrg = await db.select()
.from(userOrgs)
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
.limit(1);
if (existingUserOrg.length > 0) {
return next(createHttpError(HttpCode.CONFLICT, 'User is already a member of this organization'));
}
// Add the user to the userOrgs table
const newUserOrg = await db.insert(userOrgs).values({
userId,
orgId,
roleId
}).returning();
return response(res, {
data: newUserOrg[0],
success: true,
error: false,
message: "User added to organization successfully",
status: HttpCode.CREATED,
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
}
}

View file

@ -1,26 +1,31 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userResources } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userResources } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const addUserResourceSchema = z.object({
userId: z.string(),
resourceId: z.string().transform(Number).pipe(z.number().int().positive())
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function addUserResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addUserResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addUserResourceSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -28,15 +33,26 @@ export async function addUserResource(req: Request, res: Response, next: NextFun
const { userId, resourceId } = parsedBody.data;
// Check if the user has permission to add user resources
const hasPermission = await checkUserActionPermission(ActionsEnum.addUserResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addUserResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const newUserResource = await db.insert(userResources).values({
userId,
resourceId,
}).returning();
const newUserResource = await db
.insert(userResources)
.values({
userId,
resourceId,
})
.returning();
return response(res, {
data: newUserResource[0],
@ -47,6 +63,11 @@ export async function addUserResource(req: Request, res: Response, next: NextFun
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,27 +1,32 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, userResources, userSites } from '@server/db/schema';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, userResources, userSites } from "@server/db/schema";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import { eq } from 'drizzle-orm';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { eq } from "drizzle-orm";
import { fromError } from "zod-validation-error";
const addUserSiteSchema = z.object({
userId: z.string(),
siteId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function addUserSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addUserSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addUserSiteSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -29,18 +34,30 @@ export async function addUserSite(req: Request, res: Response, next: NextFunctio
const { userId, siteId } = parsedBody.data;
// Check if the user has permission to add user sites
const hasPermission = await checkUserActionPermission(ActionsEnum.addUserSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addUserSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const newUserSite = await db.insert(userSites).values({
userId,
siteId,
}).returning();
const newUserSite = await db
.insert(userSites)
.values({
userId,
siteId,
})
.returning();
// Add all resources associated with the site to the user
const siteResources = await db.select()
const siteResources = await db
.select()
.from(resources)
.where(eq(resources.siteId, siteId));
@ -60,6 +77,11 @@ export async function addUserSite(req: Request, res: Response, next: NextFunctio
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,6 +1,5 @@
export * from "./getUser";
export * from "./removeUserOrg";
export * from "./addUserOrg";
export * from "./listUsers";
export * from "./setUserRole";
export * from "./inviteUser";

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userActions } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userActions } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeUserActionParamsSchema = z.object({
userId: z.string(),
@ -15,17 +16,21 @@ const removeUserActionParamsSchema = z.object({
const removeUserActionSchema = z.object({
actionId: z.string(),
orgId: z.string()
orgId: z.string(),
});
export async function removeUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeUserAction(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeUserActionParamsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -37,7 +42,7 @@ export async function removeUserAction(req: Request, res: Response, next: NextFu
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -45,17 +50,28 @@ export async function removeUserAction(req: Request, res: Response, next: NextFu
const { actionId, orgId } = parsedBody.data;
// Check if the user has permission to remove user actions
const hasPermission = await checkUserActionPermission(ActionsEnum.removeUserAction, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeUserAction,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedUserAction = await db.delete(userActions)
.where(and(
eq(userActions.userId, userId),
eq(userActions.actionId, actionId),
eq(userActions.orgId, orgId)
))
const deletedUserAction = await db
.delete(userActions)
.where(
and(
eq(userActions.userId, userId),
eq(userActions.actionId, actionId),
eq(userActions.orgId, orgId)
)
)
.returning();
if (deletedUserAction.length === 0) {
@ -76,6 +92,11 @@ export async function removeUserAction(req: Request, res: Response, next: NextFu
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,27 +1,32 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userOrgs, users } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userOrgs, users } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeUserSchema = z.object({
userId: z.string().uuid(),
orgId: z.string()
orgId: z.string(),
});
export async function removeUserOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeUserOrg(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeUserSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -29,13 +34,22 @@ export async function removeUserOrg(req: Request, res: Response, next: NextFunct
const { userId, orgId } = parsedParams.data;
// Check if the user has permission to list sites
const hasPermission = await checkUserActionPermission(ActionsEnum.removeUser, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeUser,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// remove the user from the userOrgs table
await db.delete(userOrgs)
await db
.delete(userOrgs)
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)));
return response(res, {
@ -47,6 +61,11 @@ export async function removeUserOrg(req: Request, res: Response, next: NextFunct
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}

View file

@ -1,27 +1,32 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userResources } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userResources } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeUserResourceSchema = z.object({
userId: z.string(),
resourceId: z.string().transform(Number).pipe(z.number().int().positive())
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
});
export async function removeUserResource(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeUserResource(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeUserResourceSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -29,13 +34,27 @@ export async function removeUserResource(req: Request, res: Response, next: Next
const { userId, resourceId } = parsedParams.data;
// Check if the user has permission to remove user resources
const hasPermission = await checkUserActionPermission(ActionsEnum.removeUserResource, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeUserResource,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedUserResource = await db.delete(userResources)
.where(and(eq(userResources.userId, userId), eq(userResources.resourceId, resourceId)))
const deletedUserResource = await db
.delete(userResources)
.where(
and(
eq(userResources.userId, userId),
eq(userResources.resourceId, resourceId)
)
)
.returning();
if (deletedUserResource.length === 0) {
@ -56,6 +75,11 @@ export async function removeUserResource(req: Request, res: Response, next: Next
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,13 +1,14 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { resources, userResources, userSites } from '@server/db/schema';
import { and, eq } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { resources, userResources, userSites } from "@server/db/schema";
import { and, eq } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const removeUserSiteParamsSchema = z.object({
userId: z.string(),
@ -17,14 +18,18 @@ const removeUserSiteSchema = z.object({
siteId: z.number().int().positive(),
});
export async function removeUserSite(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function removeUserSite(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = removeUserSiteParamsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedParams.error.errors.map(e => e.message).join(', ')
fromError(parsedParams.error).toString()
)
);
}
@ -36,7 +41,7 @@ export async function removeUserSite(req: Request, res: Response, next: NextFunc
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -44,13 +49,24 @@ export async function removeUserSite(req: Request, res: Response, next: NextFunc
const { siteId } = parsedBody.data;
// Check if the user has permission to remove user sites
const hasPermission = await checkUserActionPermission(ActionsEnum.removeUserSite, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.removeUserSite,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
const deletedUserSite = await db.delete(userSites)
.where(and(eq(userSites.userId, userId), eq(userSites.siteId, siteId)))
const deletedUserSite = await db
.delete(userSites)
.where(
and(eq(userSites.userId, userId), eq(userSites.siteId, siteId))
)
.returning();
if (deletedUserSite.length === 0) {
@ -62,13 +78,20 @@ export async function removeUserSite(req: Request, res: Response, next: NextFunc
);
}
const siteResources = await db.select()
const siteResources = await db
.select()
.from(resources)
.where(eq(resources.siteId, siteId));
for (const resource of siteResources) {
await db.delete(userResources)
.where(and(eq(userResources.userId, userId), eq(userResources.resourceId, resource.resourceId)))
await db
.delete(userResources)
.where(
and(
eq(userResources.userId, userId),
eq(userResources.resourceId, resource.resourceId)
)
)
.returning();
}
@ -81,6 +104,11 @@ export async function removeUserSite(req: Request, res: Response, next: NextFunc
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}

View file

@ -1,28 +1,33 @@
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { db } from '@server/db';
import { userOrgs, roles } from '@server/db/schema';
import { eq, and } from 'drizzle-orm';
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { userOrgs, roles } from "@server/db/schema";
import { eq, and } from "drizzle-orm";
import response from "@server/utils/response";
import HttpCode from '@server/types/HttpCode';
import createHttpError from 'http-errors';
import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
import logger from '@server/logger';
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
const addUserRoleSchema = z.object({
userId: z.string(),
roleId: z.number().int().positive(),
orgId: z.string()
orgId: z.string(),
});
export async function addUserRole(req: Request, res: Response, next: NextFunction): Promise<any> {
export async function addUserRole(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = addUserRoleSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
parsedBody.error.errors.map(e => e.message).join(', ')
fromError(parsedBody.error).toString()
)
);
}
@ -30,22 +35,37 @@ export async function addUserRole(req: Request, res: Response, next: NextFunctio
const { userId, roleId, orgId } = parsedBody.data;
// Check if the user has permission to add user roles
const hasPermission = await checkUserActionPermission(ActionsEnum.addUserRole, req);
const hasPermission = await checkUserActionPermission(
ActionsEnum.addUserRole,
req
);
if (!hasPermission) {
return next(createHttpError(HttpCode.FORBIDDEN, 'User does not have permission to perform this action'));
return next(
createHttpError(
HttpCode.FORBIDDEN,
"User does not have permission to perform this action"
)
);
}
// Check if the role exists and belongs to the specified org
const roleExists = await db.select()
const roleExists = await db
.select()
.from(roles)
.where(and(eq(roles.roleId, roleId), eq(roles.orgId, orgId)))
.limit(1);
if (roleExists.length === 0) {
return next(createHttpError(HttpCode.NOT_FOUND, 'Role not found or does not belong to the specified organization'));
return next(
createHttpError(
HttpCode.NOT_FOUND,
"Role not found or does not belong to the specified organization"
)
);
}
const newUserRole = await db.update(userOrgs)
const newUserRole = await db
.update(userOrgs)
.set({ roleId })
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
.returning();
@ -59,6 +79,11 @@ export async function addUserRole(req: Request, res: Response, next: NextFunctio
});
} catch (error) {
logger.error(error);
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred..."
)
);
}
}
}