diff --git a/app.js b/app.js index 213741e..c65b7c1 100644 --- a/app.js +++ b/app.js @@ -33,6 +33,10 @@ app.use(express.static('views/public')) app.use('/api', routerEndpoints) +const { registerEventHandlers } = require('./events/index') + +registerEventHandlers() + databaseConnection(app) app.use(globalErrorHandler) diff --git a/components/belonging/belongingController.js b/components/belonging/belongingController.js index 562e345..c275028 100644 --- a/components/belonging/belongingController.js +++ b/components/belonging/belongingController.js @@ -1,5 +1,6 @@ const catchAsync = require('../../globalErrorHandler/catchAsync') const belongingService = require('./belongingService') +const { eventEmitter } = require('../../events/eventEmitter') exports.searchBelongings = catchAsync(async (req, res, next) => { const { facets, belongings, totalCount, pagesCount } = await belongingService.searchBelongings(req.query) @@ -22,6 +23,14 @@ exports.indexAllBelongings = catchAsync(async (req, res, next) => { }) }) +exports.indexOneBelonging = catchAsync(async (req, res, next) => { + await belongingService.indexOneBelonging() + + res.status(200).json({ + status: 'success', + }) +}) + exports.getAllBelongings = catchAsync(async (req, res, next) => { const belongings = await belongingService.getAllBelongings() @@ -34,6 +43,7 @@ exports.getAllBelongings = catchAsync(async (req, res, next) => { exports.createBelonging = catchAsync(async (req, res, next) => { const belonging = await belongingService.createBelonging(req.body) + eventEmitter.emit('createBelonging', belonging) res.status(201).json({ status: 'success', @@ -52,6 +62,7 @@ exports.getBelonging = catchAsync(async (req, res, next) => { exports.updateBelonging = catchAsync(async (req, res, next) => { const belonging = await belongingService.updateBelonging(req.params.belongingId, req.body) + await belongingService.indexAllBelongings() res.status(200).json({ status: 'success', @@ -61,6 +72,7 @@ exports.updateBelonging = catchAsync(async (req, res, next) => { exports.deleteBelonging = catchAsync(async (req, res, next) => { await belongingService.deleteBelonging(req.params.belongingId) + // eventEmitter.emit('deleteBelonging') res.status(204).json({ status: 'success', diff --git a/components/belonging/belongingModel.js b/components/belonging/belongingModel.js index 9b9c5f4..85e2341 100644 --- a/components/belonging/belongingModel.js +++ b/components/belonging/belongingModel.js @@ -20,7 +20,6 @@ const belongingSchema = new mongoose.Schema( }, unit: { type: String, - required: true, }, description: String, relatedProjects: [String], @@ -62,7 +61,7 @@ const belongingSchema = new mongoose.Schema( } ) -// belongingSchema.plugin(AutoIncrement, { inc_field: 'belongingCode' }) +belongingSchema.plugin(AutoIncrement, { inc_field: 'belongingCode' }) belongingSchema.methods.getDocumentsSignedUrls = function () { return getMultipleSignedUrls(this.documentUrls, 'belonging-documents') @@ -74,5 +73,7 @@ belongingSchema.methods.getMainImagedSignedUrl = function () { belongingSchema.index({ location: '2dsphere' }) // Enable geospatial queries +// belongingSchema.plugin(AutoIncrement, { inc_field: 'numId' }) + const Belonging = mongoose.model('Belonging', belongingSchema) module.exports = Belonging diff --git a/components/belonging/belongingRoutes.js b/components/belonging/belongingRoutes.js index 37b6346..1ed1d21 100644 --- a/components/belonging/belongingRoutes.js +++ b/components/belonging/belongingRoutes.js @@ -13,6 +13,8 @@ router.post('/admin/create', perm.requires('createabelonging'), belongingControl router.post('/admin/index-all', perm.requires('indexbelongings'), belongingController.indexAllBelongings) +router.post('/admin/index-one/:belongingId', perm.requires('indexbelongings'), belongingController.indexOneBelonging) + router.get('/admin/search', perm.requires('searchbelongings'), belongingController.searchBelongings) router.get('/admin/get-one/:belongingId', perm.requires('getabelonging'), belongingController.getBelonging) diff --git a/components/belonging/belongingService.js b/components/belonging/belongingService.js index 92cc733..4d664e6 100644 --- a/components/belonging/belongingService.js +++ b/components/belonging/belongingService.js @@ -85,7 +85,7 @@ const updateInputQuery = (inputQuery, extraQueries, features) => { const indexAllBelongings = async () => { const batchSize = 20 - const count = await Belonging.countDocuments({}, null) + const count = await Belonging.countDocuments({isActive: true}, null) const rounds = Math.ceil(count / batchSize) await ensureCollectionExists() @@ -93,7 +93,7 @@ const indexAllBelongings = async () => { for (let i = 1; i <= rounds; i++) { console.log(`Indexing ${batchSize} belongings, Round ${i}`) - const belongings = await Belonging.find({}, null, null) + const belongings = await Belonging.find({isActive: true}, null, null) .populate('category') .skip((i - 1) * batchSize) .limit(batchSize) @@ -109,8 +109,8 @@ const indexAllBelongings = async () => { isActive: belonging.isActive, // belongingCode: belonging.belongingCode, name: belonging.name, - category: belonging.category.englishName || '', - nativeCategory: belonging.category.nativeName || '', + category: belonging.category?.englishName || '', + nativeCategory: belonging.category?.nativeName || '', imageUrl: belonging.mainImageUrls[0] || '', documents: belonging.documentUrls || [] , description: belonging.description || '', @@ -118,6 +118,7 @@ const indexAllBelongings = async () => { tags: combinedTags || '', coordinates: belonging.location.coordinates || [0, 0], createdAt: Math.floor(new Date(belonging.createdAt).getTime() / 1000), // Store as timestamp in seconds + id: belonging.belongingCode.toString(), } documents.push(data) @@ -129,6 +130,34 @@ const indexAllBelongings = async () => { return { totalCount: count } } +const indexOneBelonging = async (belongingId) => { + const belonging = await getBelonging(belongingId) + + console.log(`Belonging ${belonging._id} indexing`) + + const combinedTags = belonging.tags.join(' '); + + const data = { + _id: belonging._id, + isActive: belonging.isActive, + // belongingCode: belonging.belongingCode, + name: belonging.name, + category: belonging.category?.englishName || '', + nativeCategory: belonging.category?.nativeName || '', + imageUrl: belonging.mainImageUrls[0] || '', + documents: belonging.documentUrls || [] , + description: belonging.description || '', + unit: belonging.unit || '', + tags: combinedTags || '', + coordinates: belonging.location.coordinates || [0, 0], + createdAt: Math.floor(new Date(belonging.createdAt).getTime() / 1000), // Store as timestamp in seconds + id: belonging.belongingCode.toString(), + } + + await client.collections('belongings').documents().upsert(data) + +} + const getTypeSenseSchema = () => { return { name: 'belongings', @@ -150,4 +179,4 @@ const getTypeSenseSchema = () => { } } -module.exports = { updateBelonging, indexAllBelongings, getBelonging, getAllBelongings, createBelonging, deleteBelonging, searchBelongings } +module.exports = { updateBelonging, indexAllBelongings, getBelonging, getAllBelongings, createBelonging, deleteBelonging, searchBelongings, indexOneBelonging } diff --git a/components/belonging/events/createBelonging.js b/components/belonging/events/createBelonging.js new file mode 100644 index 0000000..c79edce --- /dev/null +++ b/components/belonging/events/createBelonging.js @@ -0,0 +1,6 @@ +const belongingService = require('../belongingService') +module.exports = (eventEmitter) => { + eventEmitter.on('createBelonging', async (belongingData) => { + await belongingService.indexOneBelonging(belongingData._id) + }) +} diff --git a/components/belonging/events/deleteBelonging.js b/components/belonging/events/deleteBelonging.js new file mode 100644 index 0000000..59d618f --- /dev/null +++ b/components/belonging/events/deleteBelonging.js @@ -0,0 +1,6 @@ +const belongingService = require('../belongingService') +module.exports = (eventEmitter) => { + eventEmitter.on('deleteBelonging', async (belongingData) => { + await belongingService.indexAllBelongings() + }) +} diff --git a/events/eventEmitter.js b/events/eventEmitter.js new file mode 100644 index 0000000..acf5ce1 --- /dev/null +++ b/events/eventEmitter.js @@ -0,0 +1,40 @@ +// events/eventEmitter.js +const EventEmitter = require('events') + +class SafeEventEmitter extends EventEmitter { + emit(event, ...args) { + try { + return super.emit(event, ...args) + } catch (error) { + console.error(`Error emitting event '${event}':`, error) + this.emit('error', error) + return false + } + } + + on(event, listener) { + const wrappedListener = async (...args) => { + try { + await listener(...args) + } catch (error) { + console.error(`Error in event handler '${event}':`, error) + this.emit('error', error) + } + } + return super.on(event, wrappedListener) + } +} + +const eventEmitter = new SafeEventEmitter() + +// Add default error handler +eventEmitter.on('error', (error) => { + console.error('Event Error:', { + name: error.name, + message: error.message, + stack: error.stack, + timestamp: new Date().toISOString(), + }) +}) + +module.exports = { eventEmitter } diff --git a/events/index.js b/events/index.js new file mode 100644 index 0000000..6486b2f --- /dev/null +++ b/events/index.js @@ -0,0 +1,35 @@ +// events/index.js +const { eventEmitter } = require('./eventEmitter') +const createBelonging = require('../components/belonging/events/createBelonging') +const deleteBelonging = require('../components/belonging/events/deleteBelonging') +const registerEventHandlers = () => { + // Register all event handlers + createBelonging(eventEmitter) + deleteBelonging(eventEmitter) + // Add additional error monitoring if needed + eventEmitter.on('error', (error) => { + // You can add additional error handling here + // For example, sending to a monitoring service + console.error('Event handler error:', error) + }) + + // Log when events are registered (optional) + console.log('Event handlers registered successfully') +} + +// Helper function to safely emit events (can be used in other files) +const safeEmit = async (eventName, ...args) => { + try { + return eventEmitter.emit(eventName, ...args) + } catch (error) { + console.error(`Error safely emitting ${eventName}:`, error) + eventEmitter.emit('error', error) + return false + } +} + +module.exports = { + registerEventHandlers, + eventEmitter, + safeEmit, +}