This commit is contained in:
parent
37e3e12811
commit
eb5063a575
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.pcux.cn/xuans/Smail/config"
|
||||
"git.pcux.cn/xuans/Smail/db"
|
||||
"git.pcux.cn/xuans/Smail/dto/response"
|
||||
"git.pcux.cn/xuans/Smail/models"
|
||||
@ -433,6 +434,17 @@ func matchesHeader(email *models.Email, key, value string) bool {
|
||||
value = strings.ToLower(value)
|
||||
|
||||
switch key {
|
||||
case "message-id":
|
||||
messageID := strings.TrimSpace(email.MsgID)
|
||||
if messageID == "" {
|
||||
// 旧邮件使用与 IMAP FETCH 一致的备用标识。
|
||||
cfg := config.CurrentConfig()
|
||||
if cfg == nil || strings.TrimSpace(cfg.Domain) == "" || email.Id <= 0 {
|
||||
return false
|
||||
}
|
||||
messageID = fmt.Sprintf("%d@%s", email.Id, strings.TrimSpace(cfg.Domain))
|
||||
}
|
||||
return strings.Contains(strings.ToLower("<"+messageID+">"), value)
|
||||
case "subject":
|
||||
return strings.Contains(strings.ToLower(email.Subject), value)
|
||||
case "from":
|
||||
|
||||
67
backend/services/list/imap_search_test.go
Normal file
67
backend/services/list/imap_search_test.go
Normal file
@ -0,0 +1,67 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.pcux.cn/xuans/Smail/config"
|
||||
"git.pcux.cn/xuans/Smail/db"
|
||||
"git.pcux.cn/xuans/Smail/models"
|
||||
"git.pcux.cn/xuans/Smail/utils/context"
|
||||
"github.com/emersion/go-imap/v2"
|
||||
)
|
||||
|
||||
func TestSearchEmailsMessageID(t *testing.T) {
|
||||
initListTestDB(t)
|
||||
config.Instance.Domain = "example.test"
|
||||
matching := models.Email{MsgID: "Public-Receipt@example.test", Subject: "matching"}
|
||||
foreign := models.Email{MsgID: matching.MsgID, Subject: "foreign"}
|
||||
legacy := models.Email{Subject: "legacy"}
|
||||
if _, err := db.Instance.Insert(&matching, &foreign, &legacy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inbox := models.UserEmail{UserID: 1, EmailID: matching.Id}
|
||||
otherUser := models.UserEmail{UserID: 2, EmailID: foreign.Id}
|
||||
legacyInbox := models.UserEmail{UserID: 1, EmailID: legacy.Id}
|
||||
if _, err := db.Instance.Insert(&inbox, &otherUser, &legacyInbox); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
value string
|
||||
want int
|
||||
}{
|
||||
{name: "full header", value: "<Public-Receipt@example.test>", want: inbox.ID},
|
||||
{name: "case insensitive", value: "<PUBLIC-RECEIPT@EXAMPLE.TEST>", want: inbox.ID},
|
||||
{name: "substring", value: "receipt@", want: inbox.ID},
|
||||
{name: "legacy fallback", value: fmt.Sprintf("<%d@example.test>", legacy.Id), want: legacyInbox.ID},
|
||||
{name: "absent value", value: "<missing@example.test>"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
criteria := &imap.SearchCriteria{Header: []imap.SearchCriteriaHeaderField{{Key: "mEsSaGe-Id", Value: test.value}}}
|
||||
rows, err := SearchEmails(&context.Context{UserID: 1}, "INBOX", criteria)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if test.want == 0 {
|
||||
if len(rows) != 0 {
|
||||
t.Fatalf("unexpected matches: %#v", rows)
|
||||
}
|
||||
} else if len(rows) != 1 || rows[0].ID != test.want {
|
||||
t.Fatalf("matches = %#v, want only relation %d", rows, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageIDHeaderPresence(t *testing.T) {
|
||||
previous := config.Instance
|
||||
config.Instance = nil
|
||||
t.Cleanup(func() { config.Instance = previous })
|
||||
if matchesHeader(&models.Email{}, "Message-ID", "") {
|
||||
t.Fatal("missing header must not match an empty search value")
|
||||
}
|
||||
if !matchesHeader(&models.Email{MsgID: "stored@example.test"}, "Message-ID", "") {
|
||||
t.Fatal("stored header must match an empty search value")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user