Health probe: dump all relationships for a given contact, flag direction issues
This commit is contained in:
@@ -286,6 +286,72 @@ async function probeChecksumWithSampleContact(): Promise<CheckResult> {
|
||||
};
|
||||
}
|
||||
|
||||
async function probeContactRelationships(cid: string): Promise<CheckResult> {
|
||||
// Dumps every active relationship involving this contact, regardless of
|
||||
// direction. Useful when /api/data returns 404 — tells you whether the
|
||||
// relationship exists at all and which side this contact is on.
|
||||
try {
|
||||
const res = await civi<{
|
||||
id: number;
|
||||
contact_id_a: number;
|
||||
contact_id_b: number;
|
||||
"relationship_type_id:name_a_b": string;
|
||||
"relationship_type_id:name_b_a": string;
|
||||
is_active: boolean;
|
||||
}>("Relationship", "get", {
|
||||
select: [
|
||||
"id",
|
||||
"contact_id_a",
|
||||
"contact_id_b",
|
||||
"relationship_type_id:name_a_b",
|
||||
"relationship_type_id:name_b_a",
|
||||
"is_active",
|
||||
],
|
||||
where: [
|
||||
["OR", [["contact_id_a", "=", Number(cid)], ["contact_id_b", "=", Number(cid)]]],
|
||||
["is_active", "=", true],
|
||||
],
|
||||
limit: 50,
|
||||
});
|
||||
const rows = res.values ?? [];
|
||||
if (rows.length === 0) {
|
||||
return {
|
||||
check: "contact_relationships_dump",
|
||||
ok: false,
|
||||
detail: `Contact ${cid} has no active relationships at all. Add a relationship of type "${FORM_CONTACT_RELATIONSHIP}" with this contact on side A (Individual) and the target Organization on side B.`,
|
||||
};
|
||||
}
|
||||
const lines = rows.map((r) => {
|
||||
const sideA = String(r.contact_id_a) === cid ? "★A" : "·A";
|
||||
const sideB = String(r.contact_id_b) === cid ? "★B" : "·B";
|
||||
return ` ${sideA}=${r.contact_id_a} ${sideB}=${r.contact_id_b} type="${r["relationship_type_id:name_a_b"]}" / inverse="${r["relationship_type_id:name_b_a"]}"`;
|
||||
});
|
||||
const usable = rows.find(
|
||||
(r) =>
|
||||
String(r.contact_id_a) === cid &&
|
||||
r["relationship_type_id:name_a_b"] === FORM_CONTACT_RELATIONSHIP,
|
||||
);
|
||||
return {
|
||||
check: "contact_relationships_dump",
|
||||
ok: Boolean(usable),
|
||||
detail:
|
||||
`Active relationships involving contact ${cid} (★ marks the side this contact is on):\n` +
|
||||
lines.join("\n") +
|
||||
"\n\n" +
|
||||
(usable
|
||||
? `✓ Found a usable "${FORM_CONTACT_RELATIONSHIP}" with contact ${cid} on side A (id=${usable.id}, org=${usable.contact_id_b}).`
|
||||
: `✗ No relationship matches: type="${FORM_CONTACT_RELATIONSHIP}" with contact ${cid} on side A. ` +
|
||||
`If you see the right relationship above with contact ${cid} on side B, the relationship is stored backwards — delete and re-add with the Individual chosen first, OR change FORM_CONTACT_RELATIONSHIP in config/form.ts to the inverse name (name_b_a).`),
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
check: "contact_relationships_dump",
|
||||
ok: false,
|
||||
detail: e instanceof Error ? e.message : String(e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(req: Request) {
|
||||
const env = envSummary();
|
||||
const summary = { mode: env.ok ? "live" : "stub" };
|
||||
@@ -323,7 +389,11 @@ export async function GET(req: Request) {
|
||||
});
|
||||
}
|
||||
|
||||
// If a sample cid+cs was provided, verify that specific checksum.
|
||||
// If a sample cid+cs was provided, verify that specific checksum + dump
|
||||
// the contact's relationships.
|
||||
if (cid) {
|
||||
checks.push(await probeContactRelationships(cid));
|
||||
}
|
||||
if (cid && cs) {
|
||||
try {
|
||||
const ok = await verifyChecksum(cid, cs);
|
||||
@@ -341,7 +411,7 @@ export async function GET(req: Request) {
|
||||
detail: e instanceof Error ? e.message : String(e),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
} else if (!cid) {
|
||||
checks.push(await probeChecksumWithSampleContact());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user