mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
/** Storage quota as the UI shows it. */
|
|
export interface StorageQuota {
|
|
used: number;
|
|
/**
|
|
* The limit the user actually works against: softLimit when the server
|
|
* sets one below hardLimit, since writes start failing there (RFC 9425
|
|
* §4.1, #1242). Otherwise hardLimit.
|
|
*/
|
|
total: number;
|
|
/** hardLimit, only when it is above `total` (inbound mail still lands up to it). */
|
|
hardLimit?: number;
|
|
/** warnLimit, only when it is below `total`. */
|
|
warnAt?: number;
|
|
}
|
|
|
|
/** A Quota object as RFC 9425 defines it, plus the pre-RFC `limit` some servers send. */
|
|
export interface JMAPQuota {
|
|
resourceType?: string;
|
|
scope?: string;
|
|
types?: string[];
|
|
used?: number;
|
|
hardLimit?: number;
|
|
softLimit?: number | null;
|
|
warnLimit?: number | null;
|
|
limit?: number;
|
|
}
|
|
|
|
const positive = (n: number | null | undefined): n is number =>
|
|
typeof n === "number" && Number.isFinite(n) && n > 0;
|
|
|
|
/** Picks the mail storage quota out of a Quota/get list. */
|
|
export function toStorageQuota(quotas: JMAPQuota[]): StorageQuota | null {
|
|
const coversMail = (q: JMAPQuota) =>
|
|
!q.types?.length || q.types.some((t) => t === "Email" || t === "Mail");
|
|
// storage quotas use resourceType "octets" (e.g. Stalwart, with
|
|
// scope "account"); fall back to the pre-RFC "mail" shape for older servers.
|
|
const q =
|
|
quotas.find((q) => q.resourceType === "octets" && coversMail(q)) ||
|
|
quotas.find((q) => q.resourceType === "mail" || q.scope === "mail");
|
|
if (!q) return null;
|
|
|
|
const hard = q.hardLimit ?? q.limit ?? 0;
|
|
const soft = positive(q.softLimit) && (!positive(hard) || q.softLimit < hard) ? q.softLimit : undefined;
|
|
const total = soft ?? hard;
|
|
const quota: StorageQuota = { used: q.used ?? 0, total };
|
|
if (soft !== undefined && positive(hard)) quota.hardLimit = hard;
|
|
if (positive(q.warnLimit) && (!positive(total) || q.warnLimit < total)) quota.warnAt = q.warnLimit;
|
|
return quota;
|
|
}
|
|
|
|
export type QuotaLevel = "ok" | "warn" | "full";
|
|
|
|
/** Colour band for a quota: warnLimit when the server sets one, else 70%; full above 90%. */
|
|
export function quotaLevel(quota: StorageQuota): QuotaLevel {
|
|
if (quota.total <= 0) return "ok";
|
|
if (quota.used / quota.total > 0.9) return "full";
|
|
if (quota.warnAt !== undefined ? quota.used >= quota.warnAt : quota.used / quota.total > 0.7) return "warn";
|
|
return "ok";
|
|
}
|