teacher-tools/api/source/sample_data.d

146 lines
4.3 KiB
D
Raw Normal View History

module sample_data;
2025-01-23 17:10:32 +00:00
import ddbc;
import db;
import data_utils;
import std.random;
import std.algorithm;
import std.array;
import std.datetime;
private const STUDENT_NAMES = [
"Andrew",
"Richard",
"Klaus",
"John",
"Wilson",
"Grace",
"Sarah",
"Rebecca",
"Lily",
"Thomas",
"Michael",
"Jennifer",
"Robert",
"Christopher",
"Margaret",
"Mordecai",
"Rigby",
"Walter",
"Roy",
"Cindy"
];
2025-01-23 17:10:32 +00:00
void insertSampleData() {
Connection conn = getDb();
conn.setAutoCommit(false);
scope(exit) {
conn.commit();
conn.close();
}
addUser(conn, "sample-user-A", "test", false, false);
addUser(conn, "sample-user-B", "test", true, false);
addUser(conn, "sample-user-C", "test", false, false);
addUser(conn, "sample-user-D", "test", false, false);
2025-01-22 17:55:14 +00:00
2025-01-23 17:10:32 +00:00
ulong adminUserId = addUser(conn, "test", "test", false, true);
ulong normalUserId = addUser(conn, "test2", "test", false, false);
Random rand = Random(0);
const SysTime now = Clock.currTime();
const Date today = Date(now.year, now.month, now.day);
for (ushort i = 1; i <= 6; i++) {
2025-01-23 17:10:32 +00:00
ulong classId = addClass(conn, "2024-2025", i, adminUserId);
bool classHasAssignedDesks = uniform01(rand) < 0.5;
size_t count = uniform(10, STUDENT_NAMES.length, rand);
auto studentsToAdd = randomSample(STUDENT_NAMES, count, rand);
ushort deskNumber = 1;
foreach (name; studentsToAdd) {
bool removed = uniform01(rand) < 0.1;
ushort assignedDeskNumber = 0;
if (classHasAssignedDesks) {
assignedDeskNumber = deskNumber++;
}
2025-01-23 17:10:32 +00:00
ulong studentId = addStudent(conn, name, classId, assignedDeskNumber, removed);
// Add entries for the last N days
for (int n = 0; n < 30; n++) {
Date entryDate = today - days(n);
bool missingEntry = uniform01(rand) < 0.05;
if (missingEntry) continue;
bool absent = uniform01(rand) < 0.05;
bool phoneCompliant = uniform01(rand) < 0.85;
ubyte behaviorRating = 3;
if (uniform01(rand) < 0.25) {
behaviorRating = 2;
if (uniform01(rand) < 0.5) {
behaviorRating = 3;
}
}
2025-01-23 17:10:32 +00:00
addEntry(conn, classId, studentId, entryDate, absent, phoneCompliant, behaviorRating);
}
}
}
}
2025-01-23 17:10:32 +00:00
ulong addUser(Connection conn, string username, string password, bool locked, bool admin) {
import std.digest.sha;
string passwordHash = cast(string) sha256Of(password).toHexString().idup;
2025-01-23 17:10:32 +00:00
return insertOne(
conn,
"INSERT INTO auth_user (username, password_hash, is_locked, is_admin) VALUES (?, ?, ?, ?) RETURNING id",
username, passwordHash, locked, admin
);
}
2025-01-23 17:10:32 +00:00
ulong addClass(Connection conn, string schoolYear, ushort number, ulong userId) {
return insertOne(
conn,
"INSERT INTO classroom_compliance_class (number, school_year, user_id) VALUES (?, ?, ?) RETURNING id",
number, schoolYear, userId
);
}
2025-01-23 17:10:32 +00:00
ulong addStudent(Connection conn, string name, ulong classId, ushort deskNumber, bool removed) {
return insertOne(
conn,
"INSERT INTO classroom_compliance_student
(name, class_id, desk_number, removed)
VALUES (?, ?, ?, ?) RETURNING id",
name, classId, deskNumber, removed
);
}
void addEntry(
2025-01-23 17:10:32 +00:00
Connection conn,
ulong classId,
ulong studentId,
Date date,
bool absent,
bool phoneCompliant,
ubyte behaviorRating
) {
const entryQuery = "
INSERT INTO classroom_compliance_entry
2025-01-23 17:10:32 +00:00
(class_id, student_id, date, absent, comment, phone_compliant, behavior_rating)
VALUES (?, ?, ?, ?, ?, ?, ?)";
PreparedStatement ps = conn.prepareStatement(entryQuery);
scope(exit) ps.close();
ps.setUlong(1, classId);
ps.setUlong(2, studentId);
ps.setDate(3, date);
ps.setBoolean(4, absent);
ps.setString(5, "Testing comment");
if (absent) {
ps.setNull(6);
ps.setNull(7);
} else {
ps.setBoolean(6, phoneCompliant);
ps.setUint(7, behaviorRating);
}
ps.executeUpdate();
}