flexbiz-server 12.3.30 → 12.3.32

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 (152) hide show
  1. package/install_centos7.sh +292 -22
  2. package/package.json +3 -2
  3. package/server/app.js +16 -15
  4. package/server/auths/local.js +32 -32
  5. package/server/cluster.js +23 -22
  6. package/server/controllers/controller.js +82 -73
  7. package/server/controllers/controllerRPT.js +7 -9
  8. package/server/controllers/controllerUtils.js +36 -36
  9. package/server/controllers/createHandler.js +34 -30
  10. package/server/controllers/deleteHandler.js +11 -11
  11. package/server/controllers/exportHandler.js +18 -18
  12. package/server/controllers/findHandler.js +36 -33
  13. package/server/controllers/importHandler.js +22 -22
  14. package/server/controllers/rptExcelHandler.js +5 -4
  15. package/server/controllers/rptHandler.js +11 -10
  16. package/server/controllers/updateFieldHandler.js +2 -2
  17. package/server/controllers/updateHandler.js +37 -33
  18. package/server/controllers/viewHandler.js +13 -13
  19. package/server/data/sys/listinfo.js +59661 -33452
  20. package/server/data/sys/menuinfo.js +24 -1
  21. package/server/data/sys/moduleinfo.js +9000 -520
  22. package/server/data/sys/reportinfo.js +1348 -1176
  23. package/server/flow/nodes/data.js +3 -4
  24. package/server/global.js +4 -3
  25. package/server/libs/WorkerStaticPool.js +12 -11
  26. package/server/libs/ckcn.js +11 -11
  27. package/server/libs/dktk.js +3 -3
  28. package/server/libs/dkvt.js +9 -8
  29. package/server/libs/docs.js +1 -0
  30. package/server/libs/dtbanletheosp.js +14 -14
  31. package/server/libs/getGiaban.js +34 -35
  32. package/server/libs/htmlReport.js +8 -6
  33. package/server/libs/invoiceEasy.js +109 -0
  34. package/server/libs/invoiceViettel.js +29 -0
  35. package/server/libs/invoiceVnpt.js +22 -0
  36. package/server/libs/mailmanagement.js +2 -2
  37. package/server/libs/permission.js +27 -25
  38. package/server/libs/post-book.js +13 -13
  39. package/server/libs/post-socai.js +22 -20
  40. package/server/libs/post-sokho.js +21 -18
  41. package/server/libs/prototypes.js +5 -6
  42. package/server/libs/redis-cache.js +1 -1
  43. package/server/libs/thnxt.js +9 -8
  44. package/server/libs/tinhhoahong.js +3 -3
  45. package/server/libs/tinhhoahongnpp.js +27 -27
  46. package/server/libs/tinhkhauhao1ts.js +1 -1
  47. package/server/libs/utils.js +62 -67
  48. package/server/libs/vsocai.js +6 -6
  49. package/server/models/app.js +6 -6
  50. package/server/models/approve.js +20 -22
  51. package/server/models/banggiaban.js +5 -4
  52. package/server/models/calllog.js +1 -1
  53. package/server/models/chamcong.js +4 -4
  54. package/server/models/checkin.js +3 -2
  55. package/server/models/customer.js +2 -2
  56. package/server/models/dmloaicong.js +2 -2
  57. package/server/models/dmnv.js +2 -2
  58. package/server/models/dmvt.js +11 -10
  59. package/server/models/email.js +2 -0
  60. package/server/models/hd2.js +14 -13
  61. package/server/models/hd3.js +11 -10
  62. package/server/models/hmcn.js +2 -2
  63. package/server/models/listinfo.js +262 -164
  64. package/server/models/mailaccount.js +3 -3
  65. package/server/models/notification.js +4 -3
  66. package/server/models/options.js +3 -2
  67. package/server/models/pcl.js +6 -0
  68. package/server/models/pgh.js +5 -0
  69. package/server/models/phucap.js +4 -3
  70. package/server/models/pn1.js +6 -6
  71. package/server/models/pnc.js +6 -5
  72. package/server/models/pnh.js +6 -5
  73. package/server/models/pxc.js +6 -5
  74. package/server/models/pxh.js +7 -6
  75. package/server/models/receivedinvoice.js +2 -0
  76. package/server/models/right.js +1 -1
  77. package/server/models/socai.js +13 -13
  78. package/server/models/sokho.js +19 -19
  79. package/server/models/tdttco.js +2 -2
  80. package/server/models/tdttco_tt.js +2 -2
  81. package/server/models/tdttno.js +2 -2
  82. package/server/models/tdttno_tt.js +2 -2
  83. package/server/models/user.js +21 -25
  84. package/server/models/warrantyclaim.js +2 -0
  85. package/server/models/warrantypolicy.js +1 -0
  86. package/server/modules/lists/ls-approve.js +2 -2
  87. package/server/modules/lists/ls-calllog.js +4 -1
  88. package/server/modules/lists/ls-checkin.js +12 -6
  89. package/server/modules/lists/ls-dmchietkhau.js +12 -11
  90. package/server/modules/lists/ls-dmnkh.js +5 -5
  91. package/server/modules/lists/ls-dmnv.js +2 -2
  92. package/server/modules/lists/ls-dmvt.js +25 -25
  93. package/server/modules/lists/ls-email.js +3 -0
  94. package/server/modules/lists/ls-mailaccount.js +5 -4
  95. package/server/modules/lists/ls-phucap.js +2 -1
  96. package/server/modules/public/callin.js +6 -5
  97. package/server/modules/public/subscribe.js +3 -3
  98. package/server/modules/reports/calc-tinhluong.js +22 -16
  99. package/server/modules/reports/rp-bkct.js +4 -4
  100. package/server/modules/reports/rp-cdpskh.js +6 -6
  101. package/server/modules/reports/rp-chitietchitientheohoadon.js +2 -2
  102. package/server/modules/reports/rp-chitiettaisan.js +7 -6
  103. package/server/modules/reports/rp-chitietthutientheohoadon.js +2 -2
  104. package/server/modules/reports/rp-ckcn.js +1 -1
  105. package/server/modules/reports/rp-ctbanle2.js +14 -14
  106. package/server/modules/reports/rp-dtbanlekempk.js +9 -0
  107. package/server/modules/reports/rp-dtbanletheoct.js +13 -11
  108. package/server/modules/reports/rp-dtbanletheoctkempk.js +26 -0
  109. package/server/modules/reports/rp-getdinhmuc4lenhcp.js +5 -5
  110. package/server/modules/reports/rp-getluong.js +8 -8
  111. package/server/modules/reports/rp-getluongchuyen.js +4 -4
  112. package/server/modules/reports/rp-phanbochitienchohoadon.js +2 -2
  113. package/server/modules/reports/rp-phanbothutienchohoadon.js +4 -4
  114. package/server/modules/reports/rp-sokho.js +7 -5
  115. package/server/modules/reports/rp-soquy.js +12 -7
  116. package/server/modules/reports/rp-sotaisan.js +1 -1
  117. package/server/modules/reports/rp-thbanhangkempk.js +29 -0
  118. package/server/modules/reports/rp-thnxt.js +12 -9
  119. package/server/modules/reports/rp-thnxt_sl.js +8 -8
  120. package/server/modules/reports/rp-thnxtnpp.js +7 -8
  121. package/server/modules/reports/rp-thnxttt.js +8 -8
  122. package/server/modules/systems/sys-app.js +18 -15
  123. package/server/modules/systems/sys-listinfo.js +7 -6
  124. package/server/modules/systems/sys-trangthai.js +3 -2
  125. package/server/modules/systems/sys-user.js +6 -6
  126. package/server/modules/systems/sys-users.js +8 -8
  127. package/server/modules/vouchers/vo-bc1.js +8 -8
  128. package/server/modules/vouchers/vo-dh2.js +9 -9
  129. package/server/modules/vouchers/vo-hd2.js +95 -103
  130. package/server/modules/vouchers/vo-hd3.js +46 -38
  131. package/server/modules/vouchers/vo-htl.js +8 -9
  132. package/server/modules/vouchers/vo-pbl.js +47 -47
  133. package/server/modules/vouchers/vo-pcl.js +8 -0
  134. package/server/modules/vouchers/vo-pgh.js +19 -0
  135. package/server/modules/vouchers/vo-pn1.js +31 -29
  136. package/server/modules/vouchers/vo-pnc.js +19 -18
  137. package/server/modules/vouchers/vo-pnh.js +16 -13
  138. package/server/modules/vouchers/vo-pt1.js +16 -16
  139. package/server/modules/vouchers/vo-ptl.js +7 -8
  140. package/server/modules/vouchers/vo-pxc.js +22 -20
  141. package/server/modules/vouchers/vo-pxh.js +24 -11
  142. package/server/modules/vouchers/vo-qts.js +1 -1
  143. package/server/modules/vouchers/vo-so1.js +9 -9
  144. package/server/modules/vouchers/vo-so7.js +10 -10
  145. package/server/modules/vouchers/vo-so9.js +7 -7
  146. package/server/route.js +50 -50
  147. package/server/services/invoiceFetcher.js +15 -0
  148. package/server/workers/customerOnImport.js +3 -3
  149. package/server/workers/inputWorker.js +1 -1
  150. package/server/workers/pushNotify.js +5 -4
  151. package/server/workers/reportWorker.js +2 -2
  152. package/server/workers/restoreApp.js +18 -17
