获取用户站长无信息时返回默认值,修复与upstash合并时丢失的用户缓存信息
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
} from './types';
|
||||
import { AdminConfig } from './admin.types';
|
||||
import { DatabaseAdapter } from './d1-adapter';
|
||||
import { userInfoCache } from './user-cache';
|
||||
|
||||
/**
|
||||
* Cloudflare D1 存储实现
|
||||
@@ -178,6 +179,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET playrecord_migrated = 1 WHERE username = ?')
|
||||
.bind(userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.migratePlayRecords error:', err);
|
||||
}
|
||||
@@ -283,6 +287,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET favorite_migrated = 1 WHERE username = ?')
|
||||
.bind(userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.migrateFavorites error:', err);
|
||||
}
|
||||
@@ -533,6 +540,12 @@ export class D1Storage implements IStorage {
|
||||
|
||||
async getUserInfoV2(userName: string): Promise<any> {
|
||||
try {
|
||||
// 先从缓存获取
|
||||
const cached = userInfoCache?.get(userName);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 先尝试从数据库获取用户信息
|
||||
const user = await this.db
|
||||
.prepare('SELECT * FROM users WHERE username = ?')
|
||||
@@ -540,7 +553,7 @@ export class D1Storage implements IStorage {
|
||||
.first();
|
||||
|
||||
if (user) {
|
||||
return {
|
||||
const userInfo = {
|
||||
role: user.role as 'owner' | 'admin' | 'user',
|
||||
banned: user.banned === 1,
|
||||
tags: user.tags ? JSON.parse(user.tags as string) : undefined,
|
||||
@@ -554,18 +567,32 @@ export class D1Storage implements IStorage {
|
||||
email: user.email as string | undefined,
|
||||
emailNotifications: user.email_notifications === 1,
|
||||
};
|
||||
|
||||
// 如果是站长,强制将 role 设置为 owner
|
||||
if (userName === process.env.USERNAME) {
|
||||
userInfo.role = 'owner';
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
userInfoCache?.set(userName, userInfo);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
// 如果数据库中没有,检查是否是环境变量中的站长
|
||||
if (userName === process.env.USERNAME) {
|
||||
return {
|
||||
role: 'owner',
|
||||
// 站长即使数据库没有数据,也返回默认信息
|
||||
const ownerInfo = {
|
||||
role: 'owner' as const,
|
||||
banned: false,
|
||||
created_at: 0,
|
||||
playrecord_migrated: true,
|
||||
favorite_migrated: true,
|
||||
skip_migrated: true,
|
||||
playrecord_migrated: false,
|
||||
favorite_migrated: false,
|
||||
skip_migrated: false,
|
||||
};
|
||||
// 缓存站长信息
|
||||
userInfoCache?.set(userName, ownerInfo);
|
||||
return ownerInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -605,6 +632,9 @@ export class D1Storage implements IStorage {
|
||||
Date.now()
|
||||
)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.createUserV2 error:', err);
|
||||
throw err;
|
||||
@@ -774,6 +804,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare(`UPDATE users SET ${fields.join(', ')} WHERE username = ?`)
|
||||
.bind(...values)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.updateUserInfoV2 error:', err);
|
||||
throw err;
|
||||
@@ -788,6 +821,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET password_hash = ? WHERE username = ?')
|
||||
.bind(passwordHash, userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.changePasswordV2 error:', err);
|
||||
throw err;
|
||||
@@ -829,6 +865,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('DELETE FROM users WHERE username = ?')
|
||||
.bind(userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.deleteUserV2 error:', err);
|
||||
throw err;
|
||||
@@ -941,6 +980,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET email = ? WHERE username = ?')
|
||||
.bind(email, userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.setUserEmail error:', err);
|
||||
throw err;
|
||||
@@ -967,6 +1009,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET email_notifications = ? WHERE username = ?')
|
||||
.bind(enabled ? 1 : 0, userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.setEmailNotificationPreference error:', err);
|
||||
throw err;
|
||||
@@ -1136,6 +1181,9 @@ export class D1Storage implements IStorage {
|
||||
.prepare('UPDATE users SET skip_migrated = 1 WHERE username = ?')
|
||||
.bind(userName)
|
||||
.run();
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
} catch (err) {
|
||||
console.error('D1Storage.migrateSkipConfigs error:', err);
|
||||
}
|
||||
|
||||
@@ -703,6 +703,9 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
value: userName,
|
||||
}));
|
||||
|
||||
// 清除用户信息缓存
|
||||
userInfoCache?.delete(userName);
|
||||
|
||||
// 如果创建的是站长用户,清除站长存在状态缓存
|
||||
if (userName === process.env.USERNAME) {
|
||||
const { ownerExistenceCache } = await import('./user-cache');
|
||||
@@ -739,28 +742,59 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
email?: string;
|
||||
emailNotifications?: boolean;
|
||||
} | null> {
|
||||
const userInfo = await this.withRetry(() =>
|
||||
// 先从缓存获取
|
||||
const cached = userInfoCache?.get(userName);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const userInfoRaw = await this.withRetry(() =>
|
||||
this.adapter.hGetAll(this.userInfoKey(userName))
|
||||
);
|
||||
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
if (!userInfoRaw || Object.keys(userInfoRaw).length === 0) {
|
||||
// 如果数据库中没有,检查是否是环境变量中的站长
|
||||
if (userName === process.env.USERNAME) {
|
||||
// 站长即使数据库没有数据,也返回默认信息
|
||||
const ownerInfo = {
|
||||
role: 'owner' as const,
|
||||
banned: false,
|
||||
created_at: 0,
|
||||
playrecord_migrated: false,
|
||||
favorite_migrated: false,
|
||||
skip_migrated: false,
|
||||
};
|
||||
// 缓存站长信息
|
||||
userInfoCache?.set(userName, ownerInfo);
|
||||
return ownerInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
role: (userInfo.role as 'owner' | 'admin' | 'user') || 'user',
|
||||
banned: userInfo.banned === 'true',
|
||||
tags: userInfo.tags ? JSON.parse(userInfo.tags) : undefined,
|
||||
oidcSub: userInfo.oidcSub,
|
||||
enabledApis: userInfo.enabledApis ? JSON.parse(userInfo.enabledApis) : undefined,
|
||||
created_at: parseInt(userInfo.created_at || '0', 10),
|
||||
playrecord_migrated: userInfo.playrecord_migrated === 'true',
|
||||
favorite_migrated: userInfo.favorite_migrated === 'true',
|
||||
skip_migrated: userInfo.skip_migrated === 'true',
|
||||
last_movie_request_time: userInfo.last_movie_request_time ? parseInt(userInfo.last_movie_request_time, 10) : undefined,
|
||||
email: userInfo.email,
|
||||
emailNotifications: userInfo.emailNotifications === 'true',
|
||||
const userInfo = {
|
||||
role: (userInfoRaw.role as 'owner' | 'admin' | 'user') || 'user',
|
||||
banned: userInfoRaw.banned === 'true',
|
||||
tags: userInfoRaw.tags ? JSON.parse(userInfoRaw.tags) : undefined,
|
||||
oidcSub: userInfoRaw.oidcSub,
|
||||
enabledApis: userInfoRaw.enabledApis ? JSON.parse(userInfoRaw.enabledApis) : undefined,
|
||||
created_at: parseInt(userInfoRaw.created_at || '0', 10),
|
||||
playrecord_migrated: userInfoRaw.playrecord_migrated === 'true',
|
||||
favorite_migrated: userInfoRaw.favorite_migrated === 'true',
|
||||
skip_migrated: userInfoRaw.skip_migrated === 'true',
|
||||
last_movie_request_time: userInfoRaw.last_movie_request_time ? parseInt(userInfoRaw.last_movie_request_time, 10) : undefined,
|
||||
email: userInfoRaw.email,
|
||||
emailNotifications: userInfoRaw.emailNotifications === 'true',
|
||||
};
|
||||
|
||||
// 如果是站长,强制将 role 设置为 owner
|
||||
if (userName === process.env.USERNAME) {
|
||||
userInfo.role = 'owner';
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
userInfoCache?.set(userName, userInfo);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
// 更新用户信息(新版本)
|
||||
@@ -816,6 +850,9 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
if (Object.keys(userInfo).length > 0) {
|
||||
await this.withRetry(() => this.adapter.hSet(this.userInfoKey(userName), userInfo));
|
||||
}
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
}
|
||||
|
||||
// 修改用户密码(新版本)
|
||||
@@ -824,6 +861,9 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
await this.withRetry(() =>
|
||||
this.adapter.hSet(this.userInfoKey(userName), 'password', hashedPassword)
|
||||
);
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
}
|
||||
|
||||
// 检查用户是否存在(新版本)
|
||||
@@ -969,6 +1009,9 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
|
||||
// 删除用户的其他数据(播放记录、收藏等)
|
||||
await this.deleteUser(userName);
|
||||
|
||||
// 清除缓存
|
||||
userInfoCache?.delete(userName);
|
||||
}
|
||||
|
||||
// ---------- 搜索历史 ----------
|
||||
|
||||
Reference in New Issue
Block a user