Add candidate account archiving and password reset

This commit is contained in:
2026-07-20 16:30:06 +08:00 Unverified
parent 9f850fa045
commit 7023493f08
12 changed files with 207 additions and 41 deletions
+22 -10
View File
@@ -57,7 +57,7 @@ function buildSeedOperations(state) {
const nullable = value => value == null || value === '' ? null : value;
add(
'UPDATE schema_metadata SET schema_version = 12, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
'UPDATE schema_metadata SET schema_version = 13, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
Number(state.meta?.version || 1), state.settings?.selfRegistrationEnabled ? 1 : 0,
state.meta?.createdAt || new Date().toISOString()
);
@@ -84,10 +84,11 @@ function buildSeedOperations(state) {
add(
`INSERT INTO users (
id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active,
must_change_password, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
must_change_password, archived_at, archived_by, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
user.id, user.username, nullable(user.candidateNumber), user.passwordHash, user.role, nullable(user.adminLevel), nullable(user.schoolId),
nullable(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, user.displayName, user.createdAt
nullable(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, nullable(user.archivedAt),
nullable(user.archivedBy), user.displayName, user.createdAt
);
}
@@ -466,6 +467,8 @@ function stateFromRows(rows) {
classId: row.class_id || null,
active: row.active == null ? true : Boolean(row.active),
mustChangePassword: Boolean(row.must_change_password),
archivedAt: row.archived_at || null,
archivedBy: row.archived_by || null,
displayName: row.display_name,
createdAt: row.created_at
})),
@@ -854,10 +857,11 @@ function createRepository({ client, location, read, transaction, close }) {
operation(
`INSERT INTO users (
id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active,
must_change_password, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
must_change_password, archived_at, archived_by, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
user.id, user.username, optional(user.candidateNumber), user.passwordHash, user.role, optional(user.adminLevel), optional(user.schoolId),
optional(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, user.displayName, user.createdAt
optional(user.classId), user.active === false ? 0 : 1, user.mustChangePassword ? 1 : 0, optional(user.archivedAt),
optional(user.archivedBy), user.displayName, user.createdAt
),
operation(
`INSERT INTO candidate_profiles (
@@ -933,6 +937,14 @@ function createRepository({ client, location, read, transaction, close }) {
if (log) operations.push(auditOperation(log));
await transaction(operations);
},
async updateCandidateArchives(users, log) {
const operations = users.map(user => operation(
'UPDATE users SET archived_at = ?, archived_by = ? WHERE id = ?',
optional(user.archivedAt), optional(user.archivedBy), user.id
));
operations.push(auditOperation(log));
await transaction(operations);
},
async updateRegistrationSetting(enabled, log) {
await transaction([
operation('UPDATE schema_metadata SET self_registration_enabled = ? WHERE id = 1', enabled ? 1 : 0),
@@ -1045,10 +1057,10 @@ function createRepository({ client, location, read, transaction, close }) {
operation(
`INSERT INTO users (
id, username, candidate_number, password_hash, role, admin_level, school_id, class_id, active,
must_change_password, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
must_change_password, archived_at, archived_by, display_name, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
user.id, user.username, user.candidateNumber, user.passwordHash, user.role, optional(user.adminLevel),
user.schoolId, user.classId, 1, 1, user.displayName, user.createdAt
user.schoolId, user.classId, 1, 1, null, null, user.displayName, user.createdAt
),
operation(
`INSERT INTO candidate_profiles (