The admin pages save the whole policy from the draft they loaded. A
save from a page opened before another tab's or another admin's save,
or before a deleted plugin was dropped from the policy, used to put the
older policy back. GET /api/admin/policy now sends the policy version as
an ETag; the policy, organisation, plugins and themes pages send it back
as If-Match, and a save based on an older version answers 409 and keeps
the draft on the page. A PUT without If-Match replaces the policy as
before. Deleting a plugin or theme changes only its id in the stored
policy, and a policy import compares against what it replaces.
Test mocks of the config manager gain getPolicyVersion and updatePolicy,
which the route and the extension cleanup now call.
Message ids repeat across accounts, so a hook payload naming only an
emailId could not tell a plugin which mailbox the message lies in when
it is a shared or group account's.
onBeforeEmailStarToggle and onEmailStarToggle now carry accountId when
the starred message is not in the user's own account, as the
message-row-actions click context does. Every star (the row's button,
the reader's star, the key, the menu) goes through toggleStar, one
message at a time, so one accountId names it; the account is resolved
before the plugins are asked. An own message's payload is unchanged.
onAfterEmailSend now carries accountId, the JMAP account the sent
message lies in (a mail sent from a shared or group identity lies in
that account), so api.email.get finds it. sendEmail returns that account
as emailAccountId, the S/MIME send too. The hook also carries
composerId, the id the sending composer's slots and actions gave
plugins, so a plugin can act on what the user chose in that composer.
A plugin opens a message as a click on a list row or on a search result
entry naming one does, also a message of a shared or group account,
reached through the login that reads it. On the mail page it opens in
place, in the Pro shell in an email tab as a message link does there;
elsewhere the tab loads the message's link, at most five times a minute.
A message no login reads, or one its account does not have, is refused
with an error the plugin sees, as is one the mail page could not open.
Needs email:read.