@@ -7,7 +7,6 @@ sudo yum update -y
7
7
  sudo yum install -y epel-release
8
8
  echo "Cập nhật hệ thống hoàn tất."
9
9
 
10
- ---
11
10
 
12
11
  # --- Cài đặt MongoDB (Phiên bản mới nhất - 7.0) ---
13
12
  echo ""
@@ -54,7 +53,6 @@ sudo systemctl start mongod
54
53
  sudo systemctl enable mongod
55
54
  echo "Cài đặt MongoDB hoàn tất."
56
55
 
57
- ---
58
56
 
59
57
  # --- Cài đặt Redis và cấu hình vĩnh viễn ---
60
58
  echo ""
@@ -69,23 +67,23 @@ REDIS_CONF="/etc/redis.conf"
69
67
  # stop-writes-on-bgsave-error
70
68
  if ! grep -q "stop-writes-on-bgsave-error no" "$REDIS_CONF"; then
71
69
  sudo sed -i 's/^stop-writes-on-bgsave-error yes/stop-writes-on-bgsave-error no/' "$REDIS_CONF"
72
- if ! grep -q "stop-writes-on-bgsave-error no" "$REDIS_CONF"; then
70
+ if ! grep -q "stop-writes-on-bgsave-error no" "$REDIS_CONF"; then # Nếu không có yes/no nào thì thêm mới
73
71
  echo "stop-writes-on-bgsave-error no" | sudo tee -a "$REDIS_CONF"
74
72
  fi
75
73
  fi
76
74
 
77
75
  # dir và dbfilename
78
- # if grep -q "^dir " "$REDIS_CONF"; then
79
- # sudo sed -i 's|^dir .*|dir /home|' "$REDIS_CONF"
80
- # else
81
- # echo "dir /home" | sudo tee -a "$REDIS_CONF"
82
- # fi
83
-
84
- # if grep -q "^dbfilename " "$REDIS_CONF"; then
85
- # sudo sed -i 's/^dbfilename .*/dbfilename temp.rdb/' "$REDIS_CONF"
86
- # else
87
- # echo "dbfilename temp.rdb" | sudo tee -a "$REDIS_CONF"
88
- # fi
76
+ if grep -q "^dir " "$REDIS_CONF"; then
77
+ sudo sed -i 's|^dir .*|dir /home|' "$REDIS_CONF"
78
+ else
79
+ echo "dir /home" | sudo tee -a "$REDIS_CONF"
80
+ fi
81
+
82
+ if grep -q "^dbfilename " "$REDIS_CONF"; then
83
+ sudo sed -i 's/^dbfilename .*/dbfilename temp.rdb/' "$REDIS_CONF"
84
+ else
85
+ echo "dbfilename temp.rdb" | sudo tee -a "$REDIS_CONF"
86
+ fi
89
87
 
