이메일 인증과 비밀번호 재설정 추가
This commit is contained in:
@@ -64,6 +64,20 @@ export function initDb(dbPath) {
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_deck_favorites_share_code ON deck_favorites(share_code);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS auth_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
expires_at TEXT NOT NULL,
|
||||
used_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_auth_tokens_user_type
|
||||
ON auth_tokens(user_id, type);
|
||||
`);
|
||||
|
||||
const deckCols = db.prepare('PRAGMA table_info(decks)').all();
|
||||
@@ -81,6 +95,32 @@ export function initDb(dbPath) {
|
||||
if (!userCols.some((c) => c.name === 'last_login_at')) {
|
||||
db.exec('ALTER TABLE users ADD COLUMN last_login_at TEXT');
|
||||
}
|
||||
if (!userCols.some((c) => c.name === 'email_verified_at')) {
|
||||
db.exec('ALTER TABLE users ADD COLUMN email_verified_at TEXT');
|
||||
db.exec(`
|
||||
UPDATE users
|
||||
SET email_verified_at = COALESCE(updated_at, created_at, datetime('now'))
|
||||
WHERE email_verified_at IS NULL
|
||||
`);
|
||||
}
|
||||
|
||||
const usernameCaseConflicts = db.prepare(`
|
||||
SELECT lower(username) AS normalized_username, COUNT(*) AS count
|
||||
FROM users
|
||||
GROUP BY lower(username)
|
||||
HAVING COUNT(*) > 1
|
||||
LIMIT 1
|
||||
`).get();
|
||||
if (!usernameCaseConflicts) {
|
||||
db.exec(`
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_username_nocase
|
||||
ON users(username COLLATE NOCASE)
|
||||
`);
|
||||
} else {
|
||||
console.warn(
|
||||
'대소문자만 다른 기존 사용자명이 있어 NOCASE 고유 인덱스를 만들지 못했습니다. 관리자 확인이 필요합니다.',
|
||||
);
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
@@ -103,7 +143,10 @@ export function seedAdmin(db) {
|
||||
const existingUser = db.prepare('SELECT id FROM users WHERE email = ?').get(email);
|
||||
if (existingUser) {
|
||||
db.prepare(`
|
||||
UPDATE users SET role = 'admin', updated_at = datetime('now')
|
||||
UPDATE users
|
||||
SET role = 'admin',
|
||||
email_verified_at = COALESCE(email_verified_at, datetime('now')),
|
||||
updated_at = datetime('now')
|
||||
WHERE id = ?
|
||||
`).run(existingUser.id);
|
||||
return;
|
||||
@@ -111,7 +154,9 @@ export function seedAdmin(db) {
|
||||
|
||||
const hash = bcrypt.hashSync(password, 12);
|
||||
db.prepare(`
|
||||
INSERT INTO users (email, username, password_hash, display_name, role)
|
||||
VALUES (?, ?, ?, ?, 'admin')
|
||||
INSERT INTO users (
|
||||
email, username, password_hash, display_name, role, email_verified_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, 'admin', datetime('now'))
|
||||
`).run(email, username, hash, '관리자');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user