146 lines
4.5 KiB
TypeScript
146 lines
4.5 KiB
TypeScript
/**
|
||||
|
|
* Dev helper: jump a password user to Session 11 chat (sessions 1–10 done,
|
|||
|
|
* pre-test done, training/post-test NOT done) so you can test the post-test handoff.
|
|||
|
|
*
|
|||
|
|
* Usage:
|
|||
|
|
* npx tsx scripts/jump-to-session-11.ts alireza@gmail.com
|
|||
|
|
*/
|
|||
|
|
import { AttemptPhase, AttemptStatus, SessionProgressStatus } from '@prisma/client';
|
|||
|
|
import { prisma } from '../src/lib/prisma.ts';
|
|||
|
|
import { PROGRAM_SESSION_COUNT } from '../src/modules/sessions/catalog.ts';
|
|||
|
|
|
|||
|
|
const emailArg = process.argv[2]?.trim().toLowerCase();
|
|||
|
|
if (!emailArg) {
|
|||
|
|
console.error('Usage: npx tsx scripts/jump-to-session-11.ts <email>');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
const identity = await prisma.authIdentity.findFirst({
|
|||
|
|
where: {
|
|||
|
|
provider: 'password',
|
|||
|
|
OR: [{ email: emailArg }, { providerSubject: emailArg }],
|
|||
|
|
},
|
|||
|
|
include: {
|
|||
|
|
user: { include: { journey: true, profile: true } },
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!identity) {
|
|||
|
|
throw new Error(`No password account found for ${emailArg}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const userId = identity.userId;
|
|||
|
|
const now = new Date();
|
|||
|
|
const hourAgo = (n: number) => new Date(now.getTime() - n * 60 * 60 * 1000);
|
|||
|
|
|
|||
|
|
await prisma.$transaction(async (tx) => {
|
|||
|
|
await tx.learningJourney.upsert({
|
|||
|
|
where: { userId },
|
|||
|
|
create: {
|
|||
|
|
userId,
|
|||
|
|
currentStep: 'training_in_progress',
|
|||
|
|
preTestCompletedAt: hourAgo(20),
|
|||
|
|
trainingStartedAt: hourAgo(19),
|
|||
|
|
trainingCompletedAt: null,
|
|||
|
|
postTestCompletedAt: null,
|
|||
|
|
lastActivityAt: now,
|
|||
|
|
},
|
|||
|
|
update: {
|
|||
|
|
currentStep: 'training_in_progress',
|
|||
|
|
preTestCompletedAt: identity.user.journey?.preTestCompletedAt ?? hourAgo(20),
|
|||
|
|
trainingStartedAt: identity.user.journey?.trainingStartedAt ?? hourAgo(19),
|
|||
|
|
trainingCompletedAt: null,
|
|||
|
|
postTestCompletedAt: null,
|
|||
|
|
lastActivityAt: now,
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const existingPre = await tx.assessmentAttempt.findFirst({
|
|||
|
|
where: { userId, phase: AttemptPhase.pre, status: AttemptStatus.scored },
|
|||
|
|
});
|
|||
|
|
if (!existingPre) {
|
|||
|
|
const preAt = hourAgo(20);
|
|||
|
|
await tx.assessmentAttempt.create({
|
|||
|
|
data: {
|
|||
|
|
userId,
|
|||
|
|
phase: AttemptPhase.pre,
|
|||
|
|
status: AttemptStatus.scored,
|
|||
|
|
submittedAt: preAt,
|
|||
|
|
scoredAt: preAt,
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Clear final-session / post-test leftovers so the handoff can be retested.
|
|||
|
|
await tx.sessionProgress.deleteMany({
|
|||
|
|
where: { userId, sessionOrder: PROGRAM_SESSION_COUNT },
|
|||
|
|
});
|
|||
|
|
await tx.chatSession.deleteMany({
|
|||
|
|
where: { userId, sessionOrder: PROGRAM_SESSION_COUNT },
|
|||
|
|
});
|
|||
|
|
await tx.assessmentAttempt.deleteMany({
|
|||
|
|
where: { userId, phase: AttemptPhase.post },
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
for (let order = 1; order < PROGRAM_SESSION_COUNT; order += 1) {
|
|||
|
|
const completedAt = hourAgo(PROGRAM_SESSION_COUNT - order);
|
|||
|
|
await tx.sessionProgress.upsert({
|
|||
|
|
where: { userId_sessionOrder: { userId, sessionOrder: order } },
|
|||
|
|
create: {
|
|||
|
|
userId,
|
|||
|
|
sessionOrder: order,
|
|||
|
|
status: SessionProgressStatus.completed,
|
|||
|
|
startedAt: completedAt,
|
|||
|
|
completedAt,
|
|||
|
|
completionMetadata: {
|
|||
|
|
reason: 'Dev jump-to-session-11 helper',
|
|||
|
|
sessionComplete: true,
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
update: {
|
|||
|
|
status: SessionProgressStatus.completed,
|
|||
|
|
startedAt: completedAt,
|
|||
|
|
completedAt,
|
|||
|
|
completionMetadata: {
|
|||
|
|
reason: 'Dev jump-to-session-11 helper',
|
|||
|
|
sessionComplete: true,
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const progress = await prisma.sessionProgress.findMany({
|
|||
|
|
where: { userId, status: SessionProgressStatus.completed },
|
|||
|
|
select: { sessionOrder: true },
|
|||
|
|
orderBy: { sessionOrder: 'asc' },
|
|||
|
|
});
|
|||
|
|
const journey = await prisma.learningJourney.findUnique({ where: { userId } });
|
|||
|
|
|
|||
|
|
console.log(
|
|||
|
|
JSON.stringify(
|
|||
|
|
{
|
|||
|
|
email: identity.email ?? identity.providerSubject,
|
|||
|
|
profileName: identity.user.profile?.name ?? null,
|
|||
|
|
completedSessions: progress.map((p) => p.sessionOrder),
|
|||
|
|
nextSession: PROGRAM_SESSION_COUNT,
|
|||
|
|
trainingCompletedAt: journey?.trainingCompletedAt ?? null,
|
|||
|
|
postTestCompletedAt: journey?.postTestCompletedAt ?? null,
|
|||
|
|
hint: 'Login → open Chat. You should land on Session 11 review. Finish the wrap-up to reach post-test.',
|
|||
|
|
},
|
|||
|
|
null,
|
|||
|
|
2,
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main()
|
|||
|
|
.catch((err) => {
|
|||
|
|
console.error(err instanceof Error ? err.message : err);
|
|||
|
|
process.exit(1);
|
|||
|
|
})
|
|||
|
|
.finally(async () => {
|
|||
|
|
await prisma.$disconnect();
|
|||
|
|
});
|