@feardread/fear 2.0.0 → 2.0.2

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 CHANGED
@@ -173,14 +173,11 @@ module.exports = FEAR = (() => {
173
173
 
174
174
  mailinfo.service = mailService;
175
175
  this.mailinfo = mailinfo;
176
-
177
176
  if ( !this.mailer ) {
178
177
  this.mailer = new smtp(this);
179
178
  }
180
179
  },
181
- /**
182
- * Parse allowed origins from environment
183
- */
180
+
184
181
  getAllowedOrigins() {
185
182
  if (!this.env.ALLOWED_ORIGINS) return [];
186
183
 
@@ -190,9 +187,6 @@ module.exports = FEAR = (() => {
190
187
  .filter(origin => origin.length > 0);
191
188
  },
192
189
 
193
- /**
194
- * Get CORS configuration object
195
- */
196
190
  getCorsConfig() {
197
191
  return {
198
192
  credentials: true,
@@ -209,9 +203,6 @@ module.exports = FEAR = (() => {
209
203
  };
210
204
  },
211
205
 
212
- /**
213
- * Auto-load routes from routes directory
214
- */
215
206
  setupRoutes() {
216
207
  const routesDir = path.join(__dirname, "routes");
217
208
 
@@ -241,9 +232,6 @@ module.exports = FEAR = (() => {
241
232
  }
242
233
  },
243
234
 
244
- /**
245
- * Register a single router
246
- */
247
235
  useRouter(router, routePath = DEFAULT_ROUTE_PATH, corsOptions = null) {
248
236
  if (!router || typeof router !== 'function') {
249
237
  throw new Error('Router must be a valid Express router instance');
@@ -264,9 +252,6 @@ module.exports = FEAR = (() => {
264
252
  return this;
265
253
  },
266
254
 
267
- /**
268
- * Register multiple routers
269
- */
270
255
  useRouters(routers) {
271
256
  if (!Array.isArray(routers)) {
272
257
  throw new Error('Routers must be an array');
@@ -285,9 +270,6 @@ module.exports = FEAR = (() => {
285
270
  return this;
286
271
  },
287
272
 
288
- /**
289
- * Create a new router with FEAR utilities attached
290
- */
291
273
  createRouter() {
292
274
  const router = express.Router();
293
275
 
@@ -305,9 +287,6 @@ module.exports = FEAR = (() => {
305
287
  return router;
306
288
  },
307
289
 
308
- /**
309
- * Get list of registered routers
310
- */
311
290
  getRegisteredRouters() {
312
291
  return this.registeredRouters.map(info => ({
313
292
  path: info.path,
@@ -315,9 +294,6 @@ module.exports = FEAR = (() => {
315
294
  }));
316
295
  },
317
296
 
318
- /**
319
- * Start the HTTP server
320
- */
321
297
  start(port = null) {
322
298
  const serverPort = port || this.app.get("PORT") || DEFAULT_PORT;
323
299
 
@@ -340,9 +316,6 @@ module.exports = FEAR = (() => {
340
316
  });
341
317
  },
342
318
 
343
- /**
344
- * Gracefully shutdown the server
345
- */
346
319
  shutdown() {
347
320
  this.logger.info('Initiating graceful shutdown...');
348
321
 
@@ -382,9 +355,6 @@ module.exports = FEAR = (() => {
382
355
  });
383
356
  },
384
357
 
385
- /**
386
- * Close database connections
387
- */
388
358
  closeDatabase() {
389
359
  return new Promise((resolve, reject) => {
390
360
  if (this.db && typeof this.db.disconnect === 'function') {
@@ -400,9 +370,6 @@ module.exports = FEAR = (() => {
400
370
  });
401
371
  },
402
372
 
403
- /**
404
- * Set FEAR utilities as global
405
- */
406
373
  setAsGlobal() {
407
374
  global.FearRouter = {
408
375
  createRouter: () => this.createRouter(),
@@ -420,9 +387,6 @@ module.exports = FEAR = (() => {
420
387
  return FEAR;
421
388
  })();
422
389
 
423
- /**
424
- * Factory function to create new FEAR instance
425
- */
426
390
  exports.FearFactory = () => {
427
391
  return new FEAR();
428
392
  };
@@ -12,6 +12,41 @@ const isValidObjectId = (id) => {
12
12
  return mongoose.Types.ObjectId.isValid(id) && /^[0-9a-fA-F]{24}$/.test(id);
13
13
  };
14
14
 
15
+ /**
16
+ * Sanitizes update data by removing undefined values
17
+ * @param {Object} data - Data object to sanitize
18
+ * @returns {Object} Sanitized data object
19
+ */
20
+ const sanitizeUpdateData = (data) => {
21
+ const sanitized = { ...data };
22
+ Object.keys(sanitized).forEach(key => {
23
+ if (sanitized[key] === undefined) {
24
+ delete sanitized[key];
25
+ }
26
+ });
27
+ return sanitized;
28
+ };
29
+
30
+ /**
31
+ * Processes image data for upload
32
+ * @param {string|Array} images - Images to process
33
+ * @returns {Promise<Array>} Promise resolving to uploaded image URLs
34
+ */
35
+ const processImages = (images) => {
36
+ if (!images) return Promise.resolve(null);
37
+
38
+ const imageArray = Array.isArray(images)
39
+ ? images
40
+ : images.split(',').map(item => item.trim());
41
+
42
+ return cloud.uploadImages(imageArray)
43
+ .then(imageLinks => imageLinks || null)
44
+ .catch(error => {
45
+ console.error('Error uploading images:', error);
46
+ return null;
47
+ });
48
+ };
49
+
15
50
  /**
16
51
  * Get all documents for requested Model
17
52
  * @param {mongoose.Model} Model - Mongoose model
@@ -19,34 +54,27 @@ const isValidObjectId = (id) => {
19
54
  * @param {Object} res - Express response object
20
55
  * @returns {Promise<void>}
21
56
  */
22
- exports.all = tryCatch(async (Model, req, res) => {
57
+ exports.all = tryCatch((Model, req, res) => {
23
58
  const { sort = 'category', order = 'asc', populate = 'true' } = req.query;
24
-
25
59
  const sortOrder = order === 'desc' ? -1 : 1;
60
+
26
61
  let query = Model.find().sort({ [sort]: sortOrder });
27
62
 
28
- // Apply population if requested
29
- if (populate !== 'false') {
30
- query = query.populate();
31
- }
63
+ if (populate !== 'false') query = query.populate();
32
64
 
33
- const result = await query.exec();
65
+ return query
66
+ .exec()
67
+ .then(result => {
68
+ if (!result || result.length === 0) {
69
+ return res.status(200).json({result: [],success: true,message: "No documents found",count: 0});
70
+ }
34
71
 
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
72
+ return res.status(200).json({result,success: true,message: `Found ${result.length} documents`,count: result.length});
73
+ })
74
+ .catch(error => {
75
+ console.error('Error fetching documents:', error);
76
+ return res.status(500).json({result: null,success: false});
41
77
  });
42
- }
43
-
44
- return res.status(200).json({
45
- result,
46
- success: true,
47
- message: `Found ${result.length} documents`,
48
- count: result.length
49
- });
50
78
  });
51
79
 
52
80
  /**
@@ -56,31 +84,43 @@ exports.all = tryCatch(async (Model, req, res) => {
56
84
  * @param {Object} res - Express response object
57
85
  * @returns {Promise<void>}
58
86
  */
59
- exports.read = tryCatch(async (Model, req, res) => {
87
+ exports.read = tryCatch((Model, req, res) => {
60
88
  const { id } = req.params;
61
89
 
62
90
  if (!id || !isValidObjectId(id)) {
63
- return res.status(400).json({
64
- result: null,
65
- success: false,
66
- message: "Invalid or Missing Document ID"
67
- });
91
+ return Promise.resolve(
92
+ res.status(400).json({
93
+ result: null,
94
+ success: false,
95
+ message: "Invalid or missing document ID"
96
+ })
97
+ );
68
98
  }
69
- const result = await Model.findById(id).exec();
70
99
 
71
- if (!result) {
72
- return res.status(404).json({
73
- result: null,
74
- success: false,
75
- message: `Document with ID ${id} not found`
100
+ return Model.findById(id).exec()
101
+ .then(result => {
102
+ if (!result) {
103
+ return res.status(404).json({
104
+ result: null,
105
+ success: false,
106
+ message: `Document with ID ${id} not found`
107
+ });
108
+ }
109
+
110
+ return res.status(200).json({
111
+ result,
112
+ success: true,
113
+ message: "Document found successfully"
114
+ });
115
+ })
116
+ .catch(error => {
117
+ console.error('Error reading document:', error);
118
+ return res.status(500).json({
119
+ result: null,
120
+ success: false,
121
+ message: "Error reading document"
122
+ });
76
123
  });
77
- }
78
-
79
- return res.status(200).json({
80
- result,
81
- success: true,
82
- message: "Document found successfully"
83
- });
84
124
  });
85
125
 
86
126
  /**
@@ -90,27 +130,36 @@ exports.read = tryCatch(async (Model, req, res) => {
90
130
  * @param {Object} res - Express response object
91
131
  * @returns {Promise<void>}
92
132
  */
93
- exports.create = tryCatch(async (Model, req, res) => {
133
+ exports.create = tryCatch((Model, req, res) => {
94
134
  const documentData = { ...req.body };
95
- // Handle image uploads if present
96
- if (documentData.images) {
97
-
98
- documentData.images.split(',').map(item => item.trim());
99
-
100
- const imageLinks = await cloud.uploadImages(documentData.images);
101
-
102
- if ( imageLinks ) documentData.images = imageLinks;
103
- }
104
-
105
- console.log('Creating document:', documentData);
106
135
 
107
- const document = new Model(documentData);
108
- await document.save()
109
- .then((result) => {
110
- return res.status(201).json({ result, success: true,
111
- message: `Document created successfully in ${Model.modelName} collection`});
112
- })
113
- .catch((error) => {console.log('Error Saving document :: ', error);});
136
+ return processImages(documentData.images)
137
+ .then(imageLinks => {
138
+ if (imageLinks) {
139
+ documentData.images = imageLinks;
140
+ }
141
+
142
+ console.log('Creating document:', documentData);
143
+ const document = new Model(documentData);
144
+
145
+ return document.save();
146
+ })
147
+ .then(result => {
148
+ return res.status(201).json({
149
+ result,
150
+ success: true,
151
+ message: `Document created successfully in ${Model.modelName} collection`
152
+ });
153
+ })
154
+ .catch(error => {
155
+ console.error('Error creating document:', error);
156
+ return res.status(500).json({
157
+ result: null,
158
+ success: false,
159
+ message: "Error creating document",
160
+ error: error.message
161
+ });
162
+ });
114
163
  });
115
164
 
116
165
  /**
@@ -120,60 +169,71 @@ exports.create = tryCatch(async (Model, req, res) => {
120
169
  * @param {Object} res - Express response object
121
170
  * @returns {Promise<void>}
122
171
  */
123
- exports.update = tryCatch(async (Model, req, res) => {
172
+ exports.update = tryCatch((Model, req, res) => {
124
173
  const { id } = req.params;
125
174
 
126
175
  if (!id) {
127
- return res.status(400).json({
128
- result: null,
129
- success: false,
130
- message: "Document ID is required"
131
- });
176
+ return Promise.resolve(
177
+ res.status(400).json({
178
+ result: null,
179
+ success: false,
180
+ message: "Document ID is required"
181
+ })
182
+ );
132
183
  }
133
184
 
134
185
  if (!isValidObjectId(id)) {
135
- return res.status(400).json({
136
- result: null,
137
- success: false,
138
- message: "Invalid document ID format"
139
- });
140
- }
141
-
142
- const updateData = { ...req.body };
143
-
144
- // Remove undefined values
145
- Object.keys(updateData).forEach(key => {
146
- if (updateData[key] === undefined) {
147
- delete updateData[key];
148
- }
149
- });
150
-
151
- // Handle image uploads if present
152
- if (updateData.images && Array.isArray(updateData.images) && updateData.images.length > 0) {
153
- const uploadedImages = await cloud.uploadImages(updateData.images);
154
- updateData.images = uploadedImages;
186
+ return Promise.resolve(
187
+ res.status(400).json({
188
+ result: null,
189
+ success: false,
190
+ message: "Invalid document ID format"
191
+ })
192
+ );
155
193
  }
156
194
 
157
- // Update document
158
- const result = await Model.findByIdAndUpdate(
159
- id,
160
- updateData,
161
- { new: true, runValidators: true }
162
- ).exec();
163
-
164
- if (!result) {
165
- return res.status(404).json({
166
- result: null,
167
- success: false,
168
- message: `Document with ID ${id} not found`
195
+ const updateData = sanitizeUpdateData(req.body);
196
+
197
+ const imagePromise = (updateData.images && Array.isArray(updateData.images) && updateData.images.length > 0)
198
+ ? processImages(updateData.images)
199
+ : Promise.resolve(null);
200
+
201
+ return imagePromise
202
+ .then(uploadedImages => {
203
+ if (uploadedImages) {
204
+ updateData.images = uploadedImages;
205
+ }
206
+
207
+ return Model.findByIdAndUpdate(
208
+ id,
209
+ updateData,
210
+ { new: true, runValidators: true }
211
+ ).exec();
212
+ })
213
+ .then(result => {
214
+ if (!result) {
215
+ return res.status(404).json({
216
+ result: null,
217
+ success: false,
218
+ message: `Document with ID ${id} not found`
219
+ });
220
+ }
221
+
222
+ return res.status(200).json({
223
+ result,
224
+ success: true,
225
+ message: `Document updated successfully with ID: ${id}`
226
+ });
227
+ })
228
+ .catch(error => {
229
+ console.error('Error updating document:', error);
230
+ return res.status(500).json({
231
+ result: null,
232
+ success: false,
233
+ message: "Error updating document",
234
+ error: error.message
235
+ });
169
236
  });
170
- }
171
-
172
- return res.status(200).json({
173
- result,
174
- success: true,
175
- message: `Document updated successfully with ID: ${id}`
176
- });
177
237
  });
178
238
 
179
239
  /**
@@ -183,47 +243,60 @@ exports.update = tryCatch(async (Model, req, res) => {
183
243
  * @param {Object} res - Express response object
184
244
  * @returns {Promise<void>}
185
245
  */
186
- exports.delete = tryCatch(async (Model, req, res) => {
246
+ exports.delete = tryCatch((Model, req, res) => {
187
247
  const { id } = req.params;
188
248
 
189
249
  if (!id) {
190
- return res.status(400).json({
191
- result: null,
192
- success: false,
193
- message: "Document ID is required"
194
- });
250
+ return Promise.resolve(
251
+ res.status(400).json({
252
+ result: null,
253
+ success: false,
254
+ message: "Document ID is required"
255
+ })
256
+ );
195
257
  }
196
258
 
197
259
  if (!isValidObjectId(id)) {
198
- return res.status(400).json({
199
- result: null,
200
- success: false,
201
- message: "Invalid document ID format"
202
- });
260
+ return Promise.resolve(
261
+ res.status(400).json({
262
+ result: null,
263
+ success: false,
264
+ message: "Invalid document ID format"
265
+ })
266
+ );
203
267
  }
204
268
 
205
- const result = await Model.findByIdAndDelete(id).exec();
206
-
207
- if (!result) {
208
- return res.status(404).json({
209
- result: null,
210
- success: false,
211
- message: `Document with ID ${id} not found`
269
+ return Model.findByIdAndDelete(id)
270
+ .exec()
271
+ .then(result => {
272
+ if (!result) {
273
+ return res.status(404).json({ result: null, success: false });
274
+ }
275
+
276
+ // Clean up associated images if they exist
277
+ if (result.images && Array.isArray(result.images) && result.images.length > 0) {
278
+ console.log('Document had images that should be cleaned up:', result.images);
279
+ // Uncomment when cloud.deleteImages is available:
280
+ // return cloud.deleteImages(result.images)
281
+ // .then(() => result)
282
+ // .catch(err => {
283
+ // console.error('Error deleting images:', err);
284
+ // return result;
285
+ // });
286
+ }
287
+
288
+ return result;
289
+ })
290
+ .then(result => {
291
+ return res.status(200)
292
+ .json({ result, success: true,
293
+ message: `Document deleted successfully with ID: ${id}`
294
+ });
295
+ })
296
+ .catch(error => {
297
+ console.error('Error deleting document:', error);
298
+ return res.status(500).json({ result: error, success: false });
212
299
  });
213
- }
214
-
215
- // TODO: Clean up associated images if they exist
216
- if (result.images && Array.isArray(result.images) && result.images.length > 0) {
217
- console.log('Document had images that should be cleaned up:', result.images);
218
- // Uncomment when cloud.deleteImages is available:
219
- // await cloud.deleteImages(result.images);
220
- }
221
-
222
- return res.status(200).json({
223
- result,
224
- success: true,
225
- message: `Document deleted successfully with ID: ${id}`
226
- });
227
300
  });
228
301
 
229
302
  /**
@@ -233,7 +306,7 @@ exports.delete = tryCatch(async (Model, req, res) => {
233
306
  * @param {Object} res - Express response object
234
307
  * @returns {Promise<void>}
235
308
  */
236
- exports.list = tryCatch(async (Model, req, res) => {
309
+ exports.list = tryCatch((Model, req, res) => {
237
310
  const page = Math.max(1, parseInt(req.query.page) || 1);
238
311
  const limit = Math.min(100, Math.max(1, parseInt(req.query.items) || 10));
239
312
  const skip = (page - 1) * limit;
@@ -241,35 +314,44 @@ exports.list = tryCatch(async (Model, req, res) => {
241
314
 
242
315
  const sortOrder = order === 'asc' ? 1 : -1;
243
316
 
244
- // Execute count and find queries in parallel
245
- const [result, count] = await Promise.all([
246
- Model.find()
247
- .skip(skip)
248
- .limit(limit)
249
- .sort({ [sort]: sortOrder })
250
- .populate(populate !== 'false' ? undefined : null)
251
- .exec(),
252
- Model.countDocuments().exec()
253
- ]);
254
-
255
- const totalPages = Math.ceil(count / limit);
256
- const pagination = {
257
- currentPage: page,
258
- totalPages,
259
- totalItems: count,
260
- itemsPerPage: limit,
261
- hasNextPage: page < totalPages,
262
- hasPrevPage: page > 1
263
- };
264
-
265
- return res.status(200).json({
266
- result,
267
- success: true,
268
- pagination,
269
- message: count > 0
270
- ? `Found ${result.length} of ${count} documents`
271
- : "Collection is empty"
272
- });
317
+ const findQuery = Model.find()
318
+ .skip(skip)
319
+ .limit(limit)
320
+ .sort({ [sort]: sortOrder })
321
+ .populate(populate !== 'false' ? undefined : null)
322
+ .exec();
323
+
324
+ const countQuery = Model.countDocuments().exec();
325
+
326
+ return Promise.all([findQuery, countQuery])
327
+ .then(([result, count]) => {
328
+ const totalPages = Math.ceil(count / limit);
329
+ const pagination = {
330
+ currentPage: page,
331
+ totalPages,
332
+ totalItems: count,
333
+ itemsPerPage: limit,
334
+ hasNextPage: page < totalPages,
335
+ hasPrevPage: page > 1
336
+ };
337
+
338
+ return res.status(200).json({
339
+ result,
340
+ success: true,
341
+ pagination,
342
+ message: count > 0
343
+ ? `Found ${result.length} of ${count} documents`
344
+ : "Collection is empty"
345
+ });
346
+ })
347
+ .catch(error => {
348
+ console.error('Error listing documents:', error);
349
+ return res.status(500).json({
350
+ result: null,
351
+ success: false,
352
+ message: "Error listing documents"
353
+ });
354
+ });
273
355
  });
274
356
 
275
357
  /**
@@ -279,7 +361,7 @@ exports.list = tryCatch(async (Model, req, res) => {
279
361
  * @param {Object} res - Express response object
280
362
  * @returns {Promise<void>}
281
363
  */
282
- exports.search = tryCatch(async (Model, req, res) => {
364
+ exports.search = tryCatch((Model, req, res) => {
283
365
  console.log('CRUD search query:', req.query);
284
366
 
285
367
  const {
@@ -294,7 +376,6 @@ exports.search = tryCatch(async (Model, req, res) => {
294
376
  limit = 24
295
377
  } = req.query;
296
378
 
297
- // Build query object
298
379
  const queryObj = {
299
380
  page: parseInt(page),
300
381
  limit: parseInt(limit)
@@ -325,19 +406,28 @@ exports.search = tryCatch(async (Model, req, res) => {
325
406
  defaultSort: sortOptions[sortBy] || sortOptions.popularity
326
407
  });
327
408
 
328
- const result = await searchApi
409
+ return searchApi
329
410
  .search(['_id', 'id', 'price', 'name', 'description', 'brand', 'tags'])
330
411
  .filter()
331
412
  .sort()
332
413
  .selectFields('-__v,-updatedAt')
333
414
  .populate('reviews')
334
415
  .paginate(parseInt(limit), 50)
335
- .execute();
336
-
337
- return res.status(200).json({
338
- success: true,
339
- ...result
340
- });
416
+ .execute()
417
+ .then(result => {
418
+ return res.status(200).json({
419
+ success: true,
420
+ ...result
421
+ });
422
+ })
423
+ .catch(error => {
424
+ console.error('Error searching documents:', error);
425
+ return res.status(500).json({
426
+ success: false,
427
+ message: "Error searching documents",
428
+ error: error.message
429
+ });
430
+ });
341
431
  });
342
432
 
343
433
  /**
@@ -8,9 +8,9 @@ const Product = require("../models/product");
8
8
  * @param {Object} res - Express response object
9
9
  */
10
10
  exports.review = tryCatch(async (req, res) => {
11
- const { rating, comment } = req.body;
12
- const productId = req.params.id;
13
- const userId = req.user._id;
11
+ const { productId, username, email, rating, comment } = req.body;
12
+ //const productId = req.params.id;
13
+ //const userId = req.user._id;
14
14
 
15
15
  // Validate required fields
16
16
  if (!rating || rating < 1 || rating > 5) {
@@ -42,8 +42,9 @@ exports.review = tryCatch(async (req, res) => {
42
42
  );
43
43
 
44
44
  const reviewData = {
45
- user: userId,
46
- product: productId,
45
+ productId: productId,
46
+ username,
47
+ email,
47
48
  rating: Number(rating),
48
49
  comment: comment.trim(),
49
50
  createdAt: new Date()
@@ -74,7 +75,7 @@ exports.review = tryCatch(async (req, res) => {
74
75
  if (existingReviewIndex !== -1) {
75
76
  // Update existing review in Review collection
76
77
  await Review.findOneAndUpdate(
77
- { user: userId, product: productId },
78
+ { username, productId },
78
79
  reviewData,
79
80
  { upsert: true, new: true }
80
81
  );
@@ -24,7 +24,7 @@ module.exports = function (fear) {
24
24
  throw new Error('Mailgun requires apiKey and domain in configuration.');
25
25
  }
26
26
 
27
- const mailgun = new Mailgun(FormData);
27
+ const mailgun = new Mailgun(_this.mailConfig.mailgun);
28
28
  const clientOptions = {
29
29
  username: 'api',
30
30
  key: apiKey
@@ -125,15 +125,13 @@ categorySchema.virtual("postCount", {
125
125
  // Pre-save middleware
126
126
  categorySchema.pre("save", async function(next) {
127
127
  // Generate slug
128
- if (this.isModified("name") || this.isModified("title")) {
129
- const nameToSlugify = this.title || this.name;
128
+ if (this.isModified("title")) {
129
+ const nameToSlugify = this.title;
130
130
  this.slug = slugify(nameToSlugify, {
131
131
  lower: true,
132
132
  strict: true,
133
133
  remove: /[*+~.()'"!:@]/g
134
134
  });
135
-
136
- // Ensure unique slug
137
135
  const slugRegEx = new RegExp(`^${this.slug}(-[0-9]*)?$`, "i");
138
136
  const categoriesWithSlug = await this.constructor.find({
139
137
  slug: slugRegEx,
@@ -145,22 +143,6 @@ categorySchema.pre("save", async function(next) {
145
143
  }
146
144
  }
147
145
 
148
- // Sync name and title if one is missing
149
- if (!this.name && this.title) {
150
- this.name = this.title;
151
- }
152
- if (!this.title && this.name) {
153
- this.title = this.name;
154
- }
155
-
156
- // Sync isActive with active
157
- if (this.isModified("isActive")) {
158
- this.active = this.isActive;
159
- }
160
- if (this.isModified("active")) {
161
- this.isActive = this.active;
162
- }
163
-
164
146
  // Calculate level and build ancestors
165
147
  if (this.isModified("parent")) {
166
148
  if (this.parent) {
@@ -185,43 +167,8 @@ categorySchema.pre("save", async function(next) {
185
167
  this.path = this.slug;
186
168
  }
187
169
  }
188
-
189
- // Set SEO defaults
190
- if (!this.seo.metaTitle) {
191
- this.seo.metaTitle = (this.title || this.name).substring(0, 70);
192
- }
193
-
194
- if (!this.seo.metaDescription && this.description) {
195
- this.seo.metaDescription = this.description.substring(0, 160);
196
- }
197
-
198
- next();
199
- });
200
-
201
- // Pre-update middleware
202
- categorySchema.pre("findOneAndUpdate", async function(next) {
203
- const update = this.getUpdate();
204
-
205
- if (update.name || update.title) {
206
- const nameToSlugify = update.title || update.name;
207
- update.slug = slugify(nameToSlugify, {
208
- lower: true,
209
- strict: true,
210
- remove: /[*+~.()'"!:@]/g
211
- });
212
- }
213
-
214
- if (update.isActive !== undefined) {
215
- update.active = update.isActive;
216
- }
217
-
218
- if (update.active !== undefined) {
219
- update.isActive = update.active;
220
- }
221
-
222
170
  next();
223
171
  });
224
-
225
172
  // Post-remove middleware to clean up references
226
173
  categorySchema.post("remove", async function(doc) {
227
174
  // Remove from parent's children
package/models/review.js CHANGED
@@ -1,8 +1,11 @@
1
1
  const mongoose = require("mongoose");
2
2
 
3
3
  const reviewSchema = new mongoose.Schema({
4
- user: { type: mongoose.Schema.Types.ObjectId, ref:"User", required:true },
5
- product: { type: mongoose.Schema.Types.ObjectId, ref:"Product", required:true },
4
+ productId: { type: mongoose.Schema.Types.ObjectId, ref:"Product", required:true },
5
+ username: { type: String, required: true },
6
+ email: { type: String, required: false, unique: true, lowercase: true, trim: true,
7
+ match: [/^\S+@\S+\.\S+$/, 'Please enter a valid email']
8
+ },
6
9
  rating: { type:Number, required:true, min:1, max:5 },
7
10
  comment: { type:String, required:true },
8
11
  createdAt: { type:Date, default:Date.now }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feardread/fear",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/routes/review.js CHANGED
@@ -5,7 +5,7 @@ module.exports = (fear) => {
5
5
 
6
6
  router.post("/new", Review.review)
7
7
  .get("/rating", Review.rating)
8
- .get("/product/:id", Review.getProductReviews);
8
+ .get("/by-product/:id", Review.getProductReviews);
9
9
 
10
10
  return router;
11
11
  };