mian commit
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"teacherMap": {
|
||||
"1": "user_3AJAkSqshofbdPsW7lZh6q2eCe5",
|
||||
"2": "user_3AJAkVye7wKBBK8seog6gljyc7L",
|
||||
"3": "user_3AJAkXA9lrOHxsGcJNoJGOXKNOr",
|
||||
"4": "user_3AJAkc3f42kZzVPLvaRBFHor14J",
|
||||
"5": "user_3AJAkbsXvHmZcGu3wFpRZm732LX",
|
||||
"6": "user_3AJAke4rOtbf26yRM9JoHhtEjyD",
|
||||
"7": "user_3AJAklVf8Pnm2pH6Ql1PnfQBIID",
|
||||
"8": "user_3AJAki8tuWw9rWvZZD9xIP6CxVp",
|
||||
"9": "user_3AJAkn3ET3kFyUrx636ayvHrLds",
|
||||
"10": "user_3AJAkuiTMWimGNBtw7ymHVUqwVW",
|
||||
"11": "user_3AJAkvjGTDDsscx7g9dD998d6Gq",
|
||||
"12": "user_3AJAkr08HMjIKMG1Guzw3HJqB9L",
|
||||
"13": "user_3AJAl1xiX1ZtMg0ohV7QB2TpHm5",
|
||||
"14": "user_3AJAl1tyuI5t3DfmleToHAw6HgJ",
|
||||
"15": "user_3AJAl3Rr5gq7K1W0fhl6AVNFXrY"
|
||||
},
|
||||
"parentMap": {
|
||||
"1": "user_3AJAl6KD5fVP5MbjDZLpyoZ7sDG",
|
||||
"2": "user_3AJAl9gkapHVzn5Tik7RteIEJVZ",
|
||||
"3": "user_3AJAl5BLWwfpho7phY16SrCleE8",
|
||||
"4": "user_3AJAl7BN77L27mpmHzjCp96OlFx",
|
||||
"5": "user_3AJAlFko0fvXyleuRuyqmGkpgTV",
|
||||
"6": "user_3AJAlEyIdgY7vVA7yZQUbTwimOC",
|
||||
"7": "user_3AJAlIlHOwSpcR92ENGiHrz0nCg",
|
||||
"8": "user_3AJAlKekpw2nrtGnnMBvN0xdh3c",
|
||||
"9": "user_3AJAlLmCzuvKoqh9yh2ulnmz26h",
|
||||
"10": "user_3AJAlPbUuestp7PvH2BuX2GQK6R",
|
||||
"11": "user_3AJAlWR17pNYP0S24hiNnUKI2R1",
|
||||
"12": "user_3AJAlWTNINh2uIOEueR8dPKXjlc",
|
||||
"13": "user_3AJAlUx3a2u65hTIoxWLjmDnDuj",
|
||||
"14": "user_3AJAlac7l5vhi9lbnvuOIEZ2zoz",
|
||||
"15": "user_3AJAldy0F23q4Jm8kz8olXdoao0",
|
||||
"16": "user_3AJAlekANUdcMJeZ34EFcCjluAq",
|
||||
"17": "user_3AJAllI3cBBjs5JbcUimhrLEYvf",
|
||||
"18": "user_3AJAlp8YJPzQwvcutFoCsHAz3Sn",
|
||||
"19": "user_3AJAllVI1vR6vwSPlLPCyIb9oZB",
|
||||
"20": "user_3AJAlwjmMMnvV9la8fFlH7TYuOS",
|
||||
"21": "user_3AJAlxGYIRJnKZmvkt2HB9ukrlC",
|
||||
"22": "user_3AJAltSwlQoPrRGcsAZcJpH2sH9",
|
||||
"23": "user_3AJAlvcnUE4GGbYKK0odLUjwxqu",
|
||||
"24": "user_3AJAm16YficrMn5CeAOCAxV8iu1",
|
||||
"25": "user_3AJAlxj9Z9gE4EIwQ5pljEywIV0"
|
||||
},
|
||||
"studentMap": {
|
||||
"1": "user_3AJAm7o0RjL16Gt1jE9YLG0tib7",
|
||||
"2": "user_3AJAm9SoYdWl5sQfbf8slNI2Qn4",
|
||||
"3": "user_3AJAm8NIt39YG9DPjnAwq2G2V3G",
|
||||
"4": "user_3AJAm5KPpNLvz8DjwNU6MRCBO5e",
|
||||
"5": "user_3AJAmGDojjfnVtn7LrmLVemoCiM",
|
||||
"6": "user_3AJAmDK9jVHWfe3FjdR7emQ329K",
|
||||
"7": "user_3AJAmMNLtdeplBIS9kwXYW0FC9Z",
|
||||
"8": "user_3AJAmNXiIZz0FYILKDOZxq1ET56",
|
||||
"9": "user_3AJAmMeKtN7oMMrLgcxIEWsm0EV",
|
||||
"10": "user_3AJAmQsp9Xg8LDpxCkkmccjDCuU",
|
||||
"11": "user_3AJAmZtzvmAwwu7QJRvIpxZCNYF",
|
||||
"12": "user_3AJAmXM1fL4b0fONRdM5uIRIxBS",
|
||||
"13": "user_3AJAmi4pxmDtV24YaIaNmmack33",
|
||||
"14": "user_3AJAmf864NjSUdQ6ExiMR3zaDCn",
|
||||
"15": "user_3AJAmbZArRtgzFrBdW77qbd7P1z",
|
||||
"16": "user_3AJAmpWu9wzc4ve2kwTKPLveFST",
|
||||
"17": "user_3AJAmoVVKEmMeE8GMd7A2fgn5nY",
|
||||
"18": "user_3AJAmlYITikQW1km45TqvQ2biBm",
|
||||
"19": "user_3AJAmuEU2s2CLT9391jnj6Uxb3e",
|
||||
"20": "user_3AJAmwfQjhHcnd6Y2HGvXWTxTj8",
|
||||
"21": "user_3AJAmxavPXIvafOo84MWRqKPyRN",
|
||||
"22": "user_3AJAmxtksJ1U2UjHoP1wzXgk3JB",
|
||||
"23": "user_3AJAn3gfMCCyfaFrX0yY69XfQfQ",
|
||||
"24": "user_3AJAn1UL8HJe9pfcZboyDCqg4Zd",
|
||||
"25": "user_3AJAn4fAYAtcYCLKv1fBkBJSyxw",
|
||||
"26": "user_3AJAnBlPYjZBRY7HrMaY95WRQ59",
|
||||
"27": "user_3AJAnD31sahtYeq9Zfzu867VgB8",
|
||||
"28": "user_3AJAnK8qcNr259cZnIKpH4ZuoRH",
|
||||
"29": "user_3AJAnECM3SCOTVaHQvwaIkV1YnJ",
|
||||
"30": "user_3AJAnH4sNG5lbNwuvYHmmbU9J3U",
|
||||
"31": "user_3AJAnRjFXzyoALI4egtIvZEUFuA",
|
||||
"32": "user_3AJAnYhwtMvevCuQScoLSJePp79",
|
||||
"33": "user_3AJAnXQkG2mOAFxFm1lHaOV2aJQ",
|
||||
"34": "user_3AJAnYU4Frx0bX863nwBE9EJaGH",
|
||||
"35": "user_3AJAncF3uP2xfkU6WixizrfSSrl",
|
||||
"36": "user_3AJAngPagGao0QCe5AcGeeGGpDS",
|
||||
"37": "user_3AJAnazAi3ERTCfqVQr7jDtTOK4",
|
||||
"38": "user_3AJAnoJnVGxwohyI3ot6cwnZ6iO",
|
||||
"39": "user_3AJAnoCbmMiBBlXE3PvUN1vg3CT",
|
||||
"40": "user_3AJAniemPzyyEwPSZZ2h7iXK9lV",
|
||||
"41": "user_3AJAnvqsElaS1dwqPtmhw4N7dCS",
|
||||
"42": "user_3AJAnqp0r30RwkxKEJK3nrPJcwR",
|
||||
"43": "user_3AJAnsBcWHQQGYCpKxLbfWpSWdE",
|
||||
"44": "user_3AJAnrDUy5R1iFD1Vsb8FNlDO1I",
|
||||
"45": "user_3AJAo1kdbtoIYYx3gvEcr3D9WT8",
|
||||
"46": "user_3AJAo0CALCnqJle4D4JGt5VNqHJ",
|
||||
"47": "user_3AJAo1fZPiFTp8U0NYaprnET0Ls",
|
||||
"48": "user_3AJAoB35YG2oZHKLvT4UFBQVBqj",
|
||||
"49": "user_3AJAoDZ1nOyp3f3KO2Lefzgi6Ah",
|
||||
"50": "user_3AJAo6si4CGdeQ3teM04nPmrJe2"
|
||||
},
|
||||
"classes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "1A",
|
||||
"gradeId": 1,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkSqshofbdPsW7lZh6q2eCe5"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "2A",
|
||||
"gradeId": 2,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkVye7wKBBK8seog6gljyc7L"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "3A",
|
||||
"gradeId": 3,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkXA9lrOHxsGcJNoJGOXKNOr"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "4A",
|
||||
"gradeId": 4,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkc3f42kZzVPLvaRBFHor14J"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "5A",
|
||||
"gradeId": 5,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkbsXvHmZcGu3wFpRZm732LX"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "6A",
|
||||
"gradeId": 6,
|
||||
"capacity": 20,
|
||||
"supervisorId": "user_3AJAkSqshofbdPsW7lZh6q2eCe5"
|
||||
}
|
||||
]
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
import "dotenv/config";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import { clerkClient } from "@clerk/nextjs/server";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
"sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz",
|
||||
{ auth: { persistSession: false } }
|
||||
);
|
||||
|
||||
const PASSWORD = "&%5C400l&%";
|
||||
|
||||
async function cleanClerk() {
|
||||
console.log("Cleaning up old Clerk users...");
|
||||
const clerk = clerkClient();
|
||||
const users = await clerk.users.getUserList({ limit: 500 });
|
||||
for (const user of users.data) {
|
||||
if (
|
||||
user.publicMetadata.role === "teacher" ||
|
||||
user.publicMetadata.role === "student" ||
|
||||
user.publicMetadata.role === "parent"
|
||||
) {
|
||||
await clerk.users.deleteUser(user.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanSupabase() {
|
||||
console.log("Cleaning up Supabase tables...");
|
||||
const tables = [
|
||||
"Result", "Assignment", "Exam", "Attendance", "Event", "Announcement",
|
||||
"Lesson", "TeacherSubject", "Student", "Teacher", "Parent", "Class", "Subject", "Grade"
|
||||
];
|
||||
for (const table of tables) {
|
||||
await supabase.from(table).delete().neq("id", "0" as any);
|
||||
}
|
||||
}
|
||||
|
||||
async function seedAdmin() {
|
||||
console.log("Syncing Admin...");
|
||||
const clerk = clerkClient();
|
||||
const users = await clerk.users.getUserList({ limit: 100 });
|
||||
const adminUser = users.data.find(u => u.username === "admin" || u.emailAddresses[0]?.emailAddress?.includes("admin"));
|
||||
|
||||
if (adminUser) {
|
||||
await supabase.from("Admin").upsert({ id: adminUser.id, username: adminUser.username || "admin" });
|
||||
console.log(`Synced Admin ID: ${adminUser.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const clerk = clerkClient();
|
||||
await cleanClerk();
|
||||
await cleanSupabase();
|
||||
await seedAdmin();
|
||||
|
||||
console.log("Seeding Grades and Subjects...");
|
||||
const grades = [1, 2, 3, 4, 5, 6].map((level) => ({ id: level, level }));
|
||||
await supabase.from("Grade").insert(grades);
|
||||
|
||||
const subjectsArray = [
|
||||
{ id: 1, name: "Mathematics" },
|
||||
{ id: 2, name: "Science" },
|
||||
{ id: 3, name: "English" },
|
||||
{ id: 4, name: "History" },
|
||||
{ id: 5, name: "Geography" },
|
||||
{ id: 6, name: "Physics" },
|
||||
{ id: 7, name: "Chemistry" },
|
||||
{ id: 8, name: "Biology" },
|
||||
{ id: 9, name: "Computer Science" },
|
||||
{ id: 10, name: "Art" },
|
||||
];
|
||||
await supabase.from("Subject").insert(subjectsArray);
|
||||
|
||||
console.log("Creating 15 Teachers...");
|
||||
const teacherMap: Record<number, string> = {};
|
||||
for (let i = 1; i <= 15; i++) {
|
||||
const user = await clerk.users.createUser({
|
||||
username: `teacher${i}`,
|
||||
password: PASSWORD,
|
||||
firstName: `TName${i}`,
|
||||
lastName: `TSurname${i}`,
|
||||
publicMetadata: { role: "teacher" }
|
||||
});
|
||||
teacherMap[i] = user.id;
|
||||
|
||||
await supabase.from("Teacher").insert({
|
||||
id: user.id,
|
||||
username: `teacher${i}`,
|
||||
name: `TName${i}`,
|
||||
surname: `TSurname${i}`,
|
||||
email: `teacher${i}@example.com`,
|
||||
phone: `123-456-789${i}`,
|
||||
address: `Address${i}`,
|
||||
bloodType: "A+",
|
||||
sex: i % 2 === 0 ? "MALE" : "FEMALE",
|
||||
birthday: "1996-02-27T00:26:35.280Z"
|
||||
});
|
||||
|
||||
await supabase.from("TeacherSubject").insert([
|
||||
{ subjectId: (i % 10) + 1, teacherId: user.id, isPrimary: true },
|
||||
{ subjectId: ((i + 1) % 10) + 1, teacherId: user.id }
|
||||
]);
|
||||
}
|
||||
|
||||
console.log("Creating 6 Classes...");
|
||||
const classesArray = [
|
||||
{ id: 1, name: "1A", gradeId: 1, capacity: 20, supervisorId: teacherMap[1] },
|
||||
{ id: 2, name: "2A", gradeId: 2, capacity: 20, supervisorId: teacherMap[2] },
|
||||
{ id: 3, name: "3A", gradeId: 3, capacity: 20, supervisorId: teacherMap[3] },
|
||||
{ id: 4, name: "4A", gradeId: 4, capacity: 20, supervisorId: teacherMap[4] },
|
||||
{ id: 5, name: "5A", gradeId: 5, capacity: 20, supervisorId: teacherMap[5] },
|
||||
{ id: 6, name: "6A", gradeId: 6, capacity: 20, supervisorId: teacherMap[1] },
|
||||
];
|
||||
await supabase.from("Class").insert(classesArray);
|
||||
|
||||
console.log("Creating 25 Parents...");
|
||||
const parentMap: Record<number, string> = {};
|
||||
for (let i = 1; i <= 25; i++) {
|
||||
const user = await clerk.users.createUser({
|
||||
username: `parent${i}`,
|
||||
password: PASSWORD,
|
||||
firstName: `PName${i}`,
|
||||
lastName: `PSurname${i}`,
|
||||
publicMetadata: { role: "parent" }
|
||||
});
|
||||
parentMap[i] = user.id;
|
||||
|
||||
await supabase.from("Parent").insert({
|
||||
id: user.id,
|
||||
username: `parent${i}`,
|
||||
name: `PName${i}`,
|
||||
surname: `PSurname${i}`,
|
||||
email: `parent${i}@example.com`,
|
||||
phone: `123-456-789${i}`,
|
||||
address: `Address${i}`
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Creating 50 Students...");
|
||||
const studentMap: Record<number, string> = {};
|
||||
for (let i = 1; i <= 50; i++) {
|
||||
const user = await clerk.users.createUser({
|
||||
username: `student${i}`,
|
||||
password: PASSWORD,
|
||||
firstName: `SName${i}`,
|
||||
lastName: `SSurname${i}`,
|
||||
publicMetadata: { role: "student" }
|
||||
});
|
||||
studentMap[i] = user.id;
|
||||
|
||||
const classInfo = classesArray[(i % 6)];
|
||||
await supabase.from("Student").insert({
|
||||
id: user.id,
|
||||
username: `student${i}`,
|
||||
name: `SName${i}`,
|
||||
surname: `SSurname${i}`,
|
||||
email: `student${i}@example.com`,
|
||||
phone: `987-654-321${i}`,
|
||||
address: `Address${i}`,
|
||||
bloodType: "O-",
|
||||
sex: i % 2 === 0 ? "MALE" : "FEMALE",
|
||||
parentId: parentMap[(i % 25) + 1],
|
||||
gradeId: classInfo.gradeId,
|
||||
classId: classInfo.id,
|
||||
birthday: "2016-02-27T00:26:35.281Z"
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Exporting User IDs to seed-data.json...");
|
||||
const seedDataPath = path.join(process.cwd(), "scripts", "seed-data.json");
|
||||
const seedData = {
|
||||
teacherMap,
|
||||
parentMap,
|
||||
studentMap,
|
||||
classes: classesArray
|
||||
};
|
||||
fs.writeFileSync(seedDataPath, JSON.stringify(seedData, null, 2));
|
||||
|
||||
console.log("User generation complete! Saved to seed-data.json.");
|
||||
|
||||
/*
|
||||
const daysOfWeek: ("MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY")[] = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"];
|
||||
for (let i = 1; i <= 30; i++) {
|
||||
const classIndex = i % 6;
|
||||
const classInfo = classesArray[classIndex];
|
||||
|
||||
const teacherIndex = (i % 15) + 1;
|
||||
const teacherId = teacherMap[teacherIndex];
|
||||
const subjectId = (teacherIndex % 10) + 1;
|
||||
|
||||
// Distribute across 5 days (Monday to Friday)
|
||||
const dayIndex = i % 5;
|
||||
const dayName = daysOfWeek[dayIndex];
|
||||
|
||||
// Distribute across 6 periods (e.g., 8:00 AM to 2:00 PM)
|
||||
const periodIndex = (i % 6);
|
||||
|
||||
// Base date (a Monday): 2026-02-23T00:00:00.000Z
|
||||
const lessonDate = new Date("2026-02-23T00:00:00.000Z");
|
||||
lessonDate.setDate(lessonDate.getDate() + dayIndex);
|
||||
|
||||
// Create start time and end time (1 hour lesson)
|
||||
const startHour = 8 + periodIndex;
|
||||
const startTime = new Date(lessonDate);
|
||||
startTime.setUTCHours(startHour, 0, 0, 0);
|
||||
|
||||
const endTime = new Date(lessonDate);
|
||||
endTime.setUTCHours(startHour + 1, 0, 0, 0);
|
||||
|
||||
await supabase.from("Lesson").insert({
|
||||
id: i,
|
||||
name: `Lesson${i}`,
|
||||
day: dayName,
|
||||
startTime: startTime.toISOString(),
|
||||
endTime: endTime.toISOString(),
|
||||
subjectId: subjectId,
|
||||
classId: classInfo.id,
|
||||
teacherId: teacherId
|
||||
});
|
||||
|
||||
await supabase.from("Exam").insert({
|
||||
id: i,
|
||||
title: `Exam ${i}`,
|
||||
startTime: startTime.toISOString(),
|
||||
endTime: endTime.toISOString(),
|
||||
lessonId: i
|
||||
});
|
||||
|
||||
await supabase.from("Assignment").insert({
|
||||
id: i,
|
||||
title: `Assignment ${i}`,
|
||||
startDate: startTime.toISOString(),
|
||||
dueDate: new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(), // Due in 7 days
|
||||
lessonId: i
|
||||
});
|
||||
|
||||
// Result requires a student from the class 'classIndex'.
|
||||
// Student 'j' is in class 'j % 6'.
|
||||
const studentBase = classIndex === 0 ? 6 : classIndex;
|
||||
const studentIndex = studentBase + 6 * (i % 8); // Ensures variation 1-48
|
||||
|
||||
await supabase.from("Result").insert({
|
||||
id: i,
|
||||
score: 90 + (i % 10),
|
||||
studentId: studentMap[studentIndex],
|
||||
examId: i
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
} catch (err) {
|
||||
console.error("Seed error:", err);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,226 @@
|
||||
import "dotenv/config";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
"sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz",
|
||||
{ auth: { persistSession: false } }
|
||||
);
|
||||
|
||||
const SUBJECTS: Record<string, number> = {
|
||||
Math: 1,
|
||||
Science: 2,
|
||||
English: 3,
|
||||
History: 4,
|
||||
Art: 5,
|
||||
Music: 6,
|
||||
PE: 7,
|
||||
Computer: 8,
|
||||
Geography: 9,
|
||||
Biology: 10
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// CONFIGURATION: Adjust the timeline spread and generation odds
|
||||
// -------------------------------------------------------------
|
||||
const CONFIG = {
|
||||
monthsPast: 3, // How many months backward to generate lessons
|
||||
monthsFuture: 9, // How many months forward to generate lessons
|
||||
baseDate: new Date("2026-02-23T00:00:00.000Z"), // "Present" date
|
||||
examProbability: 0.05, // 5% chance of an Exam per lesson
|
||||
assignmentProbability: 0.1, // 10% chance of an Assignment per lesson
|
||||
attendanceProbability: 0.95, // 95% attendance rate for past lessons
|
||||
};
|
||||
|
||||
// Helper to chunk large arrays for Supabase batch inserts
|
||||
function chunkArray<T>(array: T[], size: number): T[][] {
|
||||
const chunks = [];
|
||||
for (let i = 0; i < array.length; i += size) {
|
||||
chunks.push(array.slice(i, i + size));
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
async function insertInChunks(table: string, data: any[]) {
|
||||
if (data.length === 0) return;
|
||||
console.log(`Inserting ${data.length} records into ${table}...`);
|
||||
const chunks = chunkArray(data, 1000);
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
const chunk = chunks[i];
|
||||
const { error } = await supabase.from(table).insert(chunk);
|
||||
if (error) {
|
||||
console.error(`Error inserting into ${table} (chunk ${i}):`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log("Loading user IDs from seed-data.json...");
|
||||
const seedDataPath = path.join(process.cwd(), "scripts", "seed-data.json");
|
||||
if (!fs.existsSync(seedDataPath)) {
|
||||
throw new Error("seed-data.json not found! Please run `npm run seed:users` first.");
|
||||
}
|
||||
const data = JSON.parse(fs.readFileSync(seedDataPath, "utf-8"));
|
||||
const { teacherMap, studentMap, classes } = data;
|
||||
|
||||
console.log("Cleaning old Schedule & Attendance data...");
|
||||
const tablesToClean = ["Attendance", "Result", "Assignment", "Exam", "Lesson"];
|
||||
for (const table of tablesToClean) {
|
||||
await supabase.from(table).delete().neq("id", "0" as any);
|
||||
}
|
||||
|
||||
console.log(`Building full year timetable...`);
|
||||
console.log(`- Past months: ${CONFIG.monthsPast}`);
|
||||
console.log(`- Future months: ${CONFIG.monthsFuture}`);
|
||||
|
||||
const days = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"];
|
||||
const periods = [8, 9, 10, 11, 13, 14]; // Expanded periods (8 AM - 2 PM, skipping 12 PM lunch)
|
||||
|
||||
let lessonIdCounter = 1;
|
||||
let examIdCounter = 1;
|
||||
let assignmentIdCounter = 1;
|
||||
let resultIdCounter = 1;
|
||||
let attendanceIdCounter = 1;
|
||||
|
||||
const lessonsData = [];
|
||||
const examsData = [];
|
||||
const assignmentsData = [];
|
||||
const resultsData = [];
|
||||
const attendancesData = [];
|
||||
|
||||
// Compute start of generation (aligned to a Monday)
|
||||
const startDate = new Date(CONFIG.baseDate);
|
||||
startDate.setMonth(startDate.getMonth() - CONFIG.monthsPast);
|
||||
const startDayOfWeek = startDate.getDay();
|
||||
const daysToMonday = startDayOfWeek === 0 ? -6 : 1 - startDayOfWeek;
|
||||
startDate.setDate(startDate.getDate() + daysToMonday);
|
||||
|
||||
// Compute end of generation
|
||||
const endDate = new Date(CONFIG.baseDate);
|
||||
endDate.setMonth(endDate.getMonth() + CONFIG.monthsFuture);
|
||||
|
||||
let currentWeekStart = new Date(startDate);
|
||||
|
||||
while (currentWeekStart < endDate) {
|
||||
for (let classIndex = 0; classIndex < classes.length; classIndex++) {
|
||||
const classInfo = classes[classIndex];
|
||||
|
||||
// Gather students belonging to this class based on seed logic
|
||||
const studentList: string[] = [];
|
||||
for (let i = 1; i <= 50; i++) {
|
||||
const studentBase = classIndex === 0 ? 6 : classIndex;
|
||||
const studentIdx = studentBase + 6 * (i % 8);
|
||||
if (studentMap[studentIdx] && !studentList.includes(studentMap[studentIdx])) {
|
||||
studentList.push(studentMap[studentIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
for (let dayOffset = 0; dayOffset < days.length; dayOffset++) {
|
||||
const dayName = days[dayOffset];
|
||||
const currentDate = new Date(currentWeekStart);
|
||||
currentDate.setDate(currentDate.getDate() + dayOffset);
|
||||
|
||||
for (let period = 0; period < periods.length; period++) {
|
||||
const startHour = periods[period];
|
||||
|
||||
const subjectIdx = (classIndex + dayOffset + period) % 10;
|
||||
const subjectKey = Object.keys(SUBJECTS)[subjectIdx];
|
||||
const subjectId = SUBJECTS[subjectKey];
|
||||
const teacherId = teacherMap[subjectId]; // Authorized teacher
|
||||
|
||||
const startTime = new Date(currentDate);
|
||||
startTime.setUTCHours(startHour, 0, 0, 0);
|
||||
|
||||
const endTime = new Date(currentDate);
|
||||
endTime.setUTCHours(startHour + 1, 0, 0, 0);
|
||||
|
||||
// 1. Insert Lesson
|
||||
lessonsData.push({
|
||||
id: lessonIdCounter,
|
||||
name: `${classInfo.name} ${subjectKey} (${dayName})`,
|
||||
day: dayName,
|
||||
startTime: startTime.toISOString(),
|
||||
endTime: endTime.toISOString(),
|
||||
subjectId: subjectId,
|
||||
classId: classInfo.id,
|
||||
teacherId: teacherId
|
||||
});
|
||||
|
||||
// 2. Insert Exam / Results (Random Probability)
|
||||
if (Math.random() < CONFIG.examProbability) {
|
||||
examsData.push({
|
||||
id: examIdCounter,
|
||||
title: `${subjectKey} Assessment`,
|
||||
startTime: startTime.toISOString(),
|
||||
endTime: endTime.toISOString(),
|
||||
lessonId: lessonIdCounter
|
||||
});
|
||||
|
||||
// Only give results to a subset to prevent table explosions
|
||||
for (const sId of studentList.slice(0, 4)) {
|
||||
resultsData.push({
|
||||
id: resultIdCounter++,
|
||||
score: 60 + Math.floor(Math.random() * 41), // 60-100
|
||||
studentId: sId,
|
||||
examId: examIdCounter
|
||||
});
|
||||
}
|
||||
examIdCounter++;
|
||||
}
|
||||
|
||||
// 3. Insert Assignment
|
||||
if (Math.random() < CONFIG.assignmentProbability) {
|
||||
assignmentsData.push({
|
||||
id: assignmentIdCounter++,
|
||||
title: `${subjectKey} Practice`,
|
||||
startDate: startTime.toISOString(),
|
||||
dueDate: new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
lessonId: lessonIdCounter
|
||||
});
|
||||
}
|
||||
|
||||
// 4. Insert Attendance (ONLY for dates occurring in the past)
|
||||
if (startTime < CONFIG.baseDate) {
|
||||
for (const sId of studentList) {
|
||||
attendancesData.push({
|
||||
id: attendanceIdCounter++,
|
||||
date: startTime.toISOString(),
|
||||
present: Math.random() < CONFIG.attendanceProbability,
|
||||
studentId: sId,
|
||||
lessonId: lessonIdCounter
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
lessonIdCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Advance to the next week safely
|
||||
currentWeekStart.setDate(currentWeekStart.getDate() + 7);
|
||||
}
|
||||
|
||||
// Send payload in bulk batches to Supabase to prevent network/memory bottlenecks
|
||||
await insertInChunks("Lesson", lessonsData);
|
||||
await insertInChunks("Exam", examsData);
|
||||
await insertInChunks("Assignment", assignmentsData);
|
||||
await insertInChunks("Result", resultsData);
|
||||
await insertInChunks("Attendance", attendancesData);
|
||||
|
||||
console.log(`\n✅ Timeline successfully generated!`);
|
||||
console.log(`- Lessons: ${lessonsData.length}`);
|
||||
console.log(`- Exams: ${examsData.length}`);
|
||||
console.log(`- Assignments: ${assignmentsData.length}`);
|
||||
console.log(`- Results: ${resultsData.length}`);
|
||||
console.log(`- Attendance Records: ${attendancesData.length}`);
|
||||
|
||||
} catch (err) {
|
||||
console.error("Schedule Seeding Failed:", err);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,17 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config({ path: ".env" });
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
"sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz",
|
||||
{ auth: { persistSession: false } }
|
||||
);
|
||||
|
||||
async function test() {
|
||||
const { data, error } = await supabase.from("Admin").select("*");
|
||||
console.log("Admins:", data);
|
||||
console.log("Error:", error);
|
||||
}
|
||||
|
||||
test();
|
||||
Reference in New Issue
Block a user