Skip to content

Commit 0f56a8d

Browse files
committed
fix hasDrafts for non collapsed threads message listing view
1 parent c74f56a commit 0f56a8d

2 files changed

Lines changed: 41 additions & 18 deletions

File tree

lib/api/messages.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
134134
}
135135

136136
if (includeHasDrafts && matchDraftReferences) {
137+
// MIME References contains the entire thread ancestry. meta.reference is the exact mailbox/UID pair the draft was created for.
137138
group.draftReferences = {
138139
$addToSet: {
139-
$cond: ['$draft', '$mimeTree.parsedHeader.references', false]
140+
$cond: ['$draft', '$meta.reference', false]
140141
}
141142
};
142143
}
@@ -170,13 +171,13 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
170171
}
171172

172173
if (matchDraftReferences) {
173-
const draftReferences = new Set(
174-
((matchingThreadCount && matchingThreadCount.draftReferences) || [])
175-
.flatMap(references => (references || '').toString().split(/\s+/))
176-
.filter(reference => reference)
174+
message.hasDrafts = ((matchingThreadCount && matchingThreadCount.draftReferences) || []).some(
175+
reference =>
176+
reference &&
177+
reference.mailbox &&
178+
reference.mailbox.toString() === message.mailbox.toString() &&
179+
reference.id === message.uid
177180
);
178-
179-
message.hasDrafts = draftReferences.has(message.msgid);
180181
} else {
181182
message.hasDrafts = !!(matchingThreadCount && matchingThreadCount.hasDrafts);
182183
}

test/api/messages-test.js

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ describe('Messages tests', function () {
923923
expect(search5.body.results).to.deep.eq(search.body.results); // Check if page 1 is equal to original page 1 after moving back from page 2
924924
});
925925

926-
it('should GET /users/:user/search expect success / collapseThreads controls the hasDrafts scope', async () => {
926+
it('should GET /users/:user/search expect success / collapseThreads controls hasDrafts scope and non-collapsed results match the exact draft reference', async () => {
927927
const mailboxResponse = await server
928928
.post(`/users/${user}/mailboxes`)
929929
.send({ path: `/search-collapse-threads-${Date.now().toString(36)}`, hidden: false, retention: 10000 })
@@ -954,6 +954,23 @@ describe('Messages tests', function () {
954954
})
955955
.expect(200);
956956

957+
// Keep the root in the References ancestry, but make only this reply the target of the next draft.
958+
await server.put(`/users/${user}/mailboxes/${mailbox}/messages/${reply.body.message.id}`).send({ draft: false }).expect(200);
959+
960+
const draftReply = await server
961+
.post(`/users/${user}/mailboxes/${mailbox}/messages`)
962+
.send({
963+
draft: true,
964+
to: [{ address: 'search-collapse@example.com' }],
965+
text: 'Draft reply to reply',
966+
reference: {
967+
mailbox,
968+
id: reply.body.message.id,
969+
action: 'reply'
970+
}
971+
})
972+
.expect(200);
973+
957974
const single = await server
958975
.post(`/users/${user}/mailboxes/${mailbox}/messages`)
959976
.send({
@@ -973,31 +990,36 @@ describe('Messages tests', function () {
973990
.send({})
974991
.expect(200);
975992

976-
expect(expandedPage.body.total).to.equal(2);
977-
expect(expandedPage.body.results.map(entry => entry.id)).to.deep.equal([reply.body.message.id]);
978-
expect(expandedPage.body.results[0].threadMessageCount).to.equal(2);
993+
expect(expandedPage.body.total).to.equal(3);
994+
expect(expandedPage.body.results.map(entry => entry.id)).to.deep.equal([draftReply.body.message.id]);
995+
expect(expandedPage.body.results[0].threadMessageCount).to.equal(3);
979996
expect(expandedPage.body.results[0]).to.not.have.property('hasDrafts');
980997

981998
const expandedThread = await server
982-
.get(`/users/${user}/search?thread=${thread}&includeHasDrafts=true&limit=2`)
999+
.get(`/users/${user}/search?thread=${thread}&includeHasDrafts=true&limit=3`)
9831000
.send({})
9841001
.expect(200);
9851002

986-
expect(expandedThread.body.results.map(entry => entry.id)).to.deep.equal([reply.body.message.id, root.body.message.id]);
987-
expect(expandedThread.body.results.map(entry => entry.hasDrafts)).to.deep.equal([false, true]);
1003+
expect(expandedThread.body.results.map(entry => entry.id)).to.deep.equal([
1004+
draftReply.body.message.id,
1005+
reply.body.message.id,
1006+
root.body.message.id
1007+
]);
1008+
expect(expandedThread.body.results.map(entry => entry.hasDrafts)).to.deep.equal([false, true, false]);
9881009
expect(expandedThread.body.results[0]).to.not.have.property('threadMessageCount');
9891010

9901011
const expandedMailboxPage = await server
991-
.get(`/users/${user}/mailboxes/${mailbox}/messages?includeHasDrafts=true&limit=3&order=desc`)
1012+
.get(`/users/${user}/mailboxes/${mailbox}/messages?includeHasDrafts=true&limit=4&order=desc`)
9921013
.send({})
9931014
.expect(200);
9941015

9951016
expect(expandedMailboxPage.body.results.map(entry => entry.id)).to.deep.equal([
9961017
single.body.message.id,
1018+
draftReply.body.message.id,
9971019
reply.body.message.id,
9981020
root.body.message.id
9991021
]);
1000-
expect(expandedMailboxPage.body.results.map(entry => entry.hasDrafts)).to.deep.equal([false, false, true]);
1022+
expect(expandedMailboxPage.body.results.map(entry => entry.hasDrafts)).to.deep.equal([false, false, true, false]);
10011023
expect(expandedMailboxPage.body.results[0]).to.not.have.property('threadMessageCount');
10021024

10031025
const collapsedPage1 = await server
@@ -1028,8 +1050,8 @@ describe('Messages tests', function () {
10281050
.send({})
10291051
.expect(200);
10301052

1031-
expect(collapsedPage2.body.results.map(entry => entry.id)).to.deep.equal([reply.body.message.id]);
1032-
expect(collapsedPage2.body.results[0].threadMessageCount).to.equal(2);
1053+
expect(collapsedPage2.body.results.map(entry => entry.id)).to.deep.equal([draftReply.body.message.id]);
1054+
expect(collapsedPage2.body.results[0].threadMessageCount).to.equal(3);
10331055
expect(collapsedPage2.body.results[0].hasDrafts).to.be.true;
10341056
expect(collapsedPage2.body.previousCursor).to.be.a('string');
10351057
expect(collapsedPage2.body.nextCursor).to.be.false;

0 commit comments

Comments
 (0)