166 lines
6.3 KiB
JavaScript
166 lines
6.3 KiB
JavaScript
import dotenv from 'dotenv';
|
|
import log4js from 'log4js';
|
|
import mongoose from 'mongoose';
|
|
import { jobModel } from '../../schemas/production/job.schema.js';
|
|
import { subJobModel } from '../../schemas/production/subjob.schema.js';
|
|
import { printerModel } from '../../schemas/production/printer.schema.js';
|
|
import { filamentModel } from '../../schemas/management/filament.schema.js';
|
|
import { gcodeFileModel } from '../../schemas/production/gcodefile.schema.js';
|
|
import { partModel } from '../../schemas/management/part.schema.js';
|
|
import { productModel } from '../../schemas/management/product.schema.js';
|
|
import { vendorModel } from '../../schemas/management/vendor.schema.js';
|
|
import { filamentStockModel } from '../../schemas/inventory/filamentstock.schema.js';
|
|
import { stockEventModel } from '../../schemas/inventory/stockevent.schema.js';
|
|
import { stockAuditModel } from '../../schemas/inventory/stockaudit.schema.js';
|
|
import { partStockModel } from '../../schemas/inventory/partstock.schema.js';
|
|
import { auditLogModel } from '../../schemas/management/auditlog.schema.js';
|
|
import { userModel } from '../../schemas/management/user.schema.js';
|
|
import { noteTypeModel } from '../../schemas/management/notetype.schema.js';
|
|
import { noteModel } from '../../schemas/misc/note.schema.js';
|
|
dotenv.config();
|
|
|
|
const logger = log4js.getLogger('Jobs');
|
|
logger.level = process.env.LOG_LEVEL;
|
|
|
|
// Map prefixes to models and id fields
|
|
const PREFIX_MODEL_MAP = {
|
|
PRN: { model: printerModel, idField: '_id', type: 'printer' },
|
|
FIL: { model: filamentModel, idField: '_id', type: 'filament' },
|
|
SPL: { model: null, idField: '_id', type: 'spool' }, // No spool model found
|
|
GCF: { model: gcodeFileModel, idField: '_id', type: 'gcodefile' },
|
|
JOB: { model: jobModel, idField: '_id', type: 'job' },
|
|
PRT: { model: partModel, idField: '_id', type: 'part' },
|
|
PRD: { model: productModel, idField: '_id', type: 'product' },
|
|
VEN: { model: vendorModel, idField: '_id', type: 'vendor' },
|
|
SJB: { model: subJobModel, idField: '_id', type: 'subjob' },
|
|
FLS: { model: filamentStockModel, idField: '_id', type: 'filamentstock' },
|
|
SEV: { model: stockEventModel, idField: '_id', type: 'stockevent' },
|
|
SAU: { model: stockAuditModel, idField: '_id', type: 'stockaudit' },
|
|
PTS: { model: partStockModel, idField: '_id', type: 'partstock' },
|
|
PDS: { model: null, idField: '_id', type: 'productstock' }, // No productStockModel found
|
|
ADL: { model: auditLogModel, idField: '_id', type: 'auditlog' },
|
|
USR: { model: userModel, idField: '_id', type: 'user' },
|
|
NTY: { model: noteTypeModel, idField: '_id', type: 'notetype' },
|
|
NTE: { model: noteModel, idField: '_id', type: 'note' },
|
|
};
|
|
|
|
// Helper function to build search filter from query parameters
|
|
const buildSearchFilter = (params) => {
|
|
const filter = {};
|
|
|
|
for (const [key, value] of Object.entries(params)) {
|
|
// Skip pagination and limit parameters as they're not search filters
|
|
if (key === 'limit' || key === 'page') continue;
|
|
|
|
// Handle different field types
|
|
if (key === 'name') {
|
|
filter.name = { $regex: value, $options: 'i' }; // Case-insensitive search
|
|
} else if (key === 'id' || key === '_id') {
|
|
if (mongoose.Types.ObjectId.isValid(value)) {
|
|
filter._id = value;
|
|
}
|
|
} else if (key === 'tags') {
|
|
filter.tags = { $in: [new RegExp(value, 'i')] };
|
|
} else if (key === 'state') {
|
|
filter['state.type'] = value;
|
|
} else if (key.includes('.')) {
|
|
// Handle nested fields like 'state.type', 'address.city', etc.
|
|
filter[key] = { $regex: value, $options: 'i' };
|
|
} else {
|
|
// For all other fields, do a case-insensitive search
|
|
filter[key] = { $regex: value, $options: 'i' };
|
|
}
|
|
}
|
|
|
|
return filter;
|
|
};
|
|
|
|
const trimSpotlightObject = (object) => {
|
|
return {
|
|
_id: object._id,
|
|
name: object.name || undefined,
|
|
state: object.state && object?.state.type ? { type: object.state.type } : undefined,
|
|
tags: object.tags || undefined,
|
|
email: object.email || undefined,
|
|
color: object.color || undefined,
|
|
updatedAt: object.updatedAt || undefined,
|
|
};
|
|
};
|
|
|
|
export const getSpotlightRouteHandler = async (req, res) => {
|
|
try {
|
|
const query = req.params.query;
|
|
const queryParams = req.query;
|
|
if (query.length < 3) {
|
|
res.status(200).send([]);
|
|
return;
|
|
}
|
|
const prefix = query.substring(0, 3);
|
|
const delimiter = query.substring(3, 4);
|
|
const suffix = query.substring(4);
|
|
|
|
if (delimiter == ':') {
|
|
const prefixEntry = PREFIX_MODEL_MAP[prefix];
|
|
if (!prefixEntry || !prefixEntry.model) {
|
|
res.status(400).send({ error: 'Invalid or unsupported prefix' });
|
|
return;
|
|
}
|
|
const { model, idField } = prefixEntry;
|
|
|
|
// Validate ObjectId if the idField is '_id'
|
|
if (idField === '_id' && !mongoose.Types.ObjectId.isValid(suffix)) {
|
|
res.status(404).send({ error: `${prefix} not found` });
|
|
return;
|
|
}
|
|
|
|
// Find the object by the correct field
|
|
const queryObj = {};
|
|
queryObj[idField] = suffix.toLowerCase();
|
|
let doc = await model.findOne(queryObj).lean();
|
|
if (!doc) {
|
|
res.status(404).send({ error: `${prefix} not found` });
|
|
return;
|
|
}
|
|
// Build the response with only the required fields
|
|
const response = trimSpotlightObject(doc);
|
|
res.status(200).send(response);
|
|
return;
|
|
}
|
|
|
|
console.log(queryParams);
|
|
|
|
if (Object.keys(queryParams).length > 0) {
|
|
const prefixEntry = PREFIX_MODEL_MAP[prefix];
|
|
console.log(prefixEntry);
|
|
if (!prefixEntry || !prefixEntry.model) {
|
|
res.status(400).send({ error: 'Invalid or unsupported prefix' });
|
|
return;
|
|
}
|
|
const { model } = prefixEntry;
|
|
|
|
// Use req.query for search parameters
|
|
|
|
if (Object.keys(queryParams).length === 0) {
|
|
res.status(400).send({ error: 'No search parameters provided' });
|
|
return;
|
|
}
|
|
|
|
// Build search filter
|
|
const searchFilter = buildSearchFilter(queryParams);
|
|
|
|
// Perform search with limit
|
|
const limit = parseInt(req.query.limit) || 10;
|
|
const docs = await model.find(searchFilter).limit(limit).sort({ updatedAt: -1 }).lean();
|
|
|
|
// Format response
|
|
const response = docs.map((doc) => trimSpotlightObject(doc));
|
|
|
|
res.status(200).send(response);
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
logger.error('Error in spotlight lookup:', error);
|
|
res.status(500).send({ error: error });
|
|
}
|
|
};
|