90
88
  # Vô hiệu hóa lưu dữ liệu vào đĩa (CẢNH BÁO: Mất dữ liệu khi khởi động lại)
91
89
  # Vô hiệu hóa appendonly
@@ -96,9 +94,8 @@ elif ! grep -q "^appendonly no" "$REDIS_CONF"; then
96
94
  fi
97
95
 
98
96
  # Vô hiệu hóa save
99
- # Xóa tất cả các dòng save cũ và thêm dòng save rỗng
100
- sudo sed -i '/^save /d' "$REDIS_CONF"
101
- echo "save \"\"" | sudo tee -a "$REDIS_CONF"
97
+ sudo sed -i '/^save /d' "$REDIS_CONF" # Xóa tất cả các dòng save cũ
98
+ echo "save \"\"" | sudo tee -a "$REDIS_CONF" # Thêm dòng save rỗng
102
99
 
103
100
  # Cấu hình vm.overcommit_memory để tránh lỗi "Cannot allocate memory"
104
101
  echo "Cấu hình vm.overcommit_memory..."
@@ -111,7 +108,6 @@ sudo systemctl start redis
111
108
  sudo systemctl enable redis
112
109
  echo "Cài đặt Redis và cấu hình hoàn tất."
113
110
 
114
- ---
115
111
 
116
112
  # --- Cài đặt Node.js (Phiên bản LTS mới nhất) ---
117
113
  echo ""
@@ -124,7 +120,6 @@ fi
124
120
  sudo yum install -y nodejs
125
121
  echo "Cài đặt Node.js hoàn tất."
126
122
 
127
- ---
128
123
 
129
124
  # --- Cài đặt PM2 ---
130
125
  echo ""
@@ -137,7 +132,6 @@ if ! sudo systemctl is-enabled pm2-$(whoami) &>/dev/null; then
137
132
  fi
138
133
  echo "Cài đặt PM2 hoàn tất."
139
134
 
140
- ---
141
135
 
142
136
  # --- Cài đặt Nginx và cấu hình SELinux ---
143
137
  echo ""
@@ -162,7 +156,6 @@ if ! getsebool httpd_can_network_connect | grep -q "on"; then
162
156
  fi
163
157
  echo "Cài đặt Nginx và cấu hình SELinux hoàn tất."
164
158
 
165
- ---
166
159
 
167
160
  # --- Tạo 20GB RAM ảo (Swap Space) ---
168
161
  echo ""
@@ -186,9 +179,286 @@ else
186
179
  fi
187
180
  echo "Tạo 20GB RAM ảo hoàn tất."
188
181
 
