koishi-plugin-wordpress-notifier 2.1.0 → 2.4.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/README.md +20 -0
- package/lib/index.d.ts +1 -6
- package/lib/index.js +110 -45
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -339,6 +339,26 @@ npm install
|
|
|
339
339
|
|
|
340
340
|
## 版本历史
|
|
341
341
|
|
|
342
|
+
### 2.3.0 (2026-01-25)
|
|
343
|
+
|
|
344
|
+
- 🔧 增强命令权限管理,限制敏感命令仅超级管理员可用
|
|
345
|
+
- ✅ 为`wordpress.set-url`命令添加超级管理员权限检查
|
|
346
|
+
- ✅ 为`wordpress.clean [days]`命令添加超级管理员权限检查
|
|
347
|
+
- ✅ 为`wordpress.toggle`命令添加超级管理员权限检查
|
|
348
|
+
- ✅ 为`wordpress.toggle-update`命令添加超级管理员权限检查
|
|
349
|
+
- ✅ 为`wordpress.toggle-user`命令添加超级管理员权限检查
|
|
350
|
+
- ✅ 为`wordpress.mention`命令添加超级管理员权限检查
|
|
351
|
+
- ✅ 添加了详细的日志记录,便于追踪非授权访问尝试
|
|
352
|
+
|
|
353
|
+
### 2.2.0 (2026-01-25)
|
|
354
|
+
|
|
355
|
+
- 🐛 修复重复推送问题,清理未使用的数据库表
|
|
356
|
+
- ✅ 移除了未使用的`wordpress_posts`表,统一使用`wordpress_group_pushes`表进行推送记录管理
|
|
357
|
+
- ✅ 修复了`wordpress.pushed`命令,使用`wordpress_group_pushes`表获取已推送记录
|
|
358
|
+
- ✅ 修复了`wordpress.clean`命令,移除了对`wordpress_posts`表的引用
|
|
359
|
+
- ✅ 增强了推送日志,添加了详细的调试信息,便于追踪推送流程
|
|
360
|
+
- ✅ 优化了`isGroupPushed`和`markGroupAsPushed`函数,添加了更多日志
|
|
361
|
+
|
|
342
362
|
### 2.1.0 (2026-01-25)
|
|
343
363
|
|
|
344
364
|
- 🔧 更新文档结构,将"如何获取用户注册日期"内容从版本历史移至常见问题部分
|
package/lib/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export declare const inject: string[];
|
|
|
3
3
|
export declare const name = "wordpress-notifier";
|
|
4
4
|
declare module 'koishi' {
|
|
5
5
|
interface Tables {
|
|
6
|
-
wordpress_posts: WordPressPostRecord;
|
|
7
6
|
wordpress_post_updates: WordPressPostUpdateRecord;
|
|
8
7
|
wordpress_user_registrations: WordPressUserRegistrationRecord;
|
|
9
8
|
wordpress_group_pushes: WordPressGroupPushRecord;
|
|
@@ -20,6 +19,7 @@ export interface Config {
|
|
|
20
19
|
maxArticles: number;
|
|
21
20
|
username?: string;
|
|
22
21
|
applicationPassword?: string;
|
|
22
|
+
superAdmins: string[];
|
|
23
23
|
}
|
|
24
24
|
export interface WordPressPost {
|
|
25
25
|
id: number;
|
|
@@ -50,11 +50,6 @@ export interface WordPressUser {
|
|
|
50
50
|
roles: string[];
|
|
51
51
|
[key: string]: any;
|
|
52
52
|
}
|
|
53
|
-
export interface WordPressPostRecord {
|
|
54
|
-
id: number;
|
|
55
|
-
postId: number;
|
|
56
|
-
pushedAt: Date;
|
|
57
|
-
}
|
|
58
53
|
export interface WordPressPostUpdateRecord {
|
|
59
54
|
id: number;
|
|
60
55
|
postId: number;
|
package/lib/index.js
CHANGED
|
@@ -15,18 +15,11 @@ exports.Config = koishi_1.Schema.object({
|
|
|
15
15
|
mentionAll: koishi_1.Schema.boolean().default(false).description('是否 @全体成员'),
|
|
16
16
|
maxArticles: koishi_1.Schema.number().default(5).description('每次最多推送的文章数量'),
|
|
17
17
|
username: koishi_1.Schema.string().default('').description('WordPress 用户名(用于 Basic 认证,与应用程序密码配合使用)'),
|
|
18
|
-
applicationPassword: koishi_1.Schema.string().default('').description('WordPress 应用程序密码(用于 Basic 认证,例如:hGR2sPFuYnclxHc4AvJqcUtB)')
|
|
18
|
+
applicationPassword: koishi_1.Schema.string().default('').description('WordPress 应用程序密码(用于 Basic 认证,例如:hGR2sPFuYnclxHc4AvJqcUtB)'),
|
|
19
|
+
superAdmins: koishi_1.Schema.array(koishi_1.Schema.string()).default([]).description('超级管理员 QQ 号列表')
|
|
19
20
|
});
|
|
20
21
|
function apply(ctx, config) {
|
|
21
22
|
ctx.logger.info('WordPress 推送插件已加载');
|
|
22
|
-
ctx.model.extend('wordpress_posts', {
|
|
23
|
-
id: 'integer',
|
|
24
|
-
postId: 'integer',
|
|
25
|
-
pushedAt: 'timestamp'
|
|
26
|
-
}, {
|
|
27
|
-
primary: ['id'],
|
|
28
|
-
autoInc: true
|
|
29
|
-
});
|
|
30
23
|
ctx.model.extend('wordpress_post_updates', {
|
|
31
24
|
id: 'integer',
|
|
32
25
|
postId: 'integer',
|
|
@@ -151,6 +144,7 @@ function apply(ctx, config) {
|
|
|
151
144
|
}
|
|
152
145
|
async function isGroupPushed(groupId, postId) {
|
|
153
146
|
const record = await ctx.database.get('wordpress_group_pushes', { groupId, postId });
|
|
147
|
+
ctx.logger.info(`检查群 ${groupId} 是否已推送文章 ${postId}:${record.length > 0 ? '是' : '否'}`);
|
|
154
148
|
return record.length > 0;
|
|
155
149
|
}
|
|
156
150
|
async function markUserAsPushed(userId) {
|
|
@@ -173,16 +167,20 @@ function apply(ctx, config) {
|
|
|
173
167
|
}
|
|
174
168
|
async function markGroupAsPushed(groupId, postId, isUpdate) {
|
|
175
169
|
const record = await ctx.database.get('wordpress_group_pushes', { groupId, postId });
|
|
176
|
-
|
|
170
|
+
ctx.logger.info(`准备标记群 ${groupId} 已推送文章 ${postId},当前记录数量:${record.length}`);
|
|
171
|
+
if (record.length > 0) {
|
|
177
172
|
// Koishi database API 不支持 update 方法,使用 remove + create 代替
|
|
173
|
+
ctx.logger.info(`已存在记录,删除旧记录`);
|
|
178
174
|
await ctx.database.remove('wordpress_group_pushes', { groupId, postId });
|
|
179
175
|
}
|
|
176
|
+
ctx.logger.info(`创建新的推送记录`);
|
|
180
177
|
await ctx.database.create('wordpress_group_pushes', {
|
|
181
178
|
groupId,
|
|
182
179
|
postId,
|
|
183
180
|
pushedAt: new Date(),
|
|
184
181
|
isUpdate
|
|
185
182
|
});
|
|
183
|
+
ctx.logger.info(`已标记群 ${groupId} 已推送文章 ${postId}`);
|
|
186
184
|
}
|
|
187
185
|
function formatPostMessage(post, mention = false, isUpdate = false) {
|
|
188
186
|
// 彻底过滤 HTML 标签和非法字符,只保留安全文本
|
|
@@ -305,26 +303,30 @@ function apply(ctx, config) {
|
|
|
305
303
|
// 推送新文章
|
|
306
304
|
if (config.enableAutoPush) {
|
|
307
305
|
const posts = await fetchLatestPosts();
|
|
306
|
+
ctx.logger.info(`开始检查 ${posts.length} 篇文章是否需要推送`);
|
|
308
307
|
if (posts.length > 0) {
|
|
309
308
|
for (const post of posts) {
|
|
309
|
+
ctx.logger.info(`正在处理文章: ${post.id} - ${post.title.rendered}`);
|
|
310
|
+
ctx.logger.info(`文章 ID: ${post.id}, 发布时间: ${post.date}, 修改时间: ${post.modified}`);
|
|
310
311
|
for (const target of config.targets) {
|
|
311
312
|
try {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
ctx.logger.error(`无效的目标 ${target},必须是数字类型`);
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
// 保持字符串类型,但确保内容是有效的数字格式
|
|
319
|
-
const stringTarget = numericTarget.toString();
|
|
313
|
+
ctx.logger.info(`正在处理目标: ${target}`);
|
|
314
|
+
// 直接使用原始目标字符串,不进行数字转换,避免丢失平台前缀等信息
|
|
315
|
+
const stringTarget = target;
|
|
320
316
|
// 检查该群是否已推送过此文章
|
|
321
|
-
|
|
317
|
+
const hasPushed = await isGroupPushed(stringTarget, post.id);
|
|
318
|
+
ctx.logger.info(`检查结果: 群 ${stringTarget} 已推送文章 ${post.id}:${hasPushed ? '是' : '否'}`);
|
|
319
|
+
if (!hasPushed) {
|
|
322
320
|
const segments = formatPostMessage(post, true, false);
|
|
323
321
|
ctx.logger.info(`准备推送新文章到目标: ${stringTarget}`);
|
|
324
322
|
await bot.sendMessage(stringTarget, segments);
|
|
325
323
|
ctx.logger.info(`已推送新文章到 ${stringTarget}: ${post.title.rendered}`);
|
|
326
324
|
// 标记该群已推送此文章
|
|
327
325
|
await markGroupAsPushed(stringTarget, post.id, false);
|
|
326
|
+
ctx.logger.info(`已标记群 ${stringTarget} 已推送文章 ${post.id}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
ctx.logger.info(`跳过推送: 群 ${stringTarget} 已推送过文章 ${post.id}`);
|
|
328
330
|
}
|
|
329
331
|
}
|
|
330
332
|
catch (error) {
|
|
@@ -464,31 +466,90 @@ ${targetText}
|
|
|
464
466
|
});
|
|
465
467
|
ctx.command('wordpress.toggle-update', '切换文章更新推送开关')
|
|
466
468
|
.action(async ({ session }) => {
|
|
469
|
+
// 检查是否为超级管理员
|
|
470
|
+
if (!session || !session.userId) {
|
|
471
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.toggle-update 命令');
|
|
472
|
+
return '您不是超级管理员,无法执行此命令';
|
|
473
|
+
}
|
|
474
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
475
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
476
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
477
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
478
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.toggle-update 命令`);
|
|
479
|
+
return '您不是超级管理员,无法执行此命令';
|
|
480
|
+
}
|
|
467
481
|
ctx.logger.info('命令 wordpress.toggle-update 被调用');
|
|
468
482
|
config.enableUpdatePush = !config.enableUpdatePush;
|
|
469
483
|
return `文章更新推送已${config.enableUpdatePush ? '开启' : '关闭'}`;
|
|
470
484
|
});
|
|
471
485
|
ctx.command('wordpress.toggle-user', '切换新用户注册推送开关')
|
|
472
486
|
.action(async ({ session }) => {
|
|
487
|
+
// 检查是否为超级管理员
|
|
488
|
+
if (!session || !session.userId) {
|
|
489
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.toggle-user 命令');
|
|
490
|
+
return '您不是超级管理员,无法执行此命令';
|
|
491
|
+
}
|
|
492
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
493
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
494
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
495
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
496
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.toggle-user 命令`);
|
|
497
|
+
return '您不是超级管理员,无法执行此命令';
|
|
498
|
+
}
|
|
473
499
|
ctx.logger.info('命令 wordpress.toggle-user 被调用');
|
|
474
500
|
config.enableUserPush = !config.enableUserPush;
|
|
475
501
|
return `新用户注册推送已${config.enableUserPush ? '开启' : '关闭'}`;
|
|
476
502
|
});
|
|
477
503
|
ctx.command('wordpress.toggle', '切换自动推送开关')
|
|
478
504
|
.action(async ({ session }) => {
|
|
505
|
+
// 检查是否为超级管理员
|
|
506
|
+
if (!session || !session.userId) {
|
|
507
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.toggle 命令');
|
|
508
|
+
return '您不是超级管理员,无法执行此命令';
|
|
509
|
+
}
|
|
510
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
511
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
512
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
513
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
514
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.toggle 命令`);
|
|
515
|
+
return '您不是超级管理员,无法执行此命令';
|
|
516
|
+
}
|
|
479
517
|
ctx.logger.info('命令 wordpress.toggle 被调用');
|
|
480
518
|
config.enableAutoPush = !config.enableAutoPush;
|
|
481
519
|
return `自动推送已${config.enableAutoPush ? '开启' : '关闭'}`;
|
|
482
520
|
});
|
|
483
521
|
ctx.command('wordpress.mention', '切换 @全体成员 开关')
|
|
484
522
|
.action(async ({ session }) => {
|
|
523
|
+
// 检查是否为超级管理员
|
|
524
|
+
if (!session || !session.userId) {
|
|
525
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.mention 命令');
|
|
526
|
+
return '您不是超级管理员,无法执行此命令';
|
|
527
|
+
}
|
|
528
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
529
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
530
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
531
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
532
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.mention 命令`);
|
|
533
|
+
return '您不是超级管理员,无法执行此命令';
|
|
534
|
+
}
|
|
485
535
|
ctx.logger.info('命令 wordpress.mention 被调用');
|
|
486
536
|
config.mentionAll = !config.mentionAll;
|
|
487
537
|
return `@全体成员 已${config.mentionAll ? '开启' : '关闭'}`;
|
|
488
538
|
});
|
|
489
539
|
ctx.command('wordpress.set-url <url>', '修改 WordPress 站点地址')
|
|
490
540
|
.action(async ({ session }, url) => {
|
|
491
|
-
|
|
541
|
+
// 检查是否为超级管理员
|
|
542
|
+
if (!session || !session.userId) {
|
|
543
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.set-url 命令');
|
|
544
|
+
return '您不是超级管理员,无法执行此命令';
|
|
545
|
+
}
|
|
546
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
547
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
548
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
549
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
550
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.set-url 命令`);
|
|
551
|
+
return '您不是超级管理员,无法执行此命令';
|
|
552
|
+
}
|
|
492
553
|
ctx.logger.info(`命令 wordpress.set-url 被调用,调用者:${userId},新地址:${url}`);
|
|
493
554
|
// 修改站点地址
|
|
494
555
|
config.wordpressUrl = url;
|
|
@@ -498,8 +559,8 @@ ${targetText}
|
|
|
498
559
|
ctx.command('wordpress.pushed', '查看已推送的文章列表')
|
|
499
560
|
.action(async () => {
|
|
500
561
|
ctx.logger.info('命令 wordpress.pushed 被调用');
|
|
501
|
-
//
|
|
502
|
-
const records = await ctx.database.get('
|
|
562
|
+
// 获取已推送的文章记录,使用 wordpress_group_pushes 表
|
|
563
|
+
const records = await ctx.database.get('wordpress_group_pushes', {}, {
|
|
503
564
|
sort: {
|
|
504
565
|
pushedAt: 'desc'
|
|
505
566
|
}
|
|
@@ -509,13 +570,25 @@ ${targetText}
|
|
|
509
570
|
}
|
|
510
571
|
let message = '📋 已推送文章列表(按时间倒序):\n\n';
|
|
511
572
|
for (const record of records) {
|
|
512
|
-
message += `${record.id}. 文章 ID: ${record.postId}
|
|
573
|
+
message += `${record.id}. 文章 ID: ${record.postId}(群:${record.groupId},${record.isUpdate ? '更新' : '新文章'})\n`;
|
|
513
574
|
message += `📅 推送时间: ${new Date(record.pushedAt).toLocaleString('zh-CN')}\n\n`;
|
|
514
575
|
}
|
|
515
576
|
return message;
|
|
516
577
|
});
|
|
517
578
|
ctx.command('wordpress.clean [days]', '清理指定天数前的推送记录(默认 30 天)')
|
|
518
579
|
.action(async ({ session }, days) => {
|
|
580
|
+
// 检查是否为超级管理员
|
|
581
|
+
if (!session || !session.userId) {
|
|
582
|
+
ctx.logger.warn('匿名用户尝试调用 wordpress.clean 命令');
|
|
583
|
+
return '您不是超级管理员,无法执行此命令';
|
|
584
|
+
}
|
|
585
|
+
// 获取当前用户的QQ号(兼容不同平台格式,如 onebot:123456789 -> 123456789)
|
|
586
|
+
const userId = session.userId.replace(/^\w+:/, '');
|
|
587
|
+
// 检查当前用户是否在插件配置的超级管理员列表中
|
|
588
|
+
if (!config.superAdmins || !config.superAdmins.includes(userId)) {
|
|
589
|
+
ctx.logger.warn(`非超级管理员 ${userId} 尝试调用 wordpress.clean 命令`);
|
|
590
|
+
return '您不是超级管理员,无法执行此命令';
|
|
591
|
+
}
|
|
519
592
|
ctx.logger.info(`命令 wordpress.clean 被调用,天数:${days || '默认'}`);
|
|
520
593
|
// 设置默认天数
|
|
521
594
|
const daysToKeep = days ? parseInt(days) : 30;
|
|
@@ -526,14 +599,10 @@ ${targetText}
|
|
|
526
599
|
const cutoffDate = new Date();
|
|
527
600
|
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
|
|
528
601
|
// 获取所有记录
|
|
529
|
-
const allPostRecords = await ctx.database.get('wordpress_posts', {});
|
|
530
602
|
const allUpdateRecords = await ctx.database.get('wordpress_post_updates', {});
|
|
531
603
|
const allUserRecords = await ctx.database.get('wordpress_user_registrations', {});
|
|
532
604
|
const allGroupRecords = await ctx.database.get('wordpress_group_pushes', {});
|
|
533
605
|
// 筛选需要删除的记录
|
|
534
|
-
const postRecordsToRemove = allPostRecords.filter(record => {
|
|
535
|
-
return new Date(record.pushedAt) < cutoffDate;
|
|
536
|
-
});
|
|
537
606
|
const updateRecordsToRemove = allUpdateRecords.filter(record => {
|
|
538
607
|
return new Date(record.pushedAt) < cutoffDate;
|
|
539
608
|
});
|
|
@@ -545,10 +614,6 @@ ${targetText}
|
|
|
545
614
|
});
|
|
546
615
|
// 删除旧记录
|
|
547
616
|
let result = 0;
|
|
548
|
-
for (const record of postRecordsToRemove) {
|
|
549
|
-
await ctx.database.remove('wordpress_posts', { id: record.id });
|
|
550
|
-
result++;
|
|
551
|
-
}
|
|
552
617
|
for (const record of updateRecordsToRemove) {
|
|
553
618
|
await ctx.database.remove('wordpress_post_updates', { id: record.id });
|
|
554
619
|
result++;
|
|
@@ -567,20 +632,20 @@ ${targetText}
|
|
|
567
632
|
ctx.command('wordpress', 'WordPress 推送插件菜单')
|
|
568
633
|
.action(() => {
|
|
569
634
|
ctx.logger.info('命令 wordpress 被调用');
|
|
570
|
-
return `📚 WordPress 推送插件菜单:
|
|
571
|
-
|
|
572
|
-
🔹 /wordpress.status - 查看插件状态
|
|
573
|
-
🔹 /wordpress.latest - 查看最新文章
|
|
574
|
-
🔹 /wordpress.list - 查看文章列表
|
|
575
|
-
🔹 /wordpress.push - 手动推送最新文章
|
|
576
|
-
🔹 /wordpress.set-url <url> - 修改 WordPress 站点地址
|
|
577
|
-
🔹 /wordpress.pushed - 查看已推送文章列表
|
|
578
|
-
🔹 /wordpress.clean [days] - 清理旧推送记录
|
|
579
|
-
🔹 /wordpress.toggle -
|
|
580
|
-
🔹 /wordpress.toggle-update -
|
|
581
|
-
🔹 /wordpress.toggle-user -
|
|
582
|
-
🔹 /wordpress.mention - 切换 @全体成员
|
|
583
|
-
|
|
635
|
+
return `📚 WordPress 推送插件菜单:
|
|
636
|
+
|
|
637
|
+
🔹 /wordpress.status - 查看插件状态
|
|
638
|
+
🔹 /wordpress.latest - 查看最新文章
|
|
639
|
+
🔹 /wordpress.list - 查看文章列表
|
|
640
|
+
🔹 /wordpress.push - 手动推送最新文章
|
|
641
|
+
🔹 /wordpress.set-url <url> - 修改 WordPress 站点地址
|
|
642
|
+
🔹 /wordpress.pushed - 查看已推送文章列表
|
|
643
|
+
🔹 /wordpress.clean [days] - 清理旧推送记录
|
|
644
|
+
🔹 /wordpress.toggle - 切换自动推送开关(仅超级管理员)
|
|
645
|
+
🔹 /wordpress.toggle-update - 切换文章更新推送开关(仅超级管理员)
|
|
646
|
+
🔹 /wordpress.toggle-user - 切换新用户注册推送开关(仅超级管理员)
|
|
647
|
+
🔹 /wordpress.mention - 切换 @全体成员 开关(仅超级管理员)
|
|
648
|
+
|
|
584
649
|
💡 提示:所有命令都需要加 / 前缀`;
|
|
585
650
|
});
|
|
586
651
|
ctx.on('ready', async () => {
|
package/package.json
CHANGED