116 lines
4.4 KiB
TypeScript
116 lines
4.4 KiB
TypeScript
export type MailProfileProtocol = "smtp" | "imap";
|
|
export type MailProfileEditSection = MailProfileProtocol;
|
|
export type MailProfilePanelMode = "all" | "server" | "credentials";
|
|
|
|
export type MailProfileEditTarget =
|
|
| {kind: "create";}
|
|
| {kind: "profile";}
|
|
| {kind: "server";protocol: MailProfileProtocol;serverId?: string;}
|
|
| {kind: "credentials";protocol: MailProfileProtocol;serverId?: string;credentialId?: string;};
|
|
|
|
export type MailProfileTransportLike = {
|
|
host?: string | null;
|
|
};
|
|
|
|
export type MailProfileTreeProfileLike = {
|
|
id: string;
|
|
imap?: MailProfileTransportLike | null;
|
|
};
|
|
|
|
export type MailProfileChildDescriptor = {
|
|
kind: "server" | "credential";
|
|
id: string;
|
|
protocol: MailProfileProtocol;
|
|
};
|
|
|
|
export type MailProfileTransportCredentialsLike = {
|
|
username?: string | null;
|
|
password?: string | null;
|
|
};
|
|
|
|
export type MailProfileTargetedUpdateParts = {
|
|
profile: Record<string, unknown>;
|
|
smtp: Record<string, unknown>;
|
|
imap: Record<string, unknown> | null;
|
|
credentials: {
|
|
smtp: MailProfileTransportCredentialsLike;
|
|
imap: MailProfileTransportCredentialsLike;
|
|
};
|
|
clearImap: boolean;
|
|
};
|
|
|
|
export function mailProfileChildDescriptors(profile: MailProfileTreeProfileLike): MailProfileChildDescriptor[] {
|
|
const children: MailProfileChildDescriptor[] = [
|
|
{ kind: "server", id: `server:${profile.id}:smtp`, protocol: "smtp" },
|
|
{ kind: "credential", id: `credential:${profile.id}:smtp`, protocol: "smtp" },
|
|
{ kind: "server", id: `server:${profile.id}:imap`, protocol: "imap" }
|
|
];
|
|
if (profile.imap) children.push({ kind: "credential", id: `credential:${profile.id}:imap`, protocol: "imap" });
|
|
return children;
|
|
}
|
|
|
|
export function mailProfileEditTargetInitialSection(target: MailProfileEditTarget): MailProfileEditSection {
|
|
if (target.kind === "server" || target.kind === "credentials") return target.protocol;
|
|
return "smtp";
|
|
}
|
|
|
|
export function mailProfileEditTargetPanelMode(target: MailProfileEditTarget): MailProfilePanelMode | null {
|
|
if (target.kind === "create") return "all";
|
|
if (target.kind === "server") return "server";
|
|
if (target.kind === "credentials") return "credentials";
|
|
return null;
|
|
}
|
|
|
|
export function mailProfileEditTargetVisibleSections(target: MailProfileEditTarget): MailProfileEditSection[] {
|
|
if (target.kind === "server" || target.kind === "credentials") return [target.protocol];
|
|
if (target.kind === "create") return ["smtp", "imap"];
|
|
return [];
|
|
}
|
|
|
|
export function mailProfileEditTargetShowsProfileFields(target: MailProfileEditTarget): boolean {
|
|
return target.kind === "create" || target.kind === "profile";
|
|
}
|
|
|
|
export function mailProfileEditTargetShowsSettingsPanel(target: MailProfileEditTarget): boolean {
|
|
return target.kind !== "profile";
|
|
}
|
|
|
|
/**
|
|
* Keep the PATCH authority surface equal to the focused editor. Profile and
|
|
* server edits must not accidentally replay credential fields merely because
|
|
* the form draft contains their displayed values.
|
|
*/
|
|
export function mailProfileTargetedUpdatePayload(
|
|
target: MailProfileEditTarget,
|
|
parts: MailProfileTargetedUpdateParts
|
|
): Record<string, unknown> {
|
|
if (target.kind === "profile") return parts.profile;
|
|
if (target.kind === "server") {
|
|
if (target.protocol === "smtp") return { smtp: parts.smtp };
|
|
return parts.imap === null
|
|
? { imap: null, clear_imap: parts.clearImap }
|
|
: { imap: parts.imap };
|
|
}
|
|
if (target.kind === "credentials") {
|
|
return { credentials: { [target.protocol]: parts.credentials[target.protocol] } };
|
|
}
|
|
throw new Error("Create is not an update target");
|
|
}
|
|
|
|
/** Omit blank create credentials so profile-write remains independent. */
|
|
export function mailProfileCreateCredentialsPayload(
|
|
smtp: MailProfileTransportCredentialsLike,
|
|
imap: MailProfileTransportCredentialsLike
|
|
): {smtp?: MailProfileTransportCredentialsLike;imap?: MailProfileTransportCredentialsLike;} | undefined {
|
|
const populated = (value: MailProfileTransportCredentialsLike): MailProfileTransportCredentialsLike =>
|
|
Object.fromEntries(
|
|
Object.entries(value).filter(([, item]) => item !== null && item !== undefined && item !== "")
|
|
);
|
|
const smtpCredentials = populated(smtp);
|
|
const imapCredentials = populated(imap);
|
|
const result: {smtp?: MailProfileTransportCredentialsLike;imap?: MailProfileTransportCredentialsLike;} = {};
|
|
if (Object.keys(smtpCredentials).length > 0) result.smtp = smtpCredentials;
|
|
if (Object.keys(imapCredentials).length > 0) result.imap = imapCredentials;
|
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
}
|