Migrated validation to joi / Moved prisma_helpers to dedicated file /
This commit is contained in:
parent
be1544a46f
commit
c96bdfddb0
22
src/helpers/prisma_helpers.ts
Normal file
22
src/helpers/prisma_helpers.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* A function to create a sortBy compatible object from a string
|
||||
*
|
||||
* @export
|
||||
* @param {string} SortField
|
||||
* @param {string} Order
|
||||
* @returns {object}
|
||||
*/
|
||||
export function parseDynamicSortBy(SortField: string, Order: string) {
|
||||
return JSON.parse(`{ "${SortField}": "${Order}" }`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse a string into a number or return undefined if it is not a number
|
||||
*
|
||||
* @export
|
||||
* @param {string || any} data
|
||||
* @returns {object}
|
||||
*/
|
||||
export function parseIntOrUndefined(data: any) {
|
||||
return isNaN(parseInt(data)) ? undefined : parseInt(data);
|
||||
}
|
@ -1,92 +1,62 @@
|
||||
import { Request, Response } from 'express';
|
||||
import db, { handlePrismaError } from '../../../handlers/db.js'; // Database
|
||||
import log from '../../../handlers/log.js';
|
||||
import { parseIntOrUndefined, parseDynamicSortBy } from '../../../helpers/prisma_helpers.js';
|
||||
import { schema_get } from './alertContacts_schema.js';
|
||||
|
||||
///api/v1/alertContacts?action=count&filter=...
|
||||
|
||||
// GET without args -> Get all alertContacts
|
||||
|
||||
/**
|
||||
* A function to create a sortBy compatible object from a string
|
||||
*
|
||||
* @export
|
||||
* @param {string} SortField
|
||||
* @param {string} Order
|
||||
* @returns {object}
|
||||
*/
|
||||
export function parseDynamicSortBy(SortField: string, Order: string) {
|
||||
return JSON.parse(`{ "${SortField}": "${Order}" }`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to parse a string into a number or return undefined if it is not a number
|
||||
*
|
||||
* @export
|
||||
* @param {string || any} data
|
||||
* @returns {object}
|
||||
*/
|
||||
export function parseIntOrUndefined(data: any) {
|
||||
return isNaN(parseInt(data)) ? undefined : parseInt(data);
|
||||
}
|
||||
|
||||
// GET AlertContact
|
||||
// MARK: GET AlertContact
|
||||
async function get(req: Request, res: Response) {
|
||||
// Set sane defaults if undefined for sort
|
||||
if (req.query.sort === undefined) {
|
||||
req.query.sort = 'id';
|
||||
}
|
||||
if (req.query.order === undefined) {
|
||||
req.query.order = 'asc';
|
||||
}
|
||||
const { error, value } = schema_get.validate(req.query);
|
||||
if (error) {
|
||||
log.api?.debug('Error:', req.query, value);
|
||||
res.status(400).json({ error: error.details[0].message });
|
||||
} else {
|
||||
log.api?.debug('Success:', req.query, value);
|
||||
|
||||
// Prio 1 -> Get count (with or without filter)
|
||||
// Prio 2 -> Get by id
|
||||
// Prio 3 -> Get with filter
|
||||
if ((req.query.search !== undefined && req.query.search.length > 0) || (req.query.id !== undefined && req.query.id.length > 0)) {
|
||||
if (req.query.search !== undefined && req.query.search === '*') {
|
||||
log.db.debug('Single * does not work with FullTextSearch');
|
||||
req.query.search = '';
|
||||
}
|
||||
|
||||
// When an ID is set, remove(disable) the search query
|
||||
if (req.query.id !== undefined && req.query.id.length > 0) {
|
||||
req.query.search = undefined;
|
||||
}
|
||||
|
||||
const query = {
|
||||
// Query with FullTextSearch
|
||||
const query_fts = {
|
||||
where: {
|
||||
OR: [{ id: parseIntOrUndefined(req.query.id) }, { name: { search: req.query.search } }, { phone: { search: req.query.search } }, { comment: { search: req.query.search } }]
|
||||
OR: [{ id: parseIntOrUndefined(value.id) }, { name: { search: value.search } }, { phone: { search: value.search } }, { comment: { search: value.search } }]
|
||||
},
|
||||
orderBy: parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString())
|
||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString())
|
||||
};
|
||||
|
||||
if (req.query.count === undefined) {
|
||||
if (value.search !== undefined || value.id !== undefined) {
|
||||
// with FullTextSearch
|
||||
if (!value.count) {
|
||||
// get all entrys
|
||||
await db.alertContacts.findMany(query).then((result) => {
|
||||
log.api?.trace('get all entrys - with FullTextSearch');
|
||||
await db.alertContacts.findMany(query_fts).then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
} else {
|
||||
// count all entrys (filtered or not)
|
||||
await db.alertContacts.count(query).then((result) => {
|
||||
// count all entrys
|
||||
log.api?.trace('count all entrys - with FullTextSearch');
|
||||
await db.alertContacts.count(query_fts).then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (req.query.count === undefined) {
|
||||
await db.alertContacts.findMany({ orderBy: parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString()) }).then((result) => {
|
||||
// without FullTextSearch
|
||||
if (!value.count) {
|
||||
// get all entrys
|
||||
log.api?.trace('get all entrys - without FullTextSearch');
|
||||
await db.alertContacts.findMany({ orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()) }).then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
} else {
|
||||
// count all entrys without FullTextSearch
|
||||
log.api?.trace('count all entrys - without FullTextSearch');
|
||||
await db.alertContacts.count().then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE AlertContact
|
||||
// MARK: CREATE AlertContact
|
||||
async function post(req: Request, res: Response) {
|
||||
|
||||
// Check if undefined or null
|
||||
if (req.body.name != null && req.body.phone != null) {
|
||||
await db.alertContacts
|
||||
@ -94,23 +64,24 @@ async function post(req: Request, res: Response) {
|
||||
data: {
|
||||
name: req.body.name,
|
||||
phone: req.body.phone,
|
||||
comment: req.body.comment,
|
||||
comment: req.body.comment
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
}).then((result) => {
|
||||
res.status(201).json({ status: 'CREATED', message: 'Successfully created alertContact', id: result.id });
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(201).json({ status: 'CREATED', message: 'Successfully created alertContact', id: result.id });
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({ status: 'ERROR', errorcode: "VALIDATION_ERROR", message: 'One or more required fields are missing or invalid' });
|
||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more required fields are missing or invalid' });
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATE AlertContact
|
||||
// MARK: UPDATE AlertContact
|
||||
async function patch(req: Request, res: Response) {}
|
||||
|
||||
// DELETE AlertContact
|
||||
// MARK: DELETE AlertContact
|
||||
async function del(req: Request, res: Response) {}
|
||||
|
||||
export default { get, post, patch, del };
|
||||
|
53
src/routes/api/v1/alertContacts_schema.ts
Normal file
53
src/routes/api/v1/alertContacts_schema.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { Request, Response } from 'express';
|
||||
import validator from 'joi'; // DOCS: https://joi.dev/api
|
||||
import log from '../../../handlers/log.js';
|
||||
|
||||
|
||||
const schema_get = validator.object({
|
||||
sort: validator.string().valid('id', 'name', 'phone', 'comment').default('id'),
|
||||
order: validator.string().valid('asc', 'desc').default('asc'),
|
||||
search: validator.string().min(3).max(20), // TODO: Check if * or ** or *** -> Due to crashes..
|
||||
id: validator.number().positive().precision(0),
|
||||
count: validator.boolean()
|
||||
}).nand('id', 'search'); // Allow id or search. not both.
|
||||
|
||||
const schema_post = validator.object({
|
||||
name: validator.string().min(1).max(32).required(),
|
||||
phone: validator.string().pattern(new RegExp('^\\+(\\d{1,3})\\s*(?:\\(\\s*(\\d{2,5})\\s*\\)|\\s*(\\d{2,5})\\s*)\\s*(\\d{5,15})$')).required(),
|
||||
comment: validator.string().max(64),
|
||||
})
|
||||
|
||||
const schema_patch = validator.object({
|
||||
sort: validator.string().valid('id', 'name', 'phone', 'comment').default('id'),
|
||||
order: validator.string().valid('asc', 'desc').default('asc'),
|
||||
search: validator.string().min(3).max(20), // TODO: Check if * or ** or *** -> Due to crashes..
|
||||
id: validator.number().positive().precision(0),
|
||||
count: validator.boolean()
|
||||
}).nand('id', 'search'); // Allow id or search. not both.
|
||||
|
||||
const schema_del = validator.object({
|
||||
sort: validator.string().valid('id', 'name', 'phone', 'comment').default('id'),
|
||||
order: validator.string().valid('asc', 'desc').default('asc'),
|
||||
search: validator.string().min(3).max(20), // TODO: Check if * or ** or *** -> Due to crashes..
|
||||
id: validator.number().positive().precision(0),
|
||||
count: validator.boolean()
|
||||
}).nand('id', 'search'); // Allow id or search. not both.
|
||||
|
||||
// Describe all schemas
|
||||
const schema_get_describe = schema_get.describe();
|
||||
const schema_post_describe = schema_post.describe();
|
||||
const schema_patch_describe = schema_patch.describe();
|
||||
const schema_del_describe = schema_del.describe();
|
||||
|
||||
|
||||
// GET route
|
||||
export default async function get(req: Request, res: Response) {
|
||||
res.status(200).json({
|
||||
GET: schema_get_describe,
|
||||
POST: schema_post_describe,
|
||||
PATCH: schema_patch_describe,
|
||||
DELETE: schema_del_describe
|
||||
});
|
||||
}
|
||||
|
||||
export { schema_get, schema_post, schema_patch, schema_del }
|
@ -3,14 +3,11 @@ import passport from 'passport';
|
||||
|
||||
// Route imports
|
||||
import testRoute from './test.js';
|
||||
import alertContactsRoute from './alertContacts.js';
|
||||
//import categoryRoute from './categories.js';
|
||||
//import storageUnitRoute from './storageUnits.js';
|
||||
//import storageLocationRoute from './storageLocations.js';
|
||||
//import contactInfo from './contactInfo.js';
|
||||
import versionRoute from './version.js'
|
||||
|
||||
//import search_routes from './search/index.js';
|
||||
import alertContactsRoute from './alertContacts.js';
|
||||
import alertContactsRoute_schema from './alertContacts_schema.js';
|
||||
|
||||
|
||||
// Router base is '/api/v1'
|
||||
const Router = express.Router({ strict: false });
|
||||
@ -27,11 +24,7 @@ Router.use('*', function (req, res, next) {
|
||||
|
||||
// All api routes lowercase! Yea I know but when strict: true it matters.
|
||||
Router.route('/alertcontacts').get(alertContactsRoute.get).post(alertContactsRoute.post).patch(alertContactsRoute.patch).delete(alertContactsRoute.del);
|
||||
//Router.route('/categories').get(categoryRoute.get).post(categoryRoute.post).patch(categoryRoute.patch).delete(categoryRoute.del);
|
||||
// TODO: Migrate routes to lowercase.
|
||||
//Router.route('/storageUnits').get(storageUnitRoute.get).post(storageUnitRoute.post).patch(storageUnitRoute.patch).delete(storageUnitRoute.del);
|
||||
//Router.route('/storageLocations').get(storageLocationRoute.get).post(storageLocationRoute.post).patch(storageLocationRoute.patch).delete(storageLocationRoute.del);
|
||||
//Router.route('/contactInfo').get(contactInfo.get).post(contactInfo.post).patch(contactInfo.patch).delete(contactInfo.del);
|
||||
Router.route('/alertcontacts/describe').get(alertContactsRoute_schema);
|
||||
|
||||
Router.route('/version').get(versionRoute.get);
|
||||
//Router.use('/search', search_routes);
|
||||
|
Loading…
Reference in New Issue
Block a user