fix(telegram): do not offer or record doses of a record-only medication

This commit is contained in:
Marc-André Bombeck committed 2026-09-25 10:03:09 +02:00
1 parent 37c6b0e144
commit 0e242cfea1
2 files changed
+62 -5

No files matched your search

@@ -1181,3 +1181,45 @@ describe("Telegram webhook — GET verification is rate-limited first", () => {
);
});
});
/**
* #1033 — a medication kept as a record is never offered, recorded or snoozed
* from Telegram, the same as on the web.
*/
describe("POST /api/telegram/webhook — record-only medications", () => {
function textUpdate(text: string) {
return {
update_id: 300,
message: { message_id: 30, text, chat: { id: 7777 }, from: { id: 7777 } },
};
}
function whereOf(call: unknown): Record<string, unknown> {
return (call as [{ where: Record<string, unknown> }])[0].where;
}
it("/add lists tracked medications only", async () => {
await POST(tgRequest(textUpdate("/add")));
const where = whereOf(vi.mocked(prisma.medication.findMany).mock.calls[0]);
expect(where).toMatchObject({ active: true, trackIntake: true });
});
it("the 'taken' keyword resolves tracked medications only", async () => {
await POST(tgRequest(textUpdate("taken Ramipril")));
const where = whereOf(vi.mocked(prisma.medication.findFirst).mock.calls[0]);
expect(where).toMatchObject({ active: true, trackIntake: true });
});
it("a reminder button on a record-only medication records nothing", async () => {
await POST(tgRequest(callbackUpdate("taken:med-1")));
// The gate lookup: a record-only medication resolves to nothing here,
// so no dose is written (later lookups only bind an admitted dose).
const calls = vi.mocked(prisma.medication.findFirst).mock.calls;
expect(calls.length).toBeGreaterThan(0);
expect(whereOf(calls[0])).toMatchObject({
id: "med-1",
active: true,
trackIntake: true,
});
});
});
+20 -5
View File
@@ -33,6 +33,10 @@ import {
isTelegramCapturableType,
logTelegramMeasurement,
} from "@/lib/measurements/create-from-telegram";
// v1.39.1 (#1033) — every Telegram path that offers, records or snoozes a
// dose (the /add list, the "taken" keyword, the reminder buttons) leaves a
// medication kept as a record out, as the web and the today list do.
import { TRACKED_INTAKE_WHERE } from "@/lib/medications/intake-tracking";
/**
* Telegram webhook update handlers, split out of
@@ -301,7 +305,7 @@ async function markMedicationTaken(
): Promise<{ ok: boolean; message: string; medicationName?: string }> {
const { t } = getServerTranslator(locale);
const medication = await prisma.medication.findFirst({
where: { id: medicationId, userId, active: true },
where: { id: medicationId, userId, active: true, ...TRACKED_INTAKE_WHERE },
select: { id: true, name: true },
});
if (!medication) {
@@ -518,7 +522,12 @@ export async function handleCallback(update: TelegramUpdate) {
}
const medication = await prisma.medication.findFirst({
where: { id: medicationId, userId: user.id, active: true },
where: {
id: medicationId,
userId: user.id,
active: true,
...TRACKED_INTAKE_WHERE,
},
select: { id: true, name: true },
});
if (!medication) {
@@ -560,7 +569,12 @@ export async function handleCallback(update: TelegramUpdate) {
}
const medication = await prisma.medication.findFirst({
where: { id: medicationId, userId: user.id, active: true },
where: {
id: medicationId,
userId: user.id,
active: true,
...TRACKED_INTAKE_WHERE,
},
select: { id: true, name: true },
});
if (!medication) {
@@ -1189,7 +1203,7 @@ export async function handleTextMessage(update: TelegramUpdate) {
if (/^\/add\b/i.test(text)) {
const userMsgId = message?.message_id;
const meds = await prisma.medication.findMany({
where: { userId: user.id, active: true },
where: { userId: user.id, active: true, ...TRACKED_INTAKE_WHERE },
select: { id: true, name: true, dose: true },
orderBy: { name: "asc" },
});
@@ -1297,6 +1311,7 @@ export async function handleTextMessage(update: TelegramUpdate) {
where: {
userId: user.id,
active: true,
...TRACKED_INTAKE_WHERE,
name: { equals: nameInput, mode: "insensitive" },
},
select: { id: true },
@@ -1304,7 +1319,7 @@ export async function handleTextMessage(update: TelegramUpdate) {
medicationId = med?.id ?? null;
} else {
const meds = await prisma.medication.findMany({
where: { userId: user.id, active: true },
where: { userId: user.id, active: true, ...TRACKED_INTAKE_WHERE },
select: { id: true, name: true },
orderBy: { name: "asc" },
take: 2,