修复
This commit is contained in:
@@ -4,6 +4,7 @@ import { rm } from 'node:fs/promises';
|
||||
import { isAbsolute, join, relative, resolve } from 'node:path';
|
||||
import { loadEnvFile } from 'node:process';
|
||||
import { buildSeedOperations, createDatabase, relationalTables } from '../database.mjs';
|
||||
import { createBaseDatabase } from '../src/data/base.mjs';
|
||||
import { createSeedDatabase } from '../src/data/seed.mjs';
|
||||
|
||||
const root = resolve(process.cwd());
|
||||
@@ -17,13 +18,24 @@ const client = String(configuredClient || (process.env.NODE_ENV === 'production'
|
||||
if (!['sqlite', 'mysql'].includes(client)) throw new Error(`不支持的 DATABASE_CLIENT:${client}`);
|
||||
process.env.DATABASE_CLIENT = client;
|
||||
const force = options.has('--force');
|
||||
const initializeEmpty = options.has('--empty');
|
||||
|
||||
function hashPassword(password, salt = randomBytes(16).toString('hex')) {
|
||||
const hash = pbkdf2Sync(password, salt, 120000, 32, 'sha256').toString('hex');
|
||||
return `${salt}:${hash}`;
|
||||
}
|
||||
|
||||
const seed = () => createSeedDatabase({ nowIso: () => new Date().toISOString(), hashPassword });
|
||||
const createTargetState = () => initializeEmpty
|
||||
? createBaseDatabase({
|
||||
nowIso: () => new Date().toISOString(),
|
||||
hashPassword,
|
||||
initialAdmin: {
|
||||
username: process.env.INITIAL_ADMIN_USERNAME,
|
||||
password: process.env.INITIAL_ADMIN_PASSWORD,
|
||||
displayName: process.env.INITIAL_ADMIN_DISPLAY_NAME
|
||||
}
|
||||
})
|
||||
: createSeedDatabase({ nowIso: () => new Date().toISOString(), hashPassword });
|
||||
|
||||
async function prepareSqlite() {
|
||||
const databasePath = resolve(process.env.SQLITE_PATH || join(root, 'data', 'exam.sqlite'));
|
||||
@@ -100,19 +112,28 @@ async function prepareMysql() {
|
||||
}
|
||||
const [[userRow]] = await connection.query('SELECT COUNT(*) AS count FROM users');
|
||||
if (Number(userRow.count) > 1) nonEmpty.push(`users=${userRow.count}`);
|
||||
if (nonEmpty.length && !force) {
|
||||
let recognizedTestData = false;
|
||||
if (initializeEmpty && nonEmpty.length) {
|
||||
const [[bulkUsers]] = await connection.query("SELECT COUNT(*) AS count FROM users WHERE id LIKE 'usr_bulk_%'");
|
||||
const [[testSchools]] = await connection.query("SELECT COUNT(*) AS count FROM schools WHERE id IN ('school_hz1', 'school_hz3', 'school_hz5', 'school_hz7')");
|
||||
recognizedTestData = Number(bulkUsers.count) >= 300 && Number(testSchools.count) === 4;
|
||||
}
|
||||
if (nonEmpty.length && !force && !recognizedTestData) {
|
||||
const forceCommand = initializeEmpty
|
||||
? 'npm run initialize-system:mysql -- --force'
|
||||
: 'npm run seed-test-data:mysql -- --force';
|
||||
throw new Error(
|
||||
`MySQL 数据库 ${databaseName} 已有业务数据(${nonEmpty.slice(0, 8).join(', ')}${nonEmpty.length > 8 ? ', ...' : ''})。` +
|
||||
'如确认这是可覆盖的测试库,请运行 npm run seed-test-data:mysql -- --force'
|
||||
`如确认这是可覆盖的测试库,请运行 ${forceCommand}`
|
||||
);
|
||||
}
|
||||
if (nonEmpty.length) {
|
||||
console.warn(`[force] Replacing existing business data in MySQL database ${databaseName}`);
|
||||
console.warn(`[${recognizedTestData ? 'test-data cleanup' : 'force'}] Replacing existing business data in MySQL database ${databaseName}`);
|
||||
} else {
|
||||
console.log(`Preparing empty MySQL database ${databaseName} for test data`);
|
||||
console.log(`Preparing empty MySQL database ${databaseName} for ${initializeEmpty ? 'system initialization' : 'test data'}`);
|
||||
}
|
||||
|
||||
const state = seed();
|
||||
const state = createTargetState();
|
||||
await connection.query('SET FOREIGN_KEY_CHECKS = 0');
|
||||
await connection.beginTransaction();
|
||||
try {
|
||||
@@ -145,7 +166,7 @@ if (client === 'sqlite') {
|
||||
}
|
||||
const database = await createDatabase({
|
||||
root,
|
||||
seed
|
||||
seed: createTargetState
|
||||
});
|
||||
const state = await database.read();
|
||||
await database.close();
|
||||
@@ -154,7 +175,13 @@ const pending = state.registrations.filter(item => item.status === 'pending').le
|
||||
const rejected = state.registrations.filter(item => item.status === 'rejected').length;
|
||||
const unpaid = state.registrations.filter(item => item.status === 'approved' && item.paymentStatus === 'unpaid').length;
|
||||
const paid = state.registrations.filter(item => item.status === 'approved' && item.paymentStatus === 'paid').length;
|
||||
console.log(`Imported test data into ${location}${mysqlAlreadyImported ? ' (transactional replace)' : ''}`);
|
||||
console.log(`${state.schools.length} schools, ${state.candidateProfiles.length} candidates, ${state.registrations.length} registrations`);
|
||||
console.log(`pending ${pending}, rejected ${rejected}, approved/unpaid ${unpaid}, approved/paid ${paid}`);
|
||||
console.log(`arrangement plans ${state.arrangementPlans.length}, admit cards ${state.registrations.filter(item => item.admitCard).length}`);
|
||||
if (initializeEmpty) {
|
||||
console.log(`Initialized empty system in ${location}${mysqlAlreadyImported ? ' (transactional replace)' : ''}`);
|
||||
console.log(`${state.users.length} initial administrator, ${state.schools.length} schools, ${state.candidateProfiles.length} candidates, ${state.registrations.length} registrations`);
|
||||
} else {
|
||||
console.log(`Imported test data into ${location}${mysqlAlreadyImported ? ' (transactional replace)' : ''}`);
|
||||
console.log(`${state.schools.length} schools, ${state.candidateProfiles.length} candidates, ${state.registrations.length} registrations`);
|
||||
console.log(`pending ${pending}, rejected ${rejected}, approved/unpaid ${unpaid}, approved/paid ${paid}`);
|
||||
console.log(`arrangement plans ${state.arrangementPlans.length}, admit cards ${state.registrations.filter(item => item.admitCard).length}`);
|
||||
console.log('all predefined test account passwords: 12345678');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user