diff --git a/src/routes/index.js b/src/routes/index.js index 0142844..f8bfb1b 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -20,6 +20,7 @@ import noteTypeRoutes from './management/notetypes.js'; import documentSizesRoutes from './management/documentsizes.js'; import documentTemplatesRoutes from './management/documenttemplates.js'; import documentPrintersRoutes from './management/documentprinters.js'; +import documentJobsRoutes from './management/documentjobs.js'; import noteRoutes from './misc/notes.js'; export { @@ -46,4 +47,5 @@ export { documentSizesRoutes, documentTemplatesRoutes, documentPrintersRoutes, + documentJobsRoutes, }; diff --git a/src/routes/management/documentjobs.js b/src/routes/management/documentjobs.js new file mode 100644 index 0000000..46986f5 --- /dev/null +++ b/src/routes/management/documentjobs.js @@ -0,0 +1,46 @@ +import express from 'express'; +import { isAuthenticated } from '../../keycloak.js'; +import { getFilter, convertPropertiesString } from '../../utils.js'; + +const router = express.Router(); +import { + listDocumentJobsRouteHandler, + getDocumentJobRouteHandler, + editDocumentJobRouteHandler, + newDocumentJobRouteHandler, + deleteDocumentJobRouteHandler, + listDocumentJobsByPropertiesRouteHandler, +} from '../../services/management/documentjobs.js'; + +// list of document jobs +router.get('/', isAuthenticated, (req, res) => { + const { page, limit, property, search, sort, order } = req.query; + const allowedFilters = ['name', 'width', 'height']; + const filter = getFilter(req.query, allowedFilters); + listDocumentJobsRouteHandler(req, res, page, limit, property, filter, search, sort, order); +}); + +router.get('/properties', isAuthenticated, (req, res) => { + let properties = convertPropertiesString(req.query.properties); + const allowedFilters = []; + const filter = getFilter(req.query, allowedFilters, false); + listDocumentJobsByPropertiesRouteHandler(req, res, properties, filter); +}); + +router.post('/', isAuthenticated, (req, res) => { + newDocumentJobRouteHandler(req, res); +}); + +router.get('/:id', isAuthenticated, (req, res) => { + getDocumentJobRouteHandler(req, res); +}); + +router.put('/:id', isAuthenticated, async (req, res) => { + editDocumentJobRouteHandler(req, res); +}); + +router.delete('/:id', isAuthenticated, async (req, res) => { + deleteDocumentJobRouteHandler(req, res); +}); + +export default router; diff --git a/src/schemas/management/documentjob.schema.js b/src/schemas/management/documentjob.schema.js new file mode 100644 index 0000000..0d7c59b --- /dev/null +++ b/src/schemas/management/documentjob.schema.js @@ -0,0 +1,42 @@ +import mongoose from 'mongoose'; +const { Schema } = mongoose; + +const documentJobSchema = new Schema( + { + name: { + type: String, + required: true, + unique: true, + }, + objectType: { type: String, required: false }, + state: { + type: { type: String, required: true, default: 'queued' }, + percent: { type: Number, required: false }, + }, + documentTemplate: { + type: Schema.Types.ObjectId, + ref: 'documentTemplate', + required: true, + }, + documentPrinter: { + type: Schema.Types.ObjectId, + ref: 'documentPrinter', + required: true, + }, + content: { + type: String, + required: false, + }, + }, + { timestamps: true } +); + +// Add virtual id getter +documentJobSchema.virtual('id').get(function () { + return this._id.toHexString(); +}); + +// Configure JSON serialization to include virtuals +documentJobSchema.set('toJSON', { virtuals: true }); + +export const documentJobModel = mongoose.model('documentJob', documentJobSchema); diff --git a/src/services/management/documentjobs.js b/src/services/management/documentjobs.js new file mode 100644 index 0000000..053be66 --- /dev/null +++ b/src/services/management/documentjobs.js @@ -0,0 +1,158 @@ +import dotenv from 'dotenv'; +import { documentJobModel } from '../../schemas/management/documentjob.schema.js'; +import log4js from 'log4js'; +import mongoose from 'mongoose'; +import { + deleteObject, + listObjects, + getObject, + editObject, + newObject, + listObjectsByProperties, +} from '../../database/database.js'; +dotenv.config(); + +const logger = log4js.getLogger('Document Jobs'); +logger.level = process.env.LOG_LEVEL; + +export const listDocumentJobsRouteHandler = async ( + req, + res, + page = 1, + limit = 25, + property = '', + filter = {}, + search = '', + sort = '', + order = 'ascend' +) => { + const result = await listObjects({ + model: documentJobModel, + page, + limit, + property, + filter, + search, + sort, + order, + }); + + if (result?.error) { + logger.error('Error listing document jobs.'); + res.status(result.code).send(result); + return; + } + + logger.debug(`List of document jobs (Page ${page}, Limit ${limit}). Count: ${result.length}`); + res.send(result); +}; + +export const listDocumentJobsByPropertiesRouteHandler = async ( + req, + res, + properties = '', + filter = {} +) => { + const result = await listObjectsByProperties({ + model: documentJobModel, + properties, + filter, + }); + + if (result?.error) { + logger.error('Error listing document jobs.'); + res.status(result.code).send(result); + return; + } + + logger.debug(`List of document jobs. Count: ${result.length}`); + res.send(result); +}; + +export const getDocumentJobRouteHandler = async (req, res) => { + const id = req.params.id; + const result = await getObject({ + model: documentJobModel, + id, + }); + if (result?.error) { + logger.warn(`Document Job not found with supplied id.`); + return res.status(result.code).send(result); + } + logger.debug(`Retreived document job with ID: ${id}`); + res.send(result); +}; + +export const editDocumentJobRouteHandler = async (req, res) => { + // Get ID from params + const id = new mongoose.Types.ObjectId(req.params.id); + + logger.trace(`Document Job with ID: ${id}`); + + const updateData = { + updatedAt: new Date(), + name: req.body.name, + width: req.body.width, + height: req.body.height, + }; + // Create audit log before updating + const result = await editObject({ + model: documentJobModel, + id, + updateData, + user: req.user, + }); + + if (result.error) { + logger.error('Error editing document job:', result.error); + res.status(result).send(result); + return; + } + + logger.debug(`Edited document job with ID: ${id}`); + + res.send(result); +}; + +export const newDocumentJobRouteHandler = async (req, res) => { + const newData = { + updatedAt: new Date(), + name: req.body.name, + width: req.body.width, + height: req.body.height, + }; + const result = await newObject({ + model: documentJobModel, + newData, + user: req.user, + }); + if (result.error) { + logger.error('No document job created:', result.error); + return res.status(result.code).send(result); + } + + logger.debug(`New document job with ID: ${result._id}`); + + res.send(result); +}; + +export const deleteDocumentJobRouteHandler = async (req, res) => { + // Get ID from params + const id = new mongoose.Types.ObjectId(req.params.id); + + logger.trace(`Document Job with ID: ${id}`); + + const result = await deleteObject({ + model: documentJobModel, + id, + user: req.user, + }); + if (result.error) { + logger.error('No document job deleted:', result.error); + return res.status(result.code).send(result); + } + + logger.debug(`Deleted document job with ID: ${result._id}`); + + res.send(result); +};