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:
Tom Butcher 2025-09-05 23:25:14 +01:00
parent 12be496f22
commit 4685cac563
6 changed files with 378 additions and 454 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -2,8 +2,14 @@ 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('Note Types'); const logger = log4js.getLogger('Note Types');
@ -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,
// Create audit log for new note type });
await newAuditLog(newNoteType, result._id, 'noteType', req.user); if (result.error) {
await distributeNew(result._id, 'filament'); logger.error('No note type created:', result.error);
return res.status(result.code).send(result);
res.status(200).send({ status: 'ok' }); }
} catch (updateError) {
logger.error('Error creating note type:', updateError); logger.debug(`New note type with ID: ${result._id}`);
res.status(500).send({ error: updateError.message });
} res.send(result);
};
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);
}; };

View File

@ -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;
}; };

View File

@ -1,6 +1,7 @@
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('Sub Jobs'); const logger = log4js.getLogger('Sub Jobs');
@ -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 });
}
}; };