From 9f8bfb4bce299f01464e87912a7d0330aa141d00 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:22:38 +0000
Subject: [PATCH 1/7] Initial plan
From 25d8822ffd43911c21e06d385bbb2aa0232132c3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:26:43 +0000
Subject: [PATCH 2/7] Add ClubAffairsReminder class with weekly and daily
reminder functionality
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
.../ClubAffairsReminder.cs | 337 ++++++++++++++++++
.../PluginMain.cs | 19 +-
2 files changed, 355 insertions(+), 1 deletion(-)
create mode 100644 src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
new file mode 100644
index 0000000..a37cb8c
--- /dev/null
+++ b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
@@ -0,0 +1,337 @@
+using System.Text;
+using HuaJiBot.NET.Bot;
+using Ical.Net.CalendarComponents;
+using Timer = System.Timers.Timer;
+
+namespace HuaJiBot.NET.Plugin.Calendar;
+
+///
+/// 社团事务临期提醒功能
+/// 提供一周预告和一天提醒功能
+///
+internal class ClubAffairsReminder : IDisposable
+{
+ public PluginConfig Config { get; }
+ public BotService Service { get; }
+ private readonly Func _getCalendar;
+ private Ical.Net.Calendar? Calendar => _getCalendar();
+ private readonly Timer _dailyCheckTimer;
+ private const int CheckIntervalMinutes = 60; // 每小时检查一次
+ private DateTimeOffset _lastWeeklySummaryDate = DateTimeOffset.MinValue;
+ private DateTimeOffset _lastDailyReminderDate = DateTimeOffset.MinValue;
+
+ public ClubAffairsReminder(
+ BotService service,
+ PluginConfig config,
+ Func getCalendar
+ )
+ {
+ Service = service;
+ Config = config;
+ _getCalendar = getCalendar;
+ _dailyCheckTimer = new Timer(TimeSpan.FromMinutes(CheckIntervalMinutes));
+ _dailyCheckTimer.Elapsed += (_, _) => CheckAndSendReminders();
+ _dailyCheckTimer.AutoReset = true;
+
+ // 初始延迟检查
+ Task.Delay(30_000).ContinueWith(_ => CheckAndSendReminders());
+ }
+
+ public void Start()
+ {
+ _dailyCheckTimer.Start();
+ }
+
+ private void CheckAndSendReminders()
+ {
+ try
+ {
+ var now = Utils.NetworkTime.Now;
+
+ // 检查是否应该发送每周汇总(每周一上午9:00)
+ if (ShouldSendWeeklySummary(now))
+ {
+ SendWeeklySummary(now);
+ _lastWeeklySummaryDate = now.Date;
+ }
+
+ // 检查是否应该发送每日提醒(每天上午9:00)
+ if (ShouldSendDailyReminder(now))
+ {
+ SendDailyReminder(now);
+ _lastDailyReminderDate = now.Date;
+ }
+ }
+ catch (Exception ex)
+ {
+ Service.LogError("社团事务提醒任务出现异常", ex);
+ }
+ }
+
+ private bool ShouldSendWeeklySummary(DateTimeOffset now)
+ {
+ // 每周一上午9:00发送
+ if (now.DayOfWeek != DayOfWeek.Monday)
+ return false;
+
+ if (now.Hour != 9)
+ return false;
+
+ // 检查今天是否已经发送过
+ return now.Date != _lastWeeklySummaryDate.Date;
+ }
+
+ private bool ShouldSendDailyReminder(DateTimeOffset now)
+ {
+ // 每天上午9:00发送
+ if (now.Hour != 9)
+ return false;
+
+ // 检查今天是否已经发送过
+ return now.Date != _lastDailyReminderDate.Date;
+ }
+
+ private void SendWeeklySummary(DateTimeOffset now)
+ {
+ if (Calendar is null)
+ {
+ Service.Log("[社团事务] 日历为空,跳过每周汇总发送");
+ return;
+ }
+
+ var weekStart = now;
+ var weekEnd = now.AddDays(7);
+
+ var upcomingEvents = Calendar
+ .GetEvents(weekStart, weekEnd)
+ .OrderBy(x => x.period.StartTime)
+ .ToList();
+
+ if (upcomingEvents.Count == 0)
+ {
+ Service.Log("[社团事务] 本周无即将到期的事务");
+ return;
+ }
+
+ var message = BuildWeeklySummaryMessage(now, weekEnd, upcomingEvents);
+
+ foreach (var group in Config.ReminderGroups)
+ {
+ if (group.Mode == PluginConfig.ReminderFilterConfig.FilterMode.Default ||
+ ShouldSendToGroup(upcomingEvents, group))
+ {
+ Service.SendGroupMessageAsync(null, group.GroupId, message);
+ Service.Log($"[社团事务] 已向群组 {group.GroupId} 发送每周汇总");
+ }
+ }
+ }
+
+ private void SendDailyReminder(DateTimeOffset now)
+ {
+ if (Calendar is null)
+ {
+ Service.Log("[社团事务] 日历为空,跳过每日提醒发送");
+ return;
+ }
+
+ var tomorrow = now.Date.AddDays(1);
+ var dayAfterTomorrow = tomorrow.AddDays(1);
+
+ var tomorrowEvents = Calendar
+ .GetEvents(tomorrow, dayAfterTomorrow)
+ .OrderBy(x => x.period.StartTime)
+ .ToList();
+
+ if (tomorrowEvents.Count == 0)
+ {
+ Service.Log("[社团事务] 明天无即将到期的事务");
+ return;
+ }
+
+ var message = BuildDailyReminderMessage(tomorrow, tomorrowEvents);
+
+ foreach (var group in Config.ReminderGroups)
+ {
+ var groupEvents = FilterEventsForGroup(tomorrowEvents, group);
+ if (groupEvents.Count > 0)
+ {
+ var groupMessage = BuildDailyReminderMessage(tomorrow, groupEvents);
+ Service.SendGroupMessageAsync(null, group.GroupId, groupMessage);
+ Service.Log($"[社团事务] 已向群组 {group.GroupId} 发送每日提醒");
+ }
+ }
+ }
+
+ private bool ShouldSendToGroup(
+ List<(CalendarExtensions.Period period, CalendarEvent e)> events,
+ PluginConfig.ReminderFilterConfig group
+ )
+ {
+ if (group.Mode == PluginConfig.ReminderFilterConfig.FilterMode.Default)
+ return true;
+
+ return events.Any(evt =>
+ {
+ var e = evt.e;
+ var list = group.Keywords;
+ return group.Mode switch
+ {
+ PluginConfig.ReminderFilterConfig.FilterMode.WhiteList => list.Any(x =>
+ (e.Summary?.Contains(x) ?? false)
+ || (e.Description?.Contains(x) ?? false)
+ || (e.Location ?? "").Contains(x)
+ ),
+ PluginConfig.ReminderFilterConfig.FilterMode.BlackList => !list.Any(x =>
+ (e.Summary?.Contains(x) ?? false)
+ || (e.Description?.Contains(x) ?? false)
+ || (e.Location ?? "").Contains(x)
+ ),
+ _ => false,
+ };
+ });
+ }
+
+ private List<(CalendarExtensions.Period period, CalendarEvent e)> FilterEventsForGroup(
+ List<(CalendarExtensions.Period period, CalendarEvent e)> events,
+ PluginConfig.ReminderFilterConfig group
+ )
+ {
+ if (group.Mode == PluginConfig.ReminderFilterConfig.FilterMode.Default)
+ return events;
+
+ return events
+ .Where(evt =>
+ {
+ var e = evt.e;
+ var list = group.Keywords;
+ return group.Mode switch
+ {
+ PluginConfig.ReminderFilterConfig.FilterMode.WhiteList => list.Any(x =>
+ (e.Summary?.Contains(x) ?? false)
+ || (e.Description?.Contains(x) ?? false)
+ || (e.Location ?? "").Contains(x)
+ ),
+ PluginConfig.ReminderFilterConfig.FilterMode.BlackList => !list.Any(x =>
+ (e.Summary?.Contains(x) ?? false)
+ || (e.Description?.Contains(x) ?? false)
+ || (e.Location ?? "").Contains(x)
+ ),
+ _ => true,
+ };
+ })
+ .ToList();
+ }
+
+ private string BuildWeeklySummaryMessage(
+ DateTimeOffset weekStart,
+ DateTimeOffset weekEnd,
+ List<(CalendarExtensions.Period period, CalendarEvent e)> events
+ )
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine(
+ $"📢 社团事务一周预告({weekStart:MM月dd日}~{weekEnd:MM月dd日})"
+ );
+ sb.AppendLine("以下事务将在一周内到期,请相关负责人提前准备:");
+ sb.AppendLine();
+
+ for (int i = 0; i < events.Count; i++)
+ {
+ var (period, e) = events[i];
+ var emoji = GetNumberEmoji(i + 1);
+ var dateStr = period.StartTime.ToString("MM月dd日");
+ var responsible = ExtractResponsible(e);
+ sb.AppendLine(
+ $"{emoji} [{dateStr}] {e.Summary ?? "未命名事务"}{(string.IsNullOrEmpty(responsible) ? "" : $"(负责人:{responsible})")}"
+ );
+ }
+
+ sb.AppendLine();
+ sb.AppendLine("✅ 请大家合理安排时间,确保事项按时完成。");
+ sb.AppendLine("—— 社团事务提醒机器人 🤖");
+
+ return sb.ToString();
+ }
+
+ private string BuildDailyReminderMessage(
+ DateTimeOffset tomorrow,
+ List<(CalendarExtensions.Period period, CalendarEvent e)> events
+ )
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine("⏰ 临期提醒");
+ sb.AppendLine($"明天({tomorrow:MM月dd日})截止的社团事务:");
+ sb.AppendLine();
+
+ foreach (var (period, e) in events)
+ {
+ var responsible = ExtractResponsible(e);
+ sb.AppendLine(
+ $"• {e.Summary ?? "未命名事务"}{(string.IsNullOrEmpty(responsible) ? "" : $"(负责人:{responsible})")}"
+ );
+ }
+
+ sb.AppendLine();
+ sb.AppendLine("请务必在截止前完成相关工作!");
+ sb.AppendLine("—— 社团事务提醒机器人 🤖");
+
+ return sb.ToString();
+ }
+
+ private string ExtractResponsible(CalendarEvent e)
+ {
+ // 尝试从描述中提取负责人信息
+ if (string.IsNullOrWhiteSpace(e.Description))
+ return string.Empty;
+
+ // 查找常见的负责人标识
+ var patterns = new[] { "负责人:", "负责人:", "责任人:", "责任人:" };
+ foreach (var pattern in patterns)
+ {
+ var index = e.Description.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
+ if (index >= 0)
+ {
+ var startIndex = index + pattern.Length;
+ var endIndex = e.Description.IndexOfAny(
+ new[] { '\n', '\r', ')', ')', ',', ',' },
+ startIndex
+ );
+ if (endIndex > startIndex)
+ {
+ return e.Description.Substring(startIndex, endIndex - startIndex).Trim();
+ }
+ else if (startIndex < e.Description.Length)
+ {
+ var remaining = e.Description.Substring(startIndex).Trim();
+ // 取前20个字符作为负责人名字
+ return remaining.Length > 20 ? remaining.Substring(0, 20) : remaining;
+ }
+ }
+ }
+
+ return string.Empty;
+ }
+
+ private string GetNumberEmoji(int number)
+ {
+ return number switch
+ {
+ 1 => "1️⃣",
+ 2 => "2️⃣",
+ 3 => "3️⃣",
+ 4 => "4️⃣",
+ 5 => "5️⃣",
+ 6 => "6️⃣",
+ 7 => "7️⃣",
+ 8 => "8️⃣",
+ 9 => "9️⃣",
+ 10 => "🔟",
+ _ => $"{number}.",
+ };
+ }
+
+ public void Dispose()
+ {
+ _dailyCheckTimer?.Dispose();
+ }
+}
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs b/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
index d52281f..d552b29 100644
--- a/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
+++ b/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
@@ -42,6 +42,7 @@ public PluginMain()
private RemoteSync Sync => _sync.Value;
private Ical.Net.Calendar? Calendar => _sync.Value.Calendar;
private ReminderTask? _reminderTask;
+ private ClubAffairsReminder? _clubAffairsReminder;
protected override void Initialize()
{
@@ -57,6 +58,19 @@ protected override void Initialize()
}
);
_reminderTask.Start();
+
+ // 启动社团事务临期提醒功能
+ _clubAffairsReminder = new(
+ Service,
+ Config,
+ () =>
+ {
+ _ = Sync.UpdateCalendarAsync();
+ return Calendar;
+ }
+ );
+ _clubAffairsReminder.Start();
+ Service.Log("[日程] 社团事务临期提醒功能已启动");
}
private readonly Dictionary _cache = new();
@@ -201,5 +215,8 @@ public override IEnumerable? ExportFunctions
}
}
- protected override void Unload() { }
+ protected override void Unload()
+ {
+ _clubAffairsReminder?.Dispose();
+ }
}
From 13d46c941878ad2a2a0ac5f3a6f871c89a7a1214 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:27:54 +0000
Subject: [PATCH 3/7] Add configuration options for club affairs reminder
feature
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
.../ClubAffairsReminder.cs | 19 +++---
.../PluginMain.cs | 60 +++++++++++++++----
2 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
index a37cb8c..e8934fc 100644
--- a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
+++ b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
@@ -48,15 +48,15 @@ private void CheckAndSendReminders()
{
var now = Utils.NetworkTime.Now;
- // 检查是否应该发送每周汇总(每周一上午9:00)
- if (ShouldSendWeeklySummary(now))
+ // 检查是否应该发送每周汇总
+ if (Config.ClubAffairsReminder.EnableWeeklySummary && ShouldSendWeeklySummary(now))
{
SendWeeklySummary(now);
_lastWeeklySummaryDate = now.Date;
}
- // 检查是否应该发送每日提醒(每天上午9:00)
- if (ShouldSendDailyReminder(now))
+ // 检查是否应该发送每日提醒
+ if (Config.ClubAffairsReminder.EnableDailyReminder && ShouldSendDailyReminder(now))
{
SendDailyReminder(now);
_lastDailyReminderDate = now.Date;
@@ -70,11 +70,12 @@ private void CheckAndSendReminders()
private bool ShouldSendWeeklySummary(DateTimeOffset now)
{
- // 每周一上午9:00发送
- if (now.DayOfWeek != DayOfWeek.Monday)
+ // 根据配置的星期几发送
+ if (now.DayOfWeek != Config.ClubAffairsReminder.WeeklySummaryDayOfWeek)
return false;
- if (now.Hour != 9)
+ // 根据配置的小时发送
+ if (now.Hour != Config.ClubAffairsReminder.WeeklySummaryHour)
return false;
// 检查今天是否已经发送过
@@ -83,8 +84,8 @@ private bool ShouldSendWeeklySummary(DateTimeOffset now)
private bool ShouldSendDailyReminder(DateTimeOffset now)
{
- // 每天上午9:00发送
- if (now.Hour != 9)
+ // 根据配置的小时发送
+ if (now.Hour != Config.ClubAffairsReminder.DailyReminderHour)
return false;
// 检查今天是否已经发送过
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs b/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
index d552b29..f5199b3 100644
--- a/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
+++ b/src/HuaJiBot.NET.Plugin.Calendar/PluginMain.cs
@@ -12,6 +12,37 @@ public class PluginConfig : ConfigBase
public int MinRange = -128;
public int MaxRange = 48;
public ReminderFilterConfig[] ReminderGroups = [];
+
+ // 社团事务临期提醒配置
+ public ClubAffairsReminderConfig ClubAffairsReminder { get; set; } = new();
+
+ public class ClubAffairsReminderConfig
+ {
+ ///
+ /// 是否启用每周汇总提醒(默认启用)
+ ///
+ public bool EnableWeeklySummary { get; set; } = true;
+
+ ///
+ /// 是否启用每日提醒(默认启用)
+ ///
+ public bool EnableDailyReminder { get; set; } = true;
+
+ ///
+ /// 每周汇总发送时间(小时,0-23,默认9点)
+ ///
+ public int WeeklySummaryHour { get; set; } = 9;
+
+ ///
+ /// 每日提醒发送时间(小时,0-23,默认9点)
+ ///
+ public int DailyReminderHour { get; set; } = 9;
+
+ ///
+ /// 每周汇总发送在星期几(0=周日,1=周一,默认1=周一)
+ ///
+ public DayOfWeek WeeklySummaryDayOfWeek { get; set; } = DayOfWeek.Monday;
+ }
public class ReminderFilterConfig
{
@@ -60,17 +91,24 @@ protected override void Initialize()
_reminderTask.Start();
// 启动社团事务临期提醒功能
- _clubAffairsReminder = new(
- Service,
- Config,
- () =>
- {
- _ = Sync.UpdateCalendarAsync();
- return Calendar;
- }
- );
- _clubAffairsReminder.Start();
- Service.Log("[日程] 社团事务临期提醒功能已启动");
+ if (Config.ClubAffairsReminder.EnableWeeklySummary || Config.ClubAffairsReminder.EnableDailyReminder)
+ {
+ _clubAffairsReminder = new(
+ Service,
+ Config,
+ () =>
+ {
+ _ = Sync.UpdateCalendarAsync();
+ return Calendar;
+ }
+ );
+ _clubAffairsReminder.Start();
+ Service.Log("[日程] 社团事务临期提醒功能已启动");
+ }
+ else
+ {
+ Service.Log("[日程] 社团事务临期提醒功能已禁用");
+ }
}
private readonly Dictionary _cache = new();
From be02ff7ffe4c78f6aa080eacbace0f9a26a561f3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:29:56 +0000
Subject: [PATCH 4/7] Add tests and documentation for club affairs reminder
feature
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
.../ClubAffairsReminder.README.md | 101 ++++++++++++++++
.../ClubAffairsReminderTest.cs | 110 ++++++++++++++++++
2 files changed, 211 insertions(+)
create mode 100644 src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.README.md
create mode 100644 src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.README.md b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.README.md
new file mode 100644
index 0000000..c7c862e
--- /dev/null
+++ b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.README.md
@@ -0,0 +1,101 @@
+# 社团事务临期提醒功能
+
+## 功能介绍
+
+社团事务临期提醒功能是 Calendar 插件的一部分,用于帮助社团成员更好地管理即将到期的事务,避免遗漏重要事项。
+
+## 功能特性
+
+### 1. 每周汇总预告
+
+在配置的时间(默认:每周一上午 9:00)发送一条汇总消息,列出接下来一周内即将到期的社团事务。
+
+**示例消息:**
+
+```
+📢 社团事务一周预告(10月20日~10月26日)
+以下事务将在一周内到期,请相关负责人提前准备:
+
+1️⃣ [10月22日] 迎新晚会节目单提交(负责人:李华)
+2️⃣ [10月24日] 社团经费报销材料上交(负责人:张敏)
+3️⃣ [10月25日] 社团展板更新完成(负责人:王强)
+
+✅ 请大家合理安排时间,确保事项按时完成。
+—— 社团事务提醒机器人 🤖
+```
+
+### 2. 每日临期提醒
+
+在配置的时间(默认:每天上午 9:00)发送单条提醒消息,提醒明天即将截止的事务。
+
+**示例消息:**
+
+```
+⏰ 临期提醒
+明天(10月25日)截止的社团事务:
+
+• 社团展板更新完成(负责人:王强)
+
+请务必在截止前完成相关工作!
+—— 社团事务提醒机器人 🤖
+```
+
+## 配置说明
+
+在插件配置文件中,可以通过 `ClubAffairsReminder` 节点进行配置:
+
+```json
+{
+ "ClubAffairsReminder": {
+ "EnableWeeklySummary": true,
+ "EnableDailyReminder": true,
+ "WeeklySummaryHour": 9,
+ "DailyReminderHour": 9,
+ "WeeklySummaryDayOfWeek": 1
+ }
+}
+```
+
+### 配置项说明
+
+| 配置项 | 类型 | 默认值 | 说明 |
+|--------|------|--------|------|
+| `EnableWeeklySummary` | bool | `true` | 是否启用每周汇总提醒 |
+| `EnableDailyReminder` | bool | `true` | 是否启用每日提醒 |
+| `WeeklySummaryHour` | int | `9` | 每周汇总发送时间(小时,0-23) |
+| `DailyReminderHour` | int | `9` | 每日提醒发送时间(小时,0-23) |
+| `WeeklySummaryDayOfWeek` | int | `1` | 每周汇总发送在星期几(0=周日,1=周一,...,6=周六) |
+
+## 负责人信息提取
+
+系统会自动从事务描述中提取负责人信息。支持以下格式:
+
+- `负责人:张三`
+- `负责人:张三`
+- `责任人:张三`
+- `责任人:张三`
+
+## 过滤规则
+
+提醒消息遵循现有的 `ReminderGroups` 配置,支持白名单、黑名单和默认模式:
+
+- **Default(默认)**:发送所有事务提醒
+- **WhiteList(白名单)**:仅发送包含指定关键词的事务
+- **BlackList(黑名单)**:不发送包含指定关键词的事务
+
+关键词匹配会检查事务的概要(Summary)、描述(Description)和地点(Location)字段。
+
+## 工作原理
+
+1. 系统每小时检查一次当前时间
+2. 在配置的时间点,检查是否需要发送提醒
+3. 使用日期记录防止同一天重复发送
+4. 根据过滤规则筛选要发送的群组和事务
+5. 自动提取负责人信息并格式化消息
+
+## 注意事项
+
+- 提醒功能需要正确配置 `ReminderGroups` 才能发送消息
+- 系统使用网络时间(NetworkTime)确保时间准确性
+- 日历数据需要成功同步才能发送提醒
+- 如果某一天没有即将到期的事务,不会发送空消息
diff --git a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
new file mode 100644
index 0000000..7a76b91
--- /dev/null
+++ b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
@@ -0,0 +1,110 @@
+namespace HuaJiBot.NET.UnitTest;
+
+internal class ClubAffairsReminderTest
+{
+ [Test]
+ public void TestWeeklySummaryDayOfWeek()
+ {
+ // Test that Monday is correctly identified for weekly summary
+ var monday = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8)); // Monday
+ var tuesday = new DateTimeOffset(2024, 10, 22, 9, 0, 0, TimeSpan.FromHours(8)); // Tuesday
+
+ Assert.That(monday.DayOfWeek, Is.EqualTo(DayOfWeek.Monday));
+ Assert.That(tuesday.DayOfWeek, Is.Not.EqualTo(DayOfWeek.Monday));
+ }
+
+ [Test]
+ public void TestTimeComparison()
+ {
+ // Test that hour comparison works correctly for reminder timing
+ var nineAm = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
+ var tenAm = new DateTimeOffset(2024, 10, 21, 10, 0, 0, TimeSpan.FromHours(8));
+
+ Assert.That(nineAm.Hour, Is.EqualTo(9));
+ Assert.That(tenAm.Hour, Is.EqualTo(10));
+ }
+
+ [Test]
+ public void TestDateComparison()
+ {
+ // Test date comparison for preventing duplicate reminders
+ var date1 = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
+ var date2 = new DateTimeOffset(2024, 10, 21, 10, 0, 0, TimeSpan.FromHours(8));
+ var date3 = new DateTimeOffset(2024, 10, 22, 9, 0, 0, TimeSpan.FromHours(8));
+
+ Assert.That(date1.Date, Is.EqualTo(date2.Date));
+ Assert.That(date1.Date, Is.Not.EqualTo(date3.Date));
+ }
+
+ [Test]
+ public void TestWeekRange()
+ {
+ // Test that week range calculation is correct
+ var start = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
+ var end = start.AddDays(7);
+
+ var expectedEnd = new DateTimeOffset(2024, 10, 28, 9, 0, 0, TimeSpan.FromHours(8));
+ Assert.That(end, Is.EqualTo(expectedEnd));
+ }
+
+ [Test]
+ public void TestDayRange()
+ {
+ // Test that tomorrow calculation is correct
+ var today = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
+ var tomorrow = today.Date.AddDays(1);
+ var dayAfterTomorrow = tomorrow.AddDays(1);
+
+ var expectedTomorrow = new DateTimeOffset(2024, 10, 22, 0, 0, 0, TimeSpan.FromHours(8));
+ var expectedDayAfter = new DateTimeOffset(2024, 10, 23, 0, 0, 0, TimeSpan.FromHours(8));
+
+ Assert.That(tomorrow, Is.EqualTo(expectedTomorrow));
+ Assert.That(dayAfterTomorrow, Is.EqualTo(expectedDayAfter));
+ }
+
+ [Test]
+ public void TestNumberEmoji()
+ {
+ // Test emoji mapping
+ var testCases = new Dictionary
+ {
+ { 1, "1️⃣" },
+ { 2, "2️⃣" },
+ { 3, "3️⃣" },
+ { 4, "4️⃣" },
+ { 5, "5️⃣" },
+ { 6, "6️⃣" },
+ { 7, "7️⃣" },
+ { 8, "8️⃣" },
+ { 9, "9️⃣" },
+ { 10, "🔟" },
+ };
+
+ foreach (var testCase in testCases)
+ {
+ var emoji = GetNumberEmoji(testCase.Key);
+ Assert.That(emoji, Is.EqualTo(testCase.Value));
+ }
+
+ // Test fallback for numbers > 10
+ Assert.That(GetNumberEmoji(11), Is.EqualTo("11."));
+ }
+
+ private string GetNumberEmoji(int number)
+ {
+ return number switch
+ {
+ 1 => "1️⃣",
+ 2 => "2️⃣",
+ 3 => "3️⃣",
+ 4 => "4️⃣",
+ 5 => "5️⃣",
+ 6 => "6️⃣",
+ 7 => "7️⃣",
+ 8 => "8️⃣",
+ 9 => "9️⃣",
+ 10 => "🔟",
+ _ => $"{number}.",
+ };
+ }
+}
From 396c4e45fb67b5cb4e5fa2c101ff12f43a43b2ff Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:31:44 +0000
Subject: [PATCH 5/7] Fix type mismatch in ClubAffairsReminderTest
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
index 7a76b91..9485e86 100644
--- a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
+++ b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
@@ -52,11 +52,11 @@ public void TestDayRange()
{
// Test that tomorrow calculation is correct
var today = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
- var tomorrow = today.Date.AddDays(1);
+ var tomorrow = today.AddDays(1).Date;
var dayAfterTomorrow = tomorrow.AddDays(1);
- var expectedTomorrow = new DateTimeOffset(2024, 10, 22, 0, 0, 0, TimeSpan.FromHours(8));
- var expectedDayAfter = new DateTimeOffset(2024, 10, 23, 0, 0, 0, TimeSpan.FromHours(8));
+ var expectedTomorrow = new DateTime(2024, 10, 22, 0, 0, 0);
+ var expectedDayAfter = new DateTime(2024, 10, 23, 0, 0, 0);
Assert.That(tomorrow, Is.EqualTo(expectedTomorrow));
Assert.That(dayAfterTomorrow, Is.EqualTo(expectedDayAfter));
From e4ba8dfb857b3770327547744c4c305282a735fd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:34:59 +0000
Subject: [PATCH 6/7] Fix DateTimeOffset type consistency in
ClubAffairsReminder
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs | 4 ++--
src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
index e8934fc..86c2c77 100644
--- a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
+++ b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
@@ -135,8 +135,8 @@ private void SendDailyReminder(DateTimeOffset now)
return;
}
- var tomorrow = now.Date.AddDays(1);
- var dayAfterTomorrow = tomorrow.AddDays(1);
+ var tomorrow = new DateTimeOffset(now.Date.AddDays(1), now.Offset);
+ var dayAfterTomorrow = new DateTimeOffset(now.Date.AddDays(2), now.Offset);
var tomorrowEvents = Calendar
.GetEvents(tomorrow, dayAfterTomorrow)
diff --git a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
index 9485e86..15e345f 100644
--- a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
+++ b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
@@ -52,11 +52,11 @@ public void TestDayRange()
{
// Test that tomorrow calculation is correct
var today = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
- var tomorrow = today.AddDays(1).Date;
- var dayAfterTomorrow = tomorrow.AddDays(1);
+ var tomorrow = new DateTimeOffset(today.Date.AddDays(1), today.Offset);
+ var dayAfterTomorrow = new DateTimeOffset(today.Date.AddDays(2), today.Offset);
- var expectedTomorrow = new DateTime(2024, 10, 22, 0, 0, 0);
- var expectedDayAfter = new DateTime(2024, 10, 23, 0, 0, 0);
+ var expectedTomorrow = new DateTimeOffset(2024, 10, 22, 0, 0, 0, TimeSpan.FromHours(8));
+ var expectedDayAfter = new DateTimeOffset(2024, 10, 23, 0, 0, 0, TimeSpan.FromHours(8));
Assert.That(tomorrow, Is.EqualTo(expectedTomorrow));
Assert.That(dayAfterTomorrow, Is.EqualTo(expectedDayAfter));
From 8067d584d4d32c06039a4fc20cbbb106f71299d7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Oct 2025 08:36:35 +0000
Subject: [PATCH 7/7] Add clarifying comments for DateTimeOffset usage in date
range queries
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
---
src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs | 1 +
src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs | 1 +
2 files changed, 2 insertions(+)
diff --git a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
index 86c2c77..0c53c26 100644
--- a/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
+++ b/src/HuaJiBot.NET.Plugin.Calendar/ClubAffairsReminder.cs
@@ -135,6 +135,7 @@ private void SendDailyReminder(DateTimeOffset now)
return;
}
+ // 创建明天和后天的DateTimeOffset,时间设置为00:00:00以获取整天的事务
var tomorrow = new DateTimeOffset(now.Date.AddDays(1), now.Offset);
var dayAfterTomorrow = new DateTimeOffset(now.Date.AddDays(2), now.Offset);
diff --git a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
index 15e345f..5d89172 100644
--- a/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
+++ b/src/HuaJiBot.NET.UnitTest/ClubAffairsReminderTest.cs
@@ -51,6 +51,7 @@ public void TestWeekRange()
public void TestDayRange()
{
// Test that tomorrow calculation is correct
+ // 创建午夜时间的DateTimeOffset以匹配生产代码中用于日期范围查询的行为
var today = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
var tomorrow = new DateTimeOffset(today.Date.AddDays(1), today.Offset);
var dayAfterTomorrow = new DateTimeOffset(today.Date.AddDays(2), today.Offset);