Skip to content

Commit

Permalink
added notebook validation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Morgul committed May 22, 2024
1 parent ac6d340 commit f349e07
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 96 deletions.
29 changes: 14 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"trivialperms": "^2.0.0-beta.0",
"ts-essentials": "^10.0.0",
"zod": "^3.23.8",
"zod-express": "^0.0.8",
"zod-validation-error": "^3.3.0"
},
"devDependencies": {
Expand Down
89 changes: 87 additions & 2 deletions src/server/engines/validation/express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,97 @@
// Express Validation Tools
// ---------------------------------------------------------------------------------------------------------------------

import { Request, Response, NextFunction } from 'express';

import { z } from 'zod';
import { fromError } from 'zod-validation-error';
import { Request, Response, NextFunction } from 'express';

// ---------------------------------------------------------------------------------------------------------------------

interface ProcessRequestSchema
{
params ?: z.ZodObject<any>;
query ?: z.ZodObject<any>;
body ?: z.ZodObject<any>;

}

export function processRequest(schema : ProcessRequestSchema) : any
{
return async function(req : Request, res : Response, next : NextFunction) : Promise<void>
{
const errors : any[] = [];

// Process the params, query, and body of the request, replacing them with the validated values.
try
{
if(schema.params)
{
const paramResults = schema.params.safeParse(req.params);
if(paramResults.success)
{
req.params = paramResults.data;
}
else
{
errors.push({ type: 'Params', errors: paramResults.error });
}
}

// Express 5.x has req.query as getter only, so we have to do some shenanigans to modify it
if(schema.query)
{
// Parse the query parameters
const queryResults = schema.query.safeParse(req.query);

if(queryResults.success)
{
// Delete all existing properties from req.query
for(const key in req.query)
{
delete req.query[key];
}

// Copy the validated properties to req.query
for(const key in queryResults.data)
{
req.query[key] = queryResults.data[key];
}
}
else
{
errors.push({ type: 'Query', errors: queryResults.error });
}
}

if(schema.body)
{
const bodyResults = schema.body.safeParse(req.body);
if(bodyResults.success)
{
req.body = bodyResults.data;
}
else
{
errors.push({ type: 'Body', errors: bodyResults.error });
}
}

if(errors.length > 0)
{
next(errors);
}
else
{
next();
}
}
catch (err)
{
next(err);
}
};
}

export function validationErrorHandler(err : any, req : Request, res : Response, next : NextFunction) : void
{
if(Array.isArray(err))
Expand Down
6 changes: 4 additions & 2 deletions src/server/engines/validation/models/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

import { z } from 'zod';

// Models
import { HashID } from './common';

// ---------------------------------------------------------------------------------------------------------------------

export const AccountID = z.string().min(4)
.regex(/^[a-zA-Z0-9]+$/);
export const AccountID = HashID;

export const AccountSettings = z.object({
colorMode: z.enum([ 'light', 'dark', 'auto' ]).optional()
Expand Down
12 changes: 12 additions & 0 deletions src/server/engines/validation/models/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// ---------------------------------------------------------------------------------------------------------------------
// Common Validation Models
// ---------------------------------------------------------------------------------------------------------------------

import { z } from 'zod';

// ---------------------------------------------------------------------------------------------------------------------

export const HashID = z.string().min(4)
.regex(/^[a-zA-Z0-9]+$/);

// ---------------------------------------------------------------------------------------------------------------------
44 changes: 44 additions & 0 deletions src/server/engines/validation/models/notebook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// ---------------------------------------------------------------------------------------------------------------------
// Notebook Validation Model
// ---------------------------------------------------------------------------------------------------------------------

import { z } from 'zod';

// Models
import { HashID } from './common';

// ---------------------------------------------------------------------------------------------------------------------

export const NotebookID = HashID;

export const NotebookPage = z.object({
id: z.string().min(1),
title: z.string().min(1),
content: z.string().min(1),
notebookID: NotebookID
});

export const Notebook = z.object({
id: NotebookID,
pages: z.array(NotebookPage).optional()
});

// ---------------------------------------------------------------------------------------------------------------------
// Request Validations
// ---------------------------------------------------------------------------------------------------------------------

export const RouteParams = z.object({
noteID: NotebookID,
pageID: z.string().min(1)
.optional()
});

export const NotebookFilter = z.object({
id: z.union([ NotebookID, z.array(NotebookID) ]).optional(),
email: z.union([ z.string().email(), z.array(z.string().email()) ])
.optional(),
name: z.union([ z.string().min(1), z.array(z.string().min(1)) ])
.optional()
});

// ---------------------------------------------------------------------------------------------------------------------
16 changes: 6 additions & 10 deletions src/server/routes/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,29 @@
//----------------------------------------------------------------------------------------------------------------------

import express from 'express';
import { processRequest } from 'zod-express';
import logging from '@strata-js/util-logging';

// Managers
import * as accountMan from '../managers/account';
import * as permsMan from '../utils/permissions';

// Validation
import * as AccountValidators from '../engines/validation/models/account';
import { validationErrorHandler } from '../engines/validation/express';
import { processRequest, validationErrorHandler } from '../engines/validation/express';

// Utils
import { ensureAuthenticated, errorHandler } from './utils';

// Logger
import logging from '@strata-js/util-logging';

const logger = logging.getLogger(module.filename);

//----------------------------------------------------------------------------------------------------------------------

const router = express.Router();
const logger = logging.getLogger(module.filename);

//----------------------------------------------------------------------------------------------------------------------

router.get(
'/',
processRequest({ query: AccountValidators.AccountFilter }, { passErrorToNext: true }),
processRequest({ query: AccountValidators.AccountFilter }),
async (req, resp) =>
{
resp.json((await accountMan.list(req.query)).map((accountObj) =>
Expand All @@ -47,7 +43,7 @@ router.get(

router.get(
'/:accountID',
processRequest({ params: AccountValidators.UpdateParams }, { passErrorToNext: true }),
processRequest({ params: AccountValidators.UpdateParams }),
async (req, resp) =>
{
const user = req.user;
Expand Down Expand Up @@ -81,7 +77,7 @@ router.patch(
processRequest({
params: AccountValidators.UpdateParams,
body: AccountValidators.Account.partial({ id: true })
}, { passErrorToNext: true }),
}),
async (req, resp) =>
{
// Update the account
Expand Down
Loading

0 comments on commit f349e07

Please sign in to comment.