mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: let api.email.get read a listed message of a shared account
doEmailGet asked the signed-in account for every id, so a message in a folder shared from another account came back as null even though it was in the list. A message in the loaded list is now read from the account that owns it, through resolveEmailBlobContext like attachment downloads. getAttachment and getRaw keep reading from the signed-in account only. Fixes #1273
This commit is contained in:
@@ -54,7 +54,7 @@ beforeEach(() => {
|
||||
|
||||
afterEach(() => {
|
||||
useAuthStore.setState({ client: null });
|
||||
useEmailStore.setState({ mailboxes: [], selectedEmail: null });
|
||||
useEmailStore.setState({ mailboxes: [], selectedEmail: null, selectedMailbox: '', emails: [] });
|
||||
});
|
||||
|
||||
describe('api.email.get', () => {
|
||||
@@ -67,6 +67,14 @@ describe('api.email.get', () => {
|
||||
expect(await call(READER, 'email.get', 'gone')).toBeNull();
|
||||
});
|
||||
|
||||
it('asks the owning account for a listed message of a shared folder', async () => {
|
||||
client.getEmail.mockImplementation(async (id: string, accountId?: string) => (
|
||||
id === 's1' && accountId === 'acc2' ? mail('s1', { subject: 'Shared' }) : null));
|
||||
useEmailStore.setState({ selectedMailbox: 'acc2:box', emails: [mail('s1', { mailboxIds: { 'acc2:box': true } })] });
|
||||
expect(await call(READER, 'email.get', 's1')).toEqual(expect.objectContaining({ id: 's1', subject: 'Shared' }));
|
||||
expect(client.getEmail).toHaveBeenCalledWith('s1', 'acc2');
|
||||
});
|
||||
|
||||
it('uses the open message when its body is loaded', async () => {
|
||||
useEmailStore.setState({ selectedEmail: mail('open', { bodyValues: { 1: { value: 'x' } }, textBody: [{ partId: '1' }] } as unknown as Partial<Email>) });
|
||||
expect(await call(READER, 'email.get', 'open')).toEqual(expect.objectContaining({ id: 'open', text: 'x' }));
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
// (api.email.getAttachment / getRaw). Reads go to the server through the
|
||||
// JMAP client and never change what the user has open.
|
||||
//
|
||||
// Messages are read from the signed-in account itself; mail in folders shared
|
||||
// from other accounts is not reached by id here.
|
||||
// api.email.get also reads a message of a shared account when it is in the
|
||||
// loaded list, from the account that owns it. The bytes of attachments and
|
||||
// sources are read from the signed-in account only.
|
||||
|
||||
import type { EmailReadView, EmailSummary, MailboxView } from '../plugin-types';
|
||||
import type { Email, Mailbox } from '../jmap/types';
|
||||
import type { IJMAPClient } from '../jmap/client-interface';
|
||||
import { useEmailStore } from '@/stores/email-store';
|
||||
import { resolveEmailBlobContext, useEmailStore } from '@/stores/email-store';
|
||||
import { emailSummary, emailToReadView } from '../plugin-projection';
|
||||
import {
|
||||
MAX_PLUGIN_FETCH_BYTES, readId, readInteger, readObject, sessionClient, withinRate,
|
||||
@@ -30,7 +31,14 @@ async function loadEmail(client: IJMAPClient, emailId: string): Promise<Email |
|
||||
export async function doEmailGet(id: unknown): Promise<EmailReadView | null> {
|
||||
const method = 'email.get';
|
||||
const emailId = readId(id, method, 'emailId');
|
||||
const email = await loadEmail(sessionClient(method), emailId);
|
||||
const client = sessionClient(method);
|
||||
// A listed message of a shared account is asked of the account that owns
|
||||
// it; the signed-in account doesn't know its id.
|
||||
const listed = useEmailStore.getState().emails.find((e) => e.id === emailId);
|
||||
const owner = listed ? resolveEmailBlobContext(listed, client) : null;
|
||||
const email = owner?.client && owner.accountId
|
||||
? await owner.client.getEmail(emailId, owner.accountId)
|
||||
: await loadEmail(client, emailId);
|
||||
return email ? emailToReadView(email) : null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user