182
+
183
+ # --- Tạo dự án Node.js và cấu hình Babel Build ---
184
+ echo ""
185
+ echo "--- Bắt đầu tạo dự án Node.js và cấu hình Babel Build ---"
186
+
187
+ # Lấy đường dẫn của script hiện tại
188
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
189
+
190
+ # Hỏi tên dự án từ người dùng
191
+ read -p "Nhập tên dự án Node.js của bạn (mặc định: flexbiz-server): " PROJECT_NAME
192
+ PROJECT_NAME=${PROJECT_NAME:-flexbiz-server} # Đặt giá trị mặc định nếu người dùng không nhập gì
193
+
194
+ PROJECT_PATH="$SCRIPT_DIR/$PROJECT_NAME"
195
+
196
+ # Kiểm tra xem thư mục dự án đã tồn tại chưa
197
+ if [ -d "$PROJECT_PATH" ]; then
198
+ echo "Thư mục dự án '$PROJECT_NAME' đã tồn tại tại '$PROJECT_PATH'."
199
+ echo "Bỏ qua việc tạo dự án và cài đặt dependencies/cấu hình ban đầu."
200
+ cd "$PROJECT_PATH" || { echo "Lỗi: Không thể chuyển đến thư mục dự án đã tồn tại."; exit 1; }
201
+ else
202
+ echo "Tạo thư mục dự án: $PROJECT_PATH"
203
+ mkdir -p "$PROJECT_PATH"
204
+
205
+ echo "Chuyển đến thư mục dự án và khởi tạo Node.js project..."
206
+ cd "$PROJECT_PATH" || { echo "Lỗi: Không thể chuyển đến thư mục dự án."; exit 1; }
207
+
208
+ npm init -y # Khởi tạo package.json với các giá trị mặc định
209
+
210
+ echo "Cài đặt các dependencies và devDependencies..."
211
+ npm install "blocked-at@^1.2.0" "flexbiz-server@latest" "http-proxy-middleware@3.0.5" # dependencies
212
+ npm install --save-dev "@babel/cli" "@babel/core" "@babel/node" "@babel/preset-env" # devDependencies
213
+ npm i -g "web-push"
214
+
215
+
216
+ echo "Tạo file .babelrc..."
217
+ cat << EOF > "$PROJECT_PATH/.babelrc"
218
+ {
219
+ "presets": ["@babel/preset-env"]
220
+ }
221
+ EOF
222
+
223
+ echo "Tạo thư mục src và file src/index.js..."
224
+ mkdir -p "$PROJECT_PATH/src"
225
+ cat << 'EOF_INDEXJS' > "$PROJECT_PATH/src/index.js"
226
+ import express from "express";
227
+ import Server from 'flexbiz-server/server/app';
228
+ const configs = require("./configs");
229
+
230
+ const app = express();
231
+
232
+ // Áp dụng các cấu hình
233
+ configs.use_ssl = false;
234
+ configs.BLOCKCHAIN_SOCKET = false;
235
+ configs.limitRequestSize = '50mb';
236
+ configs.limitFileSize = 1024*1024*50;
237
+ configs.has_api_barcode = true;
238
+ configs.createIndexes = true;
239
+
240
+ const port = process.argv[2] || 9999;
241
+ console.log("file start with port", port);
242
+
243
+ Server(app, {
244
+ configs,
245
+ port,
246
+ input_cpus: 4,
247
+ import_cpus: 1,
248
+ report_cpus: 1,
249
+ createRedisCache: true,
250
+ useSocket: true,
251
+ useAgenda: false,
252
+ cluster: false,
253
+ });
254
+ EOF_INDEXJS
255
+
256
+ echo "Tạo file src/configs.js (placeholder)..."
257
+ cat << 'EOF_CONFIGSJS' > "$PROJECT_PATH/src/configs.js"
258
+ // Đây là một file configs.js placeholder.
259
+ // Bạn cần thay đổi nội dung này với các cấu hình thực tế của mình.
260
+ exports.domain = 'localhost';
261
+ exports.api_url = 'http://localhost';
262
+ exports.home_url = 'http://localhost';
263
+
264
+ //Các domain không hạn chế quyền truy cập. Có thể khai báo trong api domain
265
+ exports.trust_domains = "";
266
+ exports.trust_keys =[];
267
+
268
+ exports.company = 'Tên công ty';
269
+ exports.program = "";
270
+ exports.version = "7.0.1";
271
+ exports.PORT = '443';
272
+ exports.use_ssl = true;
273
+ exports.trust_proxy = true;
274
+ exports.check_expire_date = false;//Kiểm tra hạn sử dụng của công ty
275
+ exports.timezone = 'Asia/Ho_Chi_Minh';
276
+ exports.initSysData = false;
277
+ exports.limitRequestSize = '5mb';
278
+ exports.limitFileSize = 1024*1024*2;
279
+ exports.limitRowImport = 20000;//giới hạn số dòng mỗi lần import
280
+
281
+ exports.cryptoPassword = 'ABC@1';//khoá dùng để mã hoá dữ liệu. cần thay đổi thông tin này
282
+ exports.MAX_TRY_OTP =3;
283
+
284
+ //maxLag for toobusy
285
+ exports.maxLag = 5000;
286
+
287
+ exports.check_token_expired = false;//Kiểm tra hạn sử dụng của token
288
+ exports.require_verify = false;//Yêu cầu user phải xác thực tài khoản trước khi sử dụng
289
+ exports.use_pin_as_otp = false;//Sử dụng mã pin thay cho OTP
290
+
291
+ exports.APP_SECRET = "";
292
+ //Token của user public
293
+ exports.public_token = "flex.public.token";
294
+ //Key để push thông báo qua website: use tool of webPush to create a vapidkeys. just need to run: web-push generate-vapid-keys --json
295
+ exports.vapidKeys = {"publicKey":"","privateKey":""}
296
+ //recaptcha
297
+ exports.GOOGLE_RECAPTCHA_SECRET_KEY = "";
298
+ //sử đụng google transtale api để tự động dịch label hay tin tức
299
+ exports.GOOGLE_TRANSLATE_API_KEY = "";
300
+ //đường dẫn các thư mục chứa source code và tài nguyên của hệ thống
301
+ exports.paths={
302
+ public:__dirname + "/public",
303
+ modules:__dirname + "/modules",
304
+ models:__dirname + "/models",
305
+ templates: __dirname + "/templates",
306
+ images: __dirname + "/images",
307
+ videos: __dirname + "/videos",
308
+ uploads: __dirname + "/uploads",
309
+ log: __dirname + "/log",
310
+ admin: "",
311
+ maps:"",
312
+ workers:""
313
+ }
314
+ //Cấu hình giới hạn băng thông truy cập
315
+ exports.limitRequest={
316
+ api:{
317
+ duration: 1,//seconds
318
+ points: 1000,
319
+ blockDuration:0,//seconds
320
+ },
321
+ sys:{
322
+ duration: 1,//seconds
323
+ points: 1000,
324
+ blockDuration:0,//seconds
325
+ },
326
+ public:{
327
+ duration: 1,//seconds
328
+ points: 1000,
329
+ blockDuration:0,//seconds
330
+ },
331
+ //required
332
+ auth:{
333
+ duration: 1,//seconds
334
+ points: 1000,
335
+ blockDuration:0,//seconds
336
+ },
337
+ //required
338
+ other:{
339
+ duration: 1,//seconds
340
+ points: 1000,
341
+ blockDuration:0,//seconds
342
+ },
343
+ }
344
+ //Cấu hình smtp để gửi email thông báo mặc định. Có thể cấu hình cho từng công ty thông qua màn hình khai báo thông tin công ty
345
+ exports.sender = {
346
+ "host": "",
347
+ "port": 465,
348
+ "requireTLS": true,
349
+ "tls": {
350
+ "ciphers": 'SSLv3'
351
+ },
352
+ "secureConnection": false,
353
+ "auth": {
354
+ "user": "",
355
+ "pass": ""
356
+ },
357
+ "name":"System"
358
+ }
359
+ exports.sender_otp = exports.sender;
360
+ //Tự động tạo user ADMIN
361
+ exports.adminUsers = [
362
+ {
363
+ email: 'admin',
364
+ name: 'Admin',
365
+ defaultPassword: 'admin@123456'
366
+ }
367
+ ];
368
+ //Admin hệ thống cao nhất
369
+ exports.supperAdmin = "admin";
370
+ //Các admin phụ
371
+ exports.subAdmins = [];
372
+ //User Partners
373
+ exports.partnerUsers = [];
374
+ //
375
+ exports.admins =exports.adminUsers.map(u=>u.email)
376
+ exports.partners = exports.partnerUsers.map(u=>u.email);
377
+ //Danh sách các user support hệ thống: là các admin và subAdmins
378
+ exports.supportUsers = [...exports.admins,...exports.subAdmins];
379
+ console.log("support users",exports.supportUsers);
380
+ //cấu hình sms dùng để gửi tin nhắn OTP
381
+ exports.sms = {
382
+ send: async (Phone,otp_code,id_app)=>{
383
+ let Brandname="";
384
+ let Content =``;
385
+ let ApiKey = "";
386
+ let SecretKey = "";
387
+ let SmsType ="2";
388
+ let url = ``
389
+
390
+ const axios = require('axios');
391
+ try{
392
+ let data = (await axios.get(url)).data;
393
+ if(data.CodeResult=="100"){
394
+ return data;
395
+ }else{
396
+ throw data.message || data.ErrorMessage || data.error || data;
397
+ }
398
+ }catch(e){
399
+ console.error("send sms",e);
400
+ throw e.message || e.ErrorMessage || e;
401
+ }
402
+ }
403
+ }
404
+ //openapi key dùng để kết nối với chatgpt
405
+ exports.openapi_key = "";
406
+
407
+ //google key để đọc file google document và các dịch vụ khác của google
408
+ exports.google_credentials = {
409
+
410
+ }
411
+ //Cấu hình đăng nhập bằng google nếu cần
412
+ exports.google = {
413
+ clientID: '',
414
+ clientSecret: '',
415
+ callbackURL: exports.domain + '/auth/google/callback',
416
+ scope: ['profile', 'email', 'https://www.googleapis.com/auth/drive']
417
+ };
418
+ //Cấu hình đăng nhập bằng facebook nếu cần
419
+ exports.facebook = {
420
+ clientID: '',
421
+ clientSecret: '',
422
+ callbackURL: exports.domain + '/auth/facebook/callback',
423
+ scope: ['email']
424
+ };
425
+ //Cấu hình database
426
+ exports.database = {
427
+ url: 'mongodb://127.0.0.1/flexbiz'
428
+ };
429
+ EOF_CONFIGSJS
430
+
431
+ echo "Cập nhật scripts trong package.json..."
432
+ # Cài đặt jq nếu chưa có
433
+ if ! command -v jq &> /dev/null; then
434
+ echo "Cài đặt jq để chỉnh sửa package.json..."
435
+ sudo yum install -y jq
436
+ fi
437
+
438
+ # Cập nhật script "build"
439
+ jq '.scripts.build = "babel src -d dist"' package.json > temp.json && mv temp.json package.json
440
+ # Cập nhật script "start" để chạy code đã biên dịch
441
+ jq '.scripts.start = "NODE_ENV=production NODE_OPTIONS=--max-old-space-size=2000 node dist/index.js"' package.json > temp.json && mv temp.json package.json
442
+ # Cập nhật script "dev" để chạy với babel-node (cho phát triển)
443
+ jq '.scripts.dev = "NODE_OPTIONS=--max-old-space-size=2000 babel-node src/index.js"' package.json > temp.json && mv temp.json package.json
444
+
445
+ # Xóa script "test" mặc định nếu nó còn là "echo \"Error: no test specified\" && exit 1"
446
+ if grep -q '"test": "echo \\"Error: no test specified\\" && exit 1"' package.json; then
447
+ jq 'del(.scripts.test)' package.json > temp.json && mv temp.json package.json
448
+ fi
449
+
450
+ echo "Dự án Node.js '$PROJECT_NAME' đã được tạo và các dependencies đã được cài đặt tại $PROJECT_PATH."
451
+ echo "Để biên dịch code, chạy: npm run build"
452
+ echo "Để chạy code đã biên dịch (production), chạy: npm start"
453
+ echo "Để chạy code trực tiếp với Babel (development), chạy: npm run dev"
454
+ echo "QUAN TRỌNG: Hãy chỉnh sửa file $PROJECT_PATH/src/configs.js với cấu hình thực tế của bạn."
455
+ fi
456
+
189
457
  echo ""
