mdkcontroller 1.3.3 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cores/file/DKGrid.css +13 -6
- package/Cores/file/DKGrid.js +148 -70
- package/demoApp.js +27 -46
- package/dk_modules/authorization.js +44 -17
- package/dk_modules/dkdb.js +4 -1
- package/dk_modules/users.js +11 -26
- package/main.js +8 -5
- package/package.json +4 -2
- package/readme.md +47 -1
package/Cores/file/DKGrid.css
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
.dk-table td {
|
|
20
20
|
border: 1px solid #ddd;
|
|
21
|
+
border-top-width: 0px;
|
|
22
|
+
border-bottom-width: 0px;
|
|
21
23
|
overflow: hidden;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
.dk-table .gridToolCell ul li:hover {
|
|
51
|
-
background-color: #
|
|
53
|
+
background-color: #22a4cc;
|
|
52
54
|
color: white;
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -78,6 +80,10 @@
|
|
|
78
80
|
height: 33px;
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
.dk-table .edit .active {
|
|
84
|
+
background-color: #64eadeab;
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
.dk-table .RowNavigator td>input,
|
|
82
88
|
.dk-table .RowNavigator td>textarea,
|
|
83
89
|
.dk-table .RowNavigator td>select {
|
|
@@ -85,12 +91,12 @@
|
|
|
85
91
|
font-size: 18px;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
|
-
.dk-table .edit tr:nth-child(even) {
|
|
89
|
-
background-color: #
|
|
94
|
+
.dk-table .edit tr:nth-child(even):not(.active) {
|
|
95
|
+
background-color: #d9e0e1b3;
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
.dk-table .edit tr:nth-child(odd) {
|
|
93
|
-
background-color: #
|
|
98
|
+
.dk-table .edit tr:nth-child(odd):not(.active) {
|
|
99
|
+
background-color: #f7f7f7;
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
/* .dk-table .edit input[type="checkbox"] {
|
|
@@ -118,5 +124,6 @@
|
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
.active {
|
|
121
|
-
|
|
127
|
+
color: #22a4cc;
|
|
128
|
+
font-weight: bold;
|
|
122
129
|
}
|
package/Cores/file/DKGrid.js
CHANGED
|
@@ -7,7 +7,21 @@ class DKGrid {
|
|
|
7
7
|
this.idRaw = boxId + "_autogrid_dataraw";
|
|
8
8
|
this.idEditor = boxId + "_autogrid_editor";
|
|
9
9
|
this.config = { ...DKGrid.defaultConfig, ...config };
|
|
10
|
-
this.#cache = { updated: {}, deleted: {}, origin: {} };
|
|
10
|
+
this.#cache = { updated: {}, deleted: {}, origin: {}, view: [] };
|
|
11
|
+
const myGridThis = this;
|
|
12
|
+
this.cacheHandler = {
|
|
13
|
+
set(target, key, value) {
|
|
14
|
+
target[key] = value; // Gán giá trị vào object thực
|
|
15
|
+
myGridThis.rebuildDataView();
|
|
16
|
+
myGridThis.rebuildNavPaging();
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
{
|
|
21
|
+
const cache = this.#cache;
|
|
22
|
+
cache.updated = new Proxy(cache.updated, this.cacheHandler);
|
|
23
|
+
cache.deleted = new Proxy(cache.deleted, this.cacheHandler);
|
|
24
|
+
}
|
|
11
25
|
this.rowOnFocus = null;
|
|
12
26
|
this.#event = {};
|
|
13
27
|
this.page = { current: 1, total: 1, size: 10 };
|
|
@@ -19,6 +33,7 @@ class DKGrid {
|
|
|
19
33
|
this.#init();
|
|
20
34
|
return this;
|
|
21
35
|
}
|
|
36
|
+
|
|
22
37
|
addEventListener(eventName, callback) {
|
|
23
38
|
this.#event[eventName] = this.#event[eventName] || [];
|
|
24
39
|
this.#event[eventName].push(callback);
|
|
@@ -149,11 +164,35 @@ class DKGrid {
|
|
|
149
164
|
});
|
|
150
165
|
|
|
151
166
|
this.tableRaw.addEventListener('click', function (event) {
|
|
167
|
+
const clickedRow = event.target.closest('tr');
|
|
168
|
+
if (clickedRow) {
|
|
169
|
+
clickedRow.classList.add("active");
|
|
170
|
+
if (dkgrid.cellEditting) {
|
|
171
|
+
dkgrid.#rowClick(event);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const lastRow = dkgrid.rowOnFocus;
|
|
175
|
+
if (lastRow && lastRow != clickedRow) {
|
|
176
|
+
lastRow.classList.remove("active");
|
|
177
|
+
}
|
|
178
|
+
dkgrid.rowOnFocus = clickedRow;
|
|
179
|
+
});
|
|
180
|
+
this.tableRaw.addEventListener('dblclick', function (event) {
|
|
152
181
|
const clickedRow = event.target.closest('tr');
|
|
153
182
|
if (clickedRow) {
|
|
154
183
|
dkgrid.#rowClick(event);
|
|
184
|
+
dkgrid.cellEditting = true;
|
|
155
185
|
}
|
|
156
186
|
});
|
|
187
|
+
this.tableEditor.addEventListener("focusout", function (event) {
|
|
188
|
+
setTimeout(() => {
|
|
189
|
+
let newFocusedElement = document.activeElement; // Lấy phần tử vừa được focus
|
|
190
|
+
if (!dkgrid.tableRaw.contains(newFocusedElement) && !dkgrid.tableEditor.contains(newFocusedElement)) {
|
|
191
|
+
dkgrid.#closeEditor(false);
|
|
192
|
+
dkgrid.cellEditting = false;
|
|
193
|
+
}
|
|
194
|
+
}, 100);
|
|
195
|
+
});
|
|
157
196
|
document.getElementById(this.id + "_gridToolCell").addEventListener('click', (event) => {
|
|
158
197
|
const cmdElement = event.target.closest('li[data-cmd]');
|
|
159
198
|
if (!cmdElement) return;
|
|
@@ -175,7 +214,8 @@ class DKGrid {
|
|
|
175
214
|
const page = parseInt(cmd);
|
|
176
215
|
if (page) {
|
|
177
216
|
this.page.current = Math.min(page, this.page.total);
|
|
178
|
-
this.
|
|
217
|
+
this.rebuildNavPaging();
|
|
218
|
+
this.printPage();
|
|
179
219
|
}
|
|
180
220
|
});
|
|
181
221
|
document.getElementById(dkgrid.id + "_bodyContent").addEventListener("scroll", function () {
|
|
@@ -185,40 +225,34 @@ class DKGrid {
|
|
|
185
225
|
document.getElementById(dkgrid.id + "_inputSearch").addEventListener("keydown", function (event) {
|
|
186
226
|
if (event.key === "Enter") {
|
|
187
227
|
event.preventDefault();
|
|
188
|
-
dkgrid.
|
|
228
|
+
dkgrid.rebuildDataView();
|
|
229
|
+
dkgrid.rebuildNavPaging();
|
|
230
|
+
dkgrid.printPage();
|
|
189
231
|
}
|
|
190
232
|
});
|
|
191
233
|
}
|
|
192
234
|
#keyDownOnTable(keyCode) {
|
|
193
235
|
// ESC
|
|
194
236
|
if (keyCode == 27) {
|
|
195
|
-
|
|
196
|
-
this.#closeEditor(true);
|
|
197
|
-
}
|
|
237
|
+
this.#closeEditor(true);
|
|
198
238
|
}
|
|
199
239
|
// ENTER
|
|
200
240
|
if (keyCode == 13) {
|
|
201
|
-
|
|
202
|
-
this.#closeEditor(false);
|
|
203
|
-
}
|
|
241
|
+
this.#closeEditor(false);
|
|
204
242
|
}
|
|
205
243
|
}
|
|
206
244
|
#rowClick(sender) {
|
|
207
245
|
const trTag = sender.target.closest('tr');
|
|
208
246
|
const tableConfig = this.config;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (lastRow.dataset.editting == "1") {
|
|
212
|
-
this.#closeEditor(false);
|
|
213
|
-
}
|
|
247
|
+
{
|
|
248
|
+
this.#closeEditor(false);
|
|
214
249
|
}
|
|
215
|
-
|
|
250
|
+
|
|
216
251
|
if (!tableConfig.allowEdit) return;
|
|
217
252
|
|
|
218
253
|
if (this.#openEditor(trTag) == false) {
|
|
219
254
|
return;
|
|
220
255
|
}
|
|
221
|
-
|
|
222
256
|
const cellIndex = sender.target.cellIndex;
|
|
223
257
|
const tbEditor = this.tableEditor;
|
|
224
258
|
var cell = tbEditor.querySelector('tbody').querySelectorAll('td')[cellIndex];
|
|
@@ -278,7 +312,7 @@ class DKGrid {
|
|
|
278
312
|
}
|
|
279
313
|
#closeEditor(isClear = false, isdelete = false) {
|
|
280
314
|
const trTag = this.rowOnFocus;
|
|
281
|
-
if (trTag
|
|
315
|
+
if (!trTag || trTag.dataset.editting != "1") {
|
|
282
316
|
return;
|
|
283
317
|
}
|
|
284
318
|
const tbEditor = this.tableEditor;
|
|
@@ -361,50 +395,58 @@ class DKGrid {
|
|
|
361
395
|
});
|
|
362
396
|
cache.updated = {};
|
|
363
397
|
cache.deleted = {};
|
|
398
|
+
{
|
|
399
|
+
cache.updated = new Proxy(cache.updated, this.cacheHandler);
|
|
400
|
+
cache.deleted = new Proxy(cache.deleted, this.cacheHandler);
|
|
401
|
+
}
|
|
402
|
+
cache.view = [];
|
|
403
|
+
this.rebuildDataView();
|
|
404
|
+
this.rebuildNavPaging();
|
|
405
|
+
this.printPage(1);
|
|
364
406
|
this.page.total = Math.ceil(data.length / this.page.size);
|
|
407
|
+
return;
|
|
365
408
|
}
|
|
366
|
-
this.
|
|
409
|
+
this.rebuildNavPaging();
|
|
367
410
|
}
|
|
368
|
-
|
|
369
|
-
|
|
411
|
+
rebuildDataView() {
|
|
412
|
+
{
|
|
413
|
+
const cache = this.#cache;
|
|
414
|
+
const dataCollection = this.getData();
|
|
370
415
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
dataCollection
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
416
|
+
const dataCollection_array = [];
|
|
417
|
+
const textSearch = document.getElementById(this.id + "_inputSearch").value;
|
|
418
|
+
Object.values(dataCollection).forEach(item => {
|
|
419
|
+
if (!textSearch) {
|
|
420
|
+
dataCollection_array.push(item);
|
|
421
|
+
} else {
|
|
422
|
+
let found = false;
|
|
423
|
+
this.config.column.forEach(f => {
|
|
424
|
+
if (found) return;
|
|
425
|
+
let textValue = item[f.fieldName];
|
|
426
|
+
if (f.dataType == "select") {
|
|
427
|
+
textValue = f.items.find(i => i.value == item[f.fieldName])?.text ?? textValue;
|
|
428
|
+
}
|
|
429
|
+
if (textValue?.toString().toLowerCase().includes(textSearch.toLowerCase())) {
|
|
430
|
+
dataCollection_array.push(item);
|
|
431
|
+
found = true;
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
cache.view = dataCollection_array;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
rebuildNavPaging() {
|
|
440
|
+
const cache = this.#cache;
|
|
381
441
|
this.#closeEditor(false, false);
|
|
382
|
-
|
|
383
|
-
const
|
|
384
|
-
Object.values(dataCollection).forEach(item => {
|
|
385
|
-
if (!textSearch) {
|
|
386
|
-
dataCollection_array.push(item);
|
|
387
|
-
} else {
|
|
388
|
-
this.config.column.forEach(f => {
|
|
389
|
-
let textValue = item[f.fieldName];
|
|
390
|
-
if (f.dataType == "select") {
|
|
391
|
-
textValue = f.items.find(i => i.value == item[f.fieldName])?.text ?? textValue;
|
|
392
|
-
}
|
|
393
|
-
if (textValue?.toString().toLowerCase().includes(textSearch.toLowerCase())) {
|
|
394
|
-
dataCollection_array.push(item);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
});
|
|
442
|
+
|
|
443
|
+
const dataCollection_array = cache.view;
|
|
400
444
|
|
|
401
445
|
const page = this.page;
|
|
402
446
|
page.total = Math.ceil(dataCollection_array.length / page.size);
|
|
447
|
+
const currentPage = page.current;
|
|
403
448
|
page.current = Math.min(page.current, page.total);
|
|
404
449
|
|
|
405
|
-
const start = (page.current - 1) * page.size;
|
|
406
|
-
const end = start + page.size;
|
|
407
|
-
|
|
408
450
|
this.pagingCell.innerHTML = "";
|
|
409
451
|
{
|
|
410
452
|
const min = Math.max(2, page.current - 2);
|
|
@@ -427,16 +469,32 @@ class DKGrid {
|
|
|
427
469
|
return li;
|
|
428
470
|
}
|
|
429
471
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
472
|
+
if (currentPage != page.current) {
|
|
473
|
+
this.printPage(page.current);
|
|
474
|
+
} else {
|
|
475
|
+
const dataCollection_array = cache.view;
|
|
476
|
+
const start = (page.current - 1) * page.size;
|
|
477
|
+
const end = start + page.size;
|
|
478
|
+
const dataPrint = dataCollection_array.slice(start, end);
|
|
479
|
+
this.statusBox.textContent = `${dataPrint.length}/${dataCollection_array.length}`;
|
|
434
480
|
}
|
|
435
|
-
this.printPage(dataPrint);
|
|
436
481
|
}
|
|
437
|
-
printPage(
|
|
482
|
+
printPage(pageNumber) {
|
|
438
483
|
const table = this.tableRaw;
|
|
439
484
|
const tableConfig = this.config;
|
|
485
|
+
const cache = this.#cache;
|
|
486
|
+
this.#closeEditor(false, false);
|
|
487
|
+
|
|
488
|
+
const dataCollection_array = cache.view;
|
|
489
|
+
|
|
490
|
+
const page = this.page;
|
|
491
|
+
pageNumber = pageNumber ?? page.current;
|
|
492
|
+
page.current = pageNumber;
|
|
493
|
+
const start = (page.current - 1) * page.size;
|
|
494
|
+
const end = start + page.size;
|
|
495
|
+
const dataPrint = dataCollection_array.slice(start, end);
|
|
496
|
+
this.statusBox.textContent = `${dataPrint.length}/${dataCollection_array.length}`;
|
|
497
|
+
|
|
440
498
|
const tbody = table.querySelector('tbody');
|
|
441
499
|
tbody.innerHTML = '';
|
|
442
500
|
dataPrint.forEach(
|
|
@@ -469,9 +527,6 @@ class DKGrid {
|
|
|
469
527
|
);
|
|
470
528
|
}
|
|
471
529
|
addNewRow() {
|
|
472
|
-
const tbody = this.tableRaw.querySelector('tbody');
|
|
473
|
-
const newTR = document.createElement('tr');
|
|
474
|
-
tbody.appendChild(newTR);
|
|
475
530
|
const tableConfig = this.config;
|
|
476
531
|
const primaryKey = tableConfig.primaryKey;
|
|
477
532
|
let newOb = {};
|
|
@@ -481,21 +536,31 @@ class DKGrid {
|
|
|
481
536
|
if (!newOb[primaryKey]) {
|
|
482
537
|
newOb[primaryKey] = Date.now() + '_' + DKGrid.generateRandomString(12);
|
|
483
538
|
}
|
|
484
|
-
newTR.dataset.primaryValue = newOb[primaryKey];
|
|
485
539
|
const cache = this.#cache;
|
|
486
540
|
cache.updated[newOb[primaryKey]] = (newOb);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
541
|
+
{
|
|
542
|
+
this.page.current = this.page.total;
|
|
543
|
+
this.rebuildNavPaging();
|
|
544
|
+
this.printPage();
|
|
545
|
+
}
|
|
546
|
+
const trNew = this.getRowTR(newOb[primaryKey]);
|
|
547
|
+
if (trNew) {
|
|
548
|
+
// query to first input in td
|
|
549
|
+
const td = trNew.querySelector('td:first-child');
|
|
550
|
+
if (td) {
|
|
551
|
+
this.cellEditting = true;
|
|
552
|
+
td.click();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
getRowTR(primaryValue) {
|
|
557
|
+
return this.tableRaw.querySelector(`tr[data-primary-value="${primaryValue}"]`);
|
|
490
558
|
}
|
|
491
|
-
|
|
492
559
|
deleteRow() {
|
|
493
560
|
if (this.rowOnFocus) {
|
|
494
561
|
if (confirm("Bạn có chắc chắn muốn xóa dữ liệu này?") != true) return;
|
|
495
562
|
this.#closeEditor(true, true);
|
|
496
563
|
const cache = this.#cache;
|
|
497
|
-
const tableConfig = this.config;
|
|
498
|
-
const primaryKey = tableConfig.primaryKey;
|
|
499
564
|
const lastRow = this.rowOnFocus;
|
|
500
565
|
const currentKeyValue = lastRow.dataset.primaryValue;
|
|
501
566
|
const objectOriginal = cache.origin[currentKeyValue];
|
|
@@ -507,10 +572,23 @@ class DKGrid {
|
|
|
507
572
|
if (objectCache) {
|
|
508
573
|
delete cache.updated[currentKeyValue];
|
|
509
574
|
}
|
|
575
|
+
let currentIndex = -1;
|
|
576
|
+
let datainPage = this.tableRaw.querySelectorAll(`tr`);
|
|
577
|
+
datainPage.forEach((row, index) => {
|
|
578
|
+
if (row.dataset.primaryValue == currentKeyValue) {
|
|
579
|
+
currentIndex = index;
|
|
580
|
+
}
|
|
581
|
+
});
|
|
510
582
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
583
|
+
this.rebuildDataView();
|
|
584
|
+
this.rebuildNavPaging();
|
|
585
|
+
this.printPage();
|
|
586
|
+
|
|
587
|
+
datainPage = this.tableRaw.querySelectorAll(`tr`);
|
|
588
|
+
if (currentIndex >= 0 && datainPage.length > currentIndex) {
|
|
589
|
+
this.rowOnFocus = datainPage[currentIndex];
|
|
590
|
+
this.rowOnFocus.click();
|
|
591
|
+
}
|
|
514
592
|
}
|
|
515
593
|
}
|
|
516
594
|
getData() {
|
package/demoApp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {Root} from "./index.js";
|
|
2
|
-
import {Router} from "express";
|
|
3
|
-
import * as socketIO from "socket.io";
|
|
4
|
-
|
|
1
|
+
// import { Root } from "./index.js";
|
|
2
|
+
import { Router } from "express";
|
|
3
|
+
// import * as socketIO from "socket.io";
|
|
4
|
+
import { Root } from "mdkcontroller";
|
|
5
5
|
|
|
6
6
|
const cfg = {
|
|
7
7
|
redirectHome: function (req, res) {
|
|
@@ -17,56 +17,37 @@ const cfg = {
|
|
|
17
17
|
}
|
|
18
18
|
//global.allowRegister = true;
|
|
19
19
|
const _sv = await Root("khanhnbd", cfg);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
// global.db = db;
|
|
21
|
+
// global.app = app;
|
|
22
|
+
// global.auth = auth;
|
|
23
|
+
// global.generateRandomString
|
|
24
|
+
global.db.data.yourTableName = global.db.data.yourTableName ?? [];
|
|
25
25
|
|
|
26
26
|
const newRouterApi = Router();
|
|
27
27
|
newRouterApi.get("/demoFunction/gets", authCrypt.validate, (req, res) => {
|
|
28
|
-
res.json({message: "Get all users"});
|
|
28
|
+
res.json({ message: "Get all users" });
|
|
29
29
|
});
|
|
30
30
|
newRouterApi.get('/demoPhase2/CallNonAuth', async (req, res) => {
|
|
31
31
|
const accessToken = req.cookies?.access_token;
|
|
32
|
-
|
|
33
|
-
const indexToken = tbMovie.findIndex(f => true);
|
|
34
|
-
tbMovie.slice(indexToken, 1);
|
|
35
|
-
await db.write();
|
|
36
|
-
}
|
|
32
|
+
|
|
37
33
|
res.redirect('/login');
|
|
38
34
|
});
|
|
39
35
|
app.use("/api", newRouterApi);
|
|
40
36
|
|
|
41
|
-
const io = new socketIO.Server(_sv.serverBase);
|
|
42
|
-
io.on("connection", (socket) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
37
|
+
// const io = new socketIO.Server(_sv.serverBase);
|
|
38
|
+
// io.on("connection", (socket) => {
|
|
39
|
+
// socket.on("loginSession", (data) => {
|
|
40
|
+
// const tagID = (data.token ?? "").length > 0 ? data.token : generateRandomString();
|
|
41
|
+
// socket.tagID = tagID;
|
|
42
|
+
// socket.emit("loginSession-r", socket.tagID);
|
|
43
|
+
// });
|
|
44
|
+
// socket.on("loginSessionRemote", (data) => {
|
|
45
|
+
// const tagID = data.token;
|
|
46
|
+
// socket.tagID = tagID;
|
|
47
|
+
// });
|
|
48
|
+
// socket.on("disconnect", (reason) => {
|
|
49
|
+
// const tagID = socket.tagID;
|
|
50
|
+
// });
|
|
51
|
+
// });
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
const dec = await authCrypt.decrypt(enc);
|
|
59
|
-
console.log("khanhnbd => " + enc);
|
|
60
|
-
console.log(enc + " will => " + dec);
|
|
61
|
-
_sv.startListen(8905);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
function generateRandomString(length = 8) {
|
|
65
|
-
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
66
|
-
let result = '';
|
|
67
|
-
const charactersLength = characters.length;
|
|
68
|
-
for (let i = 0; i < length; i++) {
|
|
69
|
-
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
70
|
-
}
|
|
71
|
-
return result.toUpperCase();
|
|
72
|
-
}
|
|
53
|
+
_sv.startListen(8905);
|
|
@@ -1,30 +1,55 @@
|
|
|
1
1
|
import { decrypt, encrypt } from "./dkEncrypC.js";
|
|
2
|
-
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
import NodeCache from 'node-cache';
|
|
4
|
+
const userCache = new NodeCache({ stdTTL: 30 }); // 5 phút
|
|
3
5
|
export default function () {
|
|
4
|
-
|
|
6
|
+
const secretKey = "ktrmangafws571709583";
|
|
7
|
+
function hidecreateJWT(user) {
|
|
8
|
+
const payload = {
|
|
9
|
+
userId: user.id,
|
|
10
|
+
username: user.username,
|
|
11
|
+
signcode: user.signcode,
|
|
12
|
+
};
|
|
13
|
+
const token = jwt.sign(payload, secretKey);
|
|
14
|
+
return token;
|
|
15
|
+
}
|
|
16
|
+
function hideverifyJWT(token) {
|
|
17
|
+
try {
|
|
18
|
+
const decoded = jwt.verify(token, secretKey);
|
|
19
|
+
return decoded;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("Token không hợp lệ:", error.message);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
5
25
|
const validateBase = function name(req, res) {
|
|
6
26
|
const db = global.db;
|
|
7
|
-
db.data.loginTokens = db.data.loginTokens || [];
|
|
8
|
-
const tbLoginToken = db.data.loginTokens;
|
|
9
|
-
db.data.users = db.data.users || [];
|
|
10
27
|
const tbUser = db.data.users;
|
|
11
28
|
|
|
12
|
-
const accessToken = req.cookies?.access_token;
|
|
29
|
+
const accessToken = req.cookies?.access_token || req.header('Authorization')?.replace('Bearer ', '');
|
|
13
30
|
if (accessToken) {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if (!tokenO) {
|
|
31
|
+
const jwtValidate = hideverifyJWT(accessToken);
|
|
32
|
+
if (!jwtValidate) {
|
|
17
33
|
return -1;
|
|
18
34
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
if (okGoodGood) {
|
|
22
|
-
const userO = tbUser.find(f => f.id == tokenO.userId);
|
|
23
|
-
req.user = userO; // Lưu thông tin người dùng trong request để sử dụng trong xử lý tuyến đường
|
|
24
|
-
return 1;
|
|
25
|
-
} else {
|
|
35
|
+
const userName = jwtValidate.username;
|
|
36
|
+
if (!userName) {
|
|
26
37
|
return -1;
|
|
27
38
|
}
|
|
39
|
+
|
|
40
|
+
let userO = userCache.get(userName);
|
|
41
|
+
|
|
42
|
+
if (!userO) {
|
|
43
|
+
userO = tbUser.find(f => f.username === userName);
|
|
44
|
+
if (!userO) return -1;
|
|
45
|
+
|
|
46
|
+
userCache.set(userName, userO);
|
|
47
|
+
}
|
|
48
|
+
if (userO.signcode != jwtValidate.signcode) {
|
|
49
|
+
return -1;
|
|
50
|
+
}
|
|
51
|
+
req.user = userO;
|
|
52
|
+
return 1;
|
|
28
53
|
} else {
|
|
29
54
|
return 0;
|
|
30
55
|
}
|
|
@@ -53,6 +78,8 @@ export default function () {
|
|
|
53
78
|
},
|
|
54
79
|
decrypt: function (data = "", pw = "mdkpaswoEcrHidDefat") {
|
|
55
80
|
return decrypt(data, pw);
|
|
56
|
-
}
|
|
81
|
+
},
|
|
82
|
+
createJWT: (user) => hidecreateJWT(user),
|
|
83
|
+
verifyJWT: (token) => hideverifyJWT(token)
|
|
57
84
|
}
|
|
58
85
|
};
|
package/dk_modules/dkdb.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { JSONFilePreset } from 'lowdb/node';
|
|
2
|
-
const defaultData = {
|
|
2
|
+
const defaultData = {
|
|
3
|
+
users: [{ id: -1, username: '', password: '', signcode: '' }],
|
|
4
|
+
loginTokens: [], autoSequenceNumber: []
|
|
5
|
+
};
|
|
3
6
|
export default async function (dbpath) {
|
|
4
7
|
const db = await JSONFilePreset(dbpath, defaultData);
|
|
5
8
|
console.log("Module dk_modules/dkdb.js: (dbpath)=>db");
|
package/dk_modules/users.js
CHANGED
|
@@ -8,9 +8,6 @@ export default (router, db) => {
|
|
|
8
8
|
|
|
9
9
|
db.data.users = db.data.users || [];
|
|
10
10
|
const tbUser = db.data.users;
|
|
11
|
-
db.data.loginTokens = db.data.loginTokens || [];
|
|
12
|
-
const tbLoginToken = db.data.loginTokens;
|
|
13
|
-
|
|
14
11
|
|
|
15
12
|
router.get("/users/gets", auth.validate, (req, res) => {
|
|
16
13
|
res.json({ message: "Get all users" });
|
|
@@ -22,12 +19,6 @@ export default (router, db) => {
|
|
|
22
19
|
res.json({ message: `Get user with ID ${userId}`, user: userO });
|
|
23
20
|
});
|
|
24
21
|
router.get('/users/logout', async (req, res) => {
|
|
25
|
-
const accessToken = req.cookies?.access_token;
|
|
26
|
-
if (accessToken) {
|
|
27
|
-
const indexToken = tbLoginToken.findIndex(f => f.tokenString == accessToken);
|
|
28
|
-
tbLoginToken.slice(indexToken, 1);
|
|
29
|
-
await db.write();
|
|
30
|
-
}
|
|
31
22
|
res.clearCookie('access_token', { httpOnly: true });
|
|
32
23
|
res.clearCookie('sessionUExt', {});
|
|
33
24
|
res.redirect('/login');
|
|
@@ -36,24 +27,17 @@ export default (router, db) => {
|
|
|
36
27
|
router.post("/users/login", async (req, res) => {
|
|
37
28
|
const bodyParser = req.body;
|
|
38
29
|
if (bodyParser.userName && bodyParser.password) {
|
|
39
|
-
|
|
40
|
-
let userLoging = tbUser.find(f => f.userName == bodyParser.userName.toLowerCase().trim() && auth.decrypt(f.password) == bodyParser.password);
|
|
30
|
+
let userLoging = tbUser.find(f => f.username == bodyParser.userName.toLowerCase().trim() && auth.decrypt(f.password) == bodyParser.password);
|
|
41
31
|
if (userLoging) {
|
|
42
|
-
const userIdCode = auth.encrypt(userLoging.
|
|
43
|
-
const accessToken =
|
|
44
|
-
|
|
32
|
+
const userIdCode = auth.encrypt(userLoging.username);
|
|
33
|
+
const accessToken = auth.createJWT(userLoging);
|
|
45
34
|
const expiredValue = new Date();
|
|
46
35
|
expiredValue.setMonth(expiredValue.getMonth() + 1);
|
|
47
|
-
|
|
48
|
-
tbLoginToken.push({
|
|
49
|
-
id: getNumber('loginTokens'),
|
|
50
|
-
userId: userLoging.id,
|
|
51
|
-
tokenString: accessToken,
|
|
52
|
-
expired: expiredValue
|
|
53
|
-
});
|
|
54
|
-
await db.write();
|
|
55
36
|
res.cookie('access_token', accessToken, { httpOnly: true, expires: expiredValue });
|
|
56
37
|
res.cookie('sessionUExt', userIdCode, { expires: expiredValue });
|
|
38
|
+
if (bodyParser.attacktoh) {
|
|
39
|
+
res.header('access_token', accessToken);
|
|
40
|
+
}
|
|
57
41
|
res.json({ message: `Đăng nhập thành công.`, success: true });
|
|
58
42
|
} else {
|
|
59
43
|
res.json({ message: `Tài khoản hoặc mật khẩu không chính xác.`, success: false });
|
|
@@ -81,7 +65,7 @@ export default (router, db) => {
|
|
|
81
65
|
if (bodyParser.userName && bodyParser.email && bodyParser.password) {
|
|
82
66
|
let newUser = tbUser.find(f => f.email == bodyParser.email.toLowerCase());
|
|
83
67
|
if (!newUser) {
|
|
84
|
-
let validateUserName = tbUser.find(f => f.
|
|
68
|
+
let validateUserName = tbUser.find(f => f.username == bodyParser.userName.toLowerCase());
|
|
85
69
|
if (validateUserName) {
|
|
86
70
|
res.json({ message: `Tên tài khoản đã có người đăng ký.`, success: false });
|
|
87
71
|
return;
|
|
@@ -89,14 +73,15 @@ export default (router, db) => {
|
|
|
89
73
|
tbUser
|
|
90
74
|
.push({
|
|
91
75
|
id: getNumber('users'),
|
|
92
|
-
|
|
76
|
+
username: bodyParser.userName.toLowerCase(),
|
|
93
77
|
email: bodyParser.email.toLowerCase(),
|
|
94
78
|
password: auth.encrypt(bodyParser.password),
|
|
95
79
|
active: true,
|
|
96
|
-
amount: 0
|
|
80
|
+
amount: 0,
|
|
81
|
+
signcode: global.generateRandomString(100),
|
|
97
82
|
});
|
|
98
83
|
await db.write();
|
|
99
|
-
newUser = tbUser.find(f => f.
|
|
84
|
+
newUser = tbUser.find(f => f.username == bodyParser.userName.toLowerCase());
|
|
100
85
|
res.json({
|
|
101
86
|
message: `Hello, ${bodyParser.userName}! Tài khoản đã được tạo.`,
|
|
102
87
|
user: newUser,
|
package/main.js
CHANGED
|
@@ -83,11 +83,14 @@ export default async function (appname, cfgHandler = {}) {
|
|
|
83
83
|
authen: auth,
|
|
84
84
|
serverBase: server,
|
|
85
85
|
startListen:
|
|
86
|
-
function (kport = 8095) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
async function (kport = 8095) {
|
|
87
|
+
return new Promise(resolve => {
|
|
88
|
+
server.listen(kport, () => {
|
|
89
|
+
console.log(
|
|
90
|
+
`Server is listening on port ${kport}: http://localhost:${kport}`
|
|
91
|
+
);
|
|
92
|
+
resolve();
|
|
93
|
+
});
|
|
91
94
|
});
|
|
92
95
|
}
|
|
93
96
|
}
|
package/package.json
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"cookie-parser": "^1.4.6",
|
|
4
4
|
"express": "^4.18.2",
|
|
5
|
+
"js-yaml": "^4.1.0",
|
|
6
|
+
"jsonwebtoken": "^9.0.2",
|
|
5
7
|
"lowdb": "^7.0.1",
|
|
6
|
-
"
|
|
8
|
+
"node-cache": "^5.1.2"
|
|
7
9
|
},
|
|
8
10
|
"name": "mdkcontroller",
|
|
9
|
-
"version": "1.
|
|
11
|
+
"version": "1.4.1",
|
|
10
12
|
"keywords": [],
|
|
11
13
|
"author": "KHANHNBD <khanh272421@gmail.com>",
|
|
12
14
|
"license": "ISC",
|
package/readme.md
CHANGED
|
@@ -1 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
## Installation
|
|
2
|
+
|
|
3
|
+
This is a [Node.js](https://nodejs.org/en/) module available through the
|
|
4
|
+
[npm registry](https://www.npmjs.com/). Installation is done using the
|
|
5
|
+
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
$ npm i mdkcontroller
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import {Root} from "mdkcontroller";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
This is a library that helps build websites faster, but at the basic level it supports api, socketio, login, DKTable and some files available in cores.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// import {Root} from "./index.js";
|
|
22
|
+
import {Router} from "express";
|
|
23
|
+
import {Root} from "mdkcontroller";
|
|
24
|
+
|
|
25
|
+
const cfg = {
|
|
26
|
+
redirectHome: function (req, res) {
|
|
27
|
+
// Path in current project
|
|
28
|
+
res.redirect("/pages");
|
|
29
|
+
}
|
|
30
|
+
// ,trySkipAuth: function (req, res, next) {
|
|
31
|
+
// if (true) {
|
|
32
|
+
// next();
|
|
33
|
+
// }
|
|
34
|
+
// return true;
|
|
35
|
+
// }
|
|
36
|
+
}
|
|
37
|
+
//global.allowRegister = true;
|
|
38
|
+
const _sv = await Root("khanhnbd", cfg);
|
|
39
|
+
_sv.startListen(8095);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
You can test this out with the cURL program:
|
|
43
|
+
```sh
|
|
44
|
+
curl -I -H'Accept: text/html' http://localhost:8095/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## License
|