From 61b361a6afc0436494e6a4424337a699b79644b3 Mon Sep 17 00:00:00 2001 From: smail Date: Sun, 4 Oct 2026 05:09:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=BD=91=E9=A1=B5=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E6=8C=89=E6=8A=95=E9=80=92=E6=97=B6=E9=97=B4=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E5=B9=B6=E8=A1=A5=E5=BD=95=E8=8D=89=E7=A8=BF=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=AA=8C=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/list/list.go | 7 +++- backend/services/list/list_test.go | 55 +++++++++++++++++++++++++++++ docs/云端全项目测试报告.md | 10 ++++++ docs/生产整改验收清单.md | 8 +++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/backend/services/list/list.go b/backend/services/list/list.go index 951259c..f527470 100644 --- a/backend/services/list/list.go +++ b/backend/services/list/list.go @@ -105,7 +105,12 @@ func genSQL(ctx *context.Context, count bool, tagInfo dto.SearchTag, keyword str return sql, sqlParams } - sql += " order by e.id desc" + if pop3List { + sql += " order by e.id desc" + } else { + // 网页按实际展示的投递时间排序,同一时间用邮件编号稳定分页。 + sql += " order by e.send_date desc, e.id desc" + } if limit < 10000 { sql += fmt.Sprintf(" LIMIT %d OFFSET %d ", limit, offset) diff --git a/backend/services/list/list_test.go b/backend/services/list/list_test.go index 14ab166..b0671eb 100644 --- a/backend/services/list/list_test.go +++ b/backend/services/list/list_test.go @@ -2,10 +2,14 @@ package list import ( "path/filepath" + "strings" "testing" + "time" "git.pcux.cn/xuans/Smail/config" + "git.pcux.cn/xuans/Smail/consts" "git.pcux.cn/xuans/Smail/db" + "git.pcux.cn/xuans/Smail/dto" "git.pcux.cn/xuans/Smail/models" "git.pcux.cn/xuans/Smail/utils/context" ) @@ -23,6 +27,57 @@ func initListTestDB(t *testing.T) { }) } +func TestWebListOrdersByDisplayedDateAcrossPages(t *testing.T) { + initListTestDB(t) + base := time.Date(2026, 10, 4, 0, 0, 0, 0, time.UTC) + // 旧草稿后发;相同投递时间的邮件必须有稳定次序。 + for _, item := range []struct { + id int + hour int + }{ + {101, 4}, + {102, 2}, + {103, 3}, + {104, 3}, + } { + message := models.Email{ + Id: item.id, Type: consts.EmailTypeSend, + SendDate: base.Add(time.Duration(item.hour) * time.Hour), + } + if _, err := db.Instance.Insert(&message); err != nil { + t.Fatal(err) + } + relation := models.UserEmail{UserID: 1, EmailID: item.id, GroupId: models.Sent} + if _, err := db.Instance.Insert(&relation); err != nil { + t.Fatal(err) + } + } + tag := dto.SearchTag{Type: consts.EmailTypeSend, Status: -1, GroupId: models.Sent} + ctx := &context.Context{UserID: 1} + for page, want := range [][]int{{101, 104}, {103, 102}} { + messages, total, err := GetEmailList(ctx, tag, "", false, page*2, 2) + if err != nil { + t.Fatal(err) + } + if total != 4 || len(messages) != len(want) { + t.Fatalf("page %d: total=%d, length=%d", page, total, len(messages)) + } + for i, id := range want { + if messages[i].Id != id { + t.Fatalf("page %d item %d: got %d, want %d", page, i, messages[i].Id, id) + } + } + } + query, _ := genSQL(ctx, false, tag, "", true, 0, 2) + if !strings.Contains(query, " order by e.id desc") || strings.Contains(query, "order by e.send_date") { + t.Fatalf("POP3 ordering changed: %s", query) + } + query, _ = genSQL(ctx, true, tag, "", false, 0, 2) + if strings.Contains(query, "order by") { + t.Fatalf("count query should not sort: %s", query) + } +} + func TestGetUEListByUIDUsesFullPath(t *testing.T) { initListTestDB(t) first := models.Group{Name: "leaf", UserId: 1, FullPath: "first/leaf"} diff --git a/docs/云端全项目测试报告.md b/docs/云端全项目测试报告.md index e720a6b..04705b4 100644 --- a/docs/云端全项目测试报告.md +++ b/docs/云端全项目测试报告.md @@ -1,5 +1,15 @@ # 云端全项目测试报告 +## 迁移目录提示与旧回复草稿发送补录(2026-10-04 05:10) + +- [x] 根据前段连续验收记录补录:提交 `62f65e3` 修正迁移目标文件目录提示为运行根目录下的 `data`,已构建部署版本 `review-20261004-62f65e3`。前端与三个 Go 程序构建成功;新增回归用例源码未执行,不计为自动化测试通过。 +- [x] 前段页面忽略缓存刷新,正确目录提示实际显示,当前 SQLite 为 `smailroundtrip20261004.db`;域名仍为 `cdis.cn`、`web.cdis.cn`。修复仅更新三个程序,没有覆盖配置或数据库。 +- [x] 前段管理员旧回复草稿 23 点击发送,被明确提示草稿已变更、已删除或已发送;旧页面未保存内容保留,最新草稿刷新后未被覆盖。最新草稿发送成功,旧页面再次发送仍被拒绝。 +- [x] 前段普通用户打开副本 57,最新主题、正文和引用完整,时间为 04:58;管理员发件箱显示发送成功、草稿箱为空。仅证明此草稿冲突及发送路径,不扩大为全部并发重试通过。 +- [✓] 本段交互 SSH 重新确认 Smail、Nginx active,主进程 2020866、重启计数为 0;未清库、未影响其他项目。 +- [~] 新发现网页列表显示投递时间但按邮件 ID 排序;正在精确修正网页排序,保留 POP3 原次序及 IMAP 逻辑。尚未构建部署该排序修复。 +- [!] 三库全功能、图形客户端、外部安全邮箱、Telegram、通知 SMTP、恢复、续期及最终全新部署仍未闭合,整体不放行。下方历史未修正结论以本节进展为准。 + ## SQLite 邮件隔离与分组撤权恢复(2026-10-04 04:48) - [x] 补录前段浏览器证据:普通用户访问管理员邮件副本 51、管理员访问普通用户邮件副本 52,均显示读取失败,没有主题或正文泄露。仅覆盖这两个账号与对象组合,不扩大为附件或所有接口权限通过。 diff --git a/docs/生产整改验收清单.md b/docs/生产整改验收清单.md index ee52b4d..c671dc6 100644 --- a/docs/生产整改验收清单.md +++ b/docs/生产整改验收清单.md @@ -1,5 +1,13 @@ # 生产整改验收清单 +## 迁移提示与回复草稿发送补录(2026 年 10 月 4 日 05:10) + +- [x] 补录前段 `62f65e3` 已构建部署、页面实际显示迁移目标目录 `data`;现有回归用例仅补充源码,未执行自动化测试。覆盖下方历史“目录提示仍未修正”状态。 +- [x] 补录旧回复草稿 23 发送冲突被拒、未保存内容保留、最新版本发送成功,发送后旧页面重试仍被拒;普通用户副本 57 阅读正常,管理员草稿箱为空。原“回复草稿发送分支待验收”仅在该操作范围内闭合。 +- [✓] 本段重新确认云端 Smail、Nginx active、主进程 2020866、重启计数 0;未清库或改变其他项目。 +- [~] 网页列表按 ID 而非显示时间排序,正在修正并待云端浏览器复验;POP3、IMAP 协议次序不得随网页调整。 +- [!] 三数据库全功能、客户端及通知 SMTP、外部邮箱、Telegram、恢复、续期与最终全新初始化仍待完成;整体不放行。 + ## SQLite 对象隔离与分组恢复复审(2026 年 10 月 4 日 04:48) - [x] 补录普通用户读取管理员副本 51、管理员读取普通用户副本 52 被拒绝;仅覆盖已操作对象,不扩大为全套权限或附件隔离通过。