@ecopex/ecopex-framework 1.0.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.
Files changed (81) hide show
  1. package/.env +73 -0
  2. package/README.md +248 -0
  3. package/bun.lockb +0 -0
  4. package/config/swagger/admin.js +44 -0
  5. package/config/swagger/api.js +19 -0
  6. package/database/migrations/20240000135243_timezones.js +22 -0
  7. package/database/migrations/20240000135244_countries.js +23 -0
  8. package/database/migrations/20240000135244_create_admins_table.js +66 -0
  9. package/database/migrations/20240000135244_currencies.js +21 -0
  10. package/database/migrations/20240000135244_languages.js +21 -0
  11. package/database/migrations/20240000135244_taxes.js +10 -0
  12. package/database/migrations/20240000135245_sites.js +37 -0
  13. package/database/migrations/20240000135246_payment_methods.js +33 -0
  14. package/database/migrations/20251016113547_devices.js +37 -0
  15. package/database/migrations/20251019192600_users.js +62 -0
  16. package/database/migrations/20251019213551_language_lines.js +35 -0
  17. package/database/migrations/20251222214131_category_groups.js +18 -0
  18. package/database/migrations/20251222214619_categories.js +27 -0
  19. package/database/migrations/20251222214848_brands.js +23 -0
  20. package/database/migrations/20251222214946_products.js +30 -0
  21. package/database/migrations/20251222215428_product_images.js +18 -0
  22. package/database/migrations/20251222215553_options.js +30 -0
  23. package/database/migrations/20251222215806_variants.js +23 -0
  24. package/database/migrations/20251222215940_attributes.js +25 -0
  25. package/database/migrations/20251222220135_discounts.js +15 -0
  26. package/database/migrations/20251222220253_reviews.js +22 -0
  27. package/database/migrations/20251222220341_favorites.js +10 -0
  28. package/database/migrations/20251222220422_search_logs.js +17 -0
  29. package/database/migrations/20251222220636_orders.js +16 -0
  30. package/database/migrations/20251222220806_order_items.js +19 -0
  31. package/database/migrations/20251222221317_order_statuses.js +10 -0
  32. package/database/migrations/20251222221446_order_payments.js +13 -0
  33. package/database/migrations/20251222221654_order_addresses.js +23 -0
  34. package/database/migrations/20251222221807_order_status_logs.js +13 -0
  35. package/database/seeds/admins.js +37 -0
  36. package/database/seeds/countries.js +203 -0
  37. package/database/seeds/currencies.js +165 -0
  38. package/database/seeds/languages.js +113 -0
  39. package/database/seeds/timezones.js +149 -0
  40. package/ecosystem.config.js +26 -0
  41. package/env.example +73 -0
  42. package/knexfile.js +3 -0
  43. package/libraries/2fa.js +22 -0
  44. package/libraries/aws.js +63 -0
  45. package/libraries/bcrypt.js +284 -0
  46. package/libraries/controls.js +113 -0
  47. package/libraries/date.js +14 -0
  48. package/libraries/general.js +8 -0
  49. package/libraries/image.js +57 -0
  50. package/libraries/jwt.js +178 -0
  51. package/libraries/knex.js +7 -0
  52. package/libraries/slug.js +14 -0
  53. package/libraries/stores.js +22 -0
  54. package/libraries/upload.js +194 -0
  55. package/locales/en/messages.json +4 -0
  56. package/locales/en/sql.json +3 -0
  57. package/locales/en/validation.json +52 -0
  58. package/locales/es/validation.json +52 -0
  59. package/locales/tr/validation.json +59 -0
  60. package/package.json +75 -0
  61. package/routes/admin/auto/admins.json +63 -0
  62. package/routes/admin/auto/devices.json +37 -0
  63. package/routes/admin/auto/migrations.json +21 -0
  64. package/routes/admin/auto/users.json +61 -0
  65. package/routes/admin/middlewares/index.js +87 -0
  66. package/routes/admin/spec/auth.js +626 -0
  67. package/routes/admin/spec/users.js +3 -0
  68. package/routes/auto/handler.js +635 -0
  69. package/routes/common/auto/countries.json +28 -0
  70. package/routes/common/auto/currencies.json +26 -0
  71. package/routes/common/auto/languages.json +26 -0
  72. package/routes/common/auto/taxes.json +46 -0
  73. package/routes/common/auto/timezones.json +29 -0
  74. package/stores/base.js +73 -0
  75. package/stores/index.js +195 -0
  76. package/utils/i18n.js +187 -0
  77. package/utils/jsonRouteLoader.js +587 -0
  78. package/utils/middleware.js +154 -0
  79. package/utils/routeLoader.js +227 -0
  80. package/workers/admin.js +124 -0
  81. package/workers/api.js +106 -0
