Improve social milestone sharing flow
This commit is contained in:
@@ -20,14 +20,10 @@ export async function GET(request: NextRequest) {
|
||||
if (!isAuthorized(request)) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const dryRun = request.nextUrl.searchParams.get('dryRun') === 'true';
|
||||
const now = Date.now();
|
||||
const dayAgo = new Date(now - 24 * 60 * 60 * 1000);
|
||||
const approvalNotBefore = new Date(now - approvalDelayHours() * 60 * 60 * 1000);
|
||||
const postedToday = await db.socialMilestone.count({ where: { OR: [{ status: 'posted', postedAt: { gte: dayAgo } }, { status: 'processing', claimedAt: { gte: dayAgo } }] } });
|
||||
if (postedToday > 0) return NextResponse.json({ milestone: null, reason: 'daily_limit' });
|
||||
|
||||
const milestone = await db.socialMilestone.findFirst({
|
||||
where: { status: 'approved', respondedAt: { lte: approvalNotBefore } },
|
||||
orderBy: { respondedAt: 'asc' },
|
||||
where: { brandStatus: 'approved', brandApprovedAt: { lte: approvalNotBefore } },
|
||||
orderBy: { brandApprovedAt: 'asc' },
|
||||
include: { user: { select: { id: true } }, qr: { select: { id: true, status: true } } },
|
||||
});
|
||||
// Relations are required by the schema. This guard makes the intended
|
||||
@@ -37,14 +33,10 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
if (dryRun) return NextResponse.json({ milestone: { id: milestone.id, text: milestone.consentText }, dryRun: true });
|
||||
|
||||
// A claimed item also occupies the daily slot. This prevents two workers
|
||||
// from each claiming a different milestone before either one posts.
|
||||
const claimed = await db.$transaction(async (tx) => {
|
||||
await tx.$queryRawUnsafe('SELECT pg_advisory_xact_lock(920241)');
|
||||
const occupied = await tx.socialMilestone.count({ where: { OR: [{ status: 'posted', postedAt: { gte: dayAgo } }, { status: 'processing', claimedAt: { gte: dayAgo } }] } });
|
||||
if (occupied) return 0;
|
||||
const result = await tx.socialMilestone.updateMany({
|
||||
where: { id: milestone.id, status: 'approved' }, data: { status: 'processing', claimedAt: new Date() },
|
||||
where: { id: milestone.id, brandStatus: 'approved' }, data: { brandStatus: 'processing', claimedAt: new Date() },
|
||||
});
|
||||
return result.count;
|
||||
});
|
||||
@@ -54,11 +46,16 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
if (!isAuthorized(request)) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
const body = await request.json().catch(() => null) as { id?: string; result?: 'posted' | 'failed' } | null;
|
||||
const body = await request.json().catch(() => null) as { id?: string; result?: 'posted' | 'failed'; postUrl?: string; error?: string } | null;
|
||||
if (!body?.id || !['posted', 'failed'].includes(body.result || '')) return NextResponse.json({ error: 'Invalid payload' }, { status: 400 });
|
||||
const updated = await db.socialMilestone.updateMany({
|
||||
where: { id: body.id, status: 'processing' },
|
||||
data: { status: body.result!, postedAt: body.result === 'posted' ? new Date() : null },
|
||||
where: { id: body.id, brandStatus: 'processing' },
|
||||
data: {
|
||||
brandStatus: body.result!,
|
||||
brandPostedAt: body.result === 'posted' ? new Date() : null,
|
||||
brandPostUrl: body.result === 'posted' ? body.postUrl || null : null,
|
||||
brandPostError: body.result === 'failed' ? (body.error || 'The post could not be published.') : null,
|
||||
},
|
||||
});
|
||||
if (!updated.count) return NextResponse.json({ error: 'Milestone is no longer available' }, { status: 409 });
|
||||
return NextResponse.json({ ok: true });
|
||||
|
||||
Reference in New Issue
Block a user