Add retakes, quiz templates, score history, due dates, CSV export, and prerequisites

- allow_retakes flag on items: quizzes, spelling tests, and assignments can all be retaken
- Quiz templates: save any quiz as a reusable template and load it into new items
- Score history: every quiz/test attempt logged to submission_history; click a gradebook score to see all attempts
- Due dates: optional due date per item, shown in course view and gradebook (overdue flagged with ⚠️)
- Gradebook CSV export: one-click download of any course gradebook
- Prerequisites: lock an item until a prior one is completed; locked items show 🔒 in course view

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-07-14 13:22:58 -04:00
1 parent 23b24b5d21
commit 02909e1edc
6 files changed
+375 -39

No files matched your search

+32
View File
@@ -181,8 +181,40 @@ db.exec(`
sort INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_schedule_day ON schedule(student_id, date);
CREATE TABLE IF NOT EXISTS quiz_templates (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS quiz_template_questions (
id INTEGER PRIMARY KEY,
template_id INTEGER NOT NULL REFERENCES quiz_templates(id) ON DELETE CASCADE,
type TEXT NOT NULL,
prompt TEXT NOT NULL,
choices TEXT NOT NULL DEFAULT '[]',
correct_answer TEXT NOT NULL,
points INTEGER NOT NULL DEFAULT 1,
sort INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS submission_history (
id INTEGER PRIMARY KEY,
student_id INTEGER NOT NULL REFERENCES students(id) ON DELETE CASCADE,
item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
score REAL,
points_possible REAL,
answers TEXT,
completed_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
function tryAlter(sql) {
try { db.exec(sql); } catch { /* column already exists */ }
}
tryAlter(`ALTER TABLE items ADD COLUMN due_date TEXT`);
tryAlter(`ALTER TABLE items ADD COLUMN allow_retakes INTEGER NOT NULL DEFAULT 0`);
tryAlter(`ALTER TABLE items ADD COLUMN prereq_item_id INTEGER`);
export const sha256 = (s) => createHash('sha256').update(String(s)).digest('hex');
// Default parent PIN on first run