@dongdev/fca-unofficial 3.0.30 → 3.0.31
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/CHANGELOG.md +3 -0
- package/package.json +2 -1
- package/src/api/http/httpGet.js +2 -2
- package/src/api/messaging/addUserToGroup.js +1 -1
- package/src/api/messaging/changeGroupImage.js +1 -1
- package/src/api/messaging/changeNickname.js +1 -1
- package/src/api/messaging/changeThreadColor.js +1 -1
- package/src/api/messaging/editMessage.js +1 -1
- package/src/api/messaging/searchForThread.js +2 -1
- package/src/api/messaging/sendTypingIndicator.js +1 -1
- package/src/api/messaging/setMessageReaction.js +3 -4
- package/src/api/messaging/unsendMessage.js +1 -1
- package/src/api/threads/getThreadInfo.js +2 -1
- package/src/api/users/getUserInfo.js +7 -4
- package/src/database/helpers.js +53 -0
- package/src/database/models/index.js +2 -1
- package/src/database/threadData.js +49 -53
- package/src/database/userData.js +46 -37
- package/src/utils/format/attachment.js +357 -0
- package/src/utils/format/cookie.js +9 -0
- package/src/utils/format/date.js +50 -0
- package/src/utils/format/decode.js +44 -0
- package/src/utils/format/delta.js +194 -0
- package/src/utils/format/ids.js +64 -0
- package/src/utils/format/index.js +64 -0
- package/src/utils/format/message.js +88 -0
- package/src/utils/format/presence.js +132 -0
- package/src/utils/format/readTyp.js +44 -0
- package/src/utils/format/thread.js +42 -0
- package/src/utils/format/utils.js +141 -0
- package/src/utils/loginParser/autoLogin.js +125 -0
- package/src/utils/loginParser/helpers.js +43 -0
- package/src/utils/loginParser/index.js +10 -0
- package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
- package/src/utils/loginParser/textUtils.js +28 -0
- package/src/utils/request/client.js +26 -0
- package/src/utils/request/config.js +23 -0
- package/src/utils/request/defaults.js +46 -0
- package/src/utils/request/helpers.js +46 -0
- package/src/utils/request/index.js +17 -0
- package/src/utils/request/methods.js +163 -0
- package/src/utils/request/proxy.js +21 -0
- package/src/utils/request/retry.js +77 -0
- package/src/utils/request/sanitize.js +49 -0
- package/src/utils/format.js +0 -1174
- package/src/utils/loginParser.js +0 -365
- package/src/utils/messageFormat.js +0 -1173
- package/src/utils/request.js +0 -332
package/CHANGELOG.md
CHANGED
|
@@ -291,3 +291,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
291
291
|
[3.0.28]: https://github.com/Donix-VN/fca-unofficial/compare/v3.0.27...v3.0.28
|
|
292
292
|
[3.0.27]: https://github.com/Donix-VN/fca-unofficial/compare/v3.0.25...v3.0.27
|
|
293
293
|
[1.0.10]: https://github.com/Donix-VN/fca-unofficial/releases/tag/v1.0.10
|
|
294
|
+
|
|
295
|
+
## v3.0.30 - 2026-03-07
|
|
296
|
+
- Hotfix / auto bump
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dongdev/fca-unofficial",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.31",
|
|
4
4
|
"description": "Unofficial Facebook Chat API for Node.js - Interact with Facebook Messenger programmatically",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"https-proxy-agent": "^4.0.0",
|
|
75
75
|
"mqtt": "^4.3.8",
|
|
76
76
|
"sequelize": "^6.37.6",
|
|
77
|
+
"sqlite3": "^5.1.7",
|
|
77
78
|
"totp-generator": "^1.0.0",
|
|
78
79
|
"ws": "^8.18.1"
|
|
79
80
|
},
|
package/src/api/http/httpGet.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { getType } = require("../../utils/format
|
|
4
|
-
const { get } = require("../../utils/request
|
|
3
|
+
const { getType } = require("../../utils/format");
|
|
4
|
+
const { get } = require("../../utils/request");
|
|
5
5
|
|
|
6
6
|
const httpGetFactory = function (defaultFuncs, api, ctx) {
|
|
7
7
|
return function httpGet(url, form, callback, notAPI) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID, getType } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID, getType } = require("../../utils/format");
|
|
4
4
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
5
5
|
return function addUserToGroup(userID, threadID, callback) {
|
|
6
6
|
return new Promise((resolve, reject) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
4
|
const log = require("../../../func/logAdapter");
|
|
5
5
|
|
|
6
6
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
4
|
const log = require("../../../func/logAdapter");
|
|
5
5
|
|
|
6
6
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
4
|
module.exports = (defaultFuncs, api, ctx) => {
|
|
5
5
|
return async (color, threadID, callback) => {
|
|
6
6
|
let reqID = ++ctx.wsReqNumber;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use_strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
4
|
module.exports = (defaultFuncs, api, ctx) => {
|
|
5
5
|
return (text, messageID, callback) => {
|
|
6
6
|
let reqID = ctx.wsReqNumber + 1;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { parseAndCheckLogin } = require("../../utils/client");
|
|
4
|
+
const { formatThread } = require("../../utils/format");
|
|
4
5
|
module.exports = function(defaultFuncs, api, ctx) {
|
|
5
6
|
return function searchForThread(name, callback) {
|
|
6
7
|
let resolveFunc = function() {};
|
|
@@ -43,7 +44,7 @@ module.exports = function(defaultFuncs, api, ctx) {
|
|
|
43
44
|
}
|
|
44
45
|
return callback(
|
|
45
46
|
null,
|
|
46
|
-
resData.payload.mercury_payload.threads.map(
|
|
47
|
+
resData.payload.mercury_payload.threads.map(formatThread)
|
|
47
48
|
);
|
|
48
49
|
});
|
|
49
50
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const { getType } = require("../../utils/format
|
|
2
|
+
const { getType } = require("../../utils/format");
|
|
3
3
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
4
4
|
return function sendTyping(threadID, isTyping, options, callback) {
|
|
5
5
|
var resolveFunc = function () { };
|
|
@@ -49,16 +49,15 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
49
49
|
failure_count: null,
|
|
50
50
|
label: "29",
|
|
51
51
|
payload: JSON.stringify(taskPayload),
|
|
52
|
-
queue_name:
|
|
52
|
+
queue_name: "reaction:" + messageID,
|
|
53
53
|
task_id: taskID,
|
|
54
54
|
};
|
|
55
55
|
const mqttForm = {
|
|
56
|
-
app_id: "
|
|
56
|
+
app_id: "2220391788200892",
|
|
57
57
|
payload: JSON.stringify({
|
|
58
|
-
data_trace_id: null,
|
|
59
58
|
epoch_id: parseInt(generateOfflineThreadingID()),
|
|
60
59
|
tasks: [task],
|
|
61
|
-
version_id: "
|
|
60
|
+
version_id: "24585299697835063"
|
|
62
61
|
}),
|
|
63
62
|
request_id: reqID,
|
|
64
63
|
type: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const { generateOfflineThreadingID } = require("../../utils/format
|
|
3
|
+
const { generateOfflineThreadingID } = require("../../utils/format");
|
|
4
4
|
const log = require("../../../func/logAdapter");
|
|
5
5
|
|
|
6
6
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
@@ -137,7 +137,8 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
137
137
|
const dbFiles = fs.readdirSync(path.join(__dirname, "../../database"))
|
|
138
138
|
.filter(f => path.extname(f) === ".js")
|
|
139
139
|
.reduce((acc, file) => {
|
|
140
|
-
|
|
140
|
+
const mod = require(path.join(__dirname, "../../database", file));
|
|
141
|
+
acc[path.basename(file, ".js")] = typeof mod === "function" ? mod(api) : mod;
|
|
141
142
|
return acc;
|
|
142
143
|
}, {});
|
|
143
144
|
|
|
@@ -193,10 +193,13 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
193
193
|
const queuedUsers = new Set();
|
|
194
194
|
const cooldown = new Map();
|
|
195
195
|
|
|
196
|
-
const dbFiles = fs.readdirSync(path.join(__dirname, "../../database"))
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
const dbFiles = fs.readdirSync(path.join(__dirname, "../../database"))
|
|
197
|
+
.filter(f => path.extname(f) === ".js")
|
|
198
|
+
.reduce((acc, file) => {
|
|
199
|
+
const mod = require(path.join(__dirname, "../../database", file));
|
|
200
|
+
acc[path.basename(file, ".js")] = typeof mod === "function" ? mod(api) : mod;
|
|
201
|
+
return acc;
|
|
202
|
+
}, {});
|
|
200
203
|
const { userData } = dbFiles;
|
|
201
204
|
const { create, get, update, getAll } = userData;
|
|
202
205
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared helpers for database layer (userData, threadData).
|
|
5
|
+
* Keeps validation and payload normalization in one place.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DB_NOT_INIT = "Database not initialized";
|
|
9
|
+
|
|
10
|
+
function validateId(value, fieldName = "id") {
|
|
11
|
+
if (value == null) {
|
|
12
|
+
throw new Error(`${fieldName} is required and cannot be undefined`);
|
|
13
|
+
}
|
|
14
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
15
|
+
throw new Error(`Invalid ${fieldName}: must be a string or number`);
|
|
16
|
+
}
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function validateData(data) {
|
|
21
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
22
|
+
throw new Error("Invalid data: must be a non-empty object");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string|string[]|null} keys - "userID" | ["userID","data"] | null
|
|
28
|
+
* @returns {string[]|undefined}
|
|
29
|
+
*/
|
|
30
|
+
function normalizeAttributes(keys) {
|
|
31
|
+
if (keys == null) return undefined;
|
|
32
|
+
return typeof keys === "string" ? [keys] : Array.isArray(keys) ? keys : undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Normalize payload: accept either { data } or raw object.
|
|
37
|
+
*/
|
|
38
|
+
function normalizePayload(data, key = "data") {
|
|
39
|
+
return Object.prototype.hasOwnProperty.call(data, key) ? data : { [key]: data };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function wrapError(message, cause) {
|
|
43
|
+
return new Error(`${message}: ${cause && cause.message ? cause.message : cause}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
DB_NOT_INIT,
|
|
48
|
+
validateId,
|
|
49
|
+
validateData,
|
|
50
|
+
normalizeAttributes,
|
|
51
|
+
normalizePayload,
|
|
52
|
+
wrapError
|
|
53
|
+
};
|
|
@@ -63,6 +63,7 @@ try {
|
|
|
63
63
|
|
|
64
64
|
models.sequelize = sequelize;
|
|
65
65
|
models.Sequelize = Sequelize;
|
|
66
|
+
models.isReady = true;
|
|
66
67
|
models.syncAll = async () => {
|
|
67
68
|
try {
|
|
68
69
|
if (!sequelize) {
|
|
@@ -75,10 +76,10 @@ try {
|
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
78
|
} catch (initError) {
|
|
78
|
-
// If initialization fails completely, still export a valid structure
|
|
79
79
|
console.error("Database initialization error:", initError && initError.message ? initError.message : String(initError));
|
|
80
80
|
models.sequelize = null;
|
|
81
81
|
models.Sequelize = Sequelize;
|
|
82
|
+
models.isReady = false;
|
|
82
83
|
models.syncAll = async () => {
|
|
83
84
|
throw new Error("Database not initialized");
|
|
84
85
|
};
|
|
@@ -1,97 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
throw new Error("Invalid data: must be a non-empty object.");
|
|
12
|
-
}
|
|
13
|
-
};
|
|
3
|
+
const models = require("./models");
|
|
4
|
+
const {
|
|
5
|
+
DB_NOT_INIT,
|
|
6
|
+
validateId,
|
|
7
|
+
validateData,
|
|
8
|
+
normalizeAttributes,
|
|
9
|
+
wrapError
|
|
10
|
+
} = require("./helpers");
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
const Thread = models.Thread;
|
|
13
|
+
const ID_FIELD = "threadID";
|
|
14
|
+
|
|
15
|
+
module.exports = function (bot) {
|
|
16
16
|
return {
|
|
17
17
|
async create(threadID, data) {
|
|
18
|
+
if (!Thread) {
|
|
19
|
+
return { thread: { threadID: validateId(threadID, ID_FIELD), ...(data || {}) }, created: true };
|
|
20
|
+
}
|
|
18
21
|
try {
|
|
22
|
+
threadID = validateId(threadID, ID_FIELD);
|
|
19
23
|
let thread = await Thread.findOne({ where: { threadID } });
|
|
20
|
-
if (thread) {
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
thread = await Thread.create({ threadID, ...data });
|
|
24
|
+
if (thread) return { thread: thread.get(), created: false };
|
|
25
|
+
thread = await Thread.create({ threadID, ...(data || {}) });
|
|
24
26
|
return { thread: thread.get(), created: true };
|
|
25
|
-
} catch (
|
|
26
|
-
throw
|
|
27
|
+
} catch (err) {
|
|
28
|
+
throw wrapError("Failed to create thread", err);
|
|
27
29
|
}
|
|
28
30
|
},
|
|
29
31
|
|
|
30
32
|
async get(threadID) {
|
|
33
|
+
if (!Thread) return null;
|
|
31
34
|
try {
|
|
32
|
-
threadID =
|
|
35
|
+
threadID = validateId(threadID, ID_FIELD);
|
|
33
36
|
const thread = await Thread.findOne({ where: { threadID } });
|
|
34
37
|
return thread ? thread.get() : null;
|
|
35
|
-
} catch (
|
|
36
|
-
throw
|
|
38
|
+
} catch (err) {
|
|
39
|
+
throw wrapError("Failed to get thread", err);
|
|
37
40
|
}
|
|
38
41
|
},
|
|
39
42
|
|
|
40
43
|
async update(threadID, data) {
|
|
44
|
+
if (!Thread) {
|
|
45
|
+
return { thread: { threadID: validateId(threadID, ID_FIELD), ...(data || {}) }, created: false };
|
|
46
|
+
}
|
|
41
47
|
try {
|
|
42
|
-
threadID =
|
|
48
|
+
threadID = validateId(threadID, ID_FIELD);
|
|
43
49
|
validateData(data);
|
|
44
50
|
const thread = await Thread.findOne({ where: { threadID } });
|
|
45
|
-
|
|
46
51
|
if (thread) {
|
|
47
52
|
await thread.update(data);
|
|
48
53
|
return { thread: thread.get(), created: false };
|
|
49
|
-
} else {
|
|
50
|
-
const newThread = await Thread.create({ ...data, threadID });
|
|
51
|
-
return { thread: newThread.get(), created: true };
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const newThread = await Thread.create({ ...data, threadID });
|
|
56
|
+
return { thread: newThread.get(), created: true };
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw wrapError("Failed to update thread", err);
|
|
55
59
|
}
|
|
56
60
|
},
|
|
57
61
|
|
|
58
62
|
async del(threadID) {
|
|
63
|
+
if (!Thread) throw new Error(DB_NOT_INIT);
|
|
59
64
|
try {
|
|
60
|
-
|
|
61
|
-
throw new Error("threadID is required and cannot be undefined");
|
|
62
|
-
}
|
|
63
|
-
threadID = validateThreadID(threadID);
|
|
64
|
-
if (!threadID) {
|
|
65
|
-
throw new Error("Invalid threadID");
|
|
66
|
-
}
|
|
65
|
+
threadID = validateId(threadID, ID_FIELD);
|
|
67
66
|
const result = await Thread.destroy({ where: { threadID } });
|
|
68
|
-
if (result === 0)
|
|
69
|
-
throw new Error("No thread found with the specified threadID");
|
|
70
|
-
}
|
|
67
|
+
if (result === 0) throw new Error("No thread found with the specified threadID");
|
|
71
68
|
return result;
|
|
72
|
-
} catch (
|
|
73
|
-
throw
|
|
69
|
+
} catch (err) {
|
|
70
|
+
throw wrapError("Failed to delete thread", err);
|
|
74
71
|
}
|
|
75
72
|
},
|
|
73
|
+
|
|
76
74
|
async delAll() {
|
|
75
|
+
if (!Thread) return 0;
|
|
77
76
|
try {
|
|
78
77
|
return await Thread.destroy({ where: {} });
|
|
79
|
-
} catch (
|
|
80
|
-
throw
|
|
78
|
+
} catch (err) {
|
|
79
|
+
throw wrapError("Failed to delete all threads", err);
|
|
81
80
|
}
|
|
82
81
|
},
|
|
82
|
+
|
|
83
83
|
async getAll(keys = null) {
|
|
84
|
+
if (!Thread) return [];
|
|
84
85
|
try {
|
|
85
|
-
const attributes =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
: undefined;
|
|
91
|
-
const threads = await Thread.findAll({ attributes });
|
|
92
|
-
return threads.map(thread => thread.get());
|
|
93
|
-
} catch (error) {
|
|
94
|
-
throw new Error(`Failed to get all threads: ${error.message}`);
|
|
86
|
+
const attributes = normalizeAttributes(keys);
|
|
87
|
+
const rows = await Thread.findAll({ attributes });
|
|
88
|
+
return rows.map((t) => t.get());
|
|
89
|
+
} catch (err) {
|
|
90
|
+
throw wrapError("Failed to get all threads", err);
|
|
95
91
|
}
|
|
96
92
|
}
|
|
97
93
|
};
|
package/src/database/userData.js
CHANGED
|
@@ -1,88 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
const models = require("./models");
|
|
4
|
+
const {
|
|
5
|
+
DB_NOT_INIT,
|
|
6
|
+
validateId,
|
|
7
|
+
validateData,
|
|
8
|
+
normalizeAttributes,
|
|
9
|
+
normalizePayload,
|
|
10
|
+
wrapError
|
|
11
|
+
} = require("./helpers");
|
|
12
|
+
|
|
13
|
+
const User = models.User;
|
|
14
|
+
const ID_FIELD = "userID";
|
|
15
|
+
|
|
16
|
+
function stubUser(userID, data) {
|
|
17
|
+
return { user: { userID, ...normalizePayload(data || {}, "data") }, created: true };
|
|
18
|
+
}
|
|
14
19
|
|
|
15
20
|
module.exports = function (bot) {
|
|
16
21
|
return {
|
|
17
22
|
async create(userID, data) {
|
|
23
|
+
if (!User) return stubUser(validateId(userID, ID_FIELD), data);
|
|
18
24
|
try {
|
|
19
|
-
userID =
|
|
25
|
+
userID = validateId(userID, ID_FIELD);
|
|
20
26
|
validateData(data);
|
|
27
|
+
const payload = normalizePayload(data, "data");
|
|
21
28
|
let user = await User.findOne({ where: { userID } });
|
|
22
29
|
if (user) return { user: user.get(), created: false };
|
|
23
|
-
const payload = Object.prototype.hasOwnProperty.call(data, "data") ? data : { data };
|
|
24
30
|
user = await User.create({ userID, ...payload });
|
|
25
31
|
return { user: user.get(), created: true };
|
|
26
|
-
} catch (
|
|
27
|
-
throw
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw wrapError("Failed to create user", err);
|
|
28
34
|
}
|
|
29
35
|
},
|
|
30
36
|
|
|
31
37
|
async get(userID) {
|
|
38
|
+
if (!User) return null;
|
|
32
39
|
try {
|
|
33
|
-
userID =
|
|
40
|
+
userID = validateId(userID, ID_FIELD);
|
|
34
41
|
const user = await User.findOne({ where: { userID } });
|
|
35
42
|
return user ? user.get() : null;
|
|
36
|
-
} catch (
|
|
37
|
-
throw
|
|
43
|
+
} catch (err) {
|
|
44
|
+
throw wrapError("Failed to get user", err);
|
|
38
45
|
}
|
|
39
46
|
},
|
|
40
47
|
|
|
41
48
|
async update(userID, data) {
|
|
49
|
+
if (!User) return { user: { userID: validateId(userID, ID_FIELD), ...normalizePayload(data || {}, "data") }, created: false };
|
|
42
50
|
try {
|
|
43
|
-
userID =
|
|
51
|
+
userID = validateId(userID, ID_FIELD);
|
|
44
52
|
validateData(data);
|
|
45
|
-
const payload =
|
|
53
|
+
const payload = normalizePayload(data, "data");
|
|
46
54
|
const user = await User.findOne({ where: { userID } });
|
|
47
55
|
if (user) {
|
|
48
56
|
await user.update(payload);
|
|
49
57
|
return { user: user.get(), created: false };
|
|
50
|
-
} else {
|
|
51
|
-
const newUser = await User.create({ userID, ...payload });
|
|
52
|
-
return { user: newUser.get(), created: true };
|
|
53
58
|
}
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
const newUser = await User.create({ userID, ...payload });
|
|
60
|
+
return { user: newUser.get(), created: true };
|
|
61
|
+
} catch (err) {
|
|
62
|
+
throw wrapError("Failed to update user", err);
|
|
56
63
|
}
|
|
57
64
|
},
|
|
58
65
|
|
|
59
66
|
async del(userID) {
|
|
67
|
+
if (!User) throw new Error(DB_NOT_INIT);
|
|
60
68
|
try {
|
|
61
|
-
|
|
62
|
-
userID = validateUserID(userID);
|
|
69
|
+
userID = validateId(userID, ID_FIELD);
|
|
63
70
|
const result = await User.destroy({ where: { userID } });
|
|
64
71
|
if (result === 0) throw new Error("No user found with the specified userID");
|
|
65
72
|
return result;
|
|
66
|
-
} catch (
|
|
67
|
-
throw
|
|
73
|
+
} catch (err) {
|
|
74
|
+
throw wrapError("Failed to delete user", err);
|
|
68
75
|
}
|
|
69
76
|
},
|
|
70
77
|
|
|
71
78
|
async delAll() {
|
|
79
|
+
if (!User) return 0;
|
|
72
80
|
try {
|
|
73
81
|
return await User.destroy({ where: {} });
|
|
74
|
-
} catch (
|
|
75
|
-
throw
|
|
82
|
+
} catch (err) {
|
|
83
|
+
throw wrapError("Failed to delete all users", err);
|
|
76
84
|
}
|
|
77
85
|
},
|
|
78
86
|
|
|
79
87
|
async getAll(keys = null) {
|
|
88
|
+
if (!User) return [];
|
|
80
89
|
try {
|
|
81
|
-
const attributes =
|
|
82
|
-
const
|
|
83
|
-
return
|
|
84
|
-
} catch (
|
|
85
|
-
throw
|
|
90
|
+
const attributes = normalizeAttributes(keys);
|
|
91
|
+
const rows = await User.findAll({ attributes });
|
|
92
|
+
return rows.map((u) => u.get());
|
|
93
|
+
} catch (err) {
|
|
94
|
+
throw wrapError("Failed to get all users", err);
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
97
|
};
|