mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-04 16:06:41 +00:00
fix: hide reply on drafts and scheduled messages in a conversation and quick reply to the newest real message (bulwarkmail/webmail#1404)
This commit is contained in:
@@ -40,6 +40,7 @@ import {
|
||||
queryEmailPage,
|
||||
} from '../email';
|
||||
import { senderWarningOf } from '../../lib/email-headers';
|
||||
import { scheduledEmailIdsInThread } from '../thread-scheduled';
|
||||
import { uploadBytes } from '../blob';
|
||||
import { getIdentities, updateIdentity } from '../identity';
|
||||
import { isJMAPSetError } from '../jmap-result';
|
||||
@@ -447,5 +448,23 @@ live('live Stalwart: mail, contacts, search (0.16 and 1.0)', () => {
|
||||
const [full] = await getFullEmails([id]);
|
||||
expect(senderWarningOf(full)?.status).toBe('failed');
|
||||
}, 60_000);
|
||||
|
||||
it("finds a conversation's message that waits for a scheduled send (bulwarkmail/webmail#1404)", async () => {
|
||||
const [identity] = await getIdentities();
|
||||
const result = await sendEmail(
|
||||
{ from: [{ email: USER }], to: [{ email: USER }], subject: `scheduled reply ${mailTag}`, textBody: 'live' },
|
||||
identity.id, sent, 3600, { draftsMailboxId: drafts },
|
||||
);
|
||||
try {
|
||||
const [filed] = await getFullEmails([result.emailId!]);
|
||||
const ids = await scheduledEmailIdsInThread(filed.threadId);
|
||||
expect([...ids]).toEqual([result.emailId]);
|
||||
} finally {
|
||||
await cancelScheduledSend(result.emailSubmissionId!).catch(() => undefined);
|
||||
}
|
||||
// Once cancelled it can be replied to again.
|
||||
const [filed] = await getFullEmails([result.emailId!]);
|
||||
expect((await scheduledEmailIdsInThread(filed.threadId)).size).toBe(0);
|
||||
}, 90_000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { jmapClient } from './jmap-client';
|
||||
import { SUBMISSION_ONLY_USING } from './submissions';
|
||||
|
||||
/**
|
||||
* Ids of a conversation's messages that wait for a scheduled send: a pending
|
||||
* EmailSubmission whose send time is still ahead. The conversation hides
|
||||
* Reply on them and points the quick reply past them, as it does for drafts
|
||||
* (webmail 8b29254a6, #1404). Empty when the account can't schedule or the
|
||||
* server can't answer: the cards then stay as they were.
|
||||
*/
|
||||
export async function scheduledEmailIdsInThread(threadId: string, accountId?: string): Promise<Set<string>> {
|
||||
const account = accountId ?? jmapClient.accountId;
|
||||
if (!account || !jmapClient.hasDelayedSend(account)) return new Set();
|
||||
try {
|
||||
const res = await jmapClient.request([
|
||||
['EmailSubmission/query', { accountId: account, filter: { threadIds: [threadId], undoStatus: 'pending' } }, '0'],
|
||||
['EmailSubmission/get', {
|
||||
accountId: account,
|
||||
'#ids': { resultOf: '0', name: 'EmailSubmission/query', path: '/ids' },
|
||||
properties: ['emailId', 'sendAt', 'undoStatus'],
|
||||
}, '1'],
|
||||
], SUBMISSION_ONLY_USING);
|
||||
const [name, body] = res.methodResponses?.[1] ?? [];
|
||||
if (name !== 'EmailSubmission/get') return new Set();
|
||||
const now = Date.now();
|
||||
const ids = new Set<string>();
|
||||
for (const s of (body.list as Array<{ emailId?: string; sendAt?: string; undoStatus?: string }>) ?? []) {
|
||||
if (!s.emailId || s.undoStatus !== 'pending') continue;
|
||||
const at = s.sendAt ? new Date(s.sendAt).getTime() : NaN;
|
||||
if (Number.isFinite(at) && at > now) ids.add(s.emailId);
|
||||
}
|
||||
return ids;
|
||||
} catch {
|
||||
return new Set();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user