@minato-bot/plugin-gugu 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,166 @@
1
+ import { and, between, defineRelations, desc, eq } from "drizzle-orm";
2
+ import { bigint, bigserial, pgTable, text, timestamp } from "drizzle-orm/pg-core";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ import { drizzle } from "drizzle-orm/bun-sql";
6
+ import { migrate } from "drizzle-orm/bun-sql/migrator";
7
+ import { randomInt } from "node:crypto";
8
+ import { Plugin } from "@atri-bot/core";
9
+ import dayjs from "dayjs";
10
+ import { Structs } from "node-napcat-ts";
11
+ import yargs from "yargs";
12
+ //#region src/db.ts
13
+ const timestamps = {
14
+ created_at: timestamp().notNull().defaultNow(),
15
+ updated_at: timestamp().notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
16
+ };
17
+ const Pigeons = pgTable("pigeons", {
18
+ user_id: bigserial("id", { mode: "number" }).primaryKey(),
19
+ pigeon_num: bigint("pigeon_num", { mode: "number" }).notNull(),
20
+ ...timestamps
21
+ });
22
+ const PigeonHistories = pgTable("pigeon_histories", {
23
+ id: bigserial("id", { mode: "number" }).primaryKey(),
24
+ user_id: bigserial("user_id", { mode: "number" }).notNull(),
25
+ operation: bigint("operation", { mode: "number" }).notNull(),
26
+ prev_num: bigint("prev_num", { mode: "number" }).notNull(),
27
+ current_num: bigint("current_num", { mode: "number" }).notNull(),
28
+ reason: text(),
29
+ ...timestamps
30
+ });
31
+ const Schema = {
32
+ Pigeons,
33
+ PigeonHistories
34
+ };
35
+ const Relations = defineRelations(Schema, (r) => ({ PigeonHistories: { Pigeon: r.one.Pigeons({
36
+ from: r.PigeonHistories.user_id,
37
+ to: r.Pigeons.user_id
38
+ }) } }));
39
+ //#endregion
40
+ //#region src/dbUtils.ts
41
+ if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL 环境变量未设置, 请设置 DATABASE_URL 环境变量以连接数据库");
42
+ const Drizzle = drizzle(process.env.DATABASE_URL, {
43
+ schema: Schema,
44
+ relations: Relations
45
+ });
46
+ async function migrateDrizzle() {
47
+ await migrate(Drizzle, {
48
+ migrationsFolder: path.join(import.meta.dir, "../drizzle"),
49
+ migrationsTable: "gugu_drizzle_migrations"
50
+ });
51
+ }
52
+ async function getUserPigeonInfo(user_id) {
53
+ const pigeonInfo = await Drizzle.query.Pigeons.findFirst({ where: { user_id } });
54
+ if (pigeonInfo) return pigeonInfo;
55
+ await Drizzle.insert(Schema.Pigeons).values({
56
+ user_id,
57
+ pigeon_num: 0
58
+ });
59
+ return await getUserPigeonInfo(user_id);
60
+ }
61
+ async function addUserPigeonNum(user_id, addNum, reason) {
62
+ const pigeonInfo = await getUserPigeonInfo(user_id);
63
+ if (addNum < 0) return false;
64
+ await Drizzle.update(Schema.Pigeons).set({ pigeon_num: pigeonInfo.pigeon_num + addNum }).where(eq(Schema.Pigeons.user_id, user_id));
65
+ await Drizzle.insert(Schema.PigeonHistories).values({
66
+ user_id,
67
+ operation: addNum,
68
+ prev_num: pigeonInfo.pigeon_num,
69
+ current_num: pigeonInfo.pigeon_num + addNum,
70
+ reason
71
+ });
72
+ return true;
73
+ }
74
+ async function reduceUserPigeonNum(user_id, reduceNum, reason) {
75
+ const pigeonInfo = await getUserPigeonInfo(user_id);
76
+ if (reduceNum <= 0 || pigeonInfo.pigeon_num - reduceNum < 0) return false;
77
+ await Drizzle.update(Schema.Pigeons).set({ pigeon_num: pigeonInfo.pigeon_num - reduceNum }).where(eq(Schema.Pigeons.user_id, user_id));
78
+ await Drizzle.insert(Schema.PigeonHistories).values({
79
+ user_id,
80
+ operation: reduceNum,
81
+ prev_num: pigeonInfo.pigeon_num + reduceNum,
82
+ current_num: pigeonInfo.pigeon_num,
83
+ reason
84
+ });
85
+ return true;
86
+ }
87
+ //#endregion
88
+ //#region package.json
89
+ var name = "@minato-bot/plugin-gugu";
90
+ //#endregion
91
+ //#region src/plugin.ts
92
+ const guguPluginGuguRegexp = /咕咕/;
93
+ async function handleGuguCommand(user_id, addRange) {
94
+ const today = dayjs();
95
+ if (await Drizzle.select().from(Schema.PigeonHistories).where(and(eq(Schema.PigeonHistories.user_id, user_id), eq(Schema.PigeonHistories.reason, "每日咕咕"), between(Schema.PigeonHistories.created_at, today.startOf("day").toDate(), today.endOf("day").toDate()))).then((res) => res.length > 0)) return [Structs.text(`今天已经咕咕过了! 明天再来吧!`)];
96
+ const addNum = randomInt(addRange[0], addRange[1]);
97
+ if (!await addUserPigeonNum(user_id, addNum, "每日咕咕")) return [Structs.text(`修改鸽子数失败!`)];
98
+ return [Structs.text(`咕咕成功! 获得 ${addNum} 只鸽子!`)];
99
+ }
100
+ const queryPigeonRegexp = /我的鸽子|查鸽子/;
101
+ const queryPigeonCommander = yargs().option("user_id", {
102
+ type: "number",
103
+ description: "要查询的用户ID,默认为自己"
104
+ });
105
+ const pigeonRankRegexp = /鸽子排行/;
106
+ const pigeonRankCommander = yargs().option("page", {
107
+ alias: "p",
108
+ type: "number",
109
+ description: "页码,默认为1",
110
+ default: 1
111
+ }).option("size", {
112
+ alias: "s",
113
+ type: "number",
114
+ description: "每页数量,默认为10,最大20",
115
+ default: 10
116
+ });
117
+ const plugin = new Plugin(name).setDefaultConfig({
118
+ addRange: [1, 100],
119
+ firstAdd: 300
120
+ }).onInstall(async ({ event, config, bot }) => {
121
+ await migrateDrizzle();
122
+ event.regCommandEvent({
123
+ trigger: guguPluginGuguRegexp,
124
+ callback: async ({ context }) => {
125
+ const user_id = context.user_id;
126
+ if (!await Drizzle.query.Pigeons.findFirst({ where: { user_id } })) {
127
+ await addUserPigeonNum(user_id, config.firstAdd, "初始赠送");
128
+ await bot.sendMsg(context, [Structs.text(`欢迎第一次咕咕! 作为初始奖励, 你获得了 ${config.firstAdd} 只鸽子!`)]);
129
+ }
130
+ const result = await handleGuguCommand(user_id, config.addRange);
131
+ await bot.sendMsg(context, result);
132
+ }
133
+ });
134
+ event.regCommandEvent({
135
+ trigger: queryPigeonRegexp,
136
+ commander: queryPigeonCommander,
137
+ callback: async ({ context, options }) => {
138
+ const result = await getUserPigeonInfo(options.user_id ?? context.user_id);
139
+ const username = await bot.getUsername({ user_id: result.user_id });
140
+ await bot.sendMsg(context, [Structs.text(`用户 ${username} 共有 ${result.pigeon_num} 只鸽子!`)]);
141
+ }
142
+ });
143
+ event.regCommandEvent({
144
+ trigger: pigeonRankRegexp,
145
+ commander: pigeonRankCommander,
146
+ callback: async ({ context, options }) => {
147
+ const page = Math.max(1, options.page);
148
+ const size = Math.max(1, Math.min(20, options.size));
149
+ const offset = (page - 1) * size;
150
+ const rows = await Drizzle.select().from(Schema.Pigeons).orderBy(desc(Schema.Pigeons.pigeon_num)).limit(size).offset(offset);
151
+ if (rows.length === 0) {
152
+ await bot.sendMsg(context, [Structs.text(`暂无鸽子数据!`)]);
153
+ return;
154
+ }
155
+ const total = await Drizzle.select().from(Schema.Pigeons);
156
+ const totalPages = Math.ceil(total.length / size);
157
+ const rankList = await Promise.all(rows.map(async (item, index) => {
158
+ const username = await bot.getUsername({ user_id: item.user_id });
159
+ return `${offset + index + 1}. 用户: ${username} 共有 ${item.pigeon_num} 只鸽子`;
160
+ }));
161
+ await bot.sendMsg(context, [Structs.text(`鸽子排行 (第 ${page} 页 / 共 ${totalPages} 页):\n${rankList.join("\n")}`)]);
162
+ }
163
+ });
164
+ });
165
+ //#endregion
166
+ export { Drizzle, PigeonHistories, Pigeons, Relations, Schema, addUserPigeonNum, getUserPigeonInfo, guguPluginGuguRegexp, handleGuguCommand, migrateDrizzle, pigeonRankCommander, pigeonRankRegexp, plugin, queryPigeonCommander, queryPigeonRegexp, reduceUserPigeonNum, timestamps };
@@ -0,0 +1,17 @@
1
+ CREATE TABLE "pigeon_histories" (
2
+ "id" bigserial PRIMARY KEY,
3
+ "user_id" bigserial,
4
+ "operation" bigint NOT NULL,
5
+ "prev_num" bigint NOT NULL,
6
+ "current_num" bigint NOT NULL,
7
+ "reason" text,
8
+ "created_at" timestamp DEFAULT now() NOT NULL,
9
+ "updated_at" timestamp DEFAULT now() NOT NULL
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE TABLE "pigeons" (
13
+ "id" bigserial PRIMARY KEY,
14
+ "pigeon_num" bigint NOT NULL,
15
+ "created_at" timestamp DEFAULT now() NOT NULL,
16
+ "updated_at" timestamp DEFAULT now() NOT NULL
17
+ );
@@ -0,0 +1,199 @@
1
+ {
2
+ "version": "8",
3
+ "dialect": "postgres",
4
+ "id": "ec10cb7e-96b0-4cf3-8896-f89c6c9525b8",
5
+ "prevIds": [
6
+ "00000000-0000-0000-0000-000000000000"
7
+ ],
8
+ "ddl": [
9
+ {
10
+ "isRlsEnabled": false,
11
+ "name": "pigeon_histories",
12
+ "entityType": "tables",
13
+ "schema": "public"
14
+ },
15
+ {
16
+ "isRlsEnabled": false,
17
+ "name": "pigeons",
18
+ "entityType": "tables",
19
+ "schema": "public"
20
+ },
21
+ {
22
+ "type": "bigserial",
23
+ "typeSchema": null,
24
+ "notNull": true,
25
+ "dimensions": 0,
26
+ "default": null,
27
+ "generated": null,
28
+ "identity": null,
29
+ "name": "id",
30
+ "entityType": "columns",
31
+ "schema": "public",
32
+ "table": "pigeon_histories"
33
+ },
34
+ {
35
+ "type": "bigserial",
36
+ "typeSchema": null,
37
+ "notNull": true,
38
+ "dimensions": 0,
39
+ "default": null,
40
+ "generated": null,
41
+ "identity": null,
42
+ "name": "user_id",
43
+ "entityType": "columns",
44
+ "schema": "public",
45
+ "table": "pigeon_histories"
46
+ },
47
+ {
48
+ "type": "bigint",
49
+ "typeSchema": null,
50
+ "notNull": true,
51
+ "dimensions": 0,
52
+ "default": null,
53
+ "generated": null,
54
+ "identity": null,
55
+ "name": "operation",
56
+ "entityType": "columns",
57
+ "schema": "public",
58
+ "table": "pigeon_histories"
59
+ },
60
+ {
61
+ "type": "bigint",
62
+ "typeSchema": null,
63
+ "notNull": true,
64
+ "dimensions": 0,
65
+ "default": null,
66
+ "generated": null,
67
+ "identity": null,
68
+ "name": "prev_num",
69
+ "entityType": "columns",
70
+ "schema": "public",
71
+ "table": "pigeon_histories"
72
+ },
73
+ {
74
+ "type": "bigint",
75
+ "typeSchema": null,
76
+ "notNull": true,
77
+ "dimensions": 0,
78
+ "default": null,
79
+ "generated": null,
80
+ "identity": null,
81
+ "name": "current_num",
82
+ "entityType": "columns",
83
+ "schema": "public",
84
+ "table": "pigeon_histories"
85
+ },
86
+ {
87
+ "type": "text",
88
+ "typeSchema": null,
89
+ "notNull": false,
90
+ "dimensions": 0,
91
+ "default": null,
92
+ "generated": null,
93
+ "identity": null,
94
+ "name": "reason",
95
+ "entityType": "columns",
96
+ "schema": "public",
97
+ "table": "pigeon_histories"
98
+ },
99
+ {
100
+ "type": "timestamp",
101
+ "typeSchema": null,
102
+ "notNull": true,
103
+ "dimensions": 0,
104
+ "default": "now()",
105
+ "generated": null,
106
+ "identity": null,
107
+ "name": "created_at",
108
+ "entityType": "columns",
109
+ "schema": "public",
110
+ "table": "pigeon_histories"
111
+ },
112
+ {
113
+ "type": "timestamp",
114
+ "typeSchema": null,
115
+ "notNull": true,
116
+ "dimensions": 0,
117
+ "default": "now()",
118
+ "generated": null,
119
+ "identity": null,
120
+ "name": "updated_at",
121
+ "entityType": "columns",
122
+ "schema": "public",
123
+ "table": "pigeon_histories"
124
+ },
125
+ {
126
+ "type": "bigserial",
127
+ "typeSchema": null,
128
+ "notNull": true,
129
+ "dimensions": 0,
130
+ "default": null,
131
+ "generated": null,
132
+ "identity": null,
133
+ "name": "id",
134
+ "entityType": "columns",
135
+ "schema": "public",
136
+ "table": "pigeons"
137
+ },
138
+ {
139
+ "type": "bigint",
140
+ "typeSchema": null,
141
+ "notNull": true,
142
+ "dimensions": 0,
143
+ "default": null,
144
+ "generated": null,
145
+ "identity": null,
146
+ "name": "pigeon_num",
147
+ "entityType": "columns",
148
+ "schema": "public",
149
+ "table": "pigeons"
150
+ },
151
+ {
152
+ "type": "timestamp",
153
+ "typeSchema": null,
154
+ "notNull": true,
155
+ "dimensions": 0,
156
+ "default": "now()",
157
+ "generated": null,
158
+ "identity": null,
159
+ "name": "created_at",
160
+ "entityType": "columns",
161
+ "schema": "public",
162
+ "table": "pigeons"
163
+ },
164
+ {
165
+ "type": "timestamp",
166
+ "typeSchema": null,
167
+ "notNull": true,
168
+ "dimensions": 0,
169
+ "default": "now()",
170
+ "generated": null,
171
+ "identity": null,
172
+ "name": "updated_at",
173
+ "entityType": "columns",
174
+ "schema": "public",
175
+ "table": "pigeons"
176
+ },
177
+ {
178
+ "columns": [
179
+ "id"
180
+ ],
181
+ "nameExplicit": false,
182
+ "name": "pigeon_histories_pkey",
183
+ "schema": "public",
184
+ "table": "pigeon_histories",
185
+ "entityType": "pks"
186
+ },
187
+ {
188
+ "columns": [
189
+ "id"
190
+ ],
191
+ "nameExplicit": false,
192
+ "name": "pigeons_pkey",
193
+ "schema": "public",
194
+ "table": "pigeons",
195
+ "entityType": "pks"
196
+ }
197
+ ],
198
+ "renames": []
199
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@minato-bot/plugin-gugu",
3
+ "type": "module",
4
+ "version": "2.0.0",
5
+ "description": "gugu for atri framework",
6
+ "author": "huan_kong",
7
+ "license": "MIT",
8
+ "main": "./dist/index.mjs",
9
+ "types": "./dist/index.d.mts",
10
+ "files": [
11
+ "./dist/**/*",
12
+ "./drizzle/**/*"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsdown",
16
+ "lint": "eslint",
17
+ "typecheck": "tsc --noEmit -p tsconfig.json --composite false",
18
+ "drizzle": "drizzle-kit"
19
+ },
20
+ "dependencies": {
21
+ "@atri-bot/core": "^2.1.3",
22
+ "dayjs": "^1.11.20",
23
+ "drizzle-orm": "^1.0.0-beta.19",
24
+ "node-napcat-ts": "^0.4.23",
25
+ "yargs": "^18.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/yargs": "^17.0.35",
29
+ "drizzle-kit": "^1.0.0-beta.19"
30
+ }
31
+ }