Keep adoption transfer codes stable
This commit is contained in:
+54
-38
@@ -48,6 +48,7 @@ import {
|
||||
getBirdById,
|
||||
getBirdByPublicProfileCode,
|
||||
getOpenBirdTransferCode,
|
||||
getOpenBirdTransferCodeForBird,
|
||||
listBirds,
|
||||
listDueBirdMilestoneReminders,
|
||||
listMemorializedBirds,
|
||||
@@ -654,6 +655,33 @@ const normalizeBird = (row: BirdRow) => ({
|
||||
|
||||
const createBirdTransferCodeValue = () => crypto.randomBytes(12).toString('base64url');
|
||||
|
||||
const ensureOpenBirdTransferCode = async (birdId: string, sourceWorkspaceId: number, requestedByUserId: string) => {
|
||||
const existingTransferCode = await getOpenBirdTransferCodeForBird(birdId, sourceWorkspaceId);
|
||||
|
||||
if (existingTransferCode) {
|
||||
return existingTransferCode;
|
||||
}
|
||||
|
||||
for (let attempt = 0; attempt < 3; attempt += 1) {
|
||||
try {
|
||||
return await createBirdTransferCode({
|
||||
code: createBirdTransferCodeValue(),
|
||||
birdId,
|
||||
sourceWorkspaceId,
|
||||
requestedByUserId,
|
||||
});
|
||||
} catch (error) {
|
||||
if (typeof error === 'object' && error && 'code' in error && error.code === '23505' && attempt < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const normalizePublicBirdProfile = (row: BirdRow) => ({
|
||||
id: row.id,
|
||||
workspaceId: row.workspace_id,
|
||||
@@ -3272,25 +3300,7 @@ app.post(
|
||||
return;
|
||||
}
|
||||
|
||||
let transferCode = null;
|
||||
|
||||
for (let attempt = 0; attempt < 3; attempt += 1) {
|
||||
try {
|
||||
transferCode = await createBirdTransferCode({
|
||||
code: createBirdTransferCodeValue(),
|
||||
birdId: sourceBird.id,
|
||||
sourceWorkspaceId: req.auth!.workspace.id,
|
||||
requestedByUserId: req.auth!.user.id,
|
||||
});
|
||||
break;
|
||||
} catch (error) {
|
||||
if (typeof error === 'object' && error && 'code' in error && error.code === '23505' && attempt < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const transferCode = await ensureOpenBirdTransferCode(sourceBird.id, req.auth!.workspace.id, req.auth!.user.id);
|
||||
|
||||
if (!transferCode) {
|
||||
throw new Error('Unable to create bird transfer code.');
|
||||
@@ -3312,6 +3322,30 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
app.get('/api/birds/:birdId/transfer-code', requireAuth, requireWriteAccess, requireSessionAuth, requireWorkspaceRole(['owner', 'assistant']), async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const sourceBird = await getBirdById(req.params.birdId, req.auth!.workspace.id);
|
||||
|
||||
if (!sourceBird) {
|
||||
res.status(404).json({ error: 'Bird not found.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const transferCode = await getOpenBirdTransferCodeForBird(sourceBird.id, req.auth!.workspace.id);
|
||||
|
||||
res.json({
|
||||
transferCode: transferCode
|
||||
? {
|
||||
code: transferCode.code,
|
||||
bird: normalizeBird(sourceBird),
|
||||
}
|
||||
: null,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
app.post(
|
||||
'/api/bird-transfer-codes/:code/accept',
|
||||
requireAuth,
|
||||
@@ -3384,25 +3418,7 @@ app.post(
|
||||
return;
|
||||
}
|
||||
|
||||
let transferCode = null;
|
||||
|
||||
for (let attempt = 0; attempt < 3; attempt += 1) {
|
||||
try {
|
||||
transferCode = await createBirdTransferCode({
|
||||
code: createBirdTransferCodeValue(),
|
||||
birdId: sourceBird.id,
|
||||
sourceWorkspaceId: req.auth!.workspace.id,
|
||||
requestedByUserId: req.auth!.user.id,
|
||||
});
|
||||
break;
|
||||
} catch (error) {
|
||||
if (typeof error === 'object' && error && 'code' in error && error.code === '23505' && attempt < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const transferCode = await ensureOpenBirdTransferCode(sourceBird.id, req.auth!.workspace.id, req.auth!.user.id);
|
||||
|
||||
if (!transferCode) {
|
||||
throw new Error('Unable to create bird transfer code.');
|
||||
|
||||
@@ -154,8 +154,12 @@ const drawSimpleWeightChart = (doc: PDFKit.PDFDocument, weights: WeightRow[], bi
|
||||
}
|
||||
|
||||
const latestDate = new Date(`${plottedWeights[plottedWeights.length - 1].recorded_on.slice(0, 10)}T00:00:00Z`);
|
||||
const earliestDate = new Date(`${plottedWeights[0].recorded_on.slice(0, 10)}T00:00:00Z`);
|
||||
const startDate = new Date(latestDate);
|
||||
startDate.setUTCDate(startDate.getUTCDate() - 29);
|
||||
startDate.setUTCDate(startDate.getUTCDate() - 13);
|
||||
if (earliestDate > startDate) {
|
||||
startDate.setTime(earliestDate.getTime());
|
||||
}
|
||||
const visibleWeights = plottedWeights.filter((entry) => {
|
||||
const recordedOn = new Date(`${entry.recorded_on.slice(0, 10)}T00:00:00Z`);
|
||||
return recordedOn >= startDate && recordedOn <= latestDate;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { getSignedS3ObjectUrl } from '../storage/s3Client.js';
|
||||
import type { BirdRow } from '../types.js';
|
||||
import { renderAdoptionReportPdf } from './adoptionReport.js';
|
||||
|
||||
const adoptionReportWeightHistoryDays = 425;
|
||||
const adoptionReportWeightHistoryDays = 14;
|
||||
|
||||
const parseDataImage = (value: string | null) => {
|
||||
if (!value) {
|
||||
|
||||
@@ -734,6 +734,22 @@ export const createBirdTransferCode = async ({
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const getOpenBirdTransferCodeForBird = async (birdId: string, sourceWorkspaceId: number) => {
|
||||
const result = await db.query<BirdTransferCodeRow>(
|
||||
`SELECT id, code, bird_id, source_workspace_id, requested_by_user_id, completed_at::text, completed_workspace_id, revoked_at::text, created_at
|
||||
FROM bird_transfer_codes
|
||||
WHERE bird_id = $1
|
||||
AND source_workspace_id = $2
|
||||
AND completed_at IS NULL
|
||||
AND revoked_at IS NULL
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1`,
|
||||
[birdId, sourceWorkspaceId],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const getOpenBirdTransferCode = async (code: string) => {
|
||||
const result = await db.query<
|
||||
BirdRow & {
|
||||
|
||||
Reference in New Issue
Block a user