Open a locked account whole: calendar, contacts and files too
ci / version (pull_request) Skipped
ci / node (pull_request) Successful in 1m7s
ci / publish (pull_request) Skipped
ci / announce (pull_request) Skipped
ci / docker-build (pull_request) Successful in 35s

Switching to a locked account handed to the reader moved only the mail.
Now calendar, contacts and files follow it as well, through a new
viewAccountFor that the three stores use for what they show. Settings,
signatures and push keep ownAccountFor, so nothing of the reader's is
ever written into the locked account (inbuxa AL-7).
This commit is contained in:
jcoffey-dev committed 2026-09-27 18:04:38 -07:00
1 parent 22d891b1ed
commit 173680cc41
6 files changed
+57 -14

No files matched your search

@@ -18,6 +18,9 @@ const delegated = (access: string, sendAs = false) => ({
isReadOnly: access === "read",
accountCapabilities: {
[CAP.mail]: {},
[CAP.calendars]: {},
[CAP.contacts]: {},
[CAP.filenode]: {},
"urn:inbuxa:jmap": { delegation: { locked: true, access, sendAs, until: null } },
},
});
@@ -26,11 +29,15 @@ const sessionWith = (locked: Record<string, unknown> | null) =>
({
capabilities: { [CAP.core]: { maxCallsInRequest: 16, maxObjectsInGet: 500 }, [CAP.mail]: {} },
accounts: {
own: { name: "[email protected]", isPersonal: true, accountCapabilities: { [CAP.mail]: {} } },
own: {
name: "[email protected]",
isPersonal: true,
accountCapabilities: { [CAP.mail]: {}, [CAP.calendars]: {}, [CAP.contacts]: {}, [CAP.filenode]: {} },
},
shared: { name: "[email protected]", isPersonal: false, accountCapabilities: { [CAP.mail]: {} } },
...(locked ? { locked } : {}),
},
primaryAccounts: { [CAP.mail]: "own" },
primaryAccounts: { [CAP.mail]: "own", [CAP.calendars]: "own", [CAP.contacts]: "own", [CAP.filenode]: "own" },
state: "s",
}) as unknown as JmapSession;
@@ -94,6 +101,19 @@ describe("viewing a locked account", () => {
expect(useMail.getState().accountId).toBe("own");
});
it("brings the whole account: calendar, contacts and files, never the reader's settings", () => {
const s = () => useSession.getState();
expect(s().viewAccountFor(CAP.calendars)).toBe("own");
s().view("locked");
for (const cap of [CAP.calendars, CAP.contacts, CAP.filenode]) {
expect(s().viewAccountFor(cap)).toBe("locked");
}
// Settings live in the reader's own Files, whatever is in view
expect(s().ownAccountFor(CAP.filenode)).toBe("own");
s().view(null);
expect(s().viewAccountFor(CAP.contacts)).toBe("own");
});
it("refuses an account that isn't delegated", () => {
useSession.getState().view("shared");
expect(useSession.getState().viewing).toBeNull();