mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: reuse a group account's year and month archive folders instead of creating them again or in the own account
This commit is contained in:
@@ -195,3 +195,63 @@ describe('the open message of a group account in a tag view', () => {
|
||||
expect(moveToMailbox).toHaveBeenCalledWith(client, 'eaaaaab', 'ce:b', 'login-a/ce:eaaaaab');
|
||||
});
|
||||
});
|
||||
|
||||
describe('archiving a group message by month', () => {
|
||||
// The group's Archive `k` already holds 2026/10, as the list names them:
|
||||
// store ids and parents namespaced `ce:...`, the server's ids bare.
|
||||
const year = { ...mailbox('y1', undefined, 'ce', true), name: '2026', parentId: 'ce:k' };
|
||||
const month = { ...mailbox('m1', undefined, 'ce', true), name: '10', parentId: 'ce:y1' };
|
||||
const withMonth = [...folders, year, month] as Mailbox[];
|
||||
|
||||
beforeEach(() => {
|
||||
useSettingsStore.setState({ archiveMode: 'month' } as never);
|
||||
client.createMailbox = vi.fn();
|
||||
});
|
||||
|
||||
it('reuses the year and month folders in a tag view', async () => {
|
||||
useEmailStore.setState({ mailboxes: withMonth } as never);
|
||||
render(<MailApp />);
|
||||
fireEvent.click(await screen.findByText('stub archive', {}, { timeout: 5000 }));
|
||||
await waitFor(() => expect(moveThreadToMailbox).toHaveBeenCalled());
|
||||
expect(client.createMailbox).not.toHaveBeenCalled();
|
||||
expect(moveThreadToMailbox).toHaveBeenCalledWith(client, 'eaaaaab', 'ce:m1', 'login-a/ce:eaaaaab');
|
||||
});
|
||||
|
||||
it('reuses them with the group\'s Inbox open', async () => {
|
||||
const unstamped = { ...groupMessage, sourceClientAccountId: undefined, sourceAccountId: undefined } as Email;
|
||||
useEmailStore.setState({ mailboxes: withMonth, selectedMailbox: 'ce:a', selectedKeyword: null, emails: [unstamped], selectedEmail: unstamped } as never);
|
||||
render(<MailApp />);
|
||||
fireEvent.click(await screen.findByText('stub archive', {}, { timeout: 5000 }));
|
||||
await waitFor(() => expect(moveThreadToMailbox).toHaveBeenCalled());
|
||||
expect(client.createMailbox).not.toHaveBeenCalled();
|
||||
expect(moveThreadToMailbox).toHaveBeenCalledWith(client, 'eaaaaab', 'ce:m1', 'eaaaaab');
|
||||
});
|
||||
|
||||
// The own account has a folder with the server id of the group's Archive,
|
||||
// with 2026/10 below it (live on 0.16: a's "Shared" folder is `h`, and so
|
||||
// was the group's Archive).
|
||||
it('does not take the own account\'s namesake folders', async () => {
|
||||
const unstamped = { ...groupMessage, sourceClientAccountId: undefined, sourceAccountId: undefined } as Email;
|
||||
const ownNamesakes = [
|
||||
{ ...mailbox('k', undefined, 'cf'), name: 'Shared' },
|
||||
{ ...mailbox('oy', undefined, 'cf'), name: '2026', parentId: 'k' },
|
||||
{ ...mailbox('om', undefined, 'cf'), name: '10', parentId: 'oy' },
|
||||
];
|
||||
useEmailStore.setState({ mailboxes: [...ownNamesakes, ...withMonth], selectedMailbox: 'ce:a', selectedKeyword: null, emails: [unstamped], selectedEmail: unstamped } as never);
|
||||
render(<MailApp />);
|
||||
fireEvent.click(await screen.findByText('stub archive', {}, { timeout: 5000 }));
|
||||
await waitFor(() => expect(moveThreadToMailbox).toHaveBeenCalled());
|
||||
expect(moveThreadToMailbox).toHaveBeenCalledWith(client, 'eaaaaab', 'ce:m1', 'eaaaaab');
|
||||
});
|
||||
|
||||
it('creates a missing year folder in the group account with the group\'s Inbox open', async () => {
|
||||
const unstamped = { ...groupMessage, sourceClientAccountId: undefined, sourceAccountId: undefined } as Email;
|
||||
useSettingsStore.setState({ archiveMode: 'year' } as never);
|
||||
(client.createMailbox as ReturnType<typeof vi.fn>).mockResolvedValue({ ...mailbox('y2', undefined, 'ce', true), id: 'y2', name: '2026' });
|
||||
useEmailStore.setState({ selectedMailbox: 'ce:a', selectedKeyword: null, emails: [unstamped], selectedEmail: unstamped } as never);
|
||||
render(<MailApp />);
|
||||
fireEvent.click(await screen.findByText('stub archive', {}, { timeout: 5000 }));
|
||||
await waitFor(() => expect(client.createMailbox).toHaveBeenCalled());
|
||||
expect(client.createMailbox).toHaveBeenCalledWith('2026', 'k', 'ce', undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2948,12 +2948,20 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
const year = emailDate.getFullYear().toString();
|
||||
const month = (emailDate.getMonth() + 1).toString().padStart(2, '0');
|
||||
const archiveId = archiveMailbox.originalId || archiveMailbox.id;
|
||||
// By the server's ids: the list names a shared account's folders and
|
||||
// their parents `account:id`, so a group's year folder was never
|
||||
// found again. The folders go in the Archive's own account, and only
|
||||
// that account's are looked at: the own folders have server ids too.
|
||||
const parentOf = (m: Mailbox) => (m.parentId && m.accountId && m.parentId.startsWith(`${m.accountId}:`)
|
||||
? m.parentId.slice(m.accountId.length + 1)
|
||||
: m.parentId);
|
||||
const folderAccountId = archiveMailbox.accountId ?? archiveAccountId;
|
||||
const isFolder = (m: Mailbox, name: string, parentId: string) =>
|
||||
m.name === name && parentOf(m) === parentId && (!folderAccountId || m.accountId === folderAccountId);
|
||||
|
||||
let yearMailbox = currentMailboxes.find(
|
||||
m => m.name === year && m.parentId === archiveId
|
||||
) ?? null;
|
||||
let yearMailbox = currentMailboxes.find(m => isFolder(m, year, archiveId)) ?? null;
|
||||
if (!yearMailbox) {
|
||||
yearMailbox = await createMailboxWithHooks(archiveClient, year, archiveId, archiveAccountId);
|
||||
yearMailbox = await createMailboxWithHooks(archiveClient, year, archiveId, folderAccountId);
|
||||
if (!yearMailbox) return; // a plugin refused the folder
|
||||
await refreshMailboxes();
|
||||
}
|
||||
@@ -2963,11 +2971,9 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
} else {
|
||||
const yearId = yearMailbox.originalId || yearMailbox.id;
|
||||
const afterYear = readMailboxes();
|
||||
let monthMailbox = afterYear.find(
|
||||
m => m.name === month && m.parentId === yearId
|
||||
) ?? null;
|
||||
let monthMailbox = afterYear.find(m => isFolder(m, month, yearId)) ?? null;
|
||||
if (!monthMailbox) {
|
||||
monthMailbox = await createMailboxWithHooks(archiveClient, month, yearId, archiveAccountId);
|
||||
monthMailbox = await createMailboxWithHooks(archiveClient, month, yearId, folderAccountId);
|
||||
if (!monthMailbox) return; // a plugin refused the folder
|
||||
await refreshMailboxes();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user