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 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
- if (record) {
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
- const numericTarget = Number(target);
314
- if (isNaN(numericTarget)) {
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
- if (!(await isGroupPushed(stringTarget, post.id))) {
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
- const userId = session?.userId || 'unknown';
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('wordpress_posts', {}, {
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}\n`;
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
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "koishi-plugin-wordpress-notifier",
3
- "version": "2.1.0",
2
+ "name": "koishi-plugin-wordpress-notifier",
3
+ "version": "2.4.0",
4
4
  "description": "WordPress 文章自动推送到 QQ",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",