fix: lazy DATA_DIR in sync db (multi-instance safe), demo never admin, first real user auto-promoted

This commit is contained in:
root
2026-10-17 14:59:23 +08:00
parent e5269a23ac
commit 216d18c843
4 changed files with 57 additions and 34 deletions
+5 -3
View File
@@ -11,10 +11,12 @@ export function register({ username, password, device_name, invite_code, seed })
if (cnt >= maxUsers) throw new Error('注册名额已满,请联系管理员');
}
const userCount = d.prepare('SELECT COUNT(*) AS c FROM users').get().c;
const hasAdmin = d.prepare('SELECT COUNT(*) AS c FROM users WHERE is_admin=1').get().c;
let isAdmin = 0;
if (userCount === 0) {
isAdmin = 1; // 首位注册者自动成为管理员
} else if (seed) {
if (username !== 'demo' && hasAdmin === 0) {
isAdmin = 1; // 首个真实用户自动成为管理员(demo 只是演示账号,不占管理员席位)
}
if (seed) {
// 内置演示账号播种:不要求邀请码
} else {
const code = String(invite_code || '').trim().toUpperCase();
+13 -6
View File
@@ -3,15 +3,22 @@ import { DatabaseSync } from 'node:sqlite';
import fs from 'node:fs';
import path from 'node:path';
export const DATA_DIR = process.env.DATA_DIR || path.join(process.cwd(), 'data');
export const BLOB_DIR = path.join(DATA_DIR, 'blobs');
const DB_PATH = path.join(DATA_DIR, 'sync.db');
export function blobDirNow() { return path.join(dataDirNow(), 'blobs'); }
export let BLOB_DIR = path.join(dataDirNow(), 'blobs');
export function dataDirNow() {
return process.env.DATA_DIR || path.join(process.cwd(), 'data');
}
let db = null;
export function getDb() {
if (db) return db;
fs.mkdirSync(BLOB_DIR, { recursive: true });
const DATA_DIR = dataDirNow();
const blobDir = path.join(DATA_DIR, 'blobs');
const DB_PATH = path.join(DATA_DIR, 'sync.db');
if (db && getDb._dir === DATA_DIR) return db;
if (db) { try { db.close(); } catch {} }
getDb._dir = DATA_DIR;
BLOB_DIR = blobDir;
fs.mkdirSync(blobDir, { recursive: true });
db = new DatabaseSync(DB_PATH);
db.exec('PRAGMA journal_mode = WAL;');
db.exec('PRAGMA foreign_keys = ON;');
+3
View File
@@ -233,6 +233,7 @@ const server = http.createServer(async (req, res) => {
if (existing && existing.id !== auth.user_id) await deleteUserCascade(db, existing);
const { register } = await import('./auth.mjs');
const uid = register({ username: 'demo', password: 'demo1234', device_name: 'seed-demo', seed: true }).user_id;
db.prepare('UPDATE users SET is_admin=0 WHERE username=?').run('demo');
const seeded = commandsFor(uid).handleCommand('demo_seed', {});
console.log('[footprints-sync] demo 账号已重建:', JSON.stringify(seeded));
return send(200, true, { ok: true, seeded });
@@ -568,6 +569,8 @@ try {
} else {
console.log('[footprints-sync] demo 账号已存在 (demo / demo1234)');
}
// demo 永远不是管理员(历史库也一并纠正)
d.prepare('UPDATE users SET is_admin=0 WHERE username=?').run('demo');
const seeded = commandsFor(demoId).handleCommand('demo_seed', {});
console.log('[footprints-sync] demo 演示数据:', JSON.stringify(seeded));
} catch (e) { console.log('[footprints-sync] demo 种子跳过:', e.message); }