fix: prevent sync from nullifying assigned_resource_id on tickets

- bulkUpsert now accepts preserveExistingOnNull column list, using
  COALESCE(EXCLUDED.col, table.col) so null incoming values never
  overwrite existing non-null DB values
- bulkUpsertRecords passes resource ID columns as preserve-on-null
  for TICKETS and TASKS entities
- getValidResourceIds now throws on DB error instead of returning
  empty set (which would nullify every resource reference)
- Fix mimecast mailbox-remediate fetch handlers to check res.ok and
  content-type before calling res.json(), preventing JSON parse crash
  on 502 Bad Gateway responses
This commit is contained in:
lorentz 2026-04-05 08:55:41 -04:00
parent 04a720f0d0
commit 0e8eb4871e
4 changed files with 40 additions and 26 deletions

View file

@ -1144,11 +1144,13 @@ function DeliveredAnalysisDialog({ message, onClose, onFindSimilar, allMessages
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'search', userEmail: message.to, fromAddress: message.from }),
});
const d = await res.json();
if (!res.ok) {
if (d.permissionRequired) { setPermError(d.detail); setRemedStep('idle'); return; }
throw new Error(d.error ?? `HTTP ${res.status}`);
const isJson = res.headers.get('content-type')?.includes('application/json');
const d = isJson ? await res.json() : null;
if (d?.permissionRequired) { setPermError(d.detail); setRemedStep('idle'); return; }
throw new Error(d?.error ?? `HTTP ${res.status}`);
}
const d = await res.json();
const matches = d.messages ?? [];
setRemedMatches(matches);
setRemedSelected(new Set(matches.map((m: any) => m.id)));
@ -1168,8 +1170,12 @@ function DeliveredAnalysisDialog({ message, onClose, onFindSimilar, allMessages
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'move', userEmail: message.to, messageIds: [...remedSelected] }),
});
if (!res.ok) {
const isJson = res.headers.get('content-type')?.includes('application/json');
const d = isJson ? await res.json() : null;
throw new Error(d?.error ?? `HTTP ${res.status}`);
}
const d = await res.json();
if (!res.ok) throw new Error(d.error ?? `HTTP ${res.status}`);
setRemedResults({ succeeded: d.succeeded, failed: d.failed });
setRemedStep('done');
} catch (e: any) {