Refactor note and subjob management routes: Enhanced filtering logic and added new route handlers for CRUD operations. Updated services to utilize database functions for improved data handling and error management. Implemented property-based listing for notes and subjobs, ensuring better data retrieval and organization.
This commit is contained in:
parent
12be496f22
commit
4685cac563
@ -1,42 +1,50 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { isAuthenticated } from '../../keycloak.js';
|
import { isAuthenticated } from '../../keycloak.js';
|
||||||
|
import { getFilter, convertPropertiesString } from '../../utils.js';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
import {
|
import {
|
||||||
listNoteTypesRouteHandler,
|
listNoteTypesRouteHandler,
|
||||||
getNoteTypeRouteHandler,
|
getNoteTypeRouteHandler,
|
||||||
editNoteTypeRouteHandler,
|
editNoteTypeRouteHandler,
|
||||||
newNoteTypeRouteHandler,
|
newNoteTypeRouteHandler,
|
||||||
|
deleteNoteTypeRouteHandler,
|
||||||
|
listNoteTypesByPropertiesRouteHandler,
|
||||||
} from '../../services/management/notetypes.js';
|
} from '../../services/management/notetypes.js';
|
||||||
import { parseFilter } from '../../utils.js';
|
|
||||||
|
|
||||||
const router = express.Router();
|
// list of note types
|
||||||
|
router.get('/', isAuthenticated, (req, res) => {
|
||||||
// List note types
|
|
||||||
router.get('/', isAuthenticated, async (req, res) => {
|
|
||||||
const { page, limit, property, search, sort, order } = req.query;
|
const { page, limit, property, search, sort, order } = req.query;
|
||||||
|
const allowedFilters = ['_id', 'name', 'active', 'color'];
|
||||||
const allowedFilters = ['name', 'active', 'color', '_id'];
|
const filter = getFilter(req.query, allowedFilters);
|
||||||
|
|
||||||
var filter = {};
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(req.query)) {
|
|
||||||
for (var i = 0; i < allowedFilters.length; i++) {
|
|
||||||
if (key == allowedFilters[i]) {
|
|
||||||
const parsedFilter = parseFilter(key, value);
|
|
||||||
filter = { ...filter, ...parsedFilter };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listNoteTypesRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
listNoteTypesRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get single note type
|
router.get('/properties', isAuthenticated, (req, res) => {
|
||||||
router.get('/:id', isAuthenticated, getNoteTypeRouteHandler);
|
let properties = convertPropertiesString(req.query.properties);
|
||||||
|
const allowedFilters = ['active', 'color'];
|
||||||
|
const filter = getFilter(req.query, allowedFilters, false);
|
||||||
|
var masterFilter = {};
|
||||||
|
if (req.query.masterFilter) {
|
||||||
|
masterFilter = JSON.parse(req.query.masterFilter);
|
||||||
|
}
|
||||||
|
listNoteTypesByPropertiesRouteHandler(req, res, properties, filter, masterFilter);
|
||||||
|
});
|
||||||
|
|
||||||
// Edit note type
|
router.post('/', isAuthenticated, (req, res) => {
|
||||||
router.put('/:id', isAuthenticated, editNoteTypeRouteHandler);
|
newNoteTypeRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
// Create new note type
|
router.get('/:id', isAuthenticated, (req, res) => {
|
||||||
router.post('/', isAuthenticated, newNoteTypeRouteHandler);
|
getNoteTypeRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.put('/:id', isAuthenticated, async (req, res) => {
|
||||||
|
editNoteTypeRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete('/:id', isAuthenticated, async (req, res) => {
|
||||||
|
deleteNoteTypeRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@ -7,40 +7,39 @@ import {
|
|||||||
newNoteRouteHandler,
|
newNoteRouteHandler,
|
||||||
deleteNoteRouteHandler,
|
deleteNoteRouteHandler,
|
||||||
} from '../../services/misc/notes.js';
|
} from '../../services/misc/notes.js';
|
||||||
import { parseFilter } from '../../utils.js';
|
import { getFilter } from '../../utils.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// List notes
|
// list of notes
|
||||||
router.get('/', isAuthenticated, async (req, res) => {
|
router.get('/', isAuthenticated, (req, res) => {
|
||||||
const { page, limit, property, sort, order } = req.query;
|
const { page, limit, property, search, sort, order } = req.query;
|
||||||
|
const allowedFilters = ['parent._id'];
|
||||||
const allowedFilters = ['parent', 'user._id'];
|
const filter = getFilter(req.query, allowedFilters);
|
||||||
|
listNotesRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||||
var filter = {};
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(req.query)) {
|
|
||||||
for (var i = 0; i < allowedFilters.length; i++) {
|
|
||||||
if (key == allowedFilters[i]) {
|
|
||||||
const filterObject = parseFilter(key, value);
|
|
||||||
filter = { ...filter, ...filterObject };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listNotesRouteHandler(req, res, page, limit, property, filter, '', sort, order);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get single note
|
router.get('/properties', isAuthenticated, (req, res) => {
|
||||||
router.get('/:id', isAuthenticated, getNoteRouteHandler);
|
let properties = convertPropertiesString(req.query.properties);
|
||||||
|
const allowedFilters = ['parent'];
|
||||||
|
const filter = getFilter(req.query, allowedFilters, false);
|
||||||
|
listNotesByPropertiesRouteHandler(req, res, properties, filter);
|
||||||
|
});
|
||||||
|
|
||||||
// Edit note
|
// create new note
|
||||||
router.put('/:id', isAuthenticated, editNoteRouteHandler);
|
router.post('/', isAuthenticated, (req, res) => {
|
||||||
|
newNoteRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/:id', isAuthenticated, (req, res) => {
|
||||||
|
getNoteRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
// update note info
|
||||||
|
router.put('/:id', isAuthenticated, async (req, res) => {
|
||||||
|
editNoteRouteHandler(req, res);
|
||||||
|
});
|
||||||
// Delete note
|
// Delete note
|
||||||
router.delete('/:id', isAuthenticated, deleteNoteRouteHandler);
|
router.delete('/:id', isAuthenticated, deleteNoteRouteHandler);
|
||||||
|
|
||||||
// Create new note
|
|
||||||
router.post('/', isAuthenticated, newNoteRouteHandler);
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@ -2,26 +2,30 @@ import express from 'express';
|
|||||||
import { isAuthenticated } from '../../keycloak.js';
|
import { isAuthenticated } from '../../keycloak.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
import { listSubJobsRouteHandler } from '../../services/production/subjobs.js';
|
import {
|
||||||
import { parseFilter } from '../../utils.js';
|
listSubJobsRouteHandler,
|
||||||
|
listSubJobsByPropertiesRouteHandler,
|
||||||
|
getSubJobRouteHandler,
|
||||||
|
} from '../../services/production/subjobs.js';
|
||||||
|
import { getFilter } from '../../utils.js';
|
||||||
|
|
||||||
// list of print subjobs
|
// list of sub jobs
|
||||||
router.get('/', isAuthenticated, (req, res) => {
|
router.get('/', isAuthenticated, (req, res) => {
|
||||||
const { page, limit, property, search, sort, order } = req.query;
|
const { page, limit, property, search, sort, order } = req.query;
|
||||||
const allowedFilters = ['_id', 'job._id'];
|
const allowedFilters = ['_id', 'job._id', 'printer._id'];
|
||||||
|
const filter = getFilter(req.query, allowedFilters);
|
||||||
var filter = {};
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(req.query)) {
|
|
||||||
for (var i = 0; i < allowedFilters.length; i++) {
|
|
||||||
if (key == allowedFilters[i]) {
|
|
||||||
const parsedFilter = parseFilter(key, value);
|
|
||||||
filter = { ...filter, ...parsedFilter };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listSubJobsRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
listSubJobsRouteHandler(req, res, page, limit, property, filter, search, sort, order);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/properties', isAuthenticated, (req, res) => {
|
||||||
|
let properties = convertPropertiesString(req.query.properties);
|
||||||
|
const allowedFilters = ['job'];
|
||||||
|
const filter = getFilter(req.query, allowedFilters, false);
|
||||||
|
listSubJobsByPropertiesRouteHandler(req, res, properties, filter);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/:id', isAuthenticated, (req, res) => {
|
||||||
|
getSubJobRouteHandler(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@ -2,11 +2,17 @@ import dotenv from 'dotenv';
|
|||||||
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
|
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
|
||||||
import log4js from 'log4js';
|
import log4js from 'log4js';
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import { distributeUpdate, newAuditLog, editAuditLog, distributeNew } from '../../utils.js';
|
import {
|
||||||
|
deleteObject,
|
||||||
|
listObjects,
|
||||||
|
getObject,
|
||||||
|
editObject,
|
||||||
|
newObject,
|
||||||
|
listObjectsByProperties,
|
||||||
|
} from '../../database/database.js';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const logger = log4js.getLogger('NoteTypes');
|
const logger = log4js.getLogger('Note Types');
|
||||||
logger.level = process.env.LOG_LEVEL;
|
logger.level = process.env.LOG_LEVEL;
|
||||||
|
|
||||||
export const listNoteTypesRouteHandler = async (
|
export const listNoteTypesRouteHandler = async (
|
||||||
@ -20,135 +26,135 @@ export const listNoteTypesRouteHandler = async (
|
|||||||
sort = '',
|
sort = '',
|
||||||
order = 'ascend'
|
order = 'ascend'
|
||||||
) => {
|
) => {
|
||||||
try {
|
const result = await listObjects({
|
||||||
const skip = (page - 1) * limit;
|
model: noteTypeModel,
|
||||||
let noteTypes;
|
page,
|
||||||
let aggregateCommand = [];
|
limit,
|
||||||
|
property,
|
||||||
if (search) {
|
filter,
|
||||||
// Add a text search match stage for name and brand fields
|
search,
|
||||||
aggregateCommand.push({
|
sort,
|
||||||
$match: {
|
order,
|
||||||
$text: {
|
|
||||||
$search: search,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
logger.error('Error listing note types.');
|
||||||
|
res.status(result.code).send(result);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter != {}) {
|
logger.debug(`List of note types (Page ${page}, Limit ${limit}). Count: ${result.length}`);
|
||||||
// use filtering if present
|
res.send(result);
|
||||||
aggregateCommand.push({ $match: filter });
|
};
|
||||||
|
|
||||||
|
export const listNoteTypesByPropertiesRouteHandler = async (
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
properties = '',
|
||||||
|
filter = {},
|
||||||
|
masterFilter = {}
|
||||||
|
) => {
|
||||||
|
const result = await listObjectsByProperties({
|
||||||
|
model: noteTypeModel,
|
||||||
|
properties,
|
||||||
|
filter,
|
||||||
|
masterFilter,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
logger.error('Error listing note types.');
|
||||||
|
res.status(result.code).send(result);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property != '') {
|
logger.debug(`List of note types. Count: ${result.length}`);
|
||||||
aggregateCommand.push({ $group: { _id: `$${property}` } });
|
res.send(result);
|
||||||
aggregateCommand.push({ $project: { _id: 0, [property]: '$_id' } });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add sorting if sort parameter is provided
|
|
||||||
if (sort) {
|
|
||||||
const sortOrder = order === 'descend' ? -1 : 1;
|
|
||||||
aggregateCommand.push({ $sort: { [sort]: sortOrder } });
|
|
||||||
}
|
|
||||||
|
|
||||||
aggregateCommand.push({ $skip: skip });
|
|
||||||
aggregateCommand.push({ $limit: Number(limit) });
|
|
||||||
|
|
||||||
console.log(aggregateCommand);
|
|
||||||
|
|
||||||
noteTypes = await noteTypeModel.aggregate(aggregateCommand);
|
|
||||||
|
|
||||||
logger.trace(
|
|
||||||
`List of note types (Page ${page}, Limit ${limit}, Property ${property}):`,
|
|
||||||
noteTypes
|
|
||||||
);
|
|
||||||
res.send(noteTypes);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error listing note types:', error);
|
|
||||||
res.status(500).send({ error: error });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNoteTypeRouteHandler = async (req, res) => {
|
export const getNoteTypeRouteHandler = async (req, res) => {
|
||||||
try {
|
const id = req.params.id;
|
||||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
const result = await getObject({
|
||||||
const noteType = await noteTypeModel.findOne({
|
model: noteTypeModel,
|
||||||
_id: id,
|
id,
|
||||||
});
|
});
|
||||||
|
if (result?.error) {
|
||||||
if (!noteType) {
|
logger.warn(`Note Type not found with supplied id.`);
|
||||||
logger.warn(`Note type not found with supplied id.`);
|
return res.status(result.code).send(result);
|
||||||
return res.status(404).send({ error: 'Note type not found.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(`Note type with ID: ${id}:`, noteType);
|
|
||||||
|
|
||||||
res.send({ ...noteType._doc });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error fetching note type:', error);
|
|
||||||
res.status(500).send({ error: error.message });
|
|
||||||
}
|
}
|
||||||
|
logger.debug(`Retreived note type with ID: ${id}`);
|
||||||
|
res.send(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const editNoteTypeRouteHandler = async (req, res) => {
|
export const editNoteTypeRouteHandler = async (req, res) => {
|
||||||
try {
|
// Get ID from params
|
||||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
||||||
const noteType = await noteTypeModel.findOne({ _id: id });
|
|
||||||
|
|
||||||
if (!noteType) {
|
logger.trace(`Note Type with ID: ${id}`);
|
||||||
logger.warn(`Note type not found with supplied id.`);
|
|
||||||
return res.status(404).send({ error: 'Note type not found.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(`Note type with ID: ${id}:`, noteType);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
name: req.body.name,
|
name: req.body.name,
|
||||||
color: req.body.color,
|
color: req.body.color,
|
||||||
active: req.body.active,
|
active: req.body.active,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create audit log before updating
|
// Create audit log before updating
|
||||||
await editAuditLog(noteType.toObject(), updateData, id, 'noteType', req.user._id, 'user');
|
const result = await editObject({
|
||||||
await distributeUpdate(updateData, id, 'noteType');
|
model: noteTypeModel,
|
||||||
|
id,
|
||||||
|
updateData,
|
||||||
|
user: req.user,
|
||||||
|
});
|
||||||
|
|
||||||
const result = await noteTypeModel.updateOne({ _id: id }, { $set: updateData });
|
if (result.error) {
|
||||||
if (result.nModified === 0) {
|
logger.error('Error editing note type:', result.error);
|
||||||
logger.error('No note type updated.');
|
res.status(result).send(result);
|
||||||
res.status(500).send({ error: 'No note types updated.' });
|
return;
|
||||||
}
|
|
||||||
} catch (updateError) {
|
|
||||||
logger.error('Error updating note type:', updateError);
|
|
||||||
res.status(500).send({ error: updateError.message });
|
|
||||||
}
|
|
||||||
res.send('OK');
|
|
||||||
} catch (fetchError) {
|
|
||||||
logger.error('Error fetching note type:', fetchError);
|
|
||||||
res.status(500).send({ error: fetchError.message });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug(`Edited note type with ID: ${id}`);
|
||||||
|
|
||||||
|
res.send(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newNoteTypeRouteHandler = async (req, res) => {
|
export const newNoteTypeRouteHandler = async (req, res) => {
|
||||||
try {
|
const newData = {
|
||||||
let { ...newNoteType } = req.body;
|
updatedAt: new Date(),
|
||||||
newNoteType = { ...newNoteType, createdAt: new Date(), updatedAt: new Date() };
|
name: req.body.name,
|
||||||
|
color: req.body.color,
|
||||||
const result = await noteTypeModel.create(newNoteType);
|
active: req.body.active,
|
||||||
if (result.nCreated === 0) {
|
};
|
||||||
logger.error('No note type created.');
|
const result = await newObject({
|
||||||
res.status(500).send({ error: 'No note type created.' });
|
model: noteTypeModel,
|
||||||
|
newData,
|
||||||
|
user: req.user,
|
||||||
|
});
|
||||||
|
if (result.error) {
|
||||||
|
logger.error('No note type created:', result.error);
|
||||||
|
return res.status(result.code).send(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create audit log for new note type
|
logger.debug(`New note type with ID: ${result._id}`);
|
||||||
await newAuditLog(newNoteType, result._id, 'noteType', req.user);
|
|
||||||
await distributeNew(result._id, 'filament');
|
|
||||||
|
|
||||||
res.status(200).send({ status: 'ok' });
|
res.send(result);
|
||||||
} catch (updateError) {
|
};
|
||||||
logger.error('Error creating note type:', updateError);
|
|
||||||
res.status(500).send({ error: updateError.message });
|
export const deleteNoteTypeRouteHandler = async (req, res) => {
|
||||||
}
|
// Get ID from params
|
||||||
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
||||||
|
|
||||||
|
logger.trace(`Note Type with ID: ${id}`);
|
||||||
|
|
||||||
|
const result = await deleteObject({
|
||||||
|
model: noteTypeModel,
|
||||||
|
id,
|
||||||
|
user: req.user,
|
||||||
|
});
|
||||||
|
if (result.error) {
|
||||||
|
logger.error('No note type deleted:', result.error);
|
||||||
|
return res.status(result.code).send(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(`Deleted note type with ID: ${result._id}`);
|
||||||
|
|
||||||
|
res.send(result);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import { noteModel } from '../../schemas/misc/note.schema.js';
|
import { noteModel } from '../../schemas/misc/note.schema.js';
|
||||||
import log4js from 'log4js';
|
import log4js from 'log4js';
|
||||||
import mongoose from 'mongoose';
|
|
||||||
import {
|
import {
|
||||||
deleteAuditLog,
|
deleteObject,
|
||||||
editAuditLog,
|
editObject,
|
||||||
expandObjectIds,
|
getObject,
|
||||||
flatternObjectIds,
|
listObjects,
|
||||||
newAuditLog,
|
listObjectsByProperties,
|
||||||
} from '../../utils.js';
|
newObject,
|
||||||
|
recursivelyDeleteChildObjects,
|
||||||
|
} from '../../database/database.js';
|
||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@ -21,197 +23,141 @@ export const listNotesRouteHandler = async (
|
|||||||
page = 1,
|
page = 1,
|
||||||
limit = 25,
|
limit = 25,
|
||||||
property = '',
|
property = '',
|
||||||
filter = {}
|
filter = {},
|
||||||
|
search = '',
|
||||||
|
sort = '',
|
||||||
|
order = 'ascend'
|
||||||
) => {
|
) => {
|
||||||
try {
|
const result = await listObjects({
|
||||||
const skip = (page - 1) * limit;
|
model: noteModel,
|
||||||
let notes;
|
page,
|
||||||
let aggregateCommand = [];
|
limit,
|
||||||
|
property,
|
||||||
|
filter,
|
||||||
|
search,
|
||||||
|
sort,
|
||||||
|
order,
|
||||||
|
populate: ['noteType', 'user'],
|
||||||
|
});
|
||||||
|
|
||||||
if (Object.keys(filter).length > 0) {
|
if (result?.error) {
|
||||||
aggregateCommand.push({ $match: filter });
|
logger.error('Error listing notes.');
|
||||||
|
res.status(result.code).send(result);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregateCommand.push({
|
logger.debug(`List of notes (Page ${page}, Limit ${limit}). Count: ${result.length}`);
|
||||||
$lookup: {
|
res.send(result);
|
||||||
from: 'users', // The collection name (usually lowercase plural)
|
};
|
||||||
localField: 'user', // The field in your current model
|
|
||||||
foreignField: '_id', // The field in the users collection
|
export const listNotesByPropertiesRouteHandler = async (req, res, properties = '', filter = {}) => {
|
||||||
as: 'user', // The output field name
|
const result = await listObjectsByProperties({
|
||||||
},
|
model: noteModel,
|
||||||
});
|
properties,
|
||||||
aggregateCommand.push({ $unwind: '$user' });
|
filter,
|
||||||
aggregateCommand.push({
|
populate: ['noteType', 'user'],
|
||||||
$lookup: {
|
|
||||||
from: 'notetypes', // The collection name (usually lowercase plural)
|
|
||||||
localField: 'noteType', // The field in your current model
|
|
||||||
foreignField: '_id', // The field in the users collection
|
|
||||||
as: 'noteType', // The output field name
|
|
||||||
},
|
|
||||||
});
|
|
||||||
aggregateCommand.push({ $unwind: '$noteType' });
|
|
||||||
aggregateCommand.push({
|
|
||||||
$project: {
|
|
||||||
name: 1,
|
|
||||||
_id: 1,
|
|
||||||
createdAt: 1,
|
|
||||||
updatedAt: 1,
|
|
||||||
'noteType._id': 1,
|
|
||||||
'noteType.name': 1,
|
|
||||||
'noteType.color': 1,
|
|
||||||
'user._id': 1,
|
|
||||||
'user.name': 1,
|
|
||||||
content: 1,
|
|
||||||
parent: 1,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
aggregateCommand.push({ $skip: skip });
|
if (result?.error) {
|
||||||
aggregateCommand.push({ $limit: Number(limit) });
|
logger.error('Error listing notes.');
|
||||||
|
res.status(result.code).send(result);
|
||||||
notes = await noteModel.aggregate(aggregateCommand);
|
return;
|
||||||
|
|
||||||
logger.trace(`List of notes (Page ${page}, Limit ${limit}, Property ${property}):`, notes);
|
|
||||||
res.send(notes);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error listing notes:', error);
|
|
||||||
res.status(500).send({ error: error });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug(`List of notes. Count: ${result.length}`);
|
||||||
|
res.send(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNoteRouteHandler = async (req, res) => {
|
export const getNoteRouteHandler = async (req, res) => {
|
||||||
try {
|
const id = req.params.id;
|
||||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
const result = await getObject({
|
||||||
const note = await noteModel.findOne({
|
model: noteModel,
|
||||||
_id: id,
|
id,
|
||||||
|
populate: ['noteType', 'user'],
|
||||||
});
|
});
|
||||||
|
if (result?.error) {
|
||||||
if (!note) {
|
|
||||||
logger.warn(`Note not found with supplied id.`);
|
logger.warn(`Note not found with supplied id.`);
|
||||||
return res.status(404).send({ error: 'Note not found.' });
|
return res.status(result.code).send(result);
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(`Note with ID: ${id}:`, note);
|
|
||||||
|
|
||||||
res.send({ ...note._doc });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error fetching note:', error);
|
|
||||||
res.status(500).send({ error: error.message });
|
|
||||||
}
|
}
|
||||||
|
logger.debug(`Retreived note with ID: ${id}`);
|
||||||
|
res.send(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const editNoteRouteHandler = async (req, res) => {
|
export const editNoteRouteHandler = async (req, res) => {
|
||||||
try {
|
// Get ID from params
|
||||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
||||||
const note = await noteModel.findOne({ _id: id });
|
|
||||||
|
|
||||||
if (!note) {
|
logger.trace(`Note with ID: ${id}`);
|
||||||
logger.warn(`Note not found with supplied id.`);
|
|
||||||
return res.status(404).send({ error: 'Note not found.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(`Note with ID: ${id}:`, note);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
name: req.body.name,
|
content: req.body.content,
|
||||||
color: req.body.color,
|
noteType: req.body.noteType,
|
||||||
isActive: req.body.isActive,
|
|
||||||
};
|
};
|
||||||
|
// Create audit log before updating
|
||||||
|
const result = await editObject({
|
||||||
|
model: noteModel,
|
||||||
|
id,
|
||||||
|
updateData,
|
||||||
|
user: req.user,
|
||||||
|
});
|
||||||
|
|
||||||
const result = await noteModel.updateOne({ _id: id }, { $set: updateData });
|
if (result.error) {
|
||||||
if (result.nModified === 0) {
|
logger.error('Error editing note:', result.error);
|
||||||
logger.error('No note updated.');
|
res.status(result).send(result);
|
||||||
res.status(500).send({ error: 'No notes updated.' });
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await editAuditLog(note.toObject(), updateData, id, 'note', req.user);
|
logger.debug(`Edited note with ID: ${id}`);
|
||||||
} catch (updateError) {
|
|
||||||
logger.error('Error updating note:', updateError);
|
res.send(result);
|
||||||
res.status(500).send({ error: updateError.message });
|
|
||||||
}
|
|
||||||
res.send('OK');
|
|
||||||
} catch (fetchError) {
|
|
||||||
logger.error('Error fetching note:', fetchError);
|
|
||||||
res.status(500).send({ error: fetchError.message });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newNoteRouteHandler = async (req, res) => {
|
export const newNoteRouteHandler = async (req, res) => {
|
||||||
try {
|
const newData = {
|
||||||
let { ...newNote } = req.body;
|
updatedAt: new Date(),
|
||||||
newNote = { ...newNote, createdAt: new Date(), updatedAt: new Date(), user: req.user };
|
content: req.body.content,
|
||||||
|
noteType: req.body.noteType,
|
||||||
const result = await noteModel.create(flatternObjectIds(newNote));
|
parent: req.body.parent,
|
||||||
if (result.nCreated === 0) {
|
parentType: req.body.parentType,
|
||||||
logger.error('No note created.');
|
user: req.user,
|
||||||
res.status(500).send({ error: 'No note created.' });
|
};
|
||||||
|
const result = await newObject({
|
||||||
|
model: noteModel,
|
||||||
|
newData,
|
||||||
|
user: req.user,
|
||||||
|
});
|
||||||
|
if (result.error) {
|
||||||
|
logger.error('No note created:', result.error);
|
||||||
|
return res.status(result.code).send(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
await newAuditLog(expandObjectIds(newNote), result._id, 'note', req.user);
|
logger.debug(`New note with ID: ${result._id}`);
|
||||||
|
|
||||||
res.status(200).send({ status: 'ok' });
|
res.send(result);
|
||||||
} catch (updateError) {
|
|
||||||
logger.error('Error creating note:', updateError);
|
|
||||||
res.status(500).send({ error: updateError.message });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteNoteRouteHandler = async (req, res) => {
|
export const deleteNoteRouteHandler = async (req, res) => {
|
||||||
try {
|
// Get ID from params
|
||||||
const id = new mongoose.Types.ObjectId(req.params.id);
|
const id = req.params.id;
|
||||||
const note = await noteModel.findOne({ _id: id });
|
|
||||||
|
|
||||||
if (!note) {
|
logger.trace(`Delete note with ID: ${id}`);
|
||||||
logger.warn(`Note not found with supplied id.`);
|
|
||||||
return res.status(404).send({ error: 'Note not found.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the current user owns this note
|
|
||||||
if (note.user.toString() !== req.user._id.toString()) {
|
|
||||||
logger.warn(`User ${req.user._id} attempted to delete note ${id} owned by user ${note.user}`);
|
|
||||||
return res.status(403).send({ error: 'You can only delete your own notes.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(`Deleting note with ID: ${id} and all its children`);
|
|
||||||
|
|
||||||
// Recursively find and delete all child notes
|
// Recursively find and delete all child notes
|
||||||
const deletedNoteIds = await recursivelyDeleteNotes(id, req.user);
|
const result = await recursivelyDeleteChildObjects({ model: noteModel, id, user: req.user });
|
||||||
|
|
||||||
logger.info(`Successfully deleted note ${id} and ${deletedNoteIds.length - 1} child notes`);
|
if (result?.length <= 0) {
|
||||||
|
logger.error('No notes deleted');
|
||||||
|
return res.status(404).send(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.error) {
|
||||||
|
logger.error('No note deleted:', result.error);
|
||||||
|
return res.status(result.code).send(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`Successfully deleted note ${id} and ${result.length - 1} child notes`);
|
||||||
res.send({
|
res.send({
|
||||||
status: 'ok',
|
status: 'ok',
|
||||||
deletedNoteIds: deletedNoteIds,
|
|
||||||
message: `Deleted ${deletedNoteIds.length} notes`,
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error deleting note:', error);
|
|
||||||
res.status(500).send({ error: error.message });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to recursively delete notes and their children
|
|
||||||
const recursivelyDeleteNotes = async (noteId, user) => {
|
|
||||||
const deletedIds = [];
|
|
||||||
|
|
||||||
// Find all notes that have this note as their parent
|
|
||||||
const childNotes = await noteModel.find({ parent: noteId });
|
|
||||||
|
|
||||||
// Recursively delete all children first
|
|
||||||
for (const childNote of childNotes) {
|
|
||||||
const childDeletedIds = await recursivelyDeleteNotes(childNote._id, user);
|
|
||||||
deletedIds.push(...childDeletedIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the current note
|
|
||||||
|
|
||||||
const note = await noteModel.findOne({ _id: noteId }).populate('user').populate('parent');
|
|
||||||
|
|
||||||
await deleteAuditLog(expandObjectIds(note.toObject()), noteId, 'note', user);
|
|
||||||
|
|
||||||
await noteModel.deleteOne({ _id: noteId });
|
|
||||||
deletedIds.push(noteId);
|
|
||||||
|
|
||||||
return deletedIds;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import { subJobModel } from '../../schemas/production/subjob.schema.js';
|
import { subJobModel } from '../../schemas/production/subjob.schema.js';
|
||||||
import log4js from 'log4js';
|
import log4js from 'log4js';
|
||||||
|
import { getObject, listObjects, listObjectsByProperties } from '../../database/database.js';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const logger = log4js.getLogger('SubJobs');
|
const logger = log4js.getLogger('Sub Jobs');
|
||||||
logger.level = process.env.LOG_LEVEL;
|
logger.level = process.env.LOG_LEVEL;
|
||||||
|
|
||||||
export const listSubJobsRouteHandler = async (
|
export const listSubJobsRouteHandler = async (
|
||||||
@ -17,102 +18,62 @@ export const listSubJobsRouteHandler = async (
|
|||||||
sort = '',
|
sort = '',
|
||||||
order = 'ascend'
|
order = 'ascend'
|
||||||
) => {
|
) => {
|
||||||
try {
|
const result = await listObjects({
|
||||||
// Calculate the skip value based on the page number and limit
|
model: subJobModel,
|
||||||
const skip = (page - 1) * limit;
|
page,
|
||||||
|
limit,
|
||||||
let subJobs;
|
property,
|
||||||
let aggregateCommand = [];
|
filter,
|
||||||
|
search,
|
||||||
if (search) {
|
sort,
|
||||||
// Add a text search match stage for name and other searchable fields
|
order,
|
||||||
aggregateCommand.push({
|
populate: ['printer'],
|
||||||
$match: {
|
|
||||||
$text: {
|
|
||||||
$search: search,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Lookup printer
|
|
||||||
aggregateCommand.push({
|
|
||||||
$lookup: {
|
|
||||||
from: 'printers', // The name of the Printer collection
|
|
||||||
localField: 'printer',
|
|
||||||
foreignField: '_id',
|
|
||||||
as: 'printer',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Lookup job
|
if (result?.error) {
|
||||||
aggregateCommand.push({
|
logger.error('Error listing sub jobs.');
|
||||||
$lookup: {
|
res.status(result.code).send(result);
|
||||||
from: 'jobs', // The name of the Printer collection
|
return;
|
||||||
localField: 'job',
|
|
||||||
foreignField: '_id',
|
|
||||||
as: 'job',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
aggregateCommand.push({
|
|
||||||
$unwind: {
|
|
||||||
path: '$printer',
|
|
||||||
preserveNullAndEmptyArrays: true, // Keep documents without a matching filament
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
aggregateCommand.push({
|
|
||||||
$unwind: {
|
|
||||||
path: '$job',
|
|
||||||
preserveNullAndEmptyArrays: true, // Keep documents without a matching filament
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (filter != {}) {
|
|
||||||
// use filtering if present
|
|
||||||
aggregateCommand.push({ $match: filter });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property != '') {
|
logger.debug(`List of sub jobs (Page ${page}, Limit ${limit}). Count: ${result.length}`);
|
||||||
aggregateCommand.push({ $group: { _id: `$${property}` } }); // group all same properties
|
res.send(result);
|
||||||
aggregateCommand.push({ $project: { _id: 0, [property]: '$_id' } }); // rename _id to the property name
|
};
|
||||||
} else {
|
|
||||||
aggregateCommand.push({
|
export const listSubJobsByPropertiesRouteHandler = async (
|
||||||
$project: {
|
req,
|
||||||
state: 1,
|
res,
|
||||||
_id: 1,
|
properties = '',
|
||||||
createdAt: 1,
|
filter = {},
|
||||||
startedAt: 1,
|
masterFilter = {}
|
||||||
'printer._id': 1,
|
) => {
|
||||||
'job._id': 1,
|
const result = await listObjectsByProperties({
|
||||||
'printer.name': 1,
|
model: subJobModel,
|
||||||
},
|
properties,
|
||||||
});
|
filter,
|
||||||
}
|
masterFilter,
|
||||||
|
});
|
||||||
// Add sorting if sort parameter is provided
|
|
||||||
if (sort) {
|
if (result?.error) {
|
||||||
const sortOrder = order === 'descend' ? -1 : 1;
|
logger.error('Error listing sub jobs.');
|
||||||
aggregateCommand.push({ $sort: { [sort]: sortOrder } });
|
res.status(result.code).send(result);
|
||||||
} else {
|
return;
|
||||||
// Default sorting by createdAt descending
|
}
|
||||||
aggregateCommand.push({ $sort: { createdAt: -1 } });
|
|
||||||
}
|
logger.debug(`List of sub jobs. Count: ${result.length}`);
|
||||||
|
res.send(result);
|
||||||
aggregateCommand.push({ $skip: skip });
|
};
|
||||||
aggregateCommand.push({ $limit: Number(limit) });
|
|
||||||
|
export const getSubJobRouteHandler = async (req, res) => {
|
||||||
console.log(aggregateCommand);
|
const id = req.params.id;
|
||||||
|
const result = await getObject({
|
||||||
subJobs = await subJobModel.aggregate(aggregateCommand);
|
model: subJobModel,
|
||||||
|
id,
|
||||||
logger.trace(
|
});
|
||||||
`List of print subJobs (Page ${page}, Limit ${limit}, Property ${property}, Sort ${sort}, Order ${order}):`,
|
if (result?.error) {
|
||||||
subJobs
|
logger.warn(`Sub job not found with supplied id.`);
|
||||||
);
|
return res.status(result.code).send(result);
|
||||||
res.send(subJobs);
|
}
|
||||||
} catch (error) {
|
logger.debug(`Retreived sub job with ID: ${id}`);
|
||||||
logger.error('Error listing print subJobs:', error);
|
res.send(result);
|
||||||
res.status(500).send({ error: error });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user