feat: implement message deletion functionality and improve draft handling
- Added `MoveToTrash` method in `WebmailRepository` to move messages to the Trash folder instead of deleting them permanently. - Introduced `handleDelete` method in `mailAPI` to handle message deletion requests from the client. - Updated router to include a new route for message deletion. - Enhanced the compose page to manage draft integrity, ensuring drafts are correctly associated with sent messages. - Implemented UI changes to allow users to delete messages from the mail folder view. - Added tests to verify the correct behavior of message deletion and draft handling. - Updated database migration scripts to reconcile folder counters and ensure accurate unread counts. - Added tests for TLS-RPT report parsing and webmail repository functionalities.
This commit is contained in:
1 parent
4f1b9c5217
commit
880dced9e4
20 files changed
+1053
-30
No files matched your search
@@ -72,7 +72,7 @@ func TestParseTlsRptReport_ValidJSON(t *testing.T) {
|
||||
{
|
||||
"policy": {
|
||||
"policy-type": "sts",
|
||||
"domain": "example.test"
|
||||
"policy-domain": "example.test"
|
||||
},
|
||||
"summary": {
|
||||
"total-successful-session-count": 100,
|
||||
|
||||
@@ -34,7 +34,10 @@ type tlsRptJsonReport struct {
|
||||
Policies []struct {
|
||||
Policy struct {
|
||||
PolicyType string `json:"policy-type"`
|
||||
Domain string `json:"domain"`
|
||||
// RFC 8460 section 4.4 names this "policy-domain". Reading it as
|
||||
// "domain" parsed every real report to a blank domain, so a stored
|
||||
// report could not be attributed to the domain it was about.
|
||||
Domain string `json:"policy-domain"`
|
||||
} `json:"policy"`
|
||||
Summary struct {
|
||||
TotalSuccessfulSessionCount int `json:"total-successful-session-count"`
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// This is a real report, as Google sends it daily: the gzipped JSON that
|
||||
// arrives attached to a message addressed to the TLS-RPT rua.
|
||||
const googleTlsRptReport = `{"organization-name":"Google Inc.",` +
|
||||
`"date-range":{"start-datetime":"2026-08-19T00:00:00Z","end-datetime":"2026-08-19T23:59:59Z"},` +
|
||||
`"contact-info":"smtp-tls-reporting@google.com","report-id":"2026-08-19T00:00:00Z_example.test",` +
|
||||
`"policies":[{"policy":{"policy-type":"no-policy-found","policy-domain":"example.test"},` +
|
||||
`"summary":{"total-successful-session-count":2,"total-failure-session-count":0}}]}`
|
||||
|
||||
// The field is "policy-domain" (RFC 8460 section 4.4), not "domain". Reading
|
||||
// the wrong name parsed every report to a blank domain, so a stored report
|
||||
// could not be attributed to the domain it was about.
|
||||
func TestTlsRptReportCarriesThePolicyDomain(t *testing.T) {
|
||||
report, err := ParseTlsRptReport([]byte(googleTlsRptReport))
|
||||
if err != nil {
|
||||
t.Fatalf("parse: %v", err)
|
||||
}
|
||||
if report.Domain != "example.test" {
|
||||
t.Errorf("domain is %q, want example.test", report.Domain)
|
||||
}
|
||||
if report.OrganizationName != "Google Inc." {
|
||||
t.Errorf("organization is %q", report.OrganizationName)
|
||||
}
|
||||
if len(report.Policies) != 1 {
|
||||
t.Fatalf("want 1 policy, got %d", len(report.Policies))
|
||||
}
|
||||
if report.Policies[0].SuccessCount != 2 {
|
||||
t.Errorf("success count is %d, want 2", report.Policies[0].SuccessCount)
|
||||
}
|
||||
if report.Policies[0].PolicyType != "no-policy-found" {
|
||||
t.Errorf("policy type is %q", report.Policies[0].PolicyType)
|
||||
}
|
||||
}
|
||||
|
||||
// Reports arrive gzipped, which is how they land as a .json.gz attachment.
|
||||
func TestTlsRptReportParsesGzippedPayload(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
gz := gzip.NewWriter(&buf)
|
||||
if _, err := gz.Write([]byte(googleTlsRptReport)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
report, err := ParseTlsRptReport(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("parse gzipped: %v", err)
|
||||
}
|
||||
if report.Domain != "example.test" {
|
||||
t.Errorf("domain is %q, want example.test", report.Domain)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user