diff --git a/src/database/schemas/management/documentjob.schema.js b/src/database/schemas/management/documentjob.schema.js
new file mode 100644
index 0000000..71018c6
--- /dev/null
+++ b/src/database/schemas/management/documentjob.schema.js
@@ -0,0 +1,47 @@
+import mongoose from 'mongoose';
+const { Schema } = mongoose;
+
+const documentJobSchema = new Schema(
+ {
+ name: {
+ type: String,
+ required: true,
+ unique: true,
+ },
+ objectType: { type: String, required: false },
+ object: {
+ type: Schema.Types.ObjectId,
+ refPath: 'objectType',
+ required: true,
+ },
+ 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/database/schemas/management/documentprinter.schema.js b/src/database/schemas/management/documentprinter.schema.js
new file mode 100644
index 0000000..3f3ca46
--- /dev/null
+++ b/src/database/schemas/management/documentprinter.schema.js
@@ -0,0 +1,55 @@
+import mongoose from 'mongoose';
+const { Schema } = mongoose;
+
+const connectionSchema = new Schema(
+ {
+ interface: { type: String, required: true },
+ protocol: { type: String, required: true },
+ host: { type: String, required: true },
+ port: { type: Number, required: false }
+ },
+ { _id: false }
+);
+
+const documentPrinterSchema = new Schema(
+ {
+ name: {
+ type: String,
+ required: true,
+ unique: true
+ },
+ connection: { type: connectionSchema, required: true },
+ currentDocumentSize: {
+ type: Schema.Types.ObjectId,
+ ref: 'documentSize',
+ required: false
+ },
+ tags: [{ type: String }],
+ online: { type: Boolean, required: true, default: false },
+ active: { type: Boolean, required: true, default: true },
+ state: {
+ type: { type: String, required: true, default: 'offline' },
+ message: { type: String, required: false },
+ progress: { type: Number, required: false }
+ },
+ connectedAt: { type: Date, default: null },
+ host: { type: Schema.Types.ObjectId, ref: 'host', required: true },
+ queue: [
+ { type: Schema.Types.ObjectId, ref: 'documentJob', required: false }
+ ]
+ },
+ { timestamps: true }
+);
+
+// Add virtual id getter
+documentPrinterSchema.virtual('id').get(function () {
+ return this._id.toHexString();
+});
+
+// Configure JSON serialization to include virtuals
+documentPrinterSchema.set('toJSON', { virtuals: true });
+
+export const documentPrinterModel = mongoose.model(
+ 'documentPrinter',
+ documentPrinterSchema
+);
diff --git a/src/database/schemas/management/documentsize.schema.js b/src/database/schemas/management/documentsize.schema.js
index 0e2fd40..a3da49d 100644
--- a/src/database/schemas/management/documentsize.schema.js
+++ b/src/database/schemas/management/documentsize.schema.js
@@ -6,18 +6,23 @@ const documentSizeSchema = new Schema(
name: {
type: String,
required: true,
- unique: true,
+ unique: true
},
width: {
type: Number,
required: true,
- default: 0,
+ default: 0
},
height: {
type: Number,
required: true,
- default: 0,
+ default: 0
},
+ infiniteHeight: {
+ type: Boolean,
+ required: true,
+ default: false
+ }
},
{ timestamps: true }
);
@@ -30,4 +35,7 @@ documentSizeSchema.virtual('id').get(function () {
// Configure JSON serialization to include virtuals
documentSizeSchema.set('toJSON', { virtuals: true });
-export const documentSizeModel = mongoose.model('documentSize', documentSizeSchema);
+export const documentSizeModel = mongoose.model(
+ 'documentSize',
+ documentSizeSchema
+);
diff --git a/src/socket/sockethost.js b/src/socket/sockethost.js
index 1d2affb..f5d2070 100644
--- a/src/socket/sockethost.js
+++ b/src/socket/sockethost.js
@@ -2,12 +2,18 @@ import log4js from 'log4js';
// Load configuration
import { loadConfig } from '../config.js';
import { CodeAuth, createAuthMiddleware } from '../auth/auth.js';
-import { editObject, getObject, listObjects } from '../database/database.js';
+import {
+ newObject,
+ editObject,
+ getObject,
+ listObjects
+} from '../database/database.js';
import { hostModel } from '../database/schemas/management/host.schema.js';
import { UpdateManager } from '../updates/updatemanager.js';
import { ActionManager } from '../actions/actionmanager.js';
import { getModelByName } from '../utils.js';
import { EventManager } from '../events/eventmanager.js';
+import { TemplateManager } from '../templates/templatemanager.js';
const config = loadConfig();
@@ -25,6 +31,7 @@ export class SocketHost {
this.updateManager = new UpdateManager(this);
this.actionManager = new ActionManager(this);
this.eventManager = new EventManager(this);
+ this.templateManager = new TemplateManager(this);
this.codeAuth = new CodeAuth();
this.setupSocketEventHandlers();
}
@@ -34,12 +41,33 @@ export class SocketHost {
this.socket.on('authenticate', this.handleAuthenticate.bind(this));
this.socket.on('updateHost', this.handleUpdateHost.bind(this));
this.socket.on('getObject', this.handleGetObject.bind(this));
+ this.socket.on('newObject', this.handleNewObject.bind(this));
this.socket.on('editObject', this.handleEditObject.bind(this));
this.socket.on('listObjects', this.handleListObjects.bind(this));
+ this.socket.on(
+ 'subscribeToObjectUpdates',
+ this.handleSubscribeToObjectUpdatesEvent.bind(this)
+ );
+ this.socket.on(
+ 'unsubscribeToObjectUpdates',
+ this.handleUnsubscribeToObjectUpdatesEvent.bind(this)
+ );
this.socket.on(
'subscribeToObjectActions',
this.handleSubscribeToObjectActions.bind(this)
);
+ this.socket.on(
+ 'subscribeToObjectEvent',
+ this.handleSubscribeToObjectEventEvent.bind(this)
+ );
+ this.socket.on(
+ 'unsubscribeObjectEvent',
+ this.handleUnsubscribeObjectEventEvent.bind(this)
+ );
+ this.socket.on(
+ 'renderTemplatePDF',
+ this.handleRenderTemplatePDFEvent.bind(this)
+ );
this.socket.on('objectEvent', this.handleObjectEventEvent.bind(this));
this.socket.on('disconnect', this.handleDisconnect.bind(this));
}
@@ -107,6 +135,16 @@ export class SocketHost {
});
}
+ async handleNewObject(data, callback) {
+ const object = await newObject({
+ model: getModelByName(data.objectType),
+ newData: data.newData,
+ owner: this.host,
+ ownerType: 'host'
+ });
+ callback(object);
+ }
+
async handleEditObject(data, callback) {
const object = await editObject({
model: getModelByName(data.objectType),
@@ -151,6 +189,13 @@ export class SocketHost {
);
}
+ async handleSubscribeToObjectUpdatesEvent(data) {
+ const result = await this.updateManager.subscribeToObjectUpdate(
+ data._id,
+ data.objectType
+ );
+ }
+
async handleSubscribeToObjectActions(data) {
await this.actionManager.subscribeToObjectActions(
data._id,
@@ -158,6 +203,78 @@ export class SocketHost {
);
}
+ async handleSubscribeToObjectEventEvent(data) {
+ await this.eventManager.subscribeToObjectEvent(
+ data._id,
+ data.objectType,
+ data.eventType
+ );
+ }
+
+ async handleUnsubscribeObjectEventEvent(data) {
+ await this.eventManager.removeObjectEventsListener(
+ data._id,
+ data.objectType,
+ data.eventType
+ );
+ }
+
+ async handleUnsubscribeToObjectUpdatesEvent(data) {
+ await this.updateManager.unsubscribeToObjectUpdate(
+ data._id,
+ data.objectType
+ );
+ }
+
+ async handleRenderTemplatePDFEvent(data, callback) {
+ const result = await this.templateManager.renderPDF(
+ data._id,
+ data.content,
+ data.object,
+ 1
+ );
+ callback(result);
+ }
+
+ async setDevicesState(state, online, connectedAt) {
+ logger.info('Setting devices state to', state, 'and online to', online);
+
+ const documentPrinters = await listObjects({
+ model: getModelByName('documentPrinter'),
+ filter: { host: this.host._id }
+ });
+ const printers = await listObjects({
+ model: getModelByName('printer'),
+ filter: { host: this.host._id }
+ });
+ logger.debug(
+ 'Retrieved',
+ documentPrinters.length,
+ 'document printers and',
+ printers.length,
+ 'printers'
+ );
+ for (const documentPrinter of documentPrinters) {
+ await editObject({
+ model: getModelByName('documentPrinter'),
+ id: documentPrinter._id,
+ updateData: { state: state, online: online, connectedAt: connectedAt },
+ owner: this.host,
+ ownerType: 'host'
+ });
+ }
+ for (const printer of printers) {
+ await editObject({
+ model: getModelByName('printer'),
+ id: printer._id,
+ updateData: { state: state, online: online, connectedAt: connectedAt },
+ owner: this.host,
+ ownerType: 'host'
+ });
+ }
+ logger.info('Devices state set to', state, 'and online to', online);
+ }
+
async handleDisconnect() {
if (this.authenticated) {
await editObject({
@@ -173,6 +290,13 @@ export class SocketHost {
});
this.authenticated = false;
}
+ await this.actionManager.removeAllListeners();
+ await this.eventManager.removeAllListeners();
+ await this.setDevicesState(
+ { type: 'offline', message: 'Host disconnected.' },
+ false,
+ null
+ );
logger.info('External host disconnected. Socket ID:', this.id);
}
}
diff --git a/src/socket/socketuser.js b/src/socket/socketuser.js
index c41ee5b..69d3d20 100644
--- a/src/socket/socketuser.js
+++ b/src/socket/socketuser.js
@@ -64,11 +64,16 @@ export class SocketUser {
'previewTemplate',
this.handlePreviewTemplateEvent.bind(this)
);
+ this.socket.on(
+ 'renderTemplatePDF',
+ this.handleRenderTemplatePDFEvent.bind(this)
+ );
this.socket.on(
'generateHostOtp',
this.handleGenerateHostOtpEvent.bind(this)
);
this.socket.on('objectAction', this.handleObjectActionEvent.bind(this));
+ this.socket.on('disconnect', this.handleDisconnect.bind(this));
}
async handleAuthenticateEvent(data, callback) {
@@ -196,6 +201,15 @@ export class SocketUser {
callback(result);
}
+ async handleRenderTemplatePDFEvent(data, callback) {
+ const result = await this.templateManager.renderPDF(
+ data._id,
+ data.content,
+ data.object,
+ 1
+ );
+ callback(result);
+ }
async handleGenerateHostOtpEvent(data, callback) {
const result = await generateHostOTP(data._id);
callback(result);
@@ -210,7 +224,9 @@ export class SocketUser {
);
}
- handleDisconnect() {
+ async handleDisconnect() {
+ await this.actionManager.removeAllListeners();
+ await this.eventManager.removeAllListeners();
logger.info('External user disconnected:', this.socket.user?.username);
}
}
diff --git a/src/templates/assets/basetemplate.ejs b/src/templates/assets/basetemplate.ejs
index 63d32ac..9465a5e 100644
--- a/src/templates/assets/basetemplate.ejs
+++ b/src/templates/assets/basetemplate.ejs
@@ -15,26 +15,21 @@
@@ -45,5 +40,10 @@
+ <% if (typeof previewPaginationScript !== 'undefined' && previewPaginationScript) { %>
+
+ <% } %>