mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 16:13:15 +00:00
A draft's old version is removed by id when the composer saves over it, sends it or discards it. Email ids repeat across accounts and servers - the same user logged in to two servers is account `e` on both - so the removal must go to the login and account the draft lives in. Two paths took the wrong one: - "Edit draft" in an "All folders" search or a tag view took the account from the folder still selected underneath. With a group folder selected, an own draft was opened as the group's, and its first autosave, send or discard destroyed the message with that id in the group account, while the draft stayed in the own Drafts. It now takes the login and account the result is stamped with, reads the draft through that login, and prefers that login's identity when two logins share an address. - The composer discarded through the login of the current From, and replaced or sent through it too. After switching From to another login's identity - which saves nothing by itself - discarding, the next save or the send removed the draft's id on the other server. Each save now records the login it went through (a draft opened from a list starts with the list's). A version saved through another login is removed through that one: after the new version exists when saving, after the message is out when sending, and on discard. The Pro email view, folder tabs and search preview pass their login along with the draft.
69 lines
2.7 KiB
TypeScript
69 lines
2.7 KiB
TypeScript
import type { Email, Identity, Mailbox } from '@/lib/jmap/types';
|
|
import { findDraftIdentityId } from '@/lib/reply-identity';
|
|
import { stripCrossAccountIdentityPrefix } from '@/hooks/use-pro-multi-account-identities';
|
|
|
|
/**
|
|
* Where a draft opened for editing lives: the connected account (login) that
|
|
* reaches it, and the JMAP account there when it is not that login's own. The
|
|
* composer removes the old version there when it saves, sends or discards the
|
|
* draft. Email and account ids repeat across accounts and servers, so any
|
|
* other login or account may hold an unrelated message under the same id.
|
|
*/
|
|
export interface DraftSource {
|
|
localAccountId?: string;
|
|
accountId?: string;
|
|
}
|
|
|
|
/**
|
|
* The DraftSource of `draft`, a message of the list on screen:
|
|
* - `source` when the caller knows it: a send undone or a scheduled send
|
|
* cancelled for editing is back in the account it was sent from;
|
|
* - in a list that mixes accounts (the unified views, a tag view, an "All
|
|
* folders" search) the login and account the message is stamped with. The
|
|
* folder still selected underneath a tag view or a search says nothing
|
|
* about it;
|
|
* - otherwise the list's: the viewed login (Pro multi-account sidebar) or the
|
|
* active one, and for a shared or group folder the folder's account.
|
|
*/
|
|
export function resolveDraftSource(
|
|
draft: Pick<Email, 'sourceClientAccountId' | 'sourceAccountId'>,
|
|
context: {
|
|
source?: DraftSource;
|
|
aggregate: boolean;
|
|
mailbox?: Pick<Mailbox, 'isShared' | 'accountId'>;
|
|
viewingAccountId?: string | null;
|
|
activeAccountId?: string | null;
|
|
},
|
|
): DraftSource {
|
|
const mailbox = context.aggregate ? undefined : context.mailbox;
|
|
return {
|
|
localAccountId: context.source?.localAccountId
|
|
?? draft.sourceClientAccountId
|
|
?? context.viewingAccountId
|
|
?? context.activeAccountId
|
|
?? undefined,
|
|
accountId: context.source?.accountId
|
|
?? draft.sourceAccountId
|
|
?? (mailbox?.isShared ? mailbox.accountId : undefined),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* The identity to reopen a draft with (findDraftIdentityId), taken from the
|
|
* identities of the login the draft lives in first: two logins can share an
|
|
* address - the same user on two servers - and the other one's identity
|
|
* would move the draft to its server on the first save.
|
|
*/
|
|
export function findDraftIdentityIdForLogin(
|
|
identities: Identity[],
|
|
from: { email?: string | null; name?: string | null } | null | undefined,
|
|
localAccountId: string | undefined,
|
|
): string | null {
|
|
if (localAccountId) {
|
|
const ofLogin = identities.filter((identity) => stripCrossAccountIdentityPrefix(identity.id).localAccountId === localAccountId);
|
|
const match = findDraftIdentityId(ofLogin, from);
|
|
if (match) return match;
|
|
}
|
|
return findDraftIdentityId(identities, from);
|
|
}
|