@2byte/tgbot-framework 1.0.17 → 1.0.18
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/package.json +1 -1
- package/src/core/App.ts +6 -7
- package/src/illumination/InlineKeyboard.ts +10 -0
- package/src/illumination/Message2Byte.ts +1 -1
- package/src/illumination/RunSectionRoute.ts +4 -0
- package/src/models/AccessKey.ts +24 -13
- package/src/models/Model.ts +3 -3
- package/src/user/UserModel.ts +9 -0
- package/src/user/UserStore.ts +19 -0
- package/templates/bot/database/migrations/010_access_keys.sql +12 -0
- package/templates/bot/package.json +1 -1
package/package.json
CHANGED
package/src/core/App.ts
CHANGED
|
@@ -279,12 +279,7 @@ export class App {
|
|
|
279
279
|
? startPayload.split("key=")[1] || null
|
|
280
280
|
: null;
|
|
281
281
|
}
|
|
282
|
-
|
|
283
|
-
"exists storage",
|
|
284
|
-
this.config.userStorage.exists(tgUsername),
|
|
285
|
-
"remeber:",
|
|
286
|
-
this.rememberUser(tgUsername)
|
|
287
|
-
);
|
|
282
|
+
|
|
288
283
|
// Check access by username and register user if not exists
|
|
289
284
|
if (!this.config.userStorage.exists(tgUsername) && !this.rememberUser(tgUsername)) {
|
|
290
285
|
const isAuthByUsername = !this.config.accessPublic && !accessKey;
|
|
@@ -907,7 +902,7 @@ export class App {
|
|
|
907
902
|
}
|
|
908
903
|
sectionClass = this.sectionClasses.get(sectionId) as typeof Section;
|
|
909
904
|
}
|
|
910
|
-
this.debugLog("Using section class:", sectionClass.
|
|
905
|
+
this.debugLog("Using section class:", sectionClass.name);
|
|
911
906
|
|
|
912
907
|
let sectionInstance: Section | undefined;
|
|
913
908
|
|
|
@@ -921,6 +916,10 @@ export class App {
|
|
|
921
916
|
};
|
|
922
917
|
|
|
923
918
|
const createRunnedSection = (instance: Section, route: RunSectionRoute): RunnedSection => {
|
|
919
|
+
if (route.hasCallbackParams()) {
|
|
920
|
+
instance.setCallbackParams(route.getCallbackParams());
|
|
921
|
+
this.debugLog("Set callback params for section instance:", route.getCallbackParams());
|
|
922
|
+
}
|
|
924
923
|
return {
|
|
925
924
|
instance,
|
|
926
925
|
route,
|
|
@@ -38,6 +38,16 @@ export class InlineKeyboard {
|
|
|
38
38
|
return this;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
appendArray(rows: any[][]): InlineKeyboard {
|
|
42
|
+
rows.forEach(row => this.append(row));
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
prependArray(rows: any[][]): InlineKeyboard {
|
|
47
|
+
rows.forEach(row => this.prepend(row));
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
prepend(...row: any[]): InlineKeyboard {
|
|
42
52
|
if (!Array.isArray(row)) {
|
|
43
53
|
this.keyboard.unshift([row]);
|
|
@@ -202,7 +202,7 @@ export default class Message2byte {
|
|
|
202
202
|
if (message) {
|
|
203
203
|
if ("media_group_id" in message || "caption" in message) {
|
|
204
204
|
const editMessageCaption = this.editMessageCaption(this.messageValue, this.messageExtra);
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
if (editMessageCaption && "message_id" in editMessageCaption) {
|
|
207
207
|
this.messageId = editMessageCaption.message_id as number;
|
|
208
208
|
}
|
|
@@ -74,6 +74,10 @@ export class RunSectionRoute {
|
|
|
74
74
|
getTriggers(): RunSectionRouteTrigger[] {
|
|
75
75
|
return this.runParams.triggers;
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
hasCallbackParams(): boolean {
|
|
79
|
+
return this.runParams.callbackParams && Array.from(this.runParams.callbackParams).length > 0;
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
getMethod(): string | null {
|
|
79
83
|
return this.runParams.method;
|
package/src/models/AccessKey.ts
CHANGED
|
@@ -3,9 +3,9 @@ import crypto from "crypto";
|
|
|
3
3
|
import { UserModel } from "../user/UserModel";
|
|
4
4
|
|
|
5
5
|
export interface AccessKeyData {
|
|
6
|
-
id
|
|
6
|
+
id: number;
|
|
7
7
|
user_id: number;
|
|
8
|
-
key
|
|
8
|
+
key: string;
|
|
9
9
|
used?: number;
|
|
10
10
|
used_user_id?: number | null;
|
|
11
11
|
created_at?: string;
|
|
@@ -41,31 +41,31 @@ export class AccessKey extends Model {
|
|
|
41
41
|
return key;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
static
|
|
44
|
+
static findByKey(key: string): AccessKeyData | null {
|
|
45
45
|
return this.queryOne(`SELECT * FROM ${this.tableName} WHERE key = ?`, [key]);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
static
|
|
48
|
+
static findById(id: number): AccessKeyData | null {
|
|
49
49
|
return this.queryOne(`SELECT * FROM ${this.tableName} WHERE id = ?`, [id]);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
static markUsed(key: string, usedUserId?: number):
|
|
52
|
+
static markUsed(key: string, usedUserId?: number): void {
|
|
53
53
|
this.execute(
|
|
54
54
|
`UPDATE ${this.tableName} SET used = 1, used_user_id = ?, created_at = created_at WHERE key = ?`,
|
|
55
55
|
[usedUserId || null, key]
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
static
|
|
60
|
-
|
|
59
|
+
static revoke(key: string): void {
|
|
60
|
+
this.execute(`DELETE FROM ${this.tableName} WHERE key = ?`, [key]);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
static
|
|
63
|
+
static getAll(limit = 100): AccessKeyData[] {
|
|
64
64
|
return this.query(`SELECT * FROM ${this.tableName} ORDER BY created_at DESC LIMIT ?`, [limit]);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/** Get all access keys for a given user */
|
|
68
|
-
static
|
|
68
|
+
static findByUser(userId: number, limit = 100): AccessKeyData[] {
|
|
69
69
|
return this.query(
|
|
70
70
|
`SELECT * FROM ${this.tableName} WHERE user_id = ? ORDER BY created_at DESC LIMIT ?`,
|
|
71
71
|
[userId, limit]
|
|
@@ -73,8 +73,19 @@ export class AccessKey extends Model {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/** Return the owner `UserModel` for a given access entry or null */
|
|
76
|
-
static
|
|
77
|
-
const userData =
|
|
76
|
+
static getUserByEntry(entry: AccessKeyData): any | null {
|
|
77
|
+
const userData = this.queryOne(`SELECT * FROM users WHERE id = ?`, [entry.user_id]);
|
|
78
|
+
if (!userData) return null;
|
|
79
|
+
try {
|
|
80
|
+
return UserModel.make(userData);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return userData;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static getUsedUserByEntry(entry: AccessKeyData): any | null {
|
|
87
|
+
if (!entry.used_user_id) return null;
|
|
88
|
+
const userData = this.queryOne(`SELECT * FROM users WHERE id = ?`, [entry.used_user_id]);
|
|
78
89
|
if (!userData) return null;
|
|
79
90
|
try {
|
|
80
91
|
return UserModel.make(userData);
|
|
@@ -84,8 +95,8 @@ export class AccessKey extends Model {
|
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
/** Find owner by key string */
|
|
87
|
-
static
|
|
88
|
-
const entry =
|
|
98
|
+
static getUserByKey(key: string): any | null {
|
|
99
|
+
const entry = this.findByKey(key);
|
|
89
100
|
if (!entry) return null;
|
|
90
101
|
return this.getUserByEntry(entry as AccessKeyData);
|
|
91
102
|
}
|
package/src/models/Model.ts
CHANGED
|
@@ -29,13 +29,13 @@ export abstract class Model {
|
|
|
29
29
|
return this.db.transaction(callback)();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
public static
|
|
32
|
+
public static paginate(paginateParams: ModelPaginateParams): PaginateResult {
|
|
33
33
|
const { page, route, routeParams, limit, whereSql, whereParams } = paginateParams;
|
|
34
34
|
const offset = (page - 1) * limit;
|
|
35
35
|
const sql = `SELECT * FROM ${this.tableName} ${whereSql} LIMIT ${offset}, ${limit}`;
|
|
36
36
|
|
|
37
|
-
const result =
|
|
38
|
-
const queryTotal =
|
|
37
|
+
const result = this.query(sql, whereParams);
|
|
38
|
+
const queryTotal = this.queryOne(`SELECT COUNT(*) as count FROM ${this.tableName} ${whereSql}`, whereParams);
|
|
39
39
|
const total = queryTotal ? queryTotal.count : 0;
|
|
40
40
|
const totalPages = Math.ceil(total / limit);
|
|
41
41
|
const hasPreviousPage = page > 1;
|
package/src/user/UserModel.ts
CHANGED
|
@@ -232,6 +232,15 @@ export class UserModel extends Model {
|
|
|
232
232
|
return undefined;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
static delete(id: number): boolean {
|
|
236
|
+
if (this.db) {
|
|
237
|
+
const result = this.db.run(`DELETE FROM ${this.tableName} WHERE id = ?`, [id]);
|
|
238
|
+
return result.changes > 0;
|
|
239
|
+
} else {
|
|
240
|
+
throw new Error("Database connection is not set.");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
235
244
|
get username(): string {
|
|
236
245
|
return this.attributes.tg_username;
|
|
237
246
|
}
|
package/src/user/UserStore.ts
CHANGED
|
@@ -116,4 +116,23 @@ export class UserStore {
|
|
|
116
116
|
});
|
|
117
117
|
}, 60 * 1000);
|
|
118
118
|
}
|
|
119
|
+
|
|
120
|
+
deleteByUsername(tgUsername: string): boolean {
|
|
121
|
+
const user = this.usersMap.get(tgUsername);
|
|
122
|
+
if (user) {
|
|
123
|
+
this.usersSession.delete(user);
|
|
124
|
+
return this.usersMap.delete(tgUsername);
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
deleteById(userId: number): boolean {
|
|
130
|
+
const userEntry = Array.from(this.usersMap).find(([_, user]) => user.id === userId);
|
|
131
|
+
if (userEntry) {
|
|
132
|
+
const [tgUsername, user] = userEntry;
|
|
133
|
+
this.usersSession.delete(user);
|
|
134
|
+
return this.usersMap.delete(tgUsername);
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
119
138
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- UP
|
|
2
|
+
CREATE TABLE IF NOT EXISTS access_keys (
|
|
3
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
user_id INTEGER NOT NULL,
|
|
5
|
+
key TEXT NOT NULL UNIQUE,
|
|
6
|
+
used INTEGER NOT NULL DEFAULT 0,
|
|
7
|
+
used_user_id INTEGER DEFAULT NULL,
|
|
8
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- DOWN
|
|
12
|
+
DROP TABLE IF EXISTS access_keys;
|