Skip to content

Commit be02ff7

Browse files
CopilotLazuliKao
andcommitted
Add tests and documentation for club affairs reminder feature
Co-authored-by: LazuliKao <46601807+LazuliKao@users.noreply.github.com>
1 parent 13d46c9 commit be02ff7

2 files changed

Lines changed: 211 additions & 0 deletions

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# 社团事务临期提醒功能
2+
3+
## 功能介绍
4+
5+
社团事务临期提醒功能是 Calendar 插件的一部分,用于帮助社团成员更好地管理即将到期的事务,避免遗漏重要事项。
6+
7+
## 功能特性
8+
9+
### 1. 每周汇总预告
10+
11+
在配置的时间(默认:每周一上午 9:00)发送一条汇总消息,列出接下来一周内即将到期的社团事务。
12+
13+
**示例消息:**
14+
15+
```
16+
📢 社团事务一周预告(10月20日~10月26日)
17+
以下事务将在一周内到期,请相关负责人提前准备:
18+
19+
1️⃣ [10月22日] 迎新晚会节目单提交(负责人:李华)
20+
2️⃣ [10月24日] 社团经费报销材料上交(负责人:张敏)
21+
3️⃣ [10月25日] 社团展板更新完成(负责人:王强)
22+
23+
✅ 请大家合理安排时间,确保事项按时完成。
24+
—— 社团事务提醒机器人 🤖
25+
```
26+
27+
### 2. 每日临期提醒
28+
29+
在配置的时间(默认:每天上午 9:00)发送单条提醒消息,提醒明天即将截止的事务。
30+
31+
**示例消息:**
32+
33+
```
34+
⏰ 临期提醒
35+
明天(10月25日)截止的社团事务:
36+
37+
• 社团展板更新完成(负责人:王强)
38+
39+
请务必在截止前完成相关工作!
40+
—— 社团事务提醒机器人 🤖
41+
```
42+
43+
## 配置说明
44+
45+
在插件配置文件中,可以通过 `ClubAffairsReminder` 节点进行配置:
46+
47+
```json
48+
{
49+
"ClubAffairsReminder": {
50+
"EnableWeeklySummary": true,
51+
"EnableDailyReminder": true,
52+
"WeeklySummaryHour": 9,
53+
"DailyReminderHour": 9,
54+
"WeeklySummaryDayOfWeek": 1
55+
}
56+
}
57+
```
58+
59+
### 配置项说明
60+
61+
| 配置项 | 类型 | 默认值 | 说明 |
62+
|--------|------|--------|------|
63+
| `EnableWeeklySummary` | bool | `true` | 是否启用每周汇总提醒 |
64+
| `EnableDailyReminder` | bool | `true` | 是否启用每日提醒 |
65+
| `WeeklySummaryHour` | int | `9` | 每周汇总发送时间(小时,0-23) |
66+
| `DailyReminderHour` | int | `9` | 每日提醒发送时间(小时,0-23) |
67+
| `WeeklySummaryDayOfWeek` | int | `1` | 每周汇总发送在星期几(0=周日,1=周一,...,6=周六) |
68+
69+
## 负责人信息提取
70+
71+
系统会自动从事务描述中提取负责人信息。支持以下格式:
72+
73+
- `负责人:张三`
74+
- `负责人:张三`
75+
- `责任人:张三`
76+
- `责任人:张三`
77+
78+
## 过滤规则
79+
80+
提醒消息遵循现有的 `ReminderGroups` 配置,支持白名单、黑名单和默认模式:
81+
82+
- **Default(默认)**:发送所有事务提醒
83+
- **WhiteList(白名单)**:仅发送包含指定关键词的事务
84+
- **BlackList(黑名单)**:不发送包含指定关键词的事务
85+
86+
关键词匹配会检查事务的概要(Summary)、描述(Description)和地点(Location)字段。
87+
88+
## 工作原理
89+
90+
1. 系统每小时检查一次当前时间
91+
2. 在配置的时间点,检查是否需要发送提醒
92+
3. 使用日期记录防止同一天重复发送
93+
4. 根据过滤规则筛选要发送的群组和事务
94+
5. 自动提取负责人信息并格式化消息
95+
96+
## 注意事项
97+
98+
- 提醒功能需要正确配置 `ReminderGroups` 才能发送消息
99+
- 系统使用网络时间(NetworkTime)确保时间准确性
100+
- 日历数据需要成功同步才能发送提醒
101+
- 如果某一天没有即将到期的事务,不会发送空消息
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
namespace HuaJiBot.NET.UnitTest;
2+
3+
internal class ClubAffairsReminderTest
4+
{
5+
[Test]
6+
public void TestWeeklySummaryDayOfWeek()
7+
{
8+
// Test that Monday is correctly identified for weekly summary
9+
var monday = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8)); // Monday
10+
var tuesday = new DateTimeOffset(2024, 10, 22, 9, 0, 0, TimeSpan.FromHours(8)); // Tuesday
11+
12+
Assert.That(monday.DayOfWeek, Is.EqualTo(DayOfWeek.Monday));
13+
Assert.That(tuesday.DayOfWeek, Is.Not.EqualTo(DayOfWeek.Monday));
14+
}
15+
16+
[Test]
17+
public void TestTimeComparison()
18+
{
19+
// Test that hour comparison works correctly for reminder timing
20+
var nineAm = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
21+
var tenAm = new DateTimeOffset(2024, 10, 21, 10, 0, 0, TimeSpan.FromHours(8));
22+
23+
Assert.That(nineAm.Hour, Is.EqualTo(9));
24+
Assert.That(tenAm.Hour, Is.EqualTo(10));
25+
}
26+
27+
[Test]
28+
public void TestDateComparison()
29+
{
30+
// Test date comparison for preventing duplicate reminders
31+
var date1 = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
32+
var date2 = new DateTimeOffset(2024, 10, 21, 10, 0, 0, TimeSpan.FromHours(8));
33+
var date3 = new DateTimeOffset(2024, 10, 22, 9, 0, 0, TimeSpan.FromHours(8));
34+
35+
Assert.That(date1.Date, Is.EqualTo(date2.Date));
36+
Assert.That(date1.Date, Is.Not.EqualTo(date3.Date));
37+
}
38+
39+
[Test]
40+
public void TestWeekRange()
41+
{
42+
// Test that week range calculation is correct
43+
var start = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
44+
var end = start.AddDays(7);
45+
46+
var expectedEnd = new DateTimeOffset(2024, 10, 28, 9, 0, 0, TimeSpan.FromHours(8));
47+
Assert.That(end, Is.EqualTo(expectedEnd));
48+
}
49+
50+
[Test]
51+
public void TestDayRange()
52+
{
53+
// Test that tomorrow calculation is correct
54+
var today = new DateTimeOffset(2024, 10, 21, 9, 0, 0, TimeSpan.FromHours(8));
55+
var tomorrow = today.Date.AddDays(1);
56+
var dayAfterTomorrow = tomorrow.AddDays(1);
57+
58+
var expectedTomorrow = new DateTimeOffset(2024, 10, 22, 0, 0, 0, TimeSpan.FromHours(8));
59+
var expectedDayAfter = new DateTimeOffset(2024, 10, 23, 0, 0, 0, TimeSpan.FromHours(8));
60+
61+
Assert.That(tomorrow, Is.EqualTo(expectedTomorrow));
62+
Assert.That(dayAfterTomorrow, Is.EqualTo(expectedDayAfter));
63+
}
64+
65+
[Test]
66+
public void TestNumberEmoji()
67+
{
68+
// Test emoji mapping
69+
var testCases = new Dictionary<int, string>
70+
{
71+
{ 1, "1️⃣" },
72+
{ 2, "2️⃣" },
73+
{ 3, "3️⃣" },
74+
{ 4, "4️⃣" },
75+
{ 5, "5️⃣" },
76+
{ 6, "6️⃣" },
77+
{ 7, "7️⃣" },
78+
{ 8, "8️⃣" },
79+
{ 9, "9️⃣" },
80+
{ 10, "🔟" },
81+
};
82+
83+
foreach (var testCase in testCases)
84+
{
85+
var emoji = GetNumberEmoji(testCase.Key);
86+
Assert.That(emoji, Is.EqualTo(testCase.Value));
87+
}
88+
89+
// Test fallback for numbers > 10
90+
Assert.That(GetNumberEmoji(11), Is.EqualTo("11."));
91+
}
92+
93+
private string GetNumberEmoji(int number)
94+
{
95+
return number switch
96+
{
97+
1 => "1️⃣",
98+
2 => "2️⃣",
99+
3 => "3️⃣",
100+
4 => "4️⃣",
101+
5 => "5️⃣",
102+
6 => "6️⃣",
103+
7 => "7️⃣",
104+
8 => "8️⃣",
105+
9 => "9️⃣",
106+
10 => "🔟",
107+
_ => $"{number}.",
108+
};
109+
}
110+
}

0 commit comments

Comments
 (0)