fix(upload): 上传与用户设置目录改为持久化目录并保留旧目录回退
- 上传目录默认 process.cwd()/public/uploads,支持 UPLOAD_DIR 覆盖,避免代码部署覆盖用户上传文件 - 用户设置目录默认 process.cwd()/data,支持 DATA_DIR 覆盖,旧 data/user_settings.json 自动回退读取
这个提交包含在:
@@ -161,12 +161,20 @@ app.use(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// 静态文件与对象存储目录配置
|
// 静态文件与对象存储目录配置(优先持久化目录 process.cwd()/public/uploads,避免代码构建部署覆盖用户上传文件)
|
||||||
const uploadDir = path.resolve(__dirname, '../public/uploads');
|
const persistentUploadDir = process.env.UPLOAD_DIR
|
||||||
|
? path.resolve(process.env.UPLOAD_DIR)
|
||||||
|
: path.resolve(process.cwd(), 'public/uploads');
|
||||||
|
const fallbackUploadDir = path.resolve(__dirname, '../public/uploads');
|
||||||
|
|
||||||
|
const uploadDir = persistentUploadDir;
|
||||||
if (!fs.existsSync(uploadDir)) {
|
if (!fs.existsSync(uploadDir)) {
|
||||||
fs.mkdirSync(uploadDir, { recursive: true });
|
fs.mkdirSync(uploadDir, { recursive: true });
|
||||||
}
|
}
|
||||||
app.use('/uploads', express.static(uploadDir));
|
app.use('/uploads', express.static(uploadDir));
|
||||||
|
if (uploadDir !== fallbackUploadDir && fs.existsSync(fallbackUploadDir)) {
|
||||||
|
app.use('/uploads', express.static(fallbackUploadDir));
|
||||||
|
}
|
||||||
|
|
||||||
// Multer 文件上传引擎配置
|
// Multer 文件上传引擎配置
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
@@ -4226,7 +4234,9 @@ app.post('/api/users/:id/profile', async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
// 7.2.1.b 用户隐私安全与通知订阅偏好持久化接口
|
// 7.2.1.b 用户隐私安全与通知订阅偏好持久化接口
|
||||||
// 用户设置文件存放于对外不可见的私有目录,避免被 /uploads 静态服务公开读取
|
// 用户设置文件存放于对外不可见的私有目录,避免被 /uploads 静态服务公开读取
|
||||||
const userSettingsDir = path.resolve(__dirname, '../data');
|
const userSettingsDir = process.env.DATA_DIR
|
||||||
|
? path.resolve(process.env.DATA_DIR)
|
||||||
|
: path.resolve(process.cwd(), 'data');
|
||||||
if (!fs.existsSync(userSettingsDir)) {
|
if (!fs.existsSync(userSettingsDir)) {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(userSettingsDir, { recursive: true });
|
fs.mkdirSync(userSettingsDir, { recursive: true });
|
||||||
@@ -4235,12 +4245,17 @@ if (!fs.existsSync(userSettingsDir)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const userSettingsFilePath = path.resolve(userSettingsDir, 'user_settings.json');
|
const userSettingsFilePath = path.resolve(userSettingsDir, 'user_settings.json');
|
||||||
|
const fallbackUserSettingsFilePath = path.resolve(__dirname, '../data/user_settings.json');
|
||||||
function readAllUserSettings(): Record<string, { privacyHidePhone: boolean; noticeSubscribe: boolean; updatedAt: string }> {
|
function readAllUserSettings(): Record<string, { privacyHidePhone: boolean; noticeSubscribe: boolean; updatedAt: string }> {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(userSettingsFilePath)) {
|
if (fs.existsSync(userSettingsFilePath)) {
|
||||||
const raw = fs.readFileSync(userSettingsFilePath, 'utf-8');
|
const raw = fs.readFileSync(userSettingsFilePath, 'utf-8');
|
||||||
return JSON.parse(raw) || {};
|
return JSON.parse(raw) || {};
|
||||||
}
|
}
|
||||||
|
if (userSettingsFilePath !== fallbackUserSettingsFilePath && fs.existsSync(fallbackUserSettingsFilePath)) {
|
||||||
|
const raw = fs.readFileSync(fallbackUserSettingsFilePath, 'utf-8');
|
||||||
|
return JSON.parse(raw) || {};
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logServerError('userSettings.read', e);
|
logServerError('userSettings.read', e);
|
||||||
}
|
}
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户