@feardread/fear 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FEAR.js +1 -45
- package/controllers/crud/crud.js +222 -356
- package/package.json +1 -1
- package/routes/product.js +2 -2
package/FEAR.js
CHANGED
|
@@ -23,8 +23,6 @@ module.exports = FEAR = (() => {
|
|
|
23
23
|
this.logger = null;
|
|
24
24
|
this.morgan = null;
|
|
25
25
|
this.cloud = null;
|
|
26
|
-
this.agentService = null;
|
|
27
|
-
this.agentWebInterface = null;
|
|
28
26
|
this.db = null;
|
|
29
27
|
this.handler = null;
|
|
30
28
|
this.validator = null;
|
|
@@ -38,47 +36,12 @@ module.exports = FEAR = (() => {
|
|
|
38
36
|
this.setupMiddleware();
|
|
39
37
|
this.corsConfig = this.getCorsConfig();
|
|
40
38
|
this.setupRoutes();
|
|
41
|
-
//this.setupAiAgent();
|
|
42
|
-
//this.setupAgentWebInterface();
|
|
43
39
|
};
|
|
44
40
|
|
|
45
41
|
// Consolidated prototype
|
|
46
42
|
FEAR.prototype = {
|
|
47
43
|
constructor: FEAR,
|
|
48
44
|
|
|
49
|
-
/**
|
|
50
|
-
* Initialize AI Agent service
|
|
51
|
-
*/
|
|
52
|
-
setupAiAgent() {
|
|
53
|
-
const { getInstance } = require("./libs/agent");
|
|
54
|
-
|
|
55
|
-
if (!this.agentService) {
|
|
56
|
-
this.agentService = getInstance();
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Initialize Agent Web Interface
|
|
62
|
-
*/
|
|
63
|
-
setupAgentWebInterface() {
|
|
64
|
-
try {
|
|
65
|
-
const AgentWebInterface = require("./libs/agent");
|
|
66
|
-
|
|
67
|
-
this.agentWebInterface = new AgentWebInterface(this);
|
|
68
|
-
|
|
69
|
-
// Register agent routes
|
|
70
|
-
this.useRouter(
|
|
71
|
-
this.agentWebInterface.getRouter(),
|
|
72
|
-
AGENT_ROUTE_PATH
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
this.logger.info(`Agent Web Interface initialized at ${AGENT_ROUTE_PATH}`);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
this.logger.error("Failed to initialize Agent Web Interface:", error);
|
|
78
|
-
this.logger.warn("Agent Web Interface will not be available");
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
|
|
82
45
|
/**
|
|
83
46
|
* Get AI Agent service instance
|
|
84
47
|
*/
|
|
@@ -86,13 +49,6 @@ module.exports = FEAR = (() => {
|
|
|
86
49
|
return this.agentService;
|
|
87
50
|
},
|
|
88
51
|
|
|
89
|
-
/**
|
|
90
|
-
* Get Agent Web Interface instance
|
|
91
|
-
*/
|
|
92
|
-
getAgentWebInterface() {
|
|
93
|
-
return this.agentWebInterface;
|
|
94
|
-
},
|
|
95
|
-
|
|
96
52
|
/**
|
|
97
53
|
* Clear global FearRouter
|
|
98
54
|
*/
|
|
@@ -307,7 +263,7 @@ module.exports = FEAR = (() => {
|
|
|
307
263
|
|
|
308
264
|
routers.forEach(config => {
|
|
309
265
|
if (typeof config === 'function') {
|
|
310
|
-
this.useRouter(config);
|
|
266
|
+
this.useRouter(config, DEFAULT_ROUTE_PATH, this.corsConfig);
|
|
311
267
|
} else if (config && config.router) {
|
|
312
268
|
this.useRouter(config.router, config.path, config.cors);
|
|
313
269
|
} else {
|
package/controllers/crud/crud.js
CHANGED
|
@@ -1,43 +1,52 @@
|
|
|
1
1
|
const { tryCatch } = require("../../libs/handler/error");
|
|
2
2
|
const cloud = require("../../libs/cloud");
|
|
3
3
|
const SearchApi = require("../../libs/search/api");
|
|
4
|
+
const mongoose = require("mongoose");
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* Validates MongoDB ObjectId format
|
|
8
|
+
* @param {string} id - ID to validate
|
|
9
|
+
* @returns {boolean} True if valid ObjectId
|
|
8
10
|
*/
|
|
11
|
+
const isValidObjectId = (id) => {
|
|
12
|
+
return mongoose.Types.ObjectId.isValid(id) && /^[0-9a-fA-F]{24}$/.test(id);
|
|
13
|
+
};
|
|
14
|
+
|
|
9
15
|
/**
|
|
10
16
|
* Get all documents for requested Model
|
|
11
17
|
* @param {mongoose.Model} Model - Mongoose model
|
|
12
18
|
* @param {Object} req - Express request object
|
|
13
19
|
* @param {Object} res - Express response object
|
|
14
|
-
* @returns {
|
|
15
|
-
* @returns {string} Message
|
|
16
|
-
* @returns {Array} Result: Array of found Documents
|
|
20
|
+
* @returns {Promise<void>}
|
|
17
21
|
*/
|
|
18
22
|
exports.all = tryCatch(async (Model, req, res) => {
|
|
19
|
-
const { sort = 'category', order = 'asc', populate = true } = req.query;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const { sort = 'category', order = 'asc', populate = 'true' } = req.query;
|
|
24
|
+
|
|
25
|
+
const sortOrder = order === 'desc' ? -1 : 1;
|
|
26
|
+
let query = Model.find().sort({ [sort]: sortOrder });
|
|
27
|
+
|
|
24
28
|
// Apply population if requested
|
|
25
|
-
if (populate
|
|
29
|
+
if (populate !== 'false') {
|
|
26
30
|
query = query.populate();
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.catch((error) => {
|
|
38
|
-
console.error('Error in all method:', error);
|
|
39
|
-
return res.status(500).json({ result: null, success: false, message: "Error retrieving documents", error: error.message });
|
|
32
|
+
|
|
33
|
+
const result = await query.exec();
|
|
34
|
+
|
|
35
|
+
if (!result || result.length === 0) {
|
|
36
|
+
return res.status(200).json({
|
|
37
|
+
result: [],
|
|
38
|
+
success: true,
|
|
39
|
+
message: "No documents found",
|
|
40
|
+
count: 0
|
|
40
41
|
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return res.status(200).json({
|
|
45
|
+
result,
|
|
46
|
+
success: true,
|
|
47
|
+
message: `Found ${result.length} documents`,
|
|
48
|
+
count: result.length
|
|
49
|
+
});
|
|
41
50
|
});
|
|
42
51
|
|
|
43
52
|
/**
|
|
@@ -45,65 +54,42 @@ exports.all = tryCatch(async (Model, req, res) => {
|
|
|
45
54
|
* @param {mongoose.Model} Model - Mongoose model
|
|
46
55
|
* @param {Object} req - Express request object
|
|
47
56
|
* @param {Object} res - Express response object
|
|
48
|
-
* @
|
|
49
|
-
* @returns {Document} Single Document
|
|
57
|
+
* @returns {Promise<void>}
|
|
50
58
|
*/
|
|
51
59
|
exports.read = tryCatch(async (Model, req, res) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!
|
|
60
|
+
const { id } = req.params;
|
|
61
|
+
|
|
62
|
+
if (!id) {
|
|
55
63
|
return res.status(400).json({
|
|
56
64
|
result: null,
|
|
57
65
|
success: false,
|
|
58
66
|
message: "Document ID is required"
|
|
59
67
|
});
|
|
60
68
|
}
|
|
61
|
-
*/
|
|
62
|
-
const { id } = req.query;
|
|
63
|
-
const { populate = true } = req.query;
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
// Validate ObjectId format
|
|
67
|
-
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
|
|
70
|
+
if (!isValidObjectId(id)) {
|
|
68
71
|
return res.status(400).json({
|
|
69
72
|
result: null,
|
|
70
73
|
success: false,
|
|
71
74
|
message: "Invalid document ID format"
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
|
-
*/
|
|
75
|
-
let query = Model.findById(id);
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
if (populate && populate !== 'false') {
|
|
79
|
-
query = query.populate();
|
|
80
|
-
}
|
|
78
|
+
const result = await Model.findById(id).exec();
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
success: false,
|
|
88
|
-
message: `Document with ID ${id} not found`
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return res.status(200).json({
|
|
93
|
-
result,
|
|
94
|
-
success: true,
|
|
95
|
-
message: "Document found successfully"
|
|
96
|
-
});
|
|
97
|
-
})
|
|
98
|
-
.catch((error) => {
|
|
99
|
-
console.error('Error in read method:', error);
|
|
100
|
-
return res.status(500).json({
|
|
101
|
-
result: null,
|
|
102
|
-
success: false,
|
|
103
|
-
message: "Error retrieving document",
|
|
104
|
-
error: error.message
|
|
105
|
-
});
|
|
80
|
+
if (!result) {
|
|
81
|
+
return res.status(404).json({
|
|
82
|
+
result: null,
|
|
83
|
+
success: false,
|
|
84
|
+
message: `Document with ID ${id} not found`
|
|
106
85
|
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return res.status(200).json({
|
|
89
|
+
result,
|
|
90
|
+
success: true,
|
|
91
|
+
message: "Document found successfully"
|
|
92
|
+
});
|
|
107
93
|
});
|
|
108
94
|
|
|
109
95
|
/**
|
|
@@ -111,63 +97,49 @@ exports.read = tryCatch(async (Model, req, res) => {
|
|
|
111
97
|
* @param {mongoose.Model} Model - Mongoose model
|
|
112
98
|
* @param {Object} req - Express request object
|
|
113
99
|
* @param {Object} res - Express response object
|
|
114
|
-
* @
|
|
115
|
-
* @returns {string} Message
|
|
100
|
+
* @returns {Promise<void>}
|
|
116
101
|
*/
|
|
117
102
|
exports.create = tryCatch(async (Model, req, res) => {
|
|
118
103
|
const documentData = { ...req.body };
|
|
119
104
|
|
|
120
105
|
// Handle image uploads if present
|
|
121
|
-
if (documentData.images)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
106
|
+
if (documentData.images) {
|
|
107
|
+
// Parse comma-separated string to array if needed
|
|
108
|
+
const imageArray = typeof documentData.images === 'string'
|
|
109
|
+
? documentData.images.split(',').map(item => item.trim())
|
|
110
|
+
: documentData.images;
|
|
111
|
+
|
|
112
|
+
const imageLinks = await cloud.uploadImages(imageArray);
|
|
113
|
+
|
|
114
|
+
if (imageLinks) {
|
|
115
|
+
documentData.images = imageLinks;
|
|
126
116
|
console.log('Added Images:', imageLinks);
|
|
117
|
+
}
|
|
127
118
|
}
|
|
128
|
-
console.log('Creating modified document:', documentData);
|
|
129
|
-
await new Model(documentData).save()
|
|
130
|
-
.then((result) => {
|
|
131
|
-
if (!result) {
|
|
132
|
-
throw new Error("Failed to save document");
|
|
133
|
-
}
|
|
134
|
-
return res.status(201).json({
|
|
135
|
-
result, success: true, message: `Document created successfully in ${Model.modelName} collection`
|
|
136
|
-
});
|
|
137
|
-
})
|
|
138
|
-
.catch((error) => {
|
|
139
|
-
console.error('Error in create method with images:', error);
|
|
140
|
-
|
|
141
|
-
if (error.name === "ValidationError") {
|
|
142
|
-
return res.status(400).json({
|
|
143
|
-
result: null,
|
|
144
|
-
success: false,
|
|
145
|
-
message: "Validation failed: Required fields are missing or invalid",
|
|
146
|
-
errors: error.errors
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return res.status(500).json({
|
|
151
|
-
result: null,
|
|
152
|
-
success: false,
|
|
153
|
-
message: "Internal server error during document creation",
|
|
154
|
-
error: error.message
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
119
|
|
|
120
|
+
console.log('Creating document:', documentData);
|
|
121
|
+
|
|
122
|
+
const document = new Model(documentData);
|
|
123
|
+
const result = await document.save();
|
|
124
|
+
|
|
125
|
+
return res.status(201).json({
|
|
126
|
+
result,
|
|
127
|
+
success: true,
|
|
128
|
+
message: `Document created successfully in ${Model.modelName} collection`
|
|
158
129
|
});
|
|
130
|
+
});
|
|
159
131
|
|
|
160
132
|
/**
|
|
161
133
|
* Updates a single document
|
|
162
134
|
* @param {mongoose.Model} Model - Mongoose model
|
|
163
135
|
* @param {Object} req - Express request object
|
|
164
136
|
* @param {Object} res - Express response object
|
|
165
|
-
* @
|
|
166
|
-
* @param {string} req.params.id - Document ID
|
|
167
|
-
* @returns {Document} Returns updated document
|
|
137
|
+
* @returns {Promise<void>}
|
|
168
138
|
*/
|
|
169
139
|
exports.update = tryCatch(async (Model, req, res) => {
|
|
170
|
-
|
|
140
|
+
const { id } = req.params;
|
|
141
|
+
|
|
142
|
+
if (!id) {
|
|
171
143
|
return res.status(400).json({
|
|
172
144
|
result: null,
|
|
173
145
|
success: false,
|
|
@@ -175,7 +147,14 @@ exports.update = tryCatch(async (Model, req, res) => {
|
|
|
175
147
|
});
|
|
176
148
|
}
|
|
177
149
|
|
|
178
|
-
|
|
150
|
+
if (!isValidObjectId(id)) {
|
|
151
|
+
return res.status(400).json({
|
|
152
|
+
result: null,
|
|
153
|
+
success: false,
|
|
154
|
+
message: "Invalid document ID format"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
179
158
|
const updateData = { ...req.body };
|
|
180
159
|
|
|
181
160
|
// Remove undefined values
|
|
@@ -185,114 +164,32 @@ exports.update = tryCatch(async (Model, req, res) => {
|
|
|
185
164
|
}
|
|
186
165
|
});
|
|
187
166
|
|
|
188
|
-
// Validate ObjectId format
|
|
189
|
-
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
|
|
190
|
-
return res.status(400).json({
|
|
191
|
-
result: null,
|
|
192
|
-
success: false,
|
|
193
|
-
message: "Invalid document ID format"
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
167
|
// Handle image uploads if present
|
|
198
|
-
if (updateData.images && Array.isArray(updateData.images)) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
updateData.images = uploadedImages;
|
|
202
|
-
|
|
203
|
-
// Update document with uploaded images
|
|
204
|
-
return Model.findOneAndUpdate(
|
|
205
|
-
{ _id: id },
|
|
206
|
-
updateData,
|
|
207
|
-
{ new: true, runValidators: true }
|
|
208
|
-
).exec();
|
|
209
|
-
})
|
|
210
|
-
.then((result) => {
|
|
211
|
-
if (!result) {
|
|
212
|
-
return res.status(404).json({
|
|
213
|
-
result: null,
|
|
214
|
-
success: false,
|
|
215
|
-
message: `Document with ID ${id} not found`
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return res.status(200).json({
|
|
220
|
-
result,
|
|
221
|
-
success: true,
|
|
222
|
-
message: `Document updated successfully with ID: ${id}`
|
|
223
|
-
});
|
|
224
|
-
})
|
|
225
|
-
.catch((error) => {
|
|
226
|
-
console.error('Error in update method with images:', error);
|
|
227
|
-
|
|
228
|
-
if (error.name === "ValidationError") {
|
|
229
|
-
return res.status(400).json({
|
|
230
|
-
result: null,
|
|
231
|
-
success: false,
|
|
232
|
-
message: "Validation failed: Invalid field values provided",
|
|
233
|
-
errors: error.errors
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return res.status(500).json({
|
|
238
|
-
result: null,
|
|
239
|
-
success: false,
|
|
240
|
-
message: "Internal server error during document update",
|
|
241
|
-
error: error.message
|
|
242
|
-
});
|
|
243
|
-
});
|
|
168
|
+
if (updateData.images && Array.isArray(updateData.images) && updateData.images.length > 0) {
|
|
169
|
+
const uploadedImages = await cloud.uploadImages(updateData.images);
|
|
170
|
+
updateData.images = uploadedImages;
|
|
244
171
|
}
|
|
245
172
|
|
|
246
|
-
// Update document
|
|
247
|
-
|
|
248
|
-
|
|
173
|
+
// Update document
|
|
174
|
+
const result = await Model.findByIdAndUpdate(
|
|
175
|
+
id,
|
|
249
176
|
updateData,
|
|
250
177
|
{ new: true, runValidators: true }
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
message: `Document with ID ${id} not found`
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return res.status(200).json({
|
|
263
|
-
result,
|
|
264
|
-
success: true,
|
|
265
|
-
message: `Document updated successfully with ID: ${id}`
|
|
266
|
-
});
|
|
267
|
-
})
|
|
268
|
-
.catch((error) => {
|
|
269
|
-
console.error('Error in update method:', error);
|
|
270
|
-
|
|
271
|
-
if (error.name === "ValidationError") {
|
|
272
|
-
return res.status(400).json({
|
|
273
|
-
result: null,
|
|
274
|
-
success: false,
|
|
275
|
-
message: "Validation failed: Invalid field values provided",
|
|
276
|
-
errors: error.errors
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (error.code === 11000) {
|
|
281
|
-
return res.status(409).json({
|
|
282
|
-
result: null,
|
|
283
|
-
success: false,
|
|
284
|
-
message: "Update failed: Duplicate value for unique field",
|
|
285
|
-
error: error.message
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return res.status(500).json({
|
|
290
|
-
result: null,
|
|
291
|
-
success: false,
|
|
292
|
-
message: "Internal server error during document update",
|
|
293
|
-
error: error.message
|
|
294
|
-
});
|
|
178
|
+
).exec();
|
|
179
|
+
|
|
180
|
+
if (!result) {
|
|
181
|
+
return res.status(404).json({
|
|
182
|
+
result: null,
|
|
183
|
+
success: false,
|
|
184
|
+
message: `Document with ID ${id} not found`
|
|
295
185
|
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return res.status(200).json({
|
|
189
|
+
result,
|
|
190
|
+
success: true,
|
|
191
|
+
message: `Document updated successfully with ID: ${id}`
|
|
192
|
+
});
|
|
296
193
|
});
|
|
297
194
|
|
|
298
195
|
/**
|
|
@@ -300,11 +197,12 @@ exports.update = tryCatch(async (Model, req, res) => {
|
|
|
300
197
|
* @param {mongoose.Model} Model - Mongoose model
|
|
301
198
|
* @param {Object} req - Express request object
|
|
302
199
|
* @param {Object} res - Express response object
|
|
303
|
-
* @
|
|
304
|
-
* @returns {string} Message response
|
|
200
|
+
* @returns {Promise<void>}
|
|
305
201
|
*/
|
|
306
202
|
exports.delete = tryCatch(async (Model, req, res) => {
|
|
307
|
-
|
|
203
|
+
const { id } = req.params;
|
|
204
|
+
|
|
205
|
+
if (!id) {
|
|
308
206
|
return res.status(400).json({
|
|
309
207
|
result: null,
|
|
310
208
|
success: false,
|
|
@@ -312,10 +210,7 @@ exports.delete = tryCatch(async (Model, req, res) => {
|
|
|
312
210
|
});
|
|
313
211
|
}
|
|
314
212
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
// Validate ObjectId format
|
|
318
|
-
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
|
|
213
|
+
if (!isValidObjectId(id)) {
|
|
319
214
|
return res.status(400).json({
|
|
320
215
|
result: null,
|
|
321
216
|
success: false,
|
|
@@ -323,38 +218,28 @@ exports.delete = tryCatch(async (Model, req, res) => {
|
|
|
323
218
|
});
|
|
324
219
|
}
|
|
325
220
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
message: `Document with ID ${id} not found`
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// TODO: Clean up associated images if they exist
|
|
338
|
-
if (result.images && Array.isArray(result.images)) {
|
|
339
|
-
// Could add cloud.deleteImages(result.images) here
|
|
340
|
-
console.log('Document had images that should be cleaned up:', result.images);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return res.status(200).json({
|
|
344
|
-
result,
|
|
345
|
-
success: true,
|
|
346
|
-
message: `Document deleted successfully with ID: ${id}`
|
|
347
|
-
});
|
|
348
|
-
})
|
|
349
|
-
.catch((error) => {
|
|
350
|
-
console.error('Error in delete method:', error);
|
|
351
|
-
return res.status(500).json({
|
|
352
|
-
result: null,
|
|
353
|
-
success: false,
|
|
354
|
-
message: "Error deleting document",
|
|
355
|
-
error: error.message
|
|
356
|
-
});
|
|
221
|
+
const result = await Model.findByIdAndDelete(id).exec();
|
|
222
|
+
|
|
223
|
+
if (!result) {
|
|
224
|
+
return res.status(404).json({
|
|
225
|
+
result: null,
|
|
226
|
+
success: false,
|
|
227
|
+
message: `Document with ID ${id} not found`
|
|
357
228
|
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// TODO: Clean up associated images if they exist
|
|
232
|
+
if (result.images && Array.isArray(result.images) && result.images.length > 0) {
|
|
233
|
+
console.log('Document had images that should be cleaned up:', result.images);
|
|
234
|
+
// Uncomment when cloud.deleteImages is available:
|
|
235
|
+
// await cloud.deleteImages(result.images);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return res.status(200).json({
|
|
239
|
+
result,
|
|
240
|
+
success: true,
|
|
241
|
+
message: `Document deleted successfully with ID: ${id}`
|
|
242
|
+
});
|
|
358
243
|
});
|
|
359
244
|
|
|
360
245
|
/**
|
|
@@ -362,71 +247,45 @@ exports.delete = tryCatch(async (Model, req, res) => {
|
|
|
362
247
|
* @param {mongoose.Model} Model - Mongoose model
|
|
363
248
|
* @param {Object} req - Express request object
|
|
364
249
|
* @param {Object} res - Express response object
|
|
365
|
-
* @
|
|
366
|
-
* @returns {Object} Results with pagination
|
|
250
|
+
* @returns {Promise<void>}
|
|
367
251
|
*/
|
|
368
252
|
exports.list = tryCatch(async (Model, req, res) => {
|
|
369
|
-
const page = parseInt(req.query.page) || 1;
|
|
370
|
-
const limit = parseInt(req.query.items) || 10;
|
|
253
|
+
const page = Math.max(1, parseInt(req.query.page) || 1);
|
|
254
|
+
const limit = Math.min(100, Math.max(1, parseInt(req.query.items) || 10));
|
|
371
255
|
const skip = (page - 1) * limit;
|
|
372
|
-
const { sort = 'createdAt', order = 'desc', populate = true } = req.query;
|
|
256
|
+
const { sort = 'createdAt', order = 'desc', populate = 'true' } = req.query;
|
|
373
257
|
|
|
374
|
-
// Limit maximum items per page
|
|
375
|
-
const maxLimit = Math.min(limit, 100);
|
|
376
258
|
const sortOrder = order === 'asc' ? 1 : -1;
|
|
377
259
|
|
|
378
|
-
//
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
260
|
+
// Execute count and find queries in parallel
|
|
261
|
+
const [result, count] = await Promise.all([
|
|
262
|
+
Model.find()
|
|
263
|
+
.skip(skip)
|
|
264
|
+
.limit(limit)
|
|
265
|
+
.sort({ [sort]: sortOrder })
|
|
266
|
+
.populate(populate !== 'false' ? undefined : null)
|
|
267
|
+
.exec(),
|
|
268
|
+
Model.countDocuments().exec()
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
const totalPages = Math.ceil(count / limit);
|
|
272
|
+
const pagination = {
|
|
273
|
+
currentPage: page,
|
|
274
|
+
totalPages,
|
|
275
|
+
totalItems: count,
|
|
276
|
+
itemsPerPage: limit,
|
|
277
|
+
hasNextPage: page < totalPages,
|
|
278
|
+
hasPrevPage: page > 1
|
|
279
|
+
};
|
|
390
280
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
totalItems: count,
|
|
400
|
-
itemsPerPage: maxLimit,
|
|
401
|
-
hasNextPage: page < totalPages,
|
|
402
|
-
hasPrevPage: page > 1
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
if (count > 0) {
|
|
406
|
-
return res.status(200).json({
|
|
407
|
-
result,
|
|
408
|
-
success: true,
|
|
409
|
-
pagination,
|
|
410
|
-
message: `Found ${result.length} of ${count} documents`
|
|
411
|
-
});
|
|
412
|
-
} else {
|
|
413
|
-
return res.status(200).json({
|
|
414
|
-
result: [],
|
|
415
|
-
success: true,
|
|
416
|
-
pagination,
|
|
417
|
-
message: "Collection is empty"
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
})
|
|
421
|
-
.catch((error) => {
|
|
422
|
-
console.error('Error in list method:', error);
|
|
423
|
-
return res.status(500).json({
|
|
424
|
-
result: null,
|
|
425
|
-
success: false,
|
|
426
|
-
message: "Error retrieving document list",
|
|
427
|
-
error: error.message
|
|
428
|
-
});
|
|
429
|
-
});
|
|
281
|
+
return res.status(200).json({
|
|
282
|
+
result,
|
|
283
|
+
success: true,
|
|
284
|
+
pagination,
|
|
285
|
+
message: count > 0
|
|
286
|
+
? `Found ${result.length} of ${count} documents`
|
|
287
|
+
: "Collection is empty"
|
|
288
|
+
});
|
|
430
289
|
});
|
|
431
290
|
|
|
432
291
|
/**
|
|
@@ -434,68 +293,75 @@ exports.list = tryCatch(async (Model, req, res) => {
|
|
|
434
293
|
* @param {mongoose.Model} Model - Mongoose model
|
|
435
294
|
* @param {Object} req - Express request object
|
|
436
295
|
* @param {Object} res - Express response object
|
|
437
|
-
* @
|
|
438
|
-
* @returns {Array} List of Documents
|
|
296
|
+
* @returns {Promise<void>}
|
|
439
297
|
*/
|
|
440
298
|
exports.search = tryCatch(async (Model, req, res) => {
|
|
441
|
-
console.log('
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
queryObj.price = {};
|
|
461
|
-
if (minPrice) queryObj.price.gte = minPrice;
|
|
462
|
-
if (maxPrice) queryObj.price.lte = maxPrice;
|
|
463
|
-
}
|
|
464
|
-
if (rating) queryObj.rating = { gte: rating };
|
|
465
|
-
|
|
466
|
-
const sortOptions = {
|
|
467
|
-
popularity: { popularity: -1 },
|
|
468
|
-
newest: { createdAt: -1 },
|
|
469
|
-
'price-low': { price: 1 },
|
|
470
|
-
'price-high': { price: -1 },
|
|
471
|
-
rating: { rating: -1 }
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
const Search = new SearchApi(Model, queryObj, {
|
|
475
|
-
searchFields: ['_id', 'id', 'price', 'name', 'description', 'tags'],
|
|
476
|
-
defaultSort: sortOptions[sortBy] || sortOptions.popularity
|
|
477
|
-
});
|
|
299
|
+
console.log('CRUD search query:', req.query);
|
|
300
|
+
|
|
301
|
+
const {
|
|
302
|
+
keyword,
|
|
303
|
+
category,
|
|
304
|
+
brand,
|
|
305
|
+
minPrice,
|
|
306
|
+
maxPrice,
|
|
307
|
+
rating,
|
|
308
|
+
sortBy = 'popularity',
|
|
309
|
+
page = 1,
|
|
310
|
+
limit = 24
|
|
311
|
+
} = req.query;
|
|
312
|
+
|
|
313
|
+
// Build query object
|
|
314
|
+
const queryObj = {
|
|
315
|
+
page: parseInt(page),
|
|
316
|
+
limit: parseInt(limit)
|
|
317
|
+
};
|
|
478
318
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
}
|
|
319
|
+
if (keyword) queryObj.keyword = keyword;
|
|
320
|
+
if (category) queryObj.category = category;
|
|
321
|
+
if (brand) queryObj.brand = { in: brand };
|
|
322
|
+
|
|
323
|
+
if (minPrice || maxPrice) {
|
|
324
|
+
queryObj.price = {};
|
|
325
|
+
if (minPrice) queryObj.price.gte = parseFloat(minPrice);
|
|
326
|
+
if (maxPrice) queryObj.price.lte = parseFloat(maxPrice);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (rating) queryObj.rating = { gte: parseFloat(rating) };
|
|
330
|
+
|
|
331
|
+
const sortOptions = {
|
|
332
|
+
popularity: { popularity: -1 },
|
|
333
|
+
newest: { createdAt: -1 },
|
|
334
|
+
'price-low': { price: 1 },
|
|
335
|
+
'price-high': { price: -1 },
|
|
336
|
+
rating: { rating: -1 }
|
|
337
|
+
};
|
|
490
338
|
|
|
339
|
+
const searchApi = new SearchApi(Model, queryObj, {
|
|
340
|
+
searchFields: ['_id', 'id', 'price', 'name', 'description', 'tags'],
|
|
341
|
+
defaultSort: sortOptions[sortBy] || sortOptions.popularity
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const result = await searchApi
|
|
345
|
+
.search(['_id', 'id', 'price', 'name', 'description', 'brand', 'tags'])
|
|
346
|
+
.filter()
|
|
347
|
+
.sort()
|
|
348
|
+
.selectFields('-__v,-updatedAt')
|
|
349
|
+
.populate('reviews')
|
|
350
|
+
.paginate(parseInt(limit), 50)
|
|
351
|
+
.execute();
|
|
352
|
+
|
|
353
|
+
return res.status(200).json({
|
|
354
|
+
success: true,
|
|
355
|
+
...result
|
|
356
|
+
});
|
|
357
|
+
});
|
|
491
358
|
|
|
492
359
|
/**
|
|
493
360
|
* Create a controller object with all CRUD methods bound to a specific Model
|
|
494
361
|
* @param {mongoose.Model} Model - Mongoose model
|
|
495
362
|
* @returns {Object} Controller object with all CRUD methods
|
|
496
363
|
*/
|
|
497
|
-
module.exports = (
|
|
498
|
-
|
|
364
|
+
module.exports = (Model) => {
|
|
499
365
|
return {
|
|
500
366
|
all: (req, res) => exports.all(Model, req, res),
|
|
501
367
|
read: (req, res) => exports.read(Model, req, res),
|
|
@@ -503,6 +369,6 @@ module.exports = ( Model ) => {
|
|
|
503
369
|
update: (req, res) => exports.update(Model, req, res),
|
|
504
370
|
delete: (req, res) => exports.delete(Model, req, res),
|
|
505
371
|
list: (req, res) => exports.list(Model, req, res),
|
|
506
|
-
search: (req, res) => exports.search(Model, req, res)
|
|
372
|
+
search: (req, res) => exports.search(Model, req, res)
|
|
507
373
|
};
|
|
508
374
|
};
|
package/package.json
CHANGED
package/routes/product.js
CHANGED
|
@@ -14,8 +14,8 @@ module.exports = (fear) => {
|
|
|
14
14
|
router.route('/search/all').get(Product.productSearch);
|
|
15
15
|
router.route("/one").get(handler.async(Product.read));
|
|
16
16
|
router.route("/:id")
|
|
17
|
-
.get(
|
|
18
|
-
.put(
|
|
17
|
+
.get(Product.read)
|
|
18
|
+
.put(Product.update)
|
|
19
19
|
.delete(handler.async(Product.delete));
|
|
20
20
|
|
|
21
21
|
return router;
|