@@ -0,0 +1,113 @@
1
+ const emailValidation = (email = '') => {
2
+ return String(email).toLowerCase().match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
3
+ }
4
+
5
+ const phoneValidation = (phone = '') => {
6
+ return String(phone).match(/^[\+]?([0-9][\s]?|[0-9]?)([(][0-9]{3}[)][\s]?|[0-9]{3}[-\s\.]?)[0-9]{3}[-\s\.]?[0-9]{4,6}$/im);
7
+ }
8
+
9
+ function randomChars(length) {
10
+ var result = '';
11
+ var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
12
+ var charactersLength = characters.length;
13
+ for (var i = 0; i < length; i++) {
14
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
15
+ }
16
+ return result;
17
+ }
18
+
19
+ const randomNumber = (min, max) => {
20
+ return Math.floor(Math.random() * (max - min + 1) + min);
21
+ }
22
+
23
+ function getIpAddress(req = {}) {
24
+ return req.headers['x-forwarded-for'] ||
25
+ req.socket.remoteAddress ||
26
+ null;
27
+ }
28
+
29
+ const roundTo = (n, digits) => {
30
+ if (digits === undefined) {
31
+ digits = 0;
32
+ }
33
+
34
+ var multiplicator = Math.pow(10, digits);
35
+ n = parseFloat((n * multiplicator).toFixed(11));
36
+ var test =(Math.round(n) / multiplicator);
37
+ return +(test.toFixed(digits));
38
+ }
39
+
40
+ function validateLatLng(lat, lng) {
41
+ let pattern = new RegExp('^-?([1-8]?[1-9]|[1-9]0)\\.{1}\\d{1,6}');
42
+
43
+ return pattern.test(lat) && pattern.test(lng);
44
+ }
45
+
46
+ const checkCoordinates = (address, paths) => {
47
+
48
+ if (paths) {
49
+
50
+ const allPaths = paths.c[0].reduce((o, n) => {
51
+ o.lngs.push(parseFloat(n.lng));
52
+ o.lats.push(parseFloat(n.lat));
53
+ return o
54
+ }, { lngs: [], lats: [] })
55
+
56
+ const minimumLng = Math.min(...allPaths.lngs)
57
+ const maximumLng = Math.max(...allPaths.lngs)
58
+ const minimumLat = Math.min(...allPaths.lats)
59
+ const maximumLat = Math.max(...allPaths.lats)
60
+
61
+ if (parseFloat(address.lng) >= minimumLng && parseFloat(address.lng) <= maximumLng && parseFloat(address.lat) >= minimumLat && parseFloat(address.lat) <= maximumLat) {
62
+ return true
63
+ } else {
64
+ return false
65
+ }
66
+
67
+ } else {
68
+ return false
69
+ }
70
+
71
+ }
72
+
73
+ const checkPassoword = (password) => {
74
+ return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])\S{8,}$/.test(password)
75
+ }
76
+
77
+ const sleep = async (ms) => {
78
+ return new Promise(resolve => setTimeout(resolve, ms));
79
+ }
80
+
81
+ const ipcheck = (req, whitelists = '') => {
82
+
83
+ const client_ip = req.headers['cf-connecting-ip'] || (req.headers['x-real-ip'] || req.ip)
84
+
85
+ // whitelist split
86
+ const whiteips = typeof whitelists === 'string' && whitelists != '' ? whitelists.split(',').map(n => n.trim()) : []
87
+
88
+ const status = whiteips.length > 0 ? whiteips.includes(client_ip) : true
89
+
90
+ if(!status) {
91
+ console.error(client_ip, whiteips, req.headers);
92
+ }
93
+
94
+ // check if exists
95
+ return {
96
+ status: status,
97
+ client_ip: client_ip
98
+ }
99
+ }
100
+
101
+ module.exports = {
102
+ emailValidation,
103
+ phoneValidation,
104
+ randomChars,
105
+ randomNumber,
106
+ validateLatLng,
107
+ checkCoordinates,
108
+ getIpAddress,
109
+ checkPassoword,
110
+ ipcheck,
111
+ sleep,
112
+ roundTo
113
+ }
@@ -0,0 +1,14 @@
1
+ const dayjs = require('dayjs');
2
+ const utc = require('dayjs/plugin/utc')
3
+ const timezone = require("dayjs/plugin/timezone");
4
+ dayjs.extend(utc)
5
+ dayjs.extend(timezone)
6
+
7
+ const getUtcFormated = (date = new Date()) => {
8
+ return dayjs(date).utc().format('YYYY-MM-DD HH:mm:ss')
9
+ }
10
+
11
+ module.exports = {
12
+ getUtcFormated,
13
+ dayjs
14
+ }
@@ -0,0 +1,8 @@
1
+ // title case a string
2
+ const titleCase = (str) => {
3
+ return str.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase());
4
+ }
5
+
6
+ module.exports = {
7
+ titleCase
8
+ }
@@ -0,0 +1,57 @@
1
+ const resizer = require('node-image-resizer');
2
+ const basePath = __dirname + '../uploads/'
3
+
4
+ let resizerOpts = {
5
+ all: {
6
+ path: basePath + 'thumbnails/',
7
+ quality: 80
8
+ },
9
+ versions: [{
10
+ prefix: '',
11
+ width: 800,
12
+ height: 800
13
+ }]
14
+ }
15
+
16
+ const resize = async (filePath, resizeSetup = false, quality = 80, directory = false) => {
17
+
18
+ if(directory) {
19
+ resizerOpts.all.path = basePath + directory + '/'
20
+ }
21
+
22
+ const resizeOptsAll = JSON.parse(JSON.stringify(resizerOpts))
23
+ resizeOptsAll.all.quality = quality
24
+
25
+ if (resizeSetup) {
26
+ resizeOptsAll.versions = resizeSetup.reduce((o,n) => {
27
+ const version = Object.assign({}, resizeOptsAll.versions[0], n)
28
+ version.prefix = 'resize_' + version.width + 'x' + version.height + '_'
29
+ o.push(version)
30
+ return o
31
+ }, [])
32
+ }
33
+
34
+ try {
35
+ const resizedImages = await resizer(basePath + filePath, resizeOptsAll);
36
+
37
+ return {
38
+ status: true,
39
+ files: resizedImages.reduce((o,n,k) => {
40
+ o.push({
41
+ width: resizeOptsAll.versions[k].width,
42
+ height: resizeOptsAll.versions[k].height,
43
+ fileUrl: n.replace(basePath, '')
44
+ })
45
+ return o
46
+ },[])
47
+ };
48
+ } catch (error) {
49
+ return {
50
+ status: false
51
+ }
52
+ }
53
+ }
54
+
55
+ module.exports = {
56
+ resize
57
+ }
@@ -0,0 +1,178 @@
1
+ const jwt = require('jsonwebtoken');
2
+
3
+ /**
4
+ * JWT Library Class
5
+ * Provides methods for JWT token operations including sign, verify, and decode
6
+ */
7
+ class JWT {
8
+ constructor(secretKey = process.env.JWT_SECRET || 'default-secret-key') {
9
+ this.secretKey = secretKey;
10
+ this.defaultExpiresIn = '1d';
11
+ }
12
+
13
+ /**
14
+ * Sign a payload and create a JWT token
15
+ * @param {Object} payload - The payload to encode
16
+ * @param {Object} options - JWT options (expiresIn, algorithm, etc.)
17
+ * @returns {string} JWT token
18
+ */
19
+ sign(payload, options = {}) {
20
+ try {
21
+ const defaultOptions = {
22
+ expiresIn: this.defaultExpiresIn,
23
+ algorithm: 'HS256'
24
+ };
25
+
26
+ const signOptions = { ...defaultOptions, ...options };
27
+
28
+ return jwt.sign(payload, this.secretKey, signOptions);
29
+ } catch (error) {
30
+ throw new Error(`JWT Sign Error: ${error.message}`);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Verify and decode a JWT token
36
+ * @param {string} token - The JWT token to verify
37
+ * @param {Object} options - Verification options
38
+ * @returns {Object} Decoded payload
39
+ */
40
+ verify(token, options = {}) {
41
+ try {
42
+ const verifyOptions = {
43
+ algorithms: ['HS256'],
44
+ ...options
45
+ };
46
+
47
+ return jwt.verify(token, this.secretKey, verifyOptions);
48
+ } catch (error) {
49
+ if (error.name === 'TokenExpiredError') {
50
+ return false;
51
+ } else if (error.name === 'JsonWebTokenError') {
52
+ return false;
53
+ } else if (error.name === 'NotBeforeError') {
54
+ return false;
55
+ } else {
56
+ return false;
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Decode a JWT token without verification
63
+ * @param {string} token - The JWT token to decode
64
+ * @param {Object} options - Decode options
65
+ * @returns {Object} Decoded payload (not verified)
66
+ */
67
+ decode(token, options = {}) {
68
+ try {
69
+ return jwt.decode(token, options);
70
+ } catch (error) {
71
+ throw new Error(`JWT Decode Error: ${error.message}`);
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check if a token is expired without throwing an error
77
+ * @param {string} token - The JWT token to check
78
+ * @returns {boolean} True if token is expired, false otherwise
79
+ */
80
+ isExpired(token) {
81
+ try {
82
+ const decoded = this.decode(token);
83
+ if (!decoded || !decoded.exp) {
84
+ return true;
85
+ }
86
+
87
+ const currentTime = Math.floor(Date.now() / 1000);
88
+ return decoded.exp < currentTime;
89
+ } catch (error) {
90
+ return true;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Get token expiration time
96
+ * @param {string} token - The JWT token
97
+ * @returns {Date|null} Expiration date or null if invalid
98
+ */
99
+ getExpirationTime(token) {
100
+ try {
101
+ const decoded = this.decode(token);
102
+ if (!decoded || !decoded.exp) {
103
+ return null;
104
+ }
105
+
106
+ return new Date(decoded.exp * 1000);
107
+ } catch (error) {
108
+ return null;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Refresh a token by creating a new one with the same payload
114
+ * @param {string} token - The JWT token to refresh
115
+ * @param {Object} options - New token options
116
+ * @returns {string} New JWT token
117
+ */
118
+ refresh(token, options = {}) {
119
+ try {
120
+ const decoded = this.verify(token);
121
+
122
+ // Remove standard JWT claims that shouldn't be copied
123
+ const { iat, exp, nbf, jti, ...payload } = decoded;
124
+
125
+ return this.sign(payload, options);
126
+ } catch (error) {
127
+ throw new Error(`JWT Refresh Error: ${error.message}`);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Create a token with custom expiration
133
+ * @param {Object} payload - The payload to encode
134
+ * @param {string|number} expiresIn - Expiration time (e.g., '1h', '7d', 3600)
135
+ * @returns {string} JWT token
136
+ */
137
+ createToken(payload, expiresIn = this.defaultExpiresIn) {
138
+ return this.sign(payload, { expiresIn });
139
+ }
140
+
141
+ /**
142
+ * Create a short-lived token (e.g., for email verification)
143
+ * @param {Object} payload - The payload to encode
144
+ * @param {string|number} expiresIn - Expiration time (default: '15m')
145
+ * @returns {string} JWT token
146
+ */
147
+ createShortToken(payload, expiresIn = '15m') {
148
+ return this.sign(payload, { expiresIn });
149
+ }
150
+
151
+ /**
152
+ * Create a long-lived token (e.g., for refresh tokens)
153
+ * @param {Object} payload - The payload to encode
154
+ * @param {string|number} expiresIn - Expiration time (default: '30d')
155
+ * @returns {string} JWT token
156
+ */
157
+ createLongToken(payload, expiresIn = '30d') {
158
+ return this.sign(payload, { expiresIn });
159
+ }
160
+
161
+ /**
162
+ * Set a new secret key
163
+ * @param {string} secretKey - New secret key
164
+ */
165
+ setSecretKey(secretKey) {
166
+ this.secretKey = secretKey;
167
+ }
168
+
169
+ /**
170
+ * Get the current secret key (masked for security)
171
+ * @returns {string} Masked secret key
172
+ */
173
+ getSecretKey() {
174
+ return this.secretKey ? `${this.secretKey.substring(0, 4)}...` : 'Not set';
175
+ }
176
+ }
177
+
178
+ module.exports = JWT;
@@ -0,0 +1,7 @@
1
+ const knex = require('knex');
2
+
3
+ const config = require('@root/config/database');
4
+
5
+ const db = knex(config[process.env.NODE_ENV || 'development']);
6
+
7
+ module.exports = db;
@@ -0,0 +1,14 @@
1
+ const slugify = require('slugify')
2
+
3
+ const returnSlug = (title = "") => {
4
+ return slugify(title.toLowerCase(), {
5
+ replacement: '-', // replace spaces with replacement character, defaults to `-`
6
+ remove: undefined, // remove characters that match regex, defaults to `undefined`
7
+ lower: false, // convert to lower case, defaults to `false`
8
+ strict: false, // strip special characters except replacement, defaults to `false`
9
+ locale: 'en', // language code of the locale to use
10
+ trim: true // trim leading and trailing replacement chars, defaults to `true`
11
+ })
12
+ }
13
+
14
+ module.exports = returnSlug
@@ -0,0 +1,22 @@
1
+ const db = require('@root/libraries/knex');
2
+
3
+ class Store {
4
+ constructor() {
5
+ this.db = db;
6
+ this.currencies = new Map();
7
+ }
8
+
9
+ async init() {
10
+ await this.get_currencies();
11
+ }
12
+
13
+ async get_currencies() {
14
+ const currencies = await this.db('currencies').select('currency_id', 'name', 'code', 'symbol');
15
+ currencies.forEach(currency => {
16
+ this.currencies.set(currency.currency_id, currency);
17
+ });
18
+ return this.currencies;
19
+ }
20
+ }
21
+
22
+ module.exports = new Store();
@@ -0,0 +1,194 @@
1
+ const fs = require('fs');
2
+ const axios = require('axios');
3
+ const { randomChars, sleep } = require('./controls');
4
+ const uploadBase = __dirname + '/../uploads/'
5
+ const { resize: resizeImage } = require('./image')
6
+ const sizeOf = require('image-size');
7
+ const returnSlug = require('./slug')
8
+ const { uploadAws } = require('./aws');
9
+
10
+ const uploadFile = async (fileObject = {}, prefix = '', directory = '', resizeOpts = false) => {
11
+
12
+ try {
13
+
14
+ if (directory != '' && !fs.existsSync(uploadBase + directory)) {
15
+ await fs.mkdirSync(uploadBase + directory);
16
+ }
17
+
18
+ let fileExt = fileObject.filename.split('.')
19
+ fileExt = fileExt[fileExt.length - 1];
20
+ const fileName = returnSlug((prefix != '' ? prefix + '_' : '') + '_' + randomChars(16)) + '.' + fileExt
21
+ directory = directory != '' ? directory + '/' : ''
22
+
23
+ await fs.writeFileSync(uploadBase + directory + fileName, fileObject._buf)
24
+
25
+ return await createReturnData(fileName, directory, resizeOpts, fileObject)
26
+
27
+ } catch (error) {
28
+ return {
29
+ status: false,
30
+ error
31
+ }
32
+
33
+ }
34
+
35
+ }
36
+
37
+ const createReturnData = async (fileName = '', directory = '', resizeOpts = false, fileObject = false) => {
38
+
39
+ let returnData = {
40
+ status: false
41
+ }
42
+
43
+ let awsError = false
44
+
45
+ if (resizeOpts) {
46
+ returnData = await resizeImage(directory + fileName, resizeOpts, 90, directory.replace(/\//g, ''))
47
+ returnData.resize = true
48
+ } else {
49
+ let dimensions = {}
50
+
51
+ if(fileObject && fileObject.mimetype.includes('image')) {
52
+ try {
53
+ dimensions = sizeOf(uploadBase + directory + fileName)
54
+ } catch (error) {
55
+ dimensions = {}
56
+ }
57
+ }
58
+
59
+ returnData = {
60
+ status: true,
61
+ resize: false,
62
+ file: {
63
+ width: dimensions.width || 'none',
64
+ height: dimensions.height || 'none',
65
+ field: fileObject.fieldname,
66
+ encoding: fileObject.encoding,
67
+ mimetype: fileObject.mimetype,
68
+ fileUrl: directory + fileName
69
+ }
70
+ }
71
+ }
72
+
73
+ if(process.env.AWS_STATUS == 'true') {
74
+
75
+ await sleep(1000);
76
+
77
+ if (returnData.resize) {
78
+ if (returnData.files.length > 0) {
79
+ for (let rfi = 0; rfi < returnData.files.length; rfi++) {
80
+ const file = returnData.files[rfi];
81
+ let statusUploadAws = await uploadAws(file.fileUrl, fileObject.mimetype)
82
+
83
+ if(!statusUploadAws.status) {
84
+ awsError = {
85
+ status: false,
86
+ msg: "aws_upload_error"
87
+ }
88
+ }
89
+
90
+ fs.unlinkSync(uploadBase + file.fileUrl)
91
+ }
92
+ }
93
+ } else {
94
+ let statusUploadAws = await uploadAws(returnData.file.fileUrl, returnData.file.mimetype)
95
+
96
+ if (!statusUploadAws.status) {
97
+ awsError = {
98
+ status: false,
99
+ messages: "aws_upload_error"
100
+ }
101
+ }
102
+ fs.unlinkSync(uploadBase + returnData.file.fileUrl)
103
+ }
104
+ }
105
+
106
+ if (returnData.resize) {
107
+ fs.unlinkSync(uploadBase + directory + fileName)
108
+ }
109
+
110
+ if(awsError) {
111
+ return awsError
112
+ } else {
113
+ return returnData
114
+ }
115
+
116
+ }
117
+
118
+ const downloadFile = async (fileUrl = "", directory = '') => {
119
+
120
+ try {
121
+
122
+ if (directory != '' && !fs.existsSync(uploadBase + directory)) {
123
+ await fs.mkdirSync(uploadBase + directory);
124
+ }
125
+
126
+ const fileName = randomChars(3) + new Date().getTime() + '.jpg'
127
+ directory = directory != '' ? directory + '/' : ''
128
+
129
+ const writer = await fs.createWriteStream(uploadBase + directory + fileName);
130
+
131
+ axios({
132
+ method: 'GET',
133
+ url: fileUrl,
134
+ responseType: 'stream',
135
+ }).then(response => {
136
+
137
+ //ensure that the user can call `then()` only when the file has
138
+ //been downloaded entirely.
139
+
140
+ return new Promise((resolve, reject) => {
141
+
142
+ response.data.pipe(writer);
143
+ let error = null;
144
+
145
+ writer.on('error', err => {
146
+ error = err;
147
+ writer.close();
148
+ reject(err);
149
+ });
150
+
151
+ writer.on('close', () => {
152
+ if (!error) {
153
+ resolve(true);
154
+ }
155
+ //no need to call the reject here, as it will have been called in the
156
+ //'error' stream;
157
+ });
158
+ });
159
+ });
160
+
161
+ return createReturnData(fileName, directory, false)
162
+
163
+ } catch (error) {
164
+ return {
165
+ status: false,
166
+ messages: error
167
+ }
168
+ }
169
+ }
170
+
171
+ const deleteFile = async (fileName = '') => {
172
+
173
+ try {
174
+
175
+ if (fs.existsSync(uploadBase + fileName)) {
176
+ await fs.unlinkSync(uploadBase + fileName)
177
+ }
178
+
179
+ return {
180
+ status: true
181
+ }
182
+ } catch (error) {
183
+ return {
184
+ status: false
185
+ }
186
+ }
187
+
188
+ }
189
+
190
+ module.exports = {
191
+ uploadFile,
192
+ downloadFile,
193
+ deleteFile
194
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "record_not_found": "Record not found",
3
+ "internal_server_error": "Internal server error"
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "er_dup_entry": "Duplicate entry"
3
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "validation": {
3
+ "required": "The field '{field}' is required",
4
+ "minLength": "The field '{field}' must be at least {min} characters long",
5
+ "maxLength": "The field '{field}' must be at most {max} characters long",
6
+ "min": "The field '{field}' must be at least {min}",
7
+ "max": "The field '{field}' must be at most {max}",
8
+ "email": "The field '{field}' must be a valid email address",
9
+ "integer": "The field '{field}' must be an integer",
10
+ "string": "The field '{field}' must be a string",
11
+ "boolean": "The field '{field}' must be a boolean",
12
+ "enum": "The field '{field}' must be one of: {enum}",
13
+ "format": "The field '{field}' format is invalid",
14
+ "pattern": "The field '{field}' does not match the required pattern",
15
+ "unique": "The field '{field}' must be unique",
16
+ "exists": "The field '{field}' does not exist",
17
+ "invalid": "The field '{field}' is invalid",
18
+ "tooShort": "The field '{field}' is too short",
19
+ "tooLong": "The field '{field}' is too long",
20
+ "invalidEmail": "Please provide a valid email address",
21
+ "weakPassword": "Password must be at least 6 characters long",
22
+ "invalidRole": "Role must be one of: admin, user, moderator"
23
+ },
24
+ "errors": {
25
+ "validation": "Validation Error",
26
+ "server": "Internal Server Error",
27
+ "notFound": "Resource not found",
28
+ "unauthorized": "Unauthorized access",
29
+ "forbidden": "Access forbidden",
30
+ "conflict": "Resource conflict",
31
+ "badRequest": "Bad Request"
32
+ },
33
+ "messages": {
34
+ "userCreated": "User created successfully",
35
+ "userUpdated": "User updated successfully",
36
+ "userDeleted": "User deleted successfully",
37
+ "userNotFound": "User not found",
38
+ "emailExists": "Email already exists",
39
+ "invalidCredentials": "Invalid credentials",
40
+ "accessDenied": "Access denied",
41
+ "languageChanged": "Language changed to {language}",
42
+ "adminCreated": "Admin created successfully",
43
+ "adminUpdated": "Admin updated successfully",
44
+ "adminDeleted": "Admin deleted successfully",
45
+ "adminNotFound": "Admin not found",
46
+ "twoFactorEnabled": "Two-factor authentication enabled",
47
+ "twoFactorDisabled": "Two-factor authentication disabled",
48
+ "phoneVerified": "Phone number verified successfully",
49
+ "invalidVerificationCode": "Invalid verification code",
50
+ "verificationCodeExpired": "Verification code has expired"
51
+ }
52
+ }