190
458
  echo "========================================"
191
459
  echo "Tất cả phần mềm và cấu hình đã được cài đặt thành công!"
460
+ echo "Dự án Node.js của bạn được tạo tại: $PROJECT_PATH"
461
+ echo "Để chạy dự án, hãy chuyển đến thư mục $PROJECT_PATH và chạy: npm start"
192
462
  echo "Kiểm tra trạng thái:"
193
463
  echo "MongoDB: systemctl status mongod"
194
464
  echo "Redis: systemctl status redis"
@@ -200,7 +470,7 @@ echo "SELinux httpd_can_network_connect: getsebool httpd_can_network_connect"
200
470
  echo "Redis: redis-cli config get stop-writes-on-bgsave-error"
201
471
  echo "Redis: redis-cli config get dir"
202
472
  echo "Redis: redis-cli config get dbfilename"
203
- echo "Redis: redis-cli config get appendonly"
204
473
  echo "Redis: redis-cli config get save"
474
+ echo "Redis: redis-cli config get appendonly"
205
475
  echo "MongoDB LimitNOFILE: systemctl show mongod | grep LimitNOFILE"
206
476
  echo "========================================"
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "flexbiz-server",
3
3
  "main": "./server/app.js",
4
4
  "description": "Flexible Server",
5
- "version": "12.3.30",
5
+ "version": "12.3.32",
6
6
  "author": {
7
7
  "name": "Van Truong Pham",
8
8
  "email": "invncur@gmail.com"
@@ -41,6 +41,7 @@
41
41
  "google-auth-library": "^9.15.1",
42
42
  "google-translate": "^3.0.0",
43
43
  "googleapis": "^144.0.0",
44
+ "imapflow": "^1.1.0",
44
45
  "jsonwebtoken": "^8.5.1",
45
46
  "jspdf": "^2.1.1",
46
47
  "jszip": "^3.1.5",
@@ -52,7 +53,7 @@
52
53
  "moment-timezone": "^0.5.33",
53
54
  "mongodb-backup": "^1.6.9",
54
55
  "mongodb-restore": "^1.6.2",
55
- "mongoose": "^5.12.14",
56
+ "mongoose": "^8.17.1",
56
57
  "morgan": "^1.10.0",
57
58
  "multer": "^0.1.8",
58
59
  "natives": "^1.1.6",
package/server/app.js CHANGED
@@ -1,21 +1,22 @@
1
1
  'use strict';require("events").EventEmitter.defaultMaxListeners=1E7;
2
2
  const os=require("os"),express=require("express"),bodyParser=require("body-parser"),passport=require("passport"),https=require("https"),http=require("http"),fs=require("fs"),cors=require("cors"),_global=require("./global"),defaultConfigs=require("./defaultConfigs"),crypto=require("crypto"),mainServer=function($app$$,$options$$={cluster:!0,port:443,useSocket:!0},$callbackServer$$=null){const $configs$$=global.configs={...defaultConfigs,...$options$$.configs,lite:$options$$.lite},$User$$=global.getModel("user");
3
- $configs$$.admins||($configs$$.admins=$configs$$.adminUsers.map($u$$=>$u$$.email));$configs$$.supportUsers||($configs$$.supportUsers=[...$configs$$.admins]);$configs$$.public_token||($configs$$.public_token="flex.public.token");global.port=$options$$.port||$configs$$.PORT||443;require("moment-timezone").tz.setDefault($configs$$.timezone||"Asia/Ho_Chi_Minh");$app$$||($app$$=express());$app$$.set("trust proxy",1);const $toobusy$$=require("toobusy-js");$configs$$.maxLag&&$toobusy$$.maxLag($configs$$.maxLag);
4
- $app$$.use(function($req$$,$res$$,$next$$){$toobusy$$()?(console.error("Server is busy right now. This request has been cancel:",$req$$.originalUrl),$res$$.status(503).send({error:"Server is busy right now, sorry."})):$next$$()});var $compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("express-session");$app$$.use($compress_cookieParser_morgan_multer_root_dir_uploads_session$$({secret:"QV098PVT123456HLBN",resave:!1,saveUninitialized:!0,cookie:{secure:!1}}));$compress_cookieParser_morgan_multer_root_dir_uploads_session$$=
5
- require("cookie-parser");$app$$.use($compress_cookieParser_morgan_multer_root_dir_uploads_session$$());$app$$.use(function($req$$,$res$$,$next$$){let $uid$$=$req$$.cookies.uid;$uid$$||($uid$$=$req$$.headers.uid);$uid$$||($uid$$="uid:"+crypto.randomBytes(20).toString("hex"),$res$$.cookie("uid",$uid$$,{expires:new Date(Date.now()+31536E6),sameSite:"none",secure:!0}));$res$$.set("uid",$uid$$);$req$$.cookies.uid=$uid$$;$next$$()});$compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("compression");
6
- $app$$.use($compress_cookieParser_morgan_multer_root_dir_uploads_session$$());$compress_cookieParser_morgan_multer_root_dir_uploads_session$$=$configs$$.paths.uploads||__dirname+"/uploads";const $limitFileSize$$=$configs$$.limitFileSize||1048576;$app$$.use(function($req$jscomp$2_size$$,$res$$,$next$$){if(($req$jscomp$2_size$$=$req$jscomp$2_size$$.headers["content-lenght"])&&$req$jscomp$2_size$$>$limitFileSize$$)return $res$$.status(400).send({error:"File too large"});$next$$()});$compress_cookieParser_morgan_multer_root_dir_uploads_session$$=
7
- require("multer")({dest:$compress_cookieParser_morgan_multer_root_dir_uploads_session$$,limits:{files:1,fileSize:$limitFileSize$$}});$app$$.use($compress_cookieParser_morgan_multer_root_dir_uploads_session$$);$app$$.use(cors({credentials:!0,exposedHeaders:["set-cookie","uid"],origin:($origin$$,$callback$$)=>{$callback$$(null,!0)}}));$configs$$.paths||($configs$$.paths={});!0!==$options$$.lite&&($app$$.use("/",express.static($configs$$.paths.public||__dirname+"/public")),$app$$.use("/admin",express.static($configs$$.paths.admin||
8
- __dirname+"/admin")),$app$$.use("/templates",express.static($configs$$.paths.templates||__dirname+"/templates")),$app$$.use("/images",express.static($configs$$.paths.images||__dirname+"/images")));$app$$.use(bodyParser.json({limit:$configs$$.limitRequestSize||"1mb"}));$app$$.use(bodyParser.urlencoded({limit:$configs$$.limitRequestSize||"1mb",extended:!0}));$app$$.use(passport.initialize());$compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("morgan");var $accessLogStream_rfs$$=
9
- require("rotating-file-stream");const $logDirectory$$=$configs$$.paths.log||__dirname+"/log";fs.existsSync($logDirectory$$)||fs.mkdirSync($logDirectory$$);$accessLogStream_rfs$$=$accessLogStream_rfs$$("access.log",{interval:"1d",path:$logDirectory$$});$app$$.use($compress_cookieParser_morgan_multer_root_dir_uploads_session$$("combined",{stream:$accessLogStream_rfs$$,skip:function($req$$,$res$$){return 400>$res$$.statusCode}}));$app$$.use(function($err$$,$req$$,$res$$,$next$$){console.error($err$$.stack);
10
- $res$$.status(500).send("Server Error!")});global.mongoose.connect($configs$$.database.url,{useNewUrlParser:!0}).then(async()=>{console.log("Connected to Database");const $redis$$=require("redis");global.clientRedis=$redis$$.createClient();global.clientRedis.on("error",$err$$=>console.error("Redis Client Error",$err$$));global.clientRedis.on("end",()=>{console.error("Redis connection closed.")});global.clientRedis.on("connect",function(){console.log("redis connected");0!=$options$$.createRedisCache&&
3
+ $configs$$.admins||($configs$$.admins=$configs$$.adminUsers.map($u$$=>$u$$.email));$configs$$.supportUsers||($configs$$.supportUsers=[...$configs$$.admins]);$configs$$.public_token||($configs$$.public_token="flex.public.token");var $_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=$options$$.port||$configs$$.port||$configs$$.PORT||443;$configs$$.port=$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$;global.port=$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$;
4
+ require("moment-timezone").tz.setDefault($configs$$.timezone||"Asia/Ho_Chi_Minh");$app$$||($app$$=express());$app$$.set("trust proxy",1);const $toobusy$$=require("toobusy-js");$configs$$.maxLag&&$toobusy$$.maxLag($configs$$.maxLag);$app$$.use(function($req$$,$res$$,$next$$){$toobusy$$()?(console.error("Server is busy right now. This request has been cancel:",$req$$.originalUrl),$res$$.status(503).send({error:"Server is busy right now, sorry."})):$next$$()});$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=
5
+ require("express-session");$app$$.use($_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$({secret:"QV098PVT123456HLBN",resave:!1,saveUninitialized:!0,cookie:{secure:!1}}));$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("cookie-parser");$app$$.use($_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$());$app$$.use(function($req$$,$res$$,$next$$){let $uid$$=$req$$.cookies.uid;$uid$$||($uid$$=$req$$.headers.uid);$uid$$||($uid$$="uid:"+
6
+ crypto.randomBytes(20).toString("hex"),$res$$.cookie("uid",$uid$$,{expires:new Date(Date.now()+31536E6),sameSite:"none",secure:!0}));$res$$.set("uid",$uid$$);$req$$.cookies.uid=$uid$$;$next$$()});$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("compression");$app$$.use($_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$());$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=$configs$$.paths.uploads||__dirname+"/uploads";const $limitFileSize$$=
7
+ $configs$$.limitFileSize||1048576;$app$$.use(function($req$jscomp$2_size$$,$res$$,$next$$){if(($req$jscomp$2_size$$=$req$jscomp$2_size$$.headers["content-lenght"])&&$req$jscomp$2_size$$>$limitFileSize$$)return $res$$.status(400).send({error:"File too large"});$next$$()});$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("multer")({dest:$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$,limits:{files:1,fileSize:$limitFileSize$$}});$app$$.use($_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$);
8
+ $app$$.use(cors({credentials:!0,exposedHeaders:["set-cookie","uid"],origin:($origin$$,$callback$$)=>{$callback$$(null,!0)}}));$configs$$.paths||($configs$$.paths={});!0!==$options$$.lite&&($app$$.use("/",express.static($configs$$.paths.public||__dirname+"/public")),$app$$.use("/admin",express.static($configs$$.paths.admin||__dirname+"/admin")),$app$$.use("/templates",express.static($configs$$.paths.templates||__dirname+"/templates")),$app$$.use("/images",express.static($configs$$.paths.images||__dirname+
9
+ "/images")));$app$$.use(bodyParser.json({limit:$configs$$.limitRequestSize||"1mb"}));$app$$.use(bodyParser.urlencoded({limit:$configs$$.limitRequestSize||"1mb",extended:!0}));$app$$.use(passport.initialize());$_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$=require("morgan");var $accessLogStream_rfs$$=require("rotating-file-stream");const $logDirectory$$=$configs$$.paths.log||__dirname+"/log";fs.existsSync($logDirectory$$)||fs.mkdirSync($logDirectory$$);$accessLogStream_rfs$$=
10
+ $accessLogStream_rfs$$("access.log",{interval:"1d",path:$logDirectory$$});$app$$.use($_port_compress_cookieParser_morgan_multer_root_dir_uploads_session$$("combined",{stream:$accessLogStream_rfs$$,skip:function($req$$,$res$$){return 400>$res$$.statusCode}}));$app$$.use(function($err$$,$req$$,$res$$,$next$$){console.error($err$$.stack);$res$$.status(500).send("Server Error!")});global.mongoose.connect($configs$$.database.url,{useNewUrlParser:!0}).then(async()=>{console.log("[app] Connected to Database");
11
+ const $redis$$=require("redis"),{retryStrategyRedis:$retryStrategyRedis$$}=require("./libs/utils");global.clientRedis=$redis$$.createClient({host:"127.0.0.1",port:6379,retry_strategy:$retryStrategyRedis$$});global.clientRedis.on("error",$err$$=>console.error("Redis Client Error",$err$$));global.clientRedis.on("end",()=>{console.error("[app] Redis connection closed.")});global.clientRedis.on("connect",function(){console.log("[app] redis connected");$User$$.initClientSockets();0!=$options$$.createRedisCache&&
11
12
  require("./libs/redis-cache").set();$options$$.start_abci_handler&&global.getModel("assabcihandler").start();!0!==$options$$.lite?require("./route")($app$$,()=>{if(!1!==$options$$.createServer){var $StaticPool$jscomp$0$$=require("sticky-session");$configs$$.use_ssl?($cpus_report_cpus_server_sslConfig$$=require("./sslConfig"),$cpus_report_cpus_server_sslConfig$$=https.createServer($cpus_report_cpus_server_sslConfig$$($options$$.sslDir),$app$$)):$cpus_report_cpus_server_sslConfig$$=http.createServer($app$$);
12
- $cpus_report_cpus_server_sslConfig$$.timeout=6E5;!1!==$options$$.useSocket?$User$$.initSocket($cpus_report_cpus_server_sslConfig$$):$User$$.initClientSockets();if(!1!==$options$$.cluster){if(!$StaticPool$jscomp$0$$.listen($cpus_report_cpus_server_sslConfig$$,global.port))$cpus_report_cpus_server_sslConfig$$.once("listening",function(){console.log("server started on",global.port)});$StaticPool$jscomp$0$$=require("cluster");$StaticPool$jscomp$0$$.on("exit",function($worker$$,$code$$,$signal$$){console.error("worker "+
13
- $worker$$.process.pid+" died",$code$$,$signal$$)});$StaticPool$jscomp$0$$.on("online",function($worker$$){console.info("worker "+$worker$$.process.pid+" is online")})}else $cpus_report_cpus_server_sslConfig$$.listen(global.port,()=>{console.log("server start at "+global.port+" port")})}var $cpus_report_cpus_server_sslConfig$$=os.cpus().length;$StaticPool$jscomp$0$$=$options$$.import_cpus||($options$$.start_import_data_pool?$options$$.start_report_pool||$options$$.start_input_data_pool?1:Math.round($cpus_report_cpus_server_sslConfig$$/
14
- 2):0);var $StaticPool$jscomp$1$$=$options$$.input_cpus||($options$$.start_input_data_pool?Math.max(Math.round($cpus_report_cpus_server_sslConfig$$/2),2):0);$cpus_report_cpus_server_sslConfig$$=$options$$.report_cpus||($options$$.start_import_data_pool?Math.max(Math.min($cpus_report_cpus_server_sslConfig$$-$StaticPool$jscomp$1$$-$StaticPool$jscomp$0$$,Math.round($cpus_report_cpus_server_sslConfig$$/2))-1,2):0);if($StaticPool$jscomp$1$$){const $StaticPool$$=require("./libs/WorkerStaticPool");global.inputMainPool=
15
- new $StaticPool$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$jscomp$1$$,3E5,$StaticPool$jscomp$1$$,"input pool");global.inputMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{console.error("Crud pool ready")})}$StaticPool$jscomp$0$$&&($StaticPool$jscomp$1$$=require("./libs/WorkerStaticPool"),global.importDataMainPool=new $StaticPool$jscomp$1$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$jscomp$0$$,36E5,1,"import pool"),
16
- global.importDataMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{console.error("Import pool ready")}));$cpus_report_cpus_server_sslConfig$$&&($StaticPool$jscomp$0$$=require("./libs/WorkerStaticPool"),global.reportMainPool=new $StaticPool$jscomp$0$$(__dirname+"/workers/reportWorker.js",$options$$.max_queue_reports||0,$cpus_report_cpus_server_sslConfig$$,3E5,2,"report pool"),global.reportMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{console.error("Report pool ready")}));
17
- $callbackServer$$&&$callbackServer$$()}):require("./route")($app$$,()=>{$callbackServer$$&&$callbackServer$$()},!0)})}).catch($err$$=>{console.log("Not Connected to Database ERROR! ",$err$$)});return $app$$};process.on("SIGINT",async()=>{global.sharedRedisConnection&&await global.sharedRedisConnection.quit();process.exit(0)});
13
+ $cpus_report_cpus_server_sslConfig$$.timeout=6E5;!1!==$options$$.useSocket&&$User$$.initSocket($cpus_report_cpus_server_sslConfig$$);if(!1!==$options$$.cluster){if(!$StaticPool$jscomp$0$$.listen($cpus_report_cpus_server_sslConfig$$,global.port))$cpus_report_cpus_server_sslConfig$$.once("listening",function(){console.log("[app] server started on",global.port)});$StaticPool$jscomp$0$$=require("cluster");$StaticPool$jscomp$0$$.on("exit",function($worker$$,$code$$,$signal$$){console.error("[app] worker "+
14
+ $worker$$.process.pid+" died",$code$$,$signal$$)});$StaticPool$jscomp$0$$.on("online",function($worker$$){console.info("[app] worker "+$worker$$.process.pid+" is online")})}else $cpus_report_cpus_server_sslConfig$$.listen(global.port,()=>{console.log("[app] server start at "+global.port+" port")})}var $cpus_report_cpus_server_sslConfig$$=os.cpus().length;$StaticPool$jscomp$0$$=$options$$.import_cpus||($options$$.start_import_data_pool?$options$$.start_report_pool||$options$$.start_input_data_pool?
15
+ 1:Math.round($cpus_report_cpus_server_sslConfig$$/2):0);var $StaticPool$jscomp$1$$=$options$$.input_cpus||($options$$.start_input_data_pool?Math.max(Math.round($cpus_report_cpus_server_sslConfig$$/2),2):0);$cpus_report_cpus_server_sslConfig$$=$options$$.report_cpus||($options$$.start_import_data_pool?Math.max(Math.min($cpus_report_cpus_server_sslConfig$$-$StaticPool$jscomp$1$$-$StaticPool$jscomp$0$$,Math.round($cpus_report_cpus_server_sslConfig$$/2))-1,2):0);if($StaticPool$jscomp$1$$){const $StaticPool$$=
16
+ require("./libs/WorkerStaticPool");global.inputMainPool=new $StaticPool$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$jscomp$1$$,3E5,$StaticPool$jscomp$1$$,"input pool");global.inputMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{console.log("[app] Crud pool ready")})}$StaticPool$jscomp$0$$&&($StaticPool$jscomp$1$$=require("./libs/WorkerStaticPool"),global.importDataMainPool=new $StaticPool$jscomp$1$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||
17
+ 0,$StaticPool$jscomp$0$$,36E5,1,"import pool"),global.importDataMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{console.log("[app] Import pool ready")}));$cpus_report_cpus_server_sslConfig$$&&($StaticPool$jscomp$0$$=require("./libs/WorkerStaticPool"),global.reportMainPool=new $StaticPool$jscomp$0$$(__dirname+"/workers/reportWorker.js",$options$$.max_queue_reports||0,$cpus_report_cpus_server_sslConfig$$,3E5,2,"report pool"),global.reportMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},
18
+ ()=>{console.log("[app] Report pool ready")}));$callbackServer$$&&$callbackServer$$()}):require("./route")($app$$,()=>{$callbackServer$$&&$callbackServer$$()},!0)})}).catch($err$$=>{console.log("[app] Not Connected to Database ERROR! ",$err$$)});return $app$$};process.on("SIGINT",async()=>{global.sharedRedisConnection&&await global.sharedRedisConnection.quit();process.exit(0)});
18
19
  process.on("uncaughtException",function($err$jscomp$3_error$$){console.error((new Date).toUTCString()+" uncaughtException:",$err$jscomp$3_error$$.message);console.error($err$jscomp$3_error$$.stack);$err$jscomp$3_error$$=`
19
20
  Error: ${$err$jscomp$3_error$$.message}
20
21
  Stack: ${$err$jscomp$3_error$$.stack}
21
- `;try{const $logDirectory$$=__dirname+"/log";fs.existsSync($logDirectory$$)||fs.mkdirSync($logDirectory$$);fs.writeFile(`${$logDirectory$$}/error-${(new Date).getTime()}.txt`,$err$jscomp$3_error$$,()=>{console.log("wrote log error")})}catch($e$$){console.log($e$$)}process.exit(1)});module.exports=mainServer;
22
+ `;try{const $logDirectory$$=__dirname+"/log";fs.existsSync($logDirectory$$)||fs.mkdirSync($logDirectory$$);fs.writeFile(`${$logDirectory$$}/error-${(new Date).getTime()}.txt`,$err$jscomp$3_error$$,()=>{console.log("[app] wrote log error")})}catch($e$$){console.log($e$$)}process.exit(1)});module.exports=mainServer;