Initial commit
This commit is contained in:
51
src/routes/api/v1/index.ts
Normal file
51
src/routes/api/v1/index.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import express from 'express';
|
||||
import passport from 'passport';
|
||||
|
||||
// Route imports
|
||||
import testRoute from './test.js';
|
||||
import versionRoute from './version.js'
|
||||
|
||||
import userRoute from './user.js';
|
||||
import userRoute_schema from './user_schema.js';
|
||||
|
||||
// import content_route from './content.js';
|
||||
// import content_schema from './content_schema.js';
|
||||
|
||||
// import * as content_s3_sub_route from './content_s3_sub.js';
|
||||
// import * as content_s3_sub_schema from './content_s3_sub_schema.js';
|
||||
|
||||
|
||||
// Router base is '/api/v1'
|
||||
const Router = express.Router({ strict: false });
|
||||
|
||||
// All empty strings are undefined (not null!) values (body)
|
||||
Router.use('*', function (req, res, next) {
|
||||
for (let key in req.body) {
|
||||
if (req.body[key] === '') {
|
||||
req.body[key] = undefined;
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
// All api routes lowercase! Yea I know but when strict: true it matters.
|
||||
Router.route('/user').get(userRoute.get).post(userRoute.post).patch(userRoute.patch).delete(userRoute.del);
|
||||
Router.route('/user/describe').get(userRoute_schema);
|
||||
|
||||
// Router.route('/content').get(content_route.get).post(content_route.post).patch(content_route.patch).delete(content_route.del);
|
||||
// Router.route('/content/describe').get(content_schema);
|
||||
|
||||
// Router.route('/content/downloadurl').get(content_s3_sub_route.get_downloadurl);
|
||||
// Router.route('/content/uploadurl').get(content_s3_sub_route.get_uploadurl);
|
||||
// Router.route('/content/downloadurl/describe').get(content_s3_sub_schema.get_describe_downloadurl);
|
||||
// Router.route('/content/uploadurl/describe').get(content_s3_sub_schema.get_describe_uploadurl);
|
||||
|
||||
|
||||
|
||||
Router.route('/version').get(versionRoute.get);
|
||||
//Router.use('/search', search_routes);
|
||||
|
||||
Router.route('/test').get(testRoute.get);
|
||||
|
||||
export default Router;
|
7
src/routes/api/v1/test.ts
Normal file
7
src/routes/api/v1/test.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
|
||||
function get(req: Request, res: Response) {
|
||||
res.status(200).send('API v1 Test successful!');
|
||||
};
|
||||
|
||||
export default { get };
|
165
src/routes/api/v1/user.ts
Normal file
165
src/routes/api/v1/user.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { Request, Response } from 'express';
|
||||
import db, { handlePrismaError } from '../../../handlers/db.js'; // Database
|
||||
import log from '../../../handlers/log.js';
|
||||
import { parseDynamicSortBy } from '../../../helpers/prisma_helpers.js';
|
||||
import { schema_get, schema_post, schema_patch, schema_del } from './user_schema.js';
|
||||
|
||||
// MARK: GET user
|
||||
async function get(req: Request, res: Response) {
|
||||
const { error, value } = schema_get.validate(req.query);
|
||||
if (error) {
|
||||
log.api?.debug('GET user Error:', req.query, value, error.details[0].message);
|
||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
||||
} else {
|
||||
log.api?.debug('GET user Success:', req.query, value);
|
||||
|
||||
if (value.search !== undefined || value.id !== undefined) {
|
||||
// if search or get by id
|
||||
await db
|
||||
.$transaction([
|
||||
// Same query for count and findMany
|
||||
db.user.count({
|
||||
where: {
|
||||
OR: [{ id: value.id }, { name: { search: value.search } }]
|
||||
},
|
||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
||||
skip: value.skip,
|
||||
take: value.take
|
||||
}),
|
||||
db.user.findMany({
|
||||
where: {
|
||||
OR: [{ id: value.id }, { name: { search: value.search } }]
|
||||
},
|
||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
||||
skip: value.skip,
|
||||
take: value.take
|
||||
})
|
||||
])
|
||||
.then(([count, result]) => {
|
||||
if (result.length !== 0) {
|
||||
result.forEach((element: { id: number; name: string; code: string | null | boolean }) => {
|
||||
// code-> true if code is set
|
||||
element.code = element.code !== null;
|
||||
});
|
||||
res.status(200).json({ count, result });
|
||||
} else {
|
||||
res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified object' });
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
handlePrismaError(err, res, 'GET user');
|
||||
});
|
||||
} else {
|
||||
// get all
|
||||
await db
|
||||
.$transaction([
|
||||
// Same query for count and findMany
|
||||
db.user.count({
|
||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
||||
skip: value.skip,
|
||||
take: value.take
|
||||
}),
|
||||
db.user.findMany({
|
||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
||||
skip: value.skip,
|
||||
take: value.take
|
||||
})
|
||||
])
|
||||
.then(([count, result]) => {
|
||||
if (result.length !== 0) {
|
||||
result.forEach((element: { id: number; name: string; code: string | null | boolean }) => {
|
||||
// code-> true if code is set
|
||||
element.code = element.code !== null;
|
||||
});
|
||||
res.status(200).json({ count, result });
|
||||
} else {
|
||||
res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified object' });
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
handlePrismaError(err, res, 'GET user');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: CREATE user
|
||||
async function post(req: Request, res: Response) {
|
||||
const { error, value } = schema_post.validate(req.body);
|
||||
if (error) {
|
||||
log.api?.debug('POST user Error:', req.body, value, error.details[0].message);
|
||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
||||
} else {
|
||||
log.api?.debug('POST user Success:', req.body, value);
|
||||
await db.user
|
||||
.create({
|
||||
data: {
|
||||
name: value.name,
|
||||
code: value.code
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(201).json({ status: 'CREATED', message: 'Successfully created user', id: result.id });
|
||||
})
|
||||
.catch((err) => {
|
||||
handlePrismaError(err, res, 'POST user');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UPDATE user
|
||||
async function patch(req: Request, res: Response) {
|
||||
const { error, value } = schema_patch.validate(req.body);
|
||||
if (error) {
|
||||
log.api?.debug('PATCH user Error:', req.body, value, error.details[0].message);
|
||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
||||
} else {
|
||||
log.api?.debug('PATCH user Success:', req.body, value);
|
||||
await db.user
|
||||
.update({
|
||||
where: {
|
||||
id: value.id
|
||||
},
|
||||
data: {
|
||||
name: value.name,
|
||||
code: value.code
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(200).json({ status: 'UPDATED', message: 'Successfully updated user', id: result.id });
|
||||
})
|
||||
.catch((err) => {
|
||||
handlePrismaError(err, res, 'PATCH user');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: DELETE user
|
||||
async function del(req: Request, res: Response) {
|
||||
const { error, value } = schema_del.validate(req.body);
|
||||
if (error) {
|
||||
log.api?.debug('DEL user Error:', req.body, value, error.details[0].message);
|
||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
||||
} else {
|
||||
log.api?.debug('DEL user Success:', req.body, value);
|
||||
await db.user
|
||||
.delete({
|
||||
where: {
|
||||
id: value.id
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(200).json({ status: 'DELETED', message: 'Successfully deleted user', id: result.id });
|
||||
}).catch((err) => {
|
||||
handlePrismaError(err, res, 'DEL user');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default { get, post, patch, del };
|
58
src/routes/api/v1/user_schema.ts
Normal file
58
src/routes/api/v1/user_schema.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Request, Response } from 'express';
|
||||
import validator from 'joi'; // DOCS: https://joi.dev/api
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
// MARK: GET user
|
||||
const schema_get = validator
|
||||
.object({
|
||||
sort: validator
|
||||
.string()
|
||||
.valid(...Object.keys(Prisma.UserScalarFieldEnum))
|
||||
.default('id'),
|
||||
|
||||
order: validator.string().valid('asc', 'desc').default('asc'),
|
||||
take: validator.number().min(1).max(512),
|
||||
skip: validator.number().min(0),
|
||||
// This regex ensures that the search string does not contain consecutive asterisks (**) and is at least 3 characters long.
|
||||
search: validator.string().min(3).max(20).regex(new RegExp('^(?!.*\\*{2,}).*$')),
|
||||
id: validator.number().positive().precision(0)
|
||||
})
|
||||
.nand('id', 'search'); // Allow id or search. not both.
|
||||
|
||||
// MARK: CREATE alertContact
|
||||
const schema_post = validator.object({
|
||||
name: validator.string().min(1).max(32).required(),
|
||||
code: validator.string().min(4).max(4).trim().regex(new RegExp('/^[0-9]+$/'))
|
||||
});
|
||||
|
||||
// MARK: UPDATE alertContact
|
||||
const schema_patch = validator
|
||||
.object({
|
||||
id: validator.number().positive().precision(0).required(),
|
||||
name: validator.string().min(1).max(32),
|
||||
code: validator.string().min(4).max(4).trim().regex(new RegExp('/^[0-9]+$/'))
|
||||
})
|
||||
.or('name', 'code');
|
||||
|
||||
// MARK: DELETE alertContact
|
||||
const schema_del = validator.object({
|
||||
id: validator.number().positive().precision(0).required()
|
||||
});
|
||||
|
||||
// Describe all schemas
|
||||
const schema_get_desc = schema_get.describe();
|
||||
const schema_post_desc = schema_post.describe();
|
||||
const schema_patch_desc = schema_patch.describe();
|
||||
const schema_del_desc = schema_del.describe();
|
||||
|
||||
// GET route
|
||||
export default async function get(req: Request, res: Response) {
|
||||
res.status(200).json({
|
||||
GET: schema_get_desc,
|
||||
POST: schema_post_desc,
|
||||
PATCH: schema_patch_desc,
|
||||
DELETE: schema_del_desc
|
||||
});
|
||||
}
|
||||
|
||||
export { schema_get, schema_post, schema_patch, schema_del };
|
9
src/routes/api/v1/version.ts
Normal file
9
src/routes/api/v1/version.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Request, Response } from 'express';
|
||||
|
||||
function get(req: Request, res: Response) {
|
||||
res.status(200).send({ version: '1.0.0', commit: req.app.locals.versionRev, updateAvailable: req.app.locals.versionUpdateAvailable });
|
||||
};
|
||||
|
||||
export default { get };
|
||||
|
||||
// TODO: FIXME!!!!!!
|
Reference in New Issue
Block a user