- 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.
75 lines
2.8 KiB
SQL
75 lines
2.8 KiB
SQL
-- Reconcile folders.unread_count and folders.total_count with the messages
|
|
-- that are actually in each folder.
|
|
--
|
|
-- These columns are a denormalised cache. Every write path maintained them,
|
|
-- but one did not: a message the user composed themselves - their own Sent
|
|
-- copy, and every draft autosave - was filed through the inbound path, which
|
|
-- raised unread_count unconditionally. Nothing ever opens your own outgoing
|
|
-- copy, so the flag that would bring the counter back down was never set and
|
|
-- the drift only accumulated.
|
|
--
|
|
-- The webmail now derives these numbers at read time and is self-healing, but
|
|
-- IMAP's STATUS answers from these columns, so the stored values are corrected
|
|
-- here once for the mailboxes that already drifted.
|
|
UPDATE folders f
|
|
SET unread_count = c.unread,
|
|
total_count = c.total
|
|
FROM (
|
|
SELECT f2.id,
|
|
COUNT(e.id) FILTER (
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM message_flags mf
|
|
WHERE mf.message_id = e.id
|
|
AND mf.received_at = e.received_at
|
|
AND mf.flag = '\Seen')
|
|
)::int AS unread,
|
|
COUNT(e.id)::int AS total
|
|
FROM folders f2
|
|
LEFT JOIN email_messages e
|
|
ON e.folder_id = f2.id AND e.expunged_at IS NULL
|
|
GROUP BY f2.id
|
|
) AS c
|
|
WHERE f.id = c.id
|
|
AND (f.unread_count IS DISTINCT FROM c.unread
|
|
OR f.total_count IS DISTINCT FROM c.total);
|
|
|
|
-- Existing Sent and Drafts messages were filed without the flags that say what
|
|
-- they are, so they read as unread mail that nothing could clear.
|
|
INSERT INTO message_flags (message_id, received_at, flag)
|
|
SELECT e.id, e.received_at, '\Seen'
|
|
FROM email_messages e
|
|
JOIN folders f ON f.id = e.folder_id
|
|
WHERE e.expunged_at IS NULL
|
|
AND (f.special_use IN ('sent', 'drafts')
|
|
OR LOWER(f.name) IN ('sent', 'drafts'))
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
INSERT INTO message_flags (message_id, received_at, flag)
|
|
SELECT e.id, e.received_at, '\Draft'
|
|
FROM email_messages e
|
|
JOIN folders f ON f.id = e.folder_id
|
|
WHERE e.expunged_at IS NULL
|
|
AND (f.special_use = 'drafts' OR LOWER(f.name) = 'drafts')
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Re-run the reconciliation now those flags exist, so the Sent and Drafts
|
|
-- counters land on zero unread rather than on their pre-flag values.
|
|
UPDATE folders f
|
|
SET unread_count = c.unread
|
|
FROM (
|
|
SELECT f2.id,
|
|
COUNT(e.id) FILTER (
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM message_flags mf
|
|
WHERE mf.message_id = e.id
|
|
AND mf.received_at = e.received_at
|
|
AND mf.flag = '\Seen')
|
|
)::int AS unread
|
|
FROM folders f2
|
|
LEFT JOIN email_messages e
|
|
ON e.folder_id = f2.id AND e.expunged_at IS NULL
|
|
GROUP BY f2.id
|
|
) AS c
|
|
WHERE f.id = c.id
|
|
AND f.unread_count IS DISTINCT FROM c.unread;
|