Current state
This commit is contained in:
@ -1,8 +1,10 @@
|
||||
import { PrismaClient } from '@prisma/client'; // Database
|
||||
import config from "./config.js";
|
||||
import { PrismaClient, Prisma } from '@prisma/client'; // Database
|
||||
import { Response } from 'express';
|
||||
import config from './config.js';
|
||||
import log from './log.js';
|
||||
|
||||
// TODO: Add errorhandling with some sort of message.
|
||||
export const prisma = new PrismaClient({
|
||||
const prisma = new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: config.global.db_connection_string
|
||||
@ -10,3 +12,75 @@ export const prisma = new PrismaClient({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// FIXME: any
|
||||
export function handlePrismaError(errorObj: any, res: Response) {
|
||||
|
||||
log.core.debug(errorObj);
|
||||
res.status(500).json({ status: 'ERROR', meta: errorObj.meta, errorcode: errorObj.code, message: errorObj.message });
|
||||
|
||||
|
||||
// if(errorObj instanceof Prisma.PrismaClientKnownRequestError)
|
||||
|
||||
// switch (errorObj.code) {
|
||||
// // P2002 -> "Unique constraint failed on the {constraint}"
|
||||
// // https://www.prisma.io/docs/reference/api-reference/error-reference
|
||||
// case 'P2002': //
|
||||
// log.db.error('');
|
||||
// break;
|
||||
|
||||
|
||||
// // P2003 -> "Foreign key constraint failed on the field: {field_name}"
|
||||
// // https://www.prisma.io/docs/reference/api-reference/error-reference
|
||||
// // FIXME: Is this errormessage right?
|
||||
// case 'P2003': //
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx': //
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
// case 'xxx':
|
||||
// log.db.error('');
|
||||
// break;
|
||||
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // Check if an entry already exists.
|
||||
// if (errorcode === 'P2002') {
|
||||
// // P2002 -> "Unique constraint failed on the {constraint}"
|
||||
// // https://www.prisma.io/docs/reference/api-reference/error-reference
|
||||
// res.status(409).json({ status: 'ERROR', errorcode: 'EXISTING', message: 'Item already exists' });
|
||||
// } else if (errorcode == 'P2003') {
|
||||
// // P2003 -> "Foreign key constraint failed on the field: {field_name}"
|
||||
// // https://www.prisma.io/docs/reference/api-reference/error-reference
|
||||
// // FIXME: Is this errormessage right?
|
||||
// res.status(404).json({ status: 'ERROR', errorcode: 'NOT_EXISTING', message: 'Item does not exist' });
|
||||
// } else if (errorcode == 'P2000') {
|
||||
// // P2000 -> "The provided value for the column is too long for the column's type. Column: {column_name}"
|
||||
// // https://www.prisma.io/docs/reference/api-reference/error-reference
|
||||
// res.status(404).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'One or more fields exceed the maximum length restriction' });
|
||||
// } else {
|
||||
// log.db.error(err);
|
||||
// res.status(500).json({ status: 'ERROR', errorcode: 'DB_ERROR', error: err, message: 'An error occurred during the database operation' });
|
||||
// }
|
||||
}
|
||||
|
||||
export default prisma;
|
||||
|
@ -1,24 +1,31 @@
|
||||
import { Logger } from "tslog";
|
||||
import { Logger,ISettingsParam } from "tslog";
|
||||
|
||||
const loggerConfig: any = {
|
||||
type: "pretty", // pretty, json, hidden
|
||||
name: "Core",
|
||||
hideLogPositionForProduction: true,
|
||||
prettyLogTemplate: "{{dateIsoStr}} {{logLevelName}} {{nameWithDelimiterPrefix}} "
|
||||
function loggerConfig(name: string): ISettingsParam<unknown> {
|
||||
return {
|
||||
type: "pretty", // pretty, json, hidden
|
||||
name: name,
|
||||
hideLogPositionForProduction: true,
|
||||
prettyLogTemplate: "{{dateIsoStr}} {{logLevelName}} {{nameWithDelimiterPrefix}} "
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const coreLogger = new Logger(loggerConfig);
|
||||
export const log = {
|
||||
core: coreLogger,
|
||||
db: coreLogger.getSubLogger({ name: "DB" }),
|
||||
web: coreLogger.getSubLogger({ name: "WEB" }),
|
||||
auth: coreLogger.getSubLogger({ name: "AUTH" }),
|
||||
helper: coreLogger.getSubLogger({ name: "HELPER" }),
|
||||
// FIXME: any type
|
||||
let log: any = {
|
||||
core: new Logger(loggerConfig("Core")),
|
||||
db: new Logger(loggerConfig("DB")),
|
||||
web: new Logger(loggerConfig("Web")),
|
||||
auth: new Logger(loggerConfig("Auth")),
|
||||
// helper: new Logger(loggerConfig("HELPER")),
|
||||
};
|
||||
|
||||
log["api"] = log.web.getSubLogger({ name: "API" });
|
||||
log["frontend"] = log.web.getSubLogger({ name: "Frontend" });
|
||||
|
||||
|
||||
// log.core.silly("Hello from core");
|
||||
// log.core.trace("Hello from core");
|
||||
//log.api.trace("Hello from api");
|
||||
//log.frontend.trace("Hello from frontend");
|
||||
// log.core.debug("Hello from core");
|
||||
// log.core.info("Hello from core");
|
||||
// log.core.warn("Hello from core");
|
||||
|
53
src/index.ts
53
src/index.ts
@ -2,6 +2,7 @@
|
||||
import path from 'node:path';
|
||||
import __path from "./handlers/path.js";
|
||||
import log from "./handlers/log.js";
|
||||
import db from "./handlers/db.js";
|
||||
import config from './handlers/config.js';
|
||||
|
||||
// Express & more
|
||||
@ -13,28 +14,56 @@ import bodyParser, { Options } from 'body-parser';
|
||||
import { Eta } from "eta";
|
||||
import passport from 'passport';
|
||||
|
||||
import ChildProcess from 'child_process';
|
||||
|
||||
import routes from './routes/index.js';
|
||||
|
||||
import fs from 'node:fs';
|
||||
|
||||
log.core.trace("Running from path: " + __path);
|
||||
db.$disconnect();
|
||||
|
||||
|
||||
// MARK: Express
|
||||
const app = express();
|
||||
|
||||
// TODO: Version check need to be rewritten.
|
||||
//app.locals.versionRevLong = require('child_process').execSync('git rev-parse HEAD').toString().trim();
|
||||
//app.locals.versionRev = require('child_process').execSync('git rev-parse --short HEAD').toString().trim();
|
||||
//app.locals.versionRevLatest = require('child_process').execSync('git ls-remote --refs -q').toString().trim().split('\t')[0];
|
||||
app.locals.versionRev = '0';
|
||||
app.locals.versionRevLong = '0';
|
||||
app.locals.versionRevLatest = '0';
|
||||
|
||||
if (app.locals.versionRevLong === app.locals.versionRevLatest) {
|
||||
log.core.info(`Running Latest Version (${app.locals.versionRevLong})`);
|
||||
} else {
|
||||
log.core.info(`Running Version: ${app.locals.versionRevLong} (Latest: ${app.locals.versionRevLatest})`);
|
||||
// Versioning
|
||||
try {
|
||||
const rawPkg = fs.readFileSync("package.json", 'utf8');
|
||||
const pkgJson = JSON.parse(rawPkg);
|
||||
app.locals.version = pkgJson.version;
|
||||
} catch (error) {
|
||||
log.core.error("Failed to get version from package.json.");
|
||||
app.locals.version = "0.0.0";
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
app.locals.versionRevLong = ChildProcess.execSync('git rev-parse HEAD').toString().trim();
|
||||
app.locals.versionRev = app.locals.versionRevLong.substring(0, 7);
|
||||
} catch (error) {
|
||||
log.core.error("Failed to get git revision hash.");
|
||||
app.locals.versionRev = '0';
|
||||
app.locals.versionRevLong = '0';
|
||||
}
|
||||
|
||||
try {
|
||||
app.locals.versionRevLatest = ChildProcess.execSync('git ls-remote --refs -q').toString().trim().split('\t')[0];
|
||||
} catch (error) {
|
||||
log.core.error("Failed to get latest git revision hash.");
|
||||
app.locals.versionRevLatest = '0';
|
||||
}
|
||||
|
||||
app.locals.versionUpdateAvailable = false;
|
||||
if (app.locals.versionRevLong === app.locals.versionRevLatest) {
|
||||
log.core.info(`Running Latest Version (${app.locals.versionRevLong}; ${app.locals.version})`);
|
||||
} else {
|
||||
log.core.info(`Running Version: ${app.locals.versionRevLong}; ${app.locals.version} (Latest: ${app.locals.versionRevLatest})`);
|
||||
app.locals.versionUpdateAvailable = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ETA Init
|
||||
const eta = new Eta({ views: path.join(__path, "views") })
|
||||
app.engine("eta", buildEtaEngine())
|
||||
|
116
src/routes/api/v1/alertContacts.ts
Normal file
116
src/routes/api/v1/alertContacts.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import { Request, Response } from 'express';
|
||||
import db, { handlePrismaError } from '../../../handlers/db.js'; // Database
|
||||
import log from '../../../handlers/log.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
|
||||
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';
|
||||
}
|
||||
|
||||
// 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 = {
|
||||
where: {
|
||||
OR: [{ id: parseIntOrUndefined(req.query.id) }, { name: { search: req.query.search } }, { phone: { search: req.query.search } }, { comment: { search: req.query.search } }]
|
||||
},
|
||||
orderBy: parseDynamicSortBy(req.query.sort.toString(), req.query.order.toString())
|
||||
};
|
||||
|
||||
if (req.query.count === undefined) {
|
||||
// get all entrys
|
||||
await db.alertContacts.findMany(query).then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
} else {
|
||||
// count all entrys (filtered or not)
|
||||
await db.alertContacts.count(query).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) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
} else {
|
||||
await db.alertContacts.count().then((result) => {
|
||||
res.status(200).json(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
.create({
|
||||
data: {
|
||||
name: req.body.name,
|
||||
phone: req.body.phone,
|
||||
comment: req.body.comment,
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
}).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' });
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATE AlertContact
|
||||
async function patch(req: Request, res: Response) {}
|
||||
|
||||
// DELETE AlertContact
|
||||
async function del(req: Request, res: Response) {}
|
||||
|
||||
export default { get, post, patch, del };
|
@ -3,12 +3,12 @@ import passport from 'passport';
|
||||
|
||||
// Route imports
|
||||
import testRoute from './test.js';
|
||||
//import itemRoute from './items.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 versionRoute from './version.js'
|
||||
|
||||
//import search_routes from './search/index.js';
|
||||
|
||||
@ -25,14 +25,15 @@ Router.use('*', function (req, res, next) {
|
||||
next();
|
||||
});
|
||||
|
||||
//Router.route('/items').get(itemRoute.get).post(itemRoute.post).patch(itemRoute.patch).delete(itemRoute.del);
|
||||
// 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('/version').get(versionRoute.get);
|
||||
Router.route('/version').get(versionRoute.get);
|
||||
//Router.use('/search', search_routes);
|
||||
|
||||
Router.route('/test').get(testRoute.get);
|
||||
|
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!!!!!!
|
@ -5,6 +5,7 @@ import express from 'express';
|
||||
// import skuRouteDash from './itemInfo.js'
|
||||
// import testRoute from './test.js';
|
||||
import dashboardRoute from './dashboard.js';
|
||||
import testRoute from './test.js';
|
||||
// import itemsRoute from './items.js';
|
||||
// import manage_routes from './manage/index.js';
|
||||
|
||||
@ -20,5 +21,6 @@ const Router = express.Router({ strict: false });
|
||||
// Router.use('/manage', manage_routes);
|
||||
|
||||
Router.route('/').get(dashboardRoute.get);
|
||||
Router.route('/dbTest').get(testRoute.get);
|
||||
|
||||
export default Router;
|
||||
|
7
src/routes/frontend/test.ts
Normal file
7
src/routes/frontend/test.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
|
||||
function get(req: Request, res: Response) {
|
||||
res.render("test", { message: "Hello world from eta!" })
|
||||
}
|
||||
|
||||
export default { get };
|
@ -17,6 +17,7 @@ const Router = express.Router({ strict: false });
|
||||
Router.use('/static', express.static(__path + '/static'));
|
||||
Router.use('/libs/bulma', express.static(path.join(__path, 'node_modules', 'bulma', 'css'))); // http://192.168.221.10:3000/libs/bulma/bulma.css
|
||||
Router.use('/libs/jquery', express.static(path.join(__path, 'node_modules', 'jquery', 'dist')));
|
||||
Router.use('/libs/bootstrap-icons', express.static(path.join(__path, 'node_modules', 'bootstrap-icons')));
|
||||
|
||||
// Other routers
|
||||
Router.use('/api', checkAuthentication, api_routes);
|
||||
|
Reference in New Issue
Block a user