participant-calibration flow implemented
This commit is contained in:
@@ -9,6 +9,8 @@ import { auth } from '@/lib/auth';
|
||||
import { headers } from 'next/headers';
|
||||
import type { DatasetEntryForAnnotation } from '@/lib/dialects';
|
||||
import { experiment } from '@/lib/model/experiment';
|
||||
import { experiment_calibration } from '@/lib/model/experiment_calibration';
|
||||
import { participant } from '@/lib/model/participant';
|
||||
|
||||
/**
|
||||
* Returns unannotated entries for the given dataset and authenticated user.
|
||||
@@ -133,3 +135,60 @@ export async function getAnnotationProgress(
|
||||
return { total: allEntries.length, done: annotated.length };
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if calibration is required and completed for the current user in an experiment.
|
||||
* Returns true if calibration is completed or not required, false if calibration is pending.
|
||||
*/
|
||||
export async function isCalibrationDone(experimentId: number): Promise<boolean> {
|
||||
console.log('Checking calibration status for experimentId:', experimentId);
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) throw new Error('Nicht angemeldet');
|
||||
|
||||
// Get calibration items for this experiment
|
||||
const calibrationItems = await db
|
||||
.select()
|
||||
.from(experiment_calibration)
|
||||
.where(eq(experiment_calibration.experimentId, experimentId));
|
||||
|
||||
// If no calibration items are defined, calibration is not required
|
||||
if (calibrationItems.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if participant exists for this user and experiment
|
||||
const participantRecord = await db
|
||||
.select()
|
||||
.from(participant)
|
||||
.where(
|
||||
and(
|
||||
eq(participant.experimentId, experimentId),
|
||||
eq(participant.userId, session.user.id)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
// If no participant record exists, calibration is not done
|
||||
if (participantRecord.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if calibration answers are filled
|
||||
const calibrationAnswers = participantRecord[0].calibrationAnswers as Record<number, { dialectLabel: string; confidence: number }> | null;
|
||||
|
||||
if (!calibrationAnswers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that all calibration items have complete answers
|
||||
for (const item of calibrationItems) {
|
||||
const answer = calibrationAnswers[item.id];
|
||||
|
||||
// Check if answer exists and has both required fields
|
||||
if (!answer || !answer.dialectLabel || !answer.confidence) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
import db from '@/lib/db';
|
||||
import { experiment_calibration } from '@/lib/model/experiment_calibration';
|
||||
import { participant } from '@/lib/model/participant';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { requireAdmin } from '@/lib/auth';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { headers } from 'next/headers';
|
||||
import { unlink } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
|
||||
@@ -22,6 +25,33 @@ export async function getCalibrationEntries(experimentId: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCalibrationAnswers(experimentId: number) {
|
||||
try {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) throw new Error('Nicht angemeldet');
|
||||
|
||||
const participantRecord = await db
|
||||
.select()
|
||||
.from(participant)
|
||||
.where(
|
||||
and(
|
||||
eq(participant.experimentId, experimentId),
|
||||
eq(participant.userId, session.user.id)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (participantRecord.length === 0) {
|
||||
return { success: true, data: null };
|
||||
}
|
||||
|
||||
return { success: true, data: participantRecord[0].calibrationAnswers };
|
||||
} catch (error) {
|
||||
console.error('Error fetching calibration answers:', error);
|
||||
throw new Error('Failed to fetch calibration answers');
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteCalibrationEntry(calibrationId: number, experimentId: number) {
|
||||
const result = await requireAdmin();
|
||||
if (!result.authenticated || !result.admin) {
|
||||
@@ -133,3 +163,35 @@ export async function deleteAllCalibrationEntries(experimentId: number) {
|
||||
throw new Error('Failed to delete all calibration entries');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves calibration answers for the current user in an experiment.
|
||||
* Creates or updates a participant record with the calibration answers as JSON.
|
||||
*/
|
||||
export async function saveCalibrationAnswers(
|
||||
experimentId: number,
|
||||
answers: Record<number, { calibrationItemId: number; dialectLabel: string; confidence: number }>
|
||||
): Promise<void> {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) throw new Error('Nicht angemeldet');
|
||||
|
||||
try {
|
||||
// Upsert participant record with calibration answers
|
||||
await db
|
||||
.insert(participant)
|
||||
.values({
|
||||
experimentId,
|
||||
userId: session.user.id,
|
||||
calibrationAnswers: answers,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [participant.experimentId, participant.userId],
|
||||
set: {
|
||||
calibrationAnswers: answers,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving calibration answers:', error);
|
||||
throw new Error('Failed to save calibration answers');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user