speedly 1.0.0 → 1.1.0
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/README.md +280 -0
- package/dist/cjs/auth/auth.js +86 -0
- package/dist/cjs/db/db.d.ts +181 -0
- package/dist/cjs/db/db.js +485 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +44 -0
- package/dist/cjs/model/translation.d.ts +59 -0
- package/dist/cjs/model/translation.js +13 -0
- package/dist/{modules/auth.d.ts → cjs/uploader/uploader.d.ts} +1 -1
- package/dist/cjs/uploader/uploader.js +150 -0
- package/dist/cjs/util/getConfig.d.ts +4 -0
- package/dist/cjs/util/getConfig.js +21 -0
- package/dist/cjs/util/strToObj.d.ts +2 -0
- package/dist/cjs/util/strToObj.js +9 -0
- package/dist/cjs/util/translator.d.ts +2 -0
- package/dist/cjs/util/translator.js +70 -0
- package/dist/cjs/validator/validator.d.ts +9 -0
- package/dist/cjs/validator/validator.js +32 -0
- package/dist/esm/auth/auth.js +81 -0
- package/dist/esm/db/db.d.ts +181 -0
- package/dist/esm/db/db.js +480 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/model/translation.d.ts +2 -0
- package/dist/esm/model/translation.js +8 -0
- package/dist/{modules/db.d.ts → esm/uploader/uploader.d.ts} +1 -1
- package/dist/esm/uploader/uploader.js +145 -0
- package/dist/esm/util/getConfig.d.ts +4 -0
- package/dist/esm/util/getConfig.js +16 -0
- package/dist/esm/util/strToObj.d.ts +2 -0
- package/dist/esm/util/strToObj.js +7 -0
- package/dist/esm/util/translator.d.ts +2 -0
- package/dist/esm/util/translator.js +65 -0
- package/dist/esm/validator/validator.d.ts +9 -0
- package/dist/esm/validator/validator.js +28 -0
- package/package.json +28 -15
- package/dist/index.d.ts +0 -0
- package/dist/index.js +0 -1
- package/dist/modules/auth.js +0 -68
- package/dist/modules/db/aggregation.d.ts +0 -0
- package/dist/modules/db/aggregation.js +0 -1
- package/dist/modules/db/aggregation.types.d.ts +0 -56
- package/dist/modules/db/aggregation.types.js +0 -2
- package/dist/modules/db/db.d.ts +0 -0
- package/dist/modules/db/db.js +0 -1
- package/dist/modules/db/db.type.js +0 -2
- package/dist/modules/db.js +0 -228
- package/dist/modules/types/db.d.ts +0 -38
- package/dist/modules/types/db.js +0 -1
- package/dist/modules/uploader.js +0 -57
- package/dist/modules/utils.d.ts +0 -0
- package/dist/modules/utils.js +0 -1
- package/dist/modules/validator.d.ts +0 -1
- package/dist/modules/validator.js +0 -47
- package/dist/utils/strToObj.d.ts +0 -0
- package/dist/utils/strToObj.js +0 -8
- /package/dist/{modules/db/db.type.d.ts → cjs/auth/auth.d.ts} +0 -0
- /package/dist/{modules/uploader.d.ts → esm/auth/auth.d.ts} +0 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
let __path = "./models/";
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import strToObj from '../util/strToObj';
|
|
4
|
+
import getConfig from '../util/getConfig';
|
|
5
|
+
import translator from '../util/translator';
|
|
6
|
+
let configs = {
|
|
7
|
+
dbType: "mongodb",
|
|
8
|
+
path: "../models",
|
|
9
|
+
dbEnv: "DB_URL",
|
|
10
|
+
...getConfig("db"),
|
|
11
|
+
};
|
|
12
|
+
const usingMongoDb = (collectionName, config = {}) => {
|
|
13
|
+
let model;
|
|
14
|
+
let queryState = {
|
|
15
|
+
queries: [],
|
|
16
|
+
};
|
|
17
|
+
if (config?.path)
|
|
18
|
+
__path = config.path;
|
|
19
|
+
model = require(path.join(__path, collectionName));
|
|
20
|
+
const actionHandler = {
|
|
21
|
+
find: (match = {}) => {
|
|
22
|
+
queryState.action = "find";
|
|
23
|
+
queryState.match = match;
|
|
24
|
+
return handler;
|
|
25
|
+
},
|
|
26
|
+
create: (body = {}) => {
|
|
27
|
+
queryState.action = "create";
|
|
28
|
+
queryState.body = body;
|
|
29
|
+
return handler;
|
|
30
|
+
},
|
|
31
|
+
updateOne: (match = {}, body = {}) => {
|
|
32
|
+
queryState.action = "updateOne";
|
|
33
|
+
queryState.match = match;
|
|
34
|
+
queryState.body = body;
|
|
35
|
+
return handler;
|
|
36
|
+
},
|
|
37
|
+
updateMany: (match = {}, body = {}) => {
|
|
38
|
+
queryState.action = "updateMany";
|
|
39
|
+
queryState.match = match;
|
|
40
|
+
queryState.body = body;
|
|
41
|
+
return handler;
|
|
42
|
+
},
|
|
43
|
+
deleteOne: (match = {}) => {
|
|
44
|
+
queryState.action = "deleteOne";
|
|
45
|
+
queryState.match = match;
|
|
46
|
+
return handler;
|
|
47
|
+
},
|
|
48
|
+
deleteMany: (match = {}) => {
|
|
49
|
+
queryState.action = "deleteMany";
|
|
50
|
+
queryState.match = match;
|
|
51
|
+
return handler;
|
|
52
|
+
},
|
|
53
|
+
findOne: (match = {}) => {
|
|
54
|
+
queryState.action = "findOne";
|
|
55
|
+
queryState.match = match;
|
|
56
|
+
return handler;
|
|
57
|
+
},
|
|
58
|
+
findOneAndUpdate: (match = {}, body = {}) => {
|
|
59
|
+
queryState.action = "findOneAndUpdate";
|
|
60
|
+
queryState.match = match;
|
|
61
|
+
queryState.body = body;
|
|
62
|
+
return handler;
|
|
63
|
+
},
|
|
64
|
+
aggregate: (pipeline = []) => {
|
|
65
|
+
queryState.action = "aggregate";
|
|
66
|
+
queryState.pipeline = pipeline;
|
|
67
|
+
return handler;
|
|
68
|
+
},
|
|
69
|
+
findOneAndDelete: (match = {}) => {
|
|
70
|
+
queryState.action = "findOneAndDelete";
|
|
71
|
+
queryState.match = match;
|
|
72
|
+
return handler;
|
|
73
|
+
},
|
|
74
|
+
findById: (id = "") => {
|
|
75
|
+
queryState.action = "findById";
|
|
76
|
+
queryState.id = id;
|
|
77
|
+
return handler;
|
|
78
|
+
},
|
|
79
|
+
findByIdAndUpdate: (id = "", body = {}) => {
|
|
80
|
+
queryState.action = "findByIdAndUpdate";
|
|
81
|
+
queryState.id = id;
|
|
82
|
+
queryState.body = body;
|
|
83
|
+
return handler;
|
|
84
|
+
},
|
|
85
|
+
findByIdAndDelete: (id = "") => {
|
|
86
|
+
queryState.action = "findByIdAndDelete";
|
|
87
|
+
queryState.id = id;
|
|
88
|
+
return handler;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Handles database operations for the specified model based on the action and query parameters.
|
|
93
|
+
* @param {object} req - Express request object containing query and body data.
|
|
94
|
+
* @param {object} res - Express response object used to send responses.
|
|
95
|
+
* @param {function} next - Express next middleware function for error handling.
|
|
96
|
+
*/
|
|
97
|
+
const handler = async (req, res, next) => {
|
|
98
|
+
let data = undefined, detail = {};
|
|
99
|
+
let match = {};
|
|
100
|
+
let realTimeQueries = [...queryState.queries];
|
|
101
|
+
const { sort, limit, page, select } = req.query;
|
|
102
|
+
if (req.query.search) {
|
|
103
|
+
const searchStr = Array.isArray(req.query.search)
|
|
104
|
+
? req.query.search[0]
|
|
105
|
+
: req.query.search;
|
|
106
|
+
if (typeof searchStr === "string") {
|
|
107
|
+
const splittedSearch = searchStr.trim().split(/\s|/g);
|
|
108
|
+
const searchValue = splittedSearch
|
|
109
|
+
.map((word) => `(?=.*${word.split("").join("\\s?")})`)
|
|
110
|
+
.join("");
|
|
111
|
+
match.$or = [
|
|
112
|
+
{ name: { $regex: searchValue } },
|
|
113
|
+
{ title: { $regex: searchValue } },
|
|
114
|
+
{ subTitle: { $regex: searchValue } },
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (req.query.filters) {
|
|
119
|
+
const filtersStr = Array.isArray(req.query.filters)
|
|
120
|
+
? req.query.filters[0]
|
|
121
|
+
: req.query.filters;
|
|
122
|
+
if (typeof filtersStr === "string") {
|
|
123
|
+
match = { ...match, ...JSON.parse(filtersStr) };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (typeof queryState.match == "function")
|
|
127
|
+
match = { ...match, ...queryState.match(req) };
|
|
128
|
+
if (typeof queryState.match == "object")
|
|
129
|
+
match = { ...match, ...queryState.match };
|
|
130
|
+
{
|
|
131
|
+
if (req.query.sort && queryState.action !== "aggregate") {
|
|
132
|
+
const sortQueryIndex = realTimeQueries.findIndex((q) => 'type' in q && q.type == "sort");
|
|
133
|
+
const sortStr = Array.isArray(req.query.sort)
|
|
134
|
+
? req.query.sort[0]
|
|
135
|
+
: req.query.sort;
|
|
136
|
+
const sortObject = typeof sortStr === "string" ? strToObj(sortStr) : {};
|
|
137
|
+
if (sortQueryIndex == -1)
|
|
138
|
+
realTimeQueries.push({
|
|
139
|
+
type: "sort",
|
|
140
|
+
value: (typeof sortStr === "string" ? sortStr : "") + " _id",
|
|
141
|
+
});
|
|
142
|
+
else
|
|
143
|
+
realTimeQueries.splice(sortQueryIndex, 1, {
|
|
144
|
+
type: "sort",
|
|
145
|
+
value: {
|
|
146
|
+
...((realTimeQueries[sortQueryIndex] && 'value' in realTimeQueries[sortQueryIndex] && typeof realTimeQueries[sortQueryIndex].value === 'object' && realTimeQueries[sortQueryIndex].value !== null) ? realTimeQueries[sortQueryIndex].value : {}),
|
|
147
|
+
...sortObject,
|
|
148
|
+
_id: 1,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (req.query.page && queryState.action !== "aggregate") {
|
|
153
|
+
const pageStr = Array.isArray(req.query.page) ? req.query.page[0] : typeof req.query.page === 'string' ? req.query.page : '';
|
|
154
|
+
const limitStr = Array.isArray(req.query.limit) ? req.query.limit[0] : typeof req.query.limit === 'string' ? req.query.limit : '';
|
|
155
|
+
const pageNum = parseInt(typeof pageStr === 'string' ? pageStr : '') || 1;
|
|
156
|
+
const limitNum = parseInt(typeof limitStr === 'string' ? limitStr : '') || configs?.pagination?.quantity || 20;
|
|
157
|
+
if (realTimeQueries.findIndex((q) => 'type' in q && q.type == "skip") == -1)
|
|
158
|
+
realTimeQueries.push({
|
|
159
|
+
type: "skip",
|
|
160
|
+
value: (pageNum - 1) * limitNum,
|
|
161
|
+
});
|
|
162
|
+
if (realTimeQueries.findIndex((q) => 'type' in q && q.type == "limit") == -1)
|
|
163
|
+
realTimeQueries.push({
|
|
164
|
+
type: "limit",
|
|
165
|
+
value: limitNum,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
else if (req.query.limit && queryState.action !== "aggregate") {
|
|
169
|
+
const pageStrAgg = Array.isArray(req.query.page) ? req.query.page[0] : typeof req.query.page === 'string' ? req.query.page : '';
|
|
170
|
+
const limitStrAgg = Array.isArray(req.query.limit) ? req.query.limit[0] : typeof req.query.limit === 'string' ? req.query.limit : '';
|
|
171
|
+
const pageNumAgg = parseInt(typeof pageStrAgg === 'string' ? pageStrAgg : '') || 1;
|
|
172
|
+
const limitNumAgg = parseInt(typeof limitStrAgg === 'string' ? limitStrAgg : '') || 20;
|
|
173
|
+
realTimeQueries.push({ $skip: (pageNumAgg - 1) * limitNumAgg }, { $limit: parseInt(Array.isArray(req.query.limit)
|
|
174
|
+
? String(req.query.limit[0])
|
|
175
|
+
: typeof req.query.limit === 'string'
|
|
176
|
+
? req.query.limit
|
|
177
|
+
: req.query.limit !== undefined
|
|
178
|
+
? String(req.query.limit)
|
|
179
|
+
: '') });
|
|
180
|
+
}
|
|
181
|
+
else if (req.query.limit && queryState.action == "aggregate") {
|
|
182
|
+
realTimeQueries.push({ $limit: parseInt(String(req.query.limit)) });
|
|
183
|
+
}
|
|
184
|
+
if (req.query.select && queryState.action !== "aggregate") {
|
|
185
|
+
const selectQueryIndex = realTimeQueries.findIndex((q) => 'type' in q && q.type == "select");
|
|
186
|
+
if (selectQueryIndex == -1)
|
|
187
|
+
realTimeQueries.push({ type: "select", value: req.query.select });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const page = parseInt(Array.isArray(req.query.page) ? String(req.query.page[0]) : typeof req.query.page === 'string' ? req.query.page : '') || 1;
|
|
192
|
+
const limit = parseInt(Array.isArray(req.query.limit) ? String(req.query.limit[0]) : typeof req.query.limit === 'string' ? req.query.limit : req.query.limit !== undefined ? String(req.query.limit) : '') ||
|
|
193
|
+
configs.pagination?.quantity ||
|
|
194
|
+
20;
|
|
195
|
+
switch (queryState.action) {
|
|
196
|
+
case "find":
|
|
197
|
+
if (configs.pagination?.detailed && req.query.page) {
|
|
198
|
+
const page = parseInt(Array.isArray(req.query.page) ? String(req.query.page[0]) : typeof req.query.page === 'string' ? req.query.page : '') || 1;
|
|
199
|
+
const limit = parseInt(Array.isArray(req.query.limit) ? String(req.query.limit[0]) : typeof req.query.limit === 'string' ? req.query.limit : req.query.limit !== undefined ? String(req.query.limit) : '') ||
|
|
200
|
+
configs.pagination?.quantity ||
|
|
201
|
+
20;
|
|
202
|
+
const totalPages = Math.ceil((await model.countDocuments(match)) / limit);
|
|
203
|
+
detail = {
|
|
204
|
+
...detail,
|
|
205
|
+
page,
|
|
206
|
+
limit,
|
|
207
|
+
totalPages,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
data = model?.find?.call(model, match);
|
|
211
|
+
break;
|
|
212
|
+
case "create":
|
|
213
|
+
req.body = Array.isArray(req.body)
|
|
214
|
+
? req.body.map((item) => ({
|
|
215
|
+
...item,
|
|
216
|
+
...(typeof queryState.body == "function"
|
|
217
|
+
? queryState.body(req)
|
|
218
|
+
: queryState.body),
|
|
219
|
+
}))
|
|
220
|
+
: {
|
|
221
|
+
...req.body,
|
|
222
|
+
...(typeof queryState.body == "function"
|
|
223
|
+
? queryState.body(req)
|
|
224
|
+
: queryState.body),
|
|
225
|
+
};
|
|
226
|
+
data = model?.[queryState.action]?.call(model, req.body);
|
|
227
|
+
break;
|
|
228
|
+
case "updateOne":
|
|
229
|
+
data = model?.[queryState.action]?.call(model, match, {
|
|
230
|
+
...req.body,
|
|
231
|
+
...(typeof queryState.body == "function"
|
|
232
|
+
? queryState.body(req)
|
|
233
|
+
: queryState.body),
|
|
234
|
+
});
|
|
235
|
+
break;
|
|
236
|
+
case "updateMany":
|
|
237
|
+
data = model?.[queryState.action]?.call(model, match, {
|
|
238
|
+
...req.body,
|
|
239
|
+
...(typeof queryState.body == "function"
|
|
240
|
+
? queryState.body(req)
|
|
241
|
+
: queryState.body),
|
|
242
|
+
});
|
|
243
|
+
break;
|
|
244
|
+
case "deleteOne":
|
|
245
|
+
data = model?.[queryState.action]?.call(model, match);
|
|
246
|
+
break;
|
|
247
|
+
case "deleteMany":
|
|
248
|
+
data = model?.[queryState.action]?.call(model, match);
|
|
249
|
+
break;
|
|
250
|
+
case "findOne":
|
|
251
|
+
data = model?.[queryState.action]?.call(model, match);
|
|
252
|
+
break;
|
|
253
|
+
case "findOneAndUpdate":
|
|
254
|
+
req.document = await model.findOne(match);
|
|
255
|
+
data = model?.[queryState.action]?.call(model, match, {
|
|
256
|
+
$set: {
|
|
257
|
+
...req.body,
|
|
258
|
+
...(typeof queryState.body == "function"
|
|
259
|
+
? queryState.body(req)
|
|
260
|
+
: queryState.body),
|
|
261
|
+
},
|
|
262
|
+
}, { new: true });
|
|
263
|
+
break;
|
|
264
|
+
case "findOneAndDelete":
|
|
265
|
+
data = model?.[queryState.action]?.call(model, match);
|
|
266
|
+
break;
|
|
267
|
+
case "findById":
|
|
268
|
+
data = model?.[queryState.action]?.call(model, queryState.id || req.params.id);
|
|
269
|
+
break;
|
|
270
|
+
case "aggregate":
|
|
271
|
+
if (configs.pagination?.detailed && req.query.page) {
|
|
272
|
+
const page = parseInt(req.query.page) || 1;
|
|
273
|
+
const limit = parseInt(req.query.limit) ||
|
|
274
|
+
configs.pagination?.quantity ||
|
|
275
|
+
20;
|
|
276
|
+
realTimeQueries = [
|
|
277
|
+
{
|
|
278
|
+
$facet: {
|
|
279
|
+
content: [...realTimeQueries],
|
|
280
|
+
detail: [
|
|
281
|
+
{ $group: { _id: null, count: { $sum: 1 } } },
|
|
282
|
+
{
|
|
283
|
+
$addFields: {
|
|
284
|
+
totalPages: { $ceil: { $divide: ["$count", limit] } },
|
|
285
|
+
page, limit
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
$unset: ['_id', 'count']
|
|
290
|
+
}
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
}, {
|
|
294
|
+
$unwind: '$detail'
|
|
295
|
+
}
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
realTimeQueries = [
|
|
300
|
+
{
|
|
301
|
+
$facet: {
|
|
302
|
+
content: [...realTimeQueries],
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
];
|
|
306
|
+
}
|
|
307
|
+
// res.status(200).json([...queryState.pipeline , ...realTimeQueries])
|
|
308
|
+
if (typeof queryState.pipeline == "function") {
|
|
309
|
+
data = model?.[queryState.action]?.call(model, [...queryState.pipeline(req), ...realTimeQueries]);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
data = model?.[queryState.action]?.call(model, [...(queryState.pipeline || []), ...realTimeQueries]);
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case "findByIdAndUpdate":
|
|
316
|
+
req.document = await model.findByIdAndUpdate(queryState.id || req.params.id);
|
|
317
|
+
data = model?.[queryState.action]?.call(model, queryState.id || req.params.id, Object.entries({
|
|
318
|
+
...req.body,
|
|
319
|
+
...(typeof queryState.body == "function"
|
|
320
|
+
? queryState.body(req)
|
|
321
|
+
: queryState.body),
|
|
322
|
+
}).reduce((acc, [key, value]) => {
|
|
323
|
+
if (value == "$$REMOVE") {
|
|
324
|
+
return { ...acc, $unset: { ...acc?.$unset, [key]: value } };
|
|
325
|
+
}
|
|
326
|
+
return { ...acc, $set: { ...acc?.$set, [key]: value } };
|
|
327
|
+
}, {}), { new: true });
|
|
328
|
+
break;
|
|
329
|
+
case "findByIdAndDelete":
|
|
330
|
+
data = model?.[queryState.action]?.call(model, queryState.id || req.params.id);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
if (queryState.action != "aggregate")
|
|
334
|
+
realTimeQueries.forEach((q) => {
|
|
335
|
+
if ('type' in q && typeof data?.[q.type] === "function") {
|
|
336
|
+
data = data[q.type].call(data, q.value);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
// if(req.query.select) data = data.select(req.query.select)
|
|
340
|
+
data = await data;
|
|
341
|
+
if (!data) {
|
|
342
|
+
next({
|
|
343
|
+
status: 404,
|
|
344
|
+
json: {
|
|
345
|
+
message: `${collectionName} not found.`,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
if (res.logger && req.user) {
|
|
351
|
+
if (queryState.action && queryState.action.match(/create|update|delete/i)?.[0]) {
|
|
352
|
+
res.logger(`${{ log: "لاگها" }[collectionName] ||
|
|
353
|
+
(await translator(`${collectionName}`))} ${data.name || data.title || data.id || data._id || ""} توسط ${(req.user?.firstName ? req.user?.firstName + " " : "") +
|
|
354
|
+
(req.user?.lastName || "") ||
|
|
355
|
+
`ادمین با شماره ${req.user.phoneNumber}`} ${{ create: "ایجاد", update: "بروزرسانی", delete: "حذف", nothing: '' }[queryState.action
|
|
356
|
+
.match(/create|update|delete/i)?.[0]
|
|
357
|
+
?.toLowerCase() || 'nothing'] || queryState.action} شد`, queryState.action.match(/update/i)?.[0]
|
|
358
|
+
? (await Promise.all(Object.entries(data._doc)
|
|
359
|
+
.filter(([key, value]) => ["_id", "__v", "updatedAt"].includes(key)
|
|
360
|
+
? false
|
|
361
|
+
: req.document._doc[key] == undefined ||
|
|
362
|
+
req.document._doc[key]?.toString?.() !==
|
|
363
|
+
value?.toString?.())
|
|
364
|
+
.map(async (item) => {
|
|
365
|
+
const translatedField = await translator(item[0], "fa");
|
|
366
|
+
if (req.document[item[0]] == undefined) {
|
|
367
|
+
return `فیلد ${translatedField} اضافه شد`;
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return `فیلد ${translatedField} از ${req.document[item[0]]} به ${item[1]} تغییر یافت`;
|
|
371
|
+
}
|
|
372
|
+
}))).concat(await Promise.all(Object.entries(req.document._doc)
|
|
373
|
+
.filter(([key, value]) => ["_id", "__v", "updatedAt"].includes(key)
|
|
374
|
+
? false
|
|
375
|
+
: data._doc[key] == undefined)
|
|
376
|
+
.map(async (item) => {
|
|
377
|
+
const translatedField = await translator(item[0], "fa");
|
|
378
|
+
return `فیلد ${translatedField} حذف شد`;
|
|
379
|
+
})))
|
|
380
|
+
: []);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const action = queryState.action?.match(/create|update|delet/i)?.[0] || "find";
|
|
384
|
+
const resBody = queryState.action == 'aggregate' ? {
|
|
385
|
+
message: config?.message ||
|
|
386
|
+
`the ${collectionName} was found successfully`, content: [], ...data[0]
|
|
387
|
+
} : {
|
|
388
|
+
content: data,
|
|
389
|
+
...{ detail: Object.keys(detail).length ? detail : undefined },
|
|
390
|
+
message: config?.message ||
|
|
391
|
+
`the ${collectionName} was ${action == "find" ? "found" : action + "ed"}`,
|
|
392
|
+
};
|
|
393
|
+
res.success ? res.success(200, resBody) : res.status(200).json(resBody);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
if (err && typeof err === 'object' && 'errorResponse' in err && err.errorResponse?.code == 11000)
|
|
398
|
+
return next({
|
|
399
|
+
status: 405,
|
|
400
|
+
json: {
|
|
401
|
+
message: `(${Object.entries(err.errorResponse.keyValue)[0][0]}) already exists; write a unique value`,
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
console.error("Error : model", err);
|
|
405
|
+
return next({
|
|
406
|
+
status: 500,
|
|
407
|
+
json: {
|
|
408
|
+
message: "Internal Server Error",
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
handler.select = (value) => {
|
|
414
|
+
queryState.queries.push({
|
|
415
|
+
type: "select",
|
|
416
|
+
value: typeof value == "string" ? strToObj(value, 0) : value,
|
|
417
|
+
});
|
|
418
|
+
return handler;
|
|
419
|
+
};
|
|
420
|
+
handler.sort = (value) => {
|
|
421
|
+
queryState.queries.push({
|
|
422
|
+
type: "sort",
|
|
423
|
+
value: typeof value == "string" ? strToObj(value) : value,
|
|
424
|
+
});
|
|
425
|
+
return handler;
|
|
426
|
+
};
|
|
427
|
+
handler.skip = (value) => {
|
|
428
|
+
queryState.queries.push({ type: "skip", value });
|
|
429
|
+
return handler;
|
|
430
|
+
};
|
|
431
|
+
handler.limit = (value) => {
|
|
432
|
+
queryState.queries.push({ type: "limit", value });
|
|
433
|
+
return handler;
|
|
434
|
+
};
|
|
435
|
+
handler.populate = (value) => {
|
|
436
|
+
queryState.queries.push({ type: "populate", value });
|
|
437
|
+
return handler;
|
|
438
|
+
};
|
|
439
|
+
return actionHandler;
|
|
440
|
+
};
|
|
441
|
+
// const usingMySql = (tableName, config) => {
|
|
442
|
+
// const mysqlConnection = mysql.createConnection(process.env[configs.dbEnv]);
|
|
443
|
+
// mysqlConnection.connect((err) => {
|
|
444
|
+
// if (err) console.log("DB ERR: ", err.message);
|
|
445
|
+
// else console.log("database connected successfully ");
|
|
446
|
+
// });
|
|
447
|
+
// const db = mysqlConnection.promise()
|
|
448
|
+
// let queryState = {
|
|
449
|
+
// queryString: "select * from ?",
|
|
450
|
+
// variables: [{ tableName }],
|
|
451
|
+
// };
|
|
452
|
+
// const requestHandler = async (req, res, next) => {
|
|
453
|
+
// const [result] = await db.query(queryState.queryString, queryState.variables);
|
|
454
|
+
// };
|
|
455
|
+
// const chainActions = {
|
|
456
|
+
// query: (query = "select * from ?", ...variables) => {
|
|
457
|
+
// queryState = { queryString: query, variables };
|
|
458
|
+
// return requestHandler;
|
|
459
|
+
// },
|
|
460
|
+
// };
|
|
461
|
+
// return chainActions;
|
|
462
|
+
// };
|
|
463
|
+
const db = (collectionName, config = configs) => {
|
|
464
|
+
let generatedConfig = {
|
|
465
|
+
dbType: "mongodb",
|
|
466
|
+
path: "../models",
|
|
467
|
+
dbEnv: "DB_URL",
|
|
468
|
+
...getConfig("db"),
|
|
469
|
+
};
|
|
470
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
471
|
+
generatedConfig[key] = value;
|
|
472
|
+
});
|
|
473
|
+
switch (generatedConfig.dbType) {
|
|
474
|
+
case "mongodb":
|
|
475
|
+
return usingMongoDb(collectionName, generatedConfig);
|
|
476
|
+
case "mysql":
|
|
477
|
+
// return usingMySql(collectionName, generatedConfig);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
export default db;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
const schema = new mongoose.Schema({
|
|
3
|
+
text: { type: String, required: true },
|
|
4
|
+
lang: { type: String, required: true, },
|
|
5
|
+
translatedText: { type: String, required: true },
|
|
6
|
+
}, { timestamps: true });
|
|
7
|
+
const model = mongoose.model('translation', schema);
|
|
8
|
+
export default model;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import multer from 'multer';
|
|
4
|
+
import mongoose from "mongoose";
|
|
5
|
+
const getConfig = require("../util/getConfig");
|
|
6
|
+
const relativePath = '../../../public';
|
|
7
|
+
let configs = {
|
|
8
|
+
saveInDb: false,
|
|
9
|
+
prefix: "",
|
|
10
|
+
limit: 5,
|
|
11
|
+
format: /png|jpg|webp|jpeg/i,
|
|
12
|
+
...getConfig("uploader")
|
|
13
|
+
};
|
|
14
|
+
console.log('uploader', 15, configs);
|
|
15
|
+
module.exports = (destination = "/image", config = configs) => {
|
|
16
|
+
let dest;
|
|
17
|
+
try {
|
|
18
|
+
Object.entries(config).forEach(([key, val]) => {
|
|
19
|
+
configs[key] = val;
|
|
20
|
+
});
|
|
21
|
+
const storage = multer.diskStorage({
|
|
22
|
+
destination: function (req, file, cb) {
|
|
23
|
+
try {
|
|
24
|
+
dest = typeof destination === "function"
|
|
25
|
+
? destination(req, file)
|
|
26
|
+
: destination;
|
|
27
|
+
const splitPath = dest.split("/");
|
|
28
|
+
let currentPath = path.join(__dirname, relativePath);
|
|
29
|
+
splitPath.forEach(folder => {
|
|
30
|
+
currentPath = path.join(currentPath, folder);
|
|
31
|
+
console.log('uploader', 39, currentPath, !fs.existsSync(currentPath));
|
|
32
|
+
if (!fs.existsSync(currentPath)) {
|
|
33
|
+
fs.mkdirSync(currentPath);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
cb(null, path.join(__dirname, relativePath, dest));
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
cb(err, "");
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
filename: function (req, file, cb) {
|
|
43
|
+
try {
|
|
44
|
+
const ext = path.extname(file.originalname);
|
|
45
|
+
if (!ext.slice(1).match(configs.format)) {
|
|
46
|
+
return cb(new Error("File format not acceptable"), '');
|
|
47
|
+
}
|
|
48
|
+
const originalName = Buffer.from(file.originalname, "latin1").toString("utf8");
|
|
49
|
+
const fileName = (configs.prefix ? configs.prefix + "-" : "") +
|
|
50
|
+
originalName.replace(/\.\w+$/, "") + ext;
|
|
51
|
+
const filePath = path.join(__dirname, relativePath, dest, fileName);
|
|
52
|
+
console.log('uploader', 65, filePath);
|
|
53
|
+
try {
|
|
54
|
+
fs.existsSync(filePath);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.log('uploader', 70, error);
|
|
58
|
+
}
|
|
59
|
+
if (fs.existsSync(filePath)) {
|
|
60
|
+
return cb(new Error("File already exists in the destination folder"), '');
|
|
61
|
+
}
|
|
62
|
+
cb(null, fileName);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
cb(err, '');
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
const uploader = multer({
|
|
70
|
+
storage,
|
|
71
|
+
limits: { fileSize: (configs.limit || 5) * 1024 * 1024 }, // MB
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
single: (fieldName) => (req, res, next) => {
|
|
75
|
+
uploader.single(fieldName)(req, res, async (err) => {
|
|
76
|
+
if (err) {
|
|
77
|
+
console.log('uploader', 85, err);
|
|
78
|
+
return next({ status: 405, json: { message: err.message } });
|
|
79
|
+
}
|
|
80
|
+
if (req.file) {
|
|
81
|
+
if (configs.saveInDb) {
|
|
82
|
+
const db = mongoose.connection;
|
|
83
|
+
const collection = db.collection("media");
|
|
84
|
+
const duplicate = await collection.findOne({ alt: req.body.alt });
|
|
85
|
+
if (duplicate) {
|
|
86
|
+
fs.rmSync(req.file.path);
|
|
87
|
+
return res.status(405).json({ message: "alt is repetitive" });
|
|
88
|
+
}
|
|
89
|
+
const mediaDoc = await collection.insertOne({
|
|
90
|
+
type: req.file.mimetype.split("/")[0],
|
|
91
|
+
name: req.file.filename,
|
|
92
|
+
dirPath: dest + "/",
|
|
93
|
+
alt: req.body.alt,
|
|
94
|
+
desc: req.body.desc,
|
|
95
|
+
url: "/static/" + dest + "/" + req.file.filename,
|
|
96
|
+
});
|
|
97
|
+
console.log('uploader', 101, mediaDoc);
|
|
98
|
+
req.mediaId = mediaDoc.insertedId;
|
|
99
|
+
}
|
|
100
|
+
req.body[fieldName] = path
|
|
101
|
+
.join("/static", path.relative(path.join(__dirname, relativePath), req.file.path))
|
|
102
|
+
.replaceAll(/\\/g, "/");
|
|
103
|
+
}
|
|
104
|
+
next();
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
array: (fieldName, maxCount = Infinity) => (req, res, next) => {
|
|
108
|
+
uploader.array(fieldName, maxCount)(req, res, (err) => {
|
|
109
|
+
if (err)
|
|
110
|
+
return res.status(405).json({ message: err.message });
|
|
111
|
+
if (req.files && Array.isArray(req.files) && req.files.length) {
|
|
112
|
+
req.body[fieldName] = req.files.map(file => path
|
|
113
|
+
.join("/static", path.relative(path.join(__dirname, relativePath), file.path))
|
|
114
|
+
.replaceAll(/\\/g, "/"));
|
|
115
|
+
}
|
|
116
|
+
next();
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
fields: (fields) => (req, res, next) => {
|
|
120
|
+
uploader.fields(fields)(req, res, (err) => {
|
|
121
|
+
if (err)
|
|
122
|
+
return res.status(405).json({ message: err.message });
|
|
123
|
+
next();
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
any: () => (req, res, next) => {
|
|
127
|
+
uploader.any()(req, res, (err) => {
|
|
128
|
+
if (err)
|
|
129
|
+
return res.status(405).json({ message: err.message });
|
|
130
|
+
next();
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
none: () => (req, res, next) => {
|
|
134
|
+
uploader.none()(req, res, (err) => {
|
|
135
|
+
if (err)
|
|
136
|
+
return res.status(405).json({ message: err.message });
|
|
137
|
+
next();
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.log("uploader init error", error);
|
|
144
|
+
}
|
|
145
|
+
};
|