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
@@ -259,6 +259,37 @@ func (m *mailAPI) handleSend(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusAccepted, map[string]bool{"queued": true})
|
||||
}
|
||||
|
||||
// handleDelete removes one message: to Trash from anywhere else, and for good
|
||||
// from Trash itself.
|
||||
func (m *mailAPI) handleDelete(w http.ResponseWriter, r *http.Request) {
|
||||
session, ok := m.authenticate(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Folder string `json:"folder"`
|
||||
UID uint32 `json:"uid"`
|
||||
}
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 4096)).Decode(&body); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "BAD_REQUEST", "Invalid JSON")
|
||||
return
|
||||
}
|
||||
if body.Folder == "" {
|
||||
body.Folder = "inbox"
|
||||
}
|
||||
if body.UID == 0 {
|
||||
writeError(w, http.StatusBadRequest, "INVALID_UID", "Message UID is required")
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.useCase.Delete(r.Context(), session.Email, body.Folder, body.UID); err != nil {
|
||||
m.fail(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]bool{"deleted": true})
|
||||
}
|
||||
|
||||
// handleSaveDraft stores the message being composed in the Drafts folder.
|
||||
func (m *mailAPI) handleSaveDraft(w http.ResponseWriter, r *http.Request) {
|
||||
session, ok := m.authenticate(w, r)
|
||||
@@ -299,6 +330,9 @@ func (m *mailAPI) decodeCompose(
|
||||
// previous shape - still sends a readable message rather than a blank
|
||||
// one. Only used when neither text nor html is present.
|
||||
LegacyBody string `json:"body"`
|
||||
// DraftUID is the autosaved draft this message came from, so sending
|
||||
// can clear it. Without it the draft outlived the message it became.
|
||||
DraftUID uint32 `json:"draft_uid"`
|
||||
}
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, maxComposeBytes)).Decode(&body); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "BAD_REQUEST", "Invalid JSON")
|
||||
@@ -314,13 +348,14 @@ func (m *mailAPI) decodeCompose(
|
||||
// letting the body choose From is how a webmail becomes an open relay for
|
||||
// spoofed mail.
|
||||
return usecase.ComposeInput{
|
||||
From: sender,
|
||||
To: body.To,
|
||||
Cc: body.Cc,
|
||||
Bcc: body.Bcc,
|
||||
Subject: body.Subject,
|
||||
Text: text,
|
||||
HTML: body.HTML,
|
||||
From: sender,
|
||||
To: body.To,
|
||||
Cc: body.Cc,
|
||||
Bcc: body.Bcc,
|
||||
Subject: body.Subject,
|
||||
Text: text,
|
||||
HTML: body.HTML,
|
||||
DraftUID: body.DraftUID,
|
||||
}, true
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user