Add Administration, starting with accounts
An account whose Stalwart role manages accounts now finds Administration in the account menu. It lists, searches, creates and edits accounts -- display name, other addresses, role, storage limit -- sets a new password, and deletes, each offered only when the role holds the matching permission. The server keeps the permissions list from GET /api/account, which it already called for the edition and threw the rest away. Everything else is JMAP x:Account, x:Domain and x:Role calls through the existing /api/jmap proxy, so nothing new is stored and Stalwart decides every call. Stalwart checks a grant against the caller's permissions but not a password change or a delete, so an account that outranks the viewer is shown read-only. Your own password is changed in Settings, which re-seals the session; changing it here would strand it. The mock server gains a directory behind the same permission names, with MOCK_ROLE choosing admin, tenant-admin, helpdesk or user. 68 new strings, translated in all nine catalogues; strings falling back to English stay at 16.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import type { RoleDef } from "@/lib/adminAccess";
|
||||
import type { DirectoryAccount, DirectoryDomain } from "@/lib/adminDirectory";
|
||||
import { t } from "@/lib/i18n";
|
||||
|
||||
export interface DirectoryContext {
|
||||
/** Domains to offer. Read from the server when allowed, else seen on accounts. */
|
||||
domains: DirectoryDomain[];
|
||||
/** Null when the viewer cannot read roles, which `outranks` treats as unknown. */
|
||||
roles: Map<string, RoleDef> | null;
|
||||
groups: Map<string, DirectoryAccount>;
|
||||
/** Registry ids and addresses that are the signed-in account itself. */
|
||||
self: { ids: Set<string>; address: string };
|
||||
}
|
||||
|
||||
export function isSelf(a: Pick<DirectoryAccount, "id" | "emailAddress">, ctx: DirectoryContext): boolean {
|
||||
return ctx.self.ids.has(a.id) || (!!a.emailAddress && a.emailAddress.toLowerCase() === ctx.self.address);
|
||||
}
|
||||
|
||||
export function roleName(a: Pick<DirectoryAccount, "roles">, roles: Map<string, RoleDef> | null): string {
|
||||
const r = a.roles;
|
||||
if (!r || r["@type"] === "User") return t("User");
|
||||
if (r["@type"] === "Admin") return t("Administrator");
|
||||
const names = Object.keys(r.roleIds ?? {}).map((id) => roles?.get(id)?.description).filter(Boolean);
|
||||
return names.length ? names.join(", ") : t("Custom role");
|
||||
}
|
||||
Reference in New Issue
Block a user