forked from lunanting/cangku
196 lines
5.3 KiB
JavaScript
196 lines
5.3 KiB
JavaScript
const bcrypt = require('bcryptjs');
|
|
const database = require('../config/database');
|
|
const { getRedisConfig } = require('./redisConfig');
|
|
|
|
const DEFAULT_ADMIN_PASSWORD = 'admin123';
|
|
const SETUP_COMPLETED_KEY = 'setup_completed';
|
|
const SETUP_COMPLETED_AT_KEY = 'setup_completed_at';
|
|
|
|
function normalizeBoolean(value) {
|
|
return value === true || value === 1 || value === '1' || value === 'true';
|
|
}
|
|
|
|
async function getSystemConfigMap(keys) {
|
|
const rows = await database.local.query(
|
|
`SELECT config_key, config_value
|
|
FROM system_config
|
|
WHERE config_key IN (${keys.map(() => '?').join(', ')})`,
|
|
keys
|
|
);
|
|
|
|
return rows.reduce((acc, row) => {
|
|
acc[row.config_key] = row.config_value;
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
async function upsertSystemConfig(key, value, type = 'string') {
|
|
const existing = await database.local.query(
|
|
'SELECT id FROM system_config WHERE config_key = ? LIMIT 1',
|
|
[key]
|
|
);
|
|
|
|
if (existing.length > 0) {
|
|
await database.local.query(
|
|
'UPDATE system_config SET config_value = ?, config_type = ? WHERE config_key = ?',
|
|
[value, type, key]
|
|
);
|
|
return;
|
|
}
|
|
|
|
await database.local.insert('system_config', {
|
|
config_key: key,
|
|
config_value: value,
|
|
config_type: type,
|
|
});
|
|
}
|
|
|
|
async function isBusinessDatabaseConfigured() {
|
|
const rows = await database.local.query(
|
|
`SELECT host, database_name, username, status
|
|
FROM database_configs
|
|
WHERE is_default = 1
|
|
ORDER BY id ASC
|
|
LIMIT 1`
|
|
);
|
|
|
|
const row = rows[0];
|
|
return Boolean(
|
|
row &&
|
|
row.status === 'active' &&
|
|
row.host &&
|
|
row.database_name &&
|
|
row.username
|
|
);
|
|
}
|
|
|
|
async function isAuthConfigured() {
|
|
const rows = await database.local.query(
|
|
`SELECT auth_base_url, dingtalk_enabled, dingtalk_app_key, dingtalk_app_secret,
|
|
google_enabled, google_client_id, google_client_secret
|
|
FROM auth_configs
|
|
ORDER BY id ASC
|
|
LIMIT 1`
|
|
);
|
|
|
|
const row = rows[0];
|
|
if (!row) {
|
|
return false;
|
|
}
|
|
|
|
const dingtalkReady = normalizeBoolean(row.dingtalk_enabled) && Boolean(row.dingtalk_app_key && row.dingtalk_app_secret);
|
|
const googleReady = normalizeBoolean(row.google_enabled) && Boolean(row.google_client_id && row.google_client_secret);
|
|
|
|
return Boolean((row.auth_base_url || '').trim() || dingtalkReady || googleReady);
|
|
}
|
|
|
|
async function isS3Configured() {
|
|
const rows = await database.local.query(
|
|
`SELECT bucket, access_key_id, secret_access_key
|
|
FROM s3_configs
|
|
WHERE is_default = 1
|
|
ORDER BY id ASC
|
|
LIMIT 1`
|
|
);
|
|
|
|
const row = rows[0];
|
|
return Boolean(row && row.bucket && row.access_key_id && row.secret_access_key);
|
|
}
|
|
|
|
async function getCurrentAdminUser(userId) {
|
|
const rows = await database.local.query(
|
|
`SELECT id, username, name, email, role, status, password_hash
|
|
FROM users
|
|
WHERE id = ?
|
|
LIMIT 1`,
|
|
[userId]
|
|
);
|
|
|
|
return rows[0] || null;
|
|
}
|
|
|
|
async function isUsingDefaultPassword(user) {
|
|
if (!user || !user.password_hash) {
|
|
return false;
|
|
}
|
|
|
|
return bcrypt.compare(DEFAULT_ADMIN_PASSWORD, user.password_hash);
|
|
}
|
|
|
|
async function ensureSetupConfigDefaults() {
|
|
const configMap = await getSystemConfigMap([SETUP_COMPLETED_KEY, SETUP_COMPLETED_AT_KEY]);
|
|
|
|
if (configMap[SETUP_COMPLETED_KEY] === undefined) {
|
|
const inferredCompleted = await isBusinessDatabaseConfigured();
|
|
await upsertSystemConfig(SETUP_COMPLETED_KEY, inferredCompleted ? 'true' : 'false', 'boolean');
|
|
}
|
|
|
|
if (configMap[SETUP_COMPLETED_AT_KEY] === undefined) {
|
|
await upsertSystemConfig(SETUP_COMPLETED_AT_KEY, '', 'string');
|
|
}
|
|
}
|
|
|
|
async function getSetupStatus(userId) {
|
|
await ensureSetupConfigDefaults();
|
|
|
|
const [configMap, currentUser, businessDatabaseConfigured, authConfigured, s3Configured] = await Promise.all([
|
|
getSystemConfigMap([SETUP_COMPLETED_KEY, SETUP_COMPLETED_AT_KEY]),
|
|
getCurrentAdminUser(userId),
|
|
isBusinessDatabaseConfigured(),
|
|
isAuthConfigured(),
|
|
isS3Configured(),
|
|
]);
|
|
const redisConfigured = (await getRedisConfig()).enabled;
|
|
|
|
const currentUserUsesDefaultPassword = await isUsingDefaultPassword(currentUser);
|
|
const completed = normalizeBoolean(configMap[SETUP_COMPLETED_KEY]);
|
|
|
|
return {
|
|
completed,
|
|
shouldShowWizard: !completed,
|
|
completedAt: configMap[SETUP_COMPLETED_AT_KEY] || '',
|
|
currentUser: currentUser
|
|
? {
|
|
id: currentUser.id,
|
|
username: currentUser.username,
|
|
name: currentUser.name,
|
|
email: currentUser.email,
|
|
role: currentUser.role,
|
|
status: currentUser.status,
|
|
}
|
|
: null,
|
|
currentUserUsesDefaultPassword,
|
|
steps: {
|
|
changeAdminPassword: !currentUserUsesDefaultPassword,
|
|
businessDatabase: businessDatabaseConfigured,
|
|
redisCache: redisConfigured,
|
|
authConfig: authConfigured,
|
|
objectStorage: s3Configured,
|
|
},
|
|
};
|
|
}
|
|
|
|
async function markSetupCompleted(userId) {
|
|
const status = await getSetupStatus(userId);
|
|
|
|
if (!status.steps.businessDatabase) {
|
|
throw new Error('请先完成业务数据库配置');
|
|
}
|
|
|
|
if (status.currentUserUsesDefaultPassword) {
|
|
throw new Error('请先修改默认管理员密码');
|
|
}
|
|
|
|
await upsertSystemConfig(SETUP_COMPLETED_KEY, 'true', 'boolean');
|
|
await upsertSystemConfig(SETUP_COMPLETED_AT_KEY, new Date().toISOString(), 'string');
|
|
|
|
return getSetupStatus(userId);
|
|
}
|
|
|
|
module.exports = {
|
|
DEFAULT_ADMIN_PASSWORD,
|
|
ensureSetupConfigDefaults,
|
|
getSetupStatus,
|
|
markSetupCompleted,
|
|
};
|