1bc2de655a
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
58 lines
2.6 KiB
TypeScript
58 lines
2.6 KiB
TypeScript
import { prisma } from "../db";
|
|
import { sendTo } from "../mail";
|
|
|
|
/* Notices to the owner, by email, over the SMTP the product already has.
|
|
*
|
|
* Who gets them: OPS_ALERT_TO when set, otherwise every active OWNER operator. What they carry:
|
|
* the name of a facility and what happened to it — never a coordinator's name or email, never a
|
|
* wearer, never a record. A notice must be safe to sit in a mailbox. Each caller names its own
|
|
* condition; nothing here fires on a timer, so there is nothing to dedupe — one event, one mail.
|
|
*
|
|
* Never throws and never awaited for its own sake: a notice that could fail the action it
|
|
* describes would be a reason to skip sending it. */
|
|
export async function ownerAddresses(): Promise<string[]> {
|
|
const fixed = (process.env.OPS_ALERT_TO || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
if (fixed.length) return fixed;
|
|
try {
|
|
const owners = await prisma.operator.findMany({ where: { role: "OWNER", inactive: false }, select: { email: true } });
|
|
return owners.map((o) => o.email);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function notifyOwners(subject: string, text: string): void {
|
|
ownerAddresses()
|
|
.then((to) => Promise.all(to.map((a) => sendTo(a, subject, text))))
|
|
.catch(() => { /* a notice must not fail the action */ });
|
|
}
|
|
|
|
const when = () => new Date().toLocaleString("en-AU", { timeZone: "Australia/Brisbane", dateStyle: "medium", timeStyle: "short" });
|
|
|
|
/** A facility signed up. Name only — the person who did it is a contact, and contacts are revealed, not mailed. */
|
|
export function alertNewSignup(facility: { id: string; name: string }): void {
|
|
notifyOwners(`[ops] New facility — ${facility.name}`, [
|
|
`A facility signed up for ThreadCount.`,
|
|
"",
|
|
`Facility: ${facility.name}`,
|
|
`When: ${when()} (Brisbane)`,
|
|
`Console: https://ops.threadcount.tech/ops/facilities/${facility.id}`,
|
|
"",
|
|
"It appears on the console as \"never set up\" until its staff groups are named.",
|
|
].join("\n"));
|
|
}
|
|
|
|
/** A facility was deleted from the console. Sent to every owner so a second operator's deletion reaches the first. */
|
|
export function alertFacilityDeleted(args: { name: string; by: string; ip: string; counts: string }): void {
|
|
notifyOwners(`[ops] Facility deleted — ${args.name}`, [
|
|
`${args.by} deleted a facility from the ThreadCount operations console.`,
|
|
"",
|
|
`Facility: ${args.name}`,
|
|
`Had: ${args.counts}`,
|
|
`When: ${when()} (Brisbane)`,
|
|
`From: ${args.ip || "unknown address"}`,
|
|
"",
|
|
"Every record, image and account belonging to it is gone. The pre-deploy database dumps on the box are the only copies left.",
|
|
].join("\n"));
|
|
}
|