@feardread/fear 1.0.1
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 +459 -0
- package/FEARServer.js +280 -0
- package/controllers/agent.js +438 -0
- package/controllers/auth/index.js +345 -0
- package/controllers/auth/token.js +50 -0
- package/controllers/blog.js +105 -0
- package/controllers/brand.js +10 -0
- package/controllers/cart.js +425 -0
- package/controllers/category.js +9 -0
- package/controllers/coupon.js +63 -0
- package/controllers/crud/crud.js +508 -0
- package/controllers/crud/index.js +36 -0
- package/controllers/email.js +34 -0
- package/controllers/enquiry.js +65 -0
- package/controllers/events.js +9 -0
- package/controllers/order.js +125 -0
- package/controllers/payment.js +31 -0
- package/controllers/product.js +147 -0
- package/controllers/review.js +247 -0
- package/controllers/tag.js +10 -0
- package/controllers/task.js +10 -0
- package/controllers/upload.js +41 -0
- package/controllers/user.js +401 -0
- package/index.js +7 -0
- package/libs/agent/index.js +561 -0
- package/libs/agent/modules/ai/ai.js +285 -0
- package/libs/agent/modules/ai/chat.js +518 -0
- package/libs/agent/modules/ai/config.js +688 -0
- package/libs/agent/modules/ai/operations.js +787 -0
- package/libs/agent/modules/analyze/api.js +546 -0
- package/libs/agent/modules/analyze/dorks.js +395 -0
- package/libs/agent/modules/ccard/README.md +454 -0
- package/libs/agent/modules/ccard/audit.js +479 -0
- package/libs/agent/modules/ccard/checker.js +674 -0
- package/libs/agent/modules/ccard/payment-processors.json +16 -0
- package/libs/agent/modules/ccard/validator.js +629 -0
- package/libs/agent/modules/code/analyzer.js +303 -0
- package/libs/agent/modules/code/jquery.js +1093 -0
- package/libs/agent/modules/code/react.js +1536 -0
- package/libs/agent/modules/code/refactor.js +499 -0
- package/libs/agent/modules/crypto/exchange.js +564 -0
- package/libs/agent/modules/net/proxy.js +409 -0
- package/libs/agent/modules/security/cve.js +442 -0
- package/libs/agent/modules/security/monitor.js +360 -0
- package/libs/agent/modules/security/scanner.js +300 -0
- package/libs/agent/modules/security/vulnerability.js +506 -0
- package/libs/agent/modules/security/web.js +465 -0
- package/libs/agent/modules/utils/browser.js +492 -0
- package/libs/agent/modules/utils/colorizer.js +285 -0
- package/libs/agent/modules/utils/manager.js +478 -0
- package/libs/cloud/index.js +228 -0
- package/libs/config/db.js +21 -0
- package/libs/config/validator.js +82 -0
- package/libs/db/index.js +318 -0
- package/libs/emailer/imap.js +126 -0
- package/libs/emailer/info.js +41 -0
- package/libs/emailer/smtp.js +77 -0
- package/libs/handler/async.js +3 -0
- package/libs/handler/error.js +66 -0
- package/libs/handler/index.js +161 -0
- package/libs/logger/index.js +49 -0
- package/libs/logger/morgan.js +24 -0
- package/libs/passport/passport.js +109 -0
- package/libs/search/api.js +384 -0
- package/libs/search/features.js +219 -0
- package/libs/search/service.js +64 -0
- package/libs/swagger/config.js +18 -0
- package/libs/swagger/index.js +35 -0
- package/libs/validator/index.js +254 -0
- package/models/blog.js +31 -0
- package/models/brand.js +12 -0
- package/models/cart.js +14 -0
- package/models/category.js +11 -0
- package/models/coupon.js +9 -0
- package/models/customer.js +0 -0
- package/models/enquiry.js +29 -0
- package/models/events.js +13 -0
- package/models/order.js +94 -0
- package/models/product.js +32 -0
- package/models/review.js +14 -0
- package/models/tag.js +10 -0
- package/models/task.js +11 -0
- package/models/user.js +68 -0
- package/package.json +12 -0
- package/routes/agent.js +615 -0
- package/routes/auth.js +13 -0
- package/routes/blog.js +19 -0
- package/routes/brand.js +15 -0
- package/routes/cart.js +105 -0
- package/routes/category.js +16 -0
- package/routes/coupon.js +15 -0
- package/routes/enquiry.js +14 -0
- package/routes/events.js +16 -0
- package/routes/mail.js +170 -0
- package/routes/order.js +19 -0
- package/routes/product.js +22 -0
- package/routes/review.js +11 -0
- package/routes/task.js +12 -0
- package/routes/user.js +17 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const swaggerJsdoc = require('swagger-jsdoc');
|
|
2
|
+
const swaggerUi = require('swagger-ui-express');
|
|
3
|
+
|
|
4
|
+
const options = {
|
|
5
|
+
definition: {
|
|
6
|
+
openapi: '3.0.0',
|
|
7
|
+
info: {
|
|
8
|
+
title: 'FEAR API',
|
|
9
|
+
description: "API endpoints for FEAR services documented on swagger",
|
|
10
|
+
contact: {
|
|
11
|
+
name: "Garrett Haptonstall <FearDread>",
|
|
12
|
+
email: "ghaptonstall@gmail.com",
|
|
13
|
+
url: "https://github.com/FearDread"
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
servers: [
|
|
17
|
+
{
|
|
18
|
+
url: "http://localhost:4000/",
|
|
19
|
+
description: "Local server"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
url: "http://fear.master.com:4000",
|
|
23
|
+
description: "Live server"
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
apis: ['./routes/*.js'], // Path to your API routes
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const specs = swaggerJsdoc(options);
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
specs,
|
|
34
|
+
swaggerUi,
|
|
35
|
+
};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
|
|
2
|
+
const handler = require('../handler');
|
|
3
|
+
const { body, param, query } = require('express-validator');
|
|
4
|
+
const { validationResult } = require('express-validator');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Input validation utilities
|
|
9
|
+
*/
|
|
10
|
+
exports.input = {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validate email format
|
|
14
|
+
* @param {string} email - Email to validate
|
|
15
|
+
* @returns {boolean} Is email valid
|
|
16
|
+
*/
|
|
17
|
+
email: (email) => {
|
|
18
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
19
|
+
return emailRegex.test(email);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validate password strength
|
|
24
|
+
* @param {string} password - Password to validate
|
|
25
|
+
* @returns {object} Validation result
|
|
26
|
+
*/
|
|
27
|
+
password: (password) => {
|
|
28
|
+
if (!password) {
|
|
29
|
+
return { isValid: false, message: "Password is required" };
|
|
30
|
+
}
|
|
31
|
+
if (password.length < 6) {
|
|
32
|
+
return { isValid: false, message: "Password must be at least 6 characters long" };
|
|
33
|
+
}
|
|
34
|
+
return { isValid: true };
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validate login input
|
|
39
|
+
* @param {object} data - Login data
|
|
40
|
+
* @returns {object} Validation result
|
|
41
|
+
*/
|
|
42
|
+
login: ({ email, password }) => {
|
|
43
|
+
if (!email || !password) return { isValid: false, message: "Email and password are required" };
|
|
44
|
+
if (!exports.input.email(email)) return { isValid: false, message: "Please provide a valid email address" };
|
|
45
|
+
|
|
46
|
+
return { isValid: true };
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validate registration input
|
|
51
|
+
* @param {object} data - Registration data
|
|
52
|
+
* @returns {object} Validation result
|
|
53
|
+
*/
|
|
54
|
+
register: (data) => {
|
|
55
|
+
const { email, password, firstname, lastname, name } = data;
|
|
56
|
+
|
|
57
|
+
if (!email) return { isValid: false, message: "Email is required" };
|
|
58
|
+
if (!exports.input.email(email)) return { isValid: false, message: "Please provide a valid email address" };
|
|
59
|
+
|
|
60
|
+
const passwordValidation = exports.input.password(password);
|
|
61
|
+
if (!passwordValidation.isValid) return passwordValidation;
|
|
62
|
+
|
|
63
|
+
const fullName = firstname && lastname ? `${firstname} ${lastname}` : name;
|
|
64
|
+
if (!fullName) return { isValid: false, message: "Name is required" };
|
|
65
|
+
|
|
66
|
+
return { isValid: true, name: fullName };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Basic validation middleware for express-validator
|
|
73
|
+
* Checks validation results and throws handler..error if validation fails
|
|
74
|
+
*/
|
|
75
|
+
exports.request = (req, res, next) => {
|
|
76
|
+
const errors = validationResult(req);
|
|
77
|
+
|
|
78
|
+
if (!errors.isEmpty()) {
|
|
79
|
+
const formattedErrors = errors.array().reduce((acc, error) => {
|
|
80
|
+
const field = error.path || error.param;
|
|
81
|
+
if (!acc[field]) {
|
|
82
|
+
acc[field] = [];
|
|
83
|
+
}
|
|
84
|
+
acc[field].push(error.msg);
|
|
85
|
+
return acc;
|
|
86
|
+
}, {});
|
|
87
|
+
|
|
88
|
+
const errorResponse = {
|
|
89
|
+
success: false,
|
|
90
|
+
message: 'Validation failed',
|
|
91
|
+
errors: formattedErrors,
|
|
92
|
+
errorCount: errors.array().length
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return res.status(400).json(errorResponse);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
next();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Custom validation schemas for common use cases
|
|
103
|
+
*/
|
|
104
|
+
exports.schemas = {
|
|
105
|
+
// MongoDB ObjectId validation
|
|
106
|
+
mongoId: (field = 'id') => ({
|
|
107
|
+
[field]: {
|
|
108
|
+
in: ['params', 'body', 'query'],
|
|
109
|
+
isMongoId: {
|
|
110
|
+
errorMessage: `Valid ${field} is required`
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
|
|
115
|
+
// Email validation
|
|
116
|
+
email: (field = 'email', required = true) => ({
|
|
117
|
+
[field]: {
|
|
118
|
+
in: ['body'],
|
|
119
|
+
...(required && { notEmpty: { errorMessage: `${field} is required` } }),
|
|
120
|
+
isEmail: {
|
|
121
|
+
errorMessage: 'Valid email address is required'
|
|
122
|
+
},
|
|
123
|
+
normalizeEmail: true
|
|
124
|
+
}
|
|
125
|
+
}),
|
|
126
|
+
|
|
127
|
+
// Password validation
|
|
128
|
+
password: (field = 'password', minLength = 8) => ({
|
|
129
|
+
[field]: {
|
|
130
|
+
in: ['body'],
|
|
131
|
+
isLength: {
|
|
132
|
+
options: { min: minLength },
|
|
133
|
+
errorMessage: `Password must be at least ${minLength} characters long`
|
|
134
|
+
},
|
|
135
|
+
matches: {
|
|
136
|
+
options: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
|
|
137
|
+
errorMessage: 'Password must contain at least one uppercase letter, one lowercase letter, and one number'
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}),
|
|
141
|
+
|
|
142
|
+
// Pagination validation
|
|
143
|
+
pagination: () => ({
|
|
144
|
+
page: {
|
|
145
|
+
in: ['query'],
|
|
146
|
+
optional: true,
|
|
147
|
+
isInt: {
|
|
148
|
+
options: { min: 1 },
|
|
149
|
+
errorMessage: 'Page must be a positive integer'
|
|
150
|
+
},
|
|
151
|
+
toInt: true
|
|
152
|
+
},
|
|
153
|
+
limit: {
|
|
154
|
+
in: ['query'],
|
|
155
|
+
optional: true,
|
|
156
|
+
isInt: {
|
|
157
|
+
options: { min: 1, max: 100 },
|
|
158
|
+
errorMessage: 'Limit must be between 1 and 100'
|
|
159
|
+
},
|
|
160
|
+
toInt: true
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Dynamic validation builder
|
|
167
|
+
*/
|
|
168
|
+
exports.buildValidation = (schema) => {
|
|
169
|
+
const { checkSchema } = require('express-validator');
|
|
170
|
+
return checkSchema(schema);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Sanitization helpers
|
|
175
|
+
*/
|
|
176
|
+
exports.sanitizers = {
|
|
177
|
+
trimAndEscape: (field) =>
|
|
178
|
+
body(field).trim().escape(),
|
|
179
|
+
|
|
180
|
+
normalizeEmail: (field = 'email') =>
|
|
181
|
+
body(field).normalizeEmail(),
|
|
182
|
+
|
|
183
|
+
toLowerCase: (field) =>
|
|
184
|
+
body(field).toLowerCase(),
|
|
185
|
+
|
|
186
|
+
toBoolean: (field) =>
|
|
187
|
+
body(field).toBoolean()
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Validation middleware factory
|
|
192
|
+
* Creates validation middleware with custom error handling
|
|
193
|
+
*/
|
|
194
|
+
exports.factory = (options = {}) => {
|
|
195
|
+
const {
|
|
196
|
+
detailed = true,
|
|
197
|
+
firstOnly = false,
|
|
198
|
+
location = true
|
|
199
|
+
} = options;
|
|
200
|
+
|
|
201
|
+
return (req, res, next) => {
|
|
202
|
+
const errors = validationResult(req);
|
|
203
|
+
|
|
204
|
+
if (!errors.isEmpty()) {
|
|
205
|
+
if (firstOnly) {
|
|
206
|
+
const firstError = errors.array()[0];
|
|
207
|
+
const message = location
|
|
208
|
+
? `${firstError.path}: ${firstError.msg}`
|
|
209
|
+
: firstError.msg;
|
|
210
|
+
|
|
211
|
+
throw new handler.error(message, 400);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (detailed) {
|
|
215
|
+
const formattedErrors = errors.array().reduce((acc, error) => {
|
|
216
|
+
const field = error.path || error.param;
|
|
217
|
+
if (!acc[field]) {
|
|
218
|
+
acc[field] = [];
|
|
219
|
+
}
|
|
220
|
+
acc[field].push({
|
|
221
|
+
message: error.msg,
|
|
222
|
+
value: error.value,
|
|
223
|
+
location: error.location
|
|
224
|
+
});
|
|
225
|
+
return acc;
|
|
226
|
+
}, {});
|
|
227
|
+
|
|
228
|
+
return res.status(400).json({
|
|
229
|
+
success: false,
|
|
230
|
+
message: 'Validation failed',
|
|
231
|
+
errors: formattedErrors
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Default: simple error list
|
|
236
|
+
const errorMessages = errors.array().map(error =>
|
|
237
|
+
includeLocation ? `${error.path}: ${error.msg}` : error.msg
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
throw new handler.error(errorMessages.join(', '), 400);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
next();
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
input: exports.input,
|
|
249
|
+
request: exports.request,
|
|
250
|
+
schemas: exports.schemas,
|
|
251
|
+
builder: exports.buildValidation,
|
|
252
|
+
factory: exports.factory,
|
|
253
|
+
sanitizers: exports.sanitizers,
|
|
254
|
+
}
|
package/models/blog.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const blogSchema = new mongoose.Schema({
|
|
4
|
+
title: { type: String, required: true },
|
|
5
|
+
slug: { type: String, required: false },
|
|
6
|
+
description: { type: String, required: true },
|
|
7
|
+
section: { type:String, required: false, default: "Marketing" },
|
|
8
|
+
category: { type: mongoose.Schema.Types.String, ref: "Category" },
|
|
9
|
+
numViews: { type: Number, default: 0 },
|
|
10
|
+
isLiked: { type: Boolean, default: false },
|
|
11
|
+
isDisliked: { type: Boolean, default: false },
|
|
12
|
+
likes: [{
|
|
13
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
14
|
+
ref: "User",
|
|
15
|
+
}],
|
|
16
|
+
dislikes: [{
|
|
17
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
18
|
+
ref: "User",
|
|
19
|
+
}],
|
|
20
|
+
author: { type: String, default: "Admin" },
|
|
21
|
+
images: [],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
toJSON: { virtuals: true },
|
|
25
|
+
toObject: { virtuals: true },
|
|
26
|
+
timestamps: true,
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
//Export the model
|
|
31
|
+
module.exports = mongoose.model("Blog", blogSchema);
|
package/models/brand.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const brandSchema = new mongoose.Schema({
|
|
4
|
+
title: { type: String, required: true, unique: true, index: true },
|
|
5
|
+
logo: { type: Object, required: false, default:
|
|
6
|
+
{ public_id: '', secure_url: ''}},
|
|
7
|
+
isActive: { type: Boolean, default: true }
|
|
8
|
+
},
|
|
9
|
+
{ timestamps: true }
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
module.exports = mongoose.model("Brand", brandSchema);
|
package/models/cart.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const cartSchema = new mongoose.Schema({
|
|
4
|
+
userId: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
|
|
5
|
+
productId: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
|
|
6
|
+
quantity: { type: Number, required: true },
|
|
7
|
+
price: { type: Number, required: true },
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
timestamps: true,
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
module.exports = mongoose.model("Cart", cartSchema);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const mongoose = require("mongoose"); // Erase if already required
|
|
2
|
+
|
|
3
|
+
// Declare the Schema of the Mongo model
|
|
4
|
+
const categorySchema = new mongoose.Schema({
|
|
5
|
+
title: { type: String, required: true, unique: true, index: true },
|
|
6
|
+
},
|
|
7
|
+
{ timestamps: true }
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
//Export the model
|
|
11
|
+
module.exports = mongoose.model("Category", categorySchema);
|
package/models/coupon.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const couponSchema = new mongoose.Schema({
|
|
4
|
+
name: { type: String, required: true, unique: true, uppercase: true },
|
|
5
|
+
expiry: { type: Date, required: true },
|
|
6
|
+
discount: { type: Number, required: true },
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
module.exports = mongoose.model("Coupon", couponSchema);
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const mongoose = require("mongoose"); // Erase if already required
|
|
2
|
+
|
|
3
|
+
// Declare the Schema of the Mongo model
|
|
4
|
+
var enqSchema = new mongoose.Schema({
|
|
5
|
+
name: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
},
|
|
9
|
+
email: {
|
|
10
|
+
type: String,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
mobile: {
|
|
14
|
+
type: String,
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
comment: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
status: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: "Submitted",
|
|
24
|
+
enum: ["Submitted", "Contacted", "In Progress", "Resolved"],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
//Export the model
|
|
29
|
+
module.exports = mongoose.model("Enquiry", enqSchema);
|
package/models/events.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const eventSchema = new mongoose.Schema({
|
|
4
|
+
title: { type: String, required: true, unique: true, index: true },
|
|
5
|
+
start: { type: Date, required: true, default: mongoose.now() },
|
|
6
|
+
end: { type: Date, required: false, default: mongoose.now() },
|
|
7
|
+
allDay: { type: Boolean, default: false },
|
|
8
|
+
color: { type: String, required: false, default: 'azure' }
|
|
9
|
+
},
|
|
10
|
+
{ timestamps: true }
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
module.exports = mongoose.model("Events", eventSchema);
|
package/models/order.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const mongoose = require("mongoose"); // Erase if already required
|
|
2
|
+
|
|
3
|
+
// Declare the Schema of the Mongo model
|
|
4
|
+
var orderSchema = new mongoose.Schema(
|
|
5
|
+
{
|
|
6
|
+
user: {
|
|
7
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
8
|
+
ref: "User",
|
|
9
|
+
required: true,
|
|
10
|
+
},
|
|
11
|
+
shippingInfo: {
|
|
12
|
+
firstname: {
|
|
13
|
+
type: String,
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
lastname: {
|
|
17
|
+
type: String,
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
address: {
|
|
21
|
+
type: String,
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
city: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
state: {
|
|
29
|
+
type: String,
|
|
30
|
+
required: true,
|
|
31
|
+
},
|
|
32
|
+
other: {
|
|
33
|
+
type: String,
|
|
34
|
+
},
|
|
35
|
+
pincode: {
|
|
36
|
+
type: Number,
|
|
37
|
+
required: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
paymentInfo: {
|
|
41
|
+
razorpayOrderId: {
|
|
42
|
+
type: String,
|
|
43
|
+
required: true,
|
|
44
|
+
},
|
|
45
|
+
razorpayPaymentId: {
|
|
46
|
+
type: String,
|
|
47
|
+
required: true,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
orderItems: [
|
|
51
|
+
{
|
|
52
|
+
product: {
|
|
53
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
54
|
+
ref: "Product",
|
|
55
|
+
required: true,
|
|
56
|
+
},
|
|
57
|
+
quantity: {
|
|
58
|
+
type: Number,
|
|
59
|
+
required: true,
|
|
60
|
+
},
|
|
61
|
+
price: {
|
|
62
|
+
type: Number,
|
|
63
|
+
required: true,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
paidAt: {
|
|
68
|
+
type: Date,
|
|
69
|
+
default: Date.now(),
|
|
70
|
+
},
|
|
71
|
+
month: {
|
|
72
|
+
type: Number,
|
|
73
|
+
default: new Date().getMonth(),
|
|
74
|
+
},
|
|
75
|
+
totalPrice: {
|
|
76
|
+
type: Number,
|
|
77
|
+
required: true,
|
|
78
|
+
},
|
|
79
|
+
totalPriceAfterDiscount: {
|
|
80
|
+
type: Number,
|
|
81
|
+
required: true,
|
|
82
|
+
},
|
|
83
|
+
orderStatus: {
|
|
84
|
+
type: String,
|
|
85
|
+
default: "Ordered",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
timestamps: true,
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
//Export the model
|
|
94
|
+
module.exports = mongoose.model("Order", orderSchema);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const mongoose = require("mongoose"); // Erase if already required
|
|
2
|
+
const Review = require("./review");
|
|
3
|
+
|
|
4
|
+
// Declare the Schema of the Mongo model
|
|
5
|
+
const productSchema = new mongoose.Schema({
|
|
6
|
+
title: { type: String, required: true, trim: true },
|
|
7
|
+
slug: { type: String, required: false, unique: true, lowercase: true },
|
|
8
|
+
description: { type: String, required: true },
|
|
9
|
+
price: { type: Number, required: true },
|
|
10
|
+
category: { type: mongoose.Schema.Types.String, ref: "Category" },
|
|
11
|
+
brand: { type: mongoose.Schema.Types.String, ref: "Brand" , required: false },
|
|
12
|
+
quantity: { type: Number, required: true },
|
|
13
|
+
sold: { type: Number, default: 0 },
|
|
14
|
+
reviews: [Review.schema],
|
|
15
|
+
images: [{
|
|
16
|
+
public_id: String,
|
|
17
|
+
url: String
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
tags: String,
|
|
21
|
+
ratings: [{
|
|
22
|
+
star: Number,
|
|
23
|
+
comment: String,
|
|
24
|
+
postedby: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
totalrating: { type: Number, default: 0 },
|
|
28
|
+
}, { timestamps: true }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
//Export the model
|
|
32
|
+
module.exports = mongoose.model("Product", productSchema);
|
package/models/review.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
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 },
|
|
6
|
+
rating: { type:Number, required:true, min:1, max:5 },
|
|
7
|
+
comment: { type:String, required:true },
|
|
8
|
+
createdAt: { type:Date, default:Date.now }
|
|
9
|
+
},
|
|
10
|
+
{ timestamps: true, versionKey:false}
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module.exports = mongoose.model("Review", reviewSchema);
|
package/models/tag.js
ADDED
package/models/task.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const taskSchema = new mongoose.Schema({
|
|
4
|
+
task: { type: String, required: true, index: true },
|
|
5
|
+
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
|
|
6
|
+
createdAt: { type:Date, default:Date.now },
|
|
7
|
+
isComplete: { type: Boolean, default: false},
|
|
8
|
+
}, {timestamps: true}
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
module.exports = mongoose.model("Task", taskSchema);
|
package/models/user.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const bcrypt = require("bcrypt");
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
|
|
5
|
+
const userSchema = new mongoose.Schema({
|
|
6
|
+
name: { type: String, required: true },
|
|
7
|
+
lastname: { type: String, required: false },
|
|
8
|
+
email: { type: String, required: true, unique: true },
|
|
9
|
+
username: { type: String, required: false, unique: false },
|
|
10
|
+
mobile: { type: String, required: false, unique: true },
|
|
11
|
+
password: { type: String, required: true },
|
|
12
|
+
avatar: { type: Object, required: false, default: {
|
|
13
|
+
public_id: '',
|
|
14
|
+
secure_url: ''
|
|
15
|
+
}},
|
|
16
|
+
role: { type: String, default: "customer" },
|
|
17
|
+
isBlocked: { type: Boolean, default: false },
|
|
18
|
+
address: { type: String },
|
|
19
|
+
shipping: { type: String },
|
|
20
|
+
wishlist: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
|
|
21
|
+
refreshToken: { type: String },
|
|
22
|
+
passwordChangedAt: Date,
|
|
23
|
+
passwordResetToken: String,
|
|
24
|
+
passwordResetExpires: Date
|
|
25
|
+
},
|
|
26
|
+
{ timestamps: true }
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Hooks
|
|
30
|
+
userSchema.pre("save", async function (next) {
|
|
31
|
+
if (!this.isModified("password")) {
|
|
32
|
+
next();
|
|
33
|
+
}
|
|
34
|
+
const salt = await bcrypt.genSaltSync(10);
|
|
35
|
+
this.password = await bcrypt.hash(this.password, salt);
|
|
36
|
+
next();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Methods
|
|
40
|
+
userSchema.methods.compare = async function (entered) {
|
|
41
|
+
return await bcrypt.compare(entered, this.password);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
userSchema.methods.token = async function () {
|
|
45
|
+
const resettoken = crypto.randomBytes(32).toString("hex");
|
|
46
|
+
|
|
47
|
+
this.passwordResetToken = crypto.createHash("sha256").update(resettoken).digest("hex");
|
|
48
|
+
this.passwordResetExpires = Date.now() + 30 * 60 * 1000;
|
|
49
|
+
|
|
50
|
+
return resettoken;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//Statics
|
|
54
|
+
userSchema.statics.countUsers = function () {
|
|
55
|
+
return this.countDocuments({});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
userSchema.statics.findByEmail = async function (email) {
|
|
59
|
+
return await this.findOne({ email });
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Query
|
|
63
|
+
userSchema.query.paginate = function ({ page, limit }) {
|
|
64
|
+
const skip = limit * (page - 1);
|
|
65
|
+
return this.skip(skip).limit(limit);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = mongoose.model("User", userSchema);
|
package/package.json
ADDED