sửa lỗi privacy cho nhiều scene con, không cho phép ghi hoặc nhận sai

This commit is contained in:
2026-06-10 09:35:00 +07:00
parent 37d1b0095d
commit 02cd68f23c
12 changed files with 162 additions and 20 deletions
+73 -1
View File
@@ -78,4 +78,76 @@ const deleteSceneCascade = async (rootSceneId, performer = 'System') => {
return { deletedCount: scenesToDelete.length };
};
module.exports = { deleteSceneCascade };
/**
* Lan truyền thiết lập quyền riêng tư từ Scene cha xuống TOÀN BỘ các Scene con trong Tour (Đệ quy/BFS).
* Đảm bảo tính nhất quán của toàn bộ Tour khi thay đổi quyền truy cập.
* @param {string} parentSceneId - ID của Scene cha vừa được cập nhật
* @param {Object} privacyData - Dữ liệu quyền riêng tư từ Scene cha (privacy, tokens, v.v.)
*/
const propagateScenePrivacy = async (parentSceneId, privacyData) => {
const { privacy, shareToken, shareTokenExpires, sharedWith, sharedEmails } = privacyData;
// 1. Tìm tất cả các scene con ở mọi cấp độ bằng thuật toán BFS
let queue = [parentSceneId.toString()];
let allChildIds = [];
const visited = new Set(queue);
while (queue.length > 0) {
const currentId = queue.shift();
// Tìm các hotspots xuất phát từ scene hiện tại (bỏ qua link quay lại để tránh vòng lặp)
const hotspots = await Hotspot.find({
parent_scene_id: currentId,
is_auto_return: { $ne: true }
}).select('target_scene_id');
for (const hs of hotspots) {
if (hs.target_scene_id) {
const targetIdStr = hs.target_scene_id.toString();
if (!visited.has(targetIdStr)) {
visited.add(targetIdStr);
allChildIds.push(targetIdStr);
queue.push(targetIdStr);
}
}
}
}
if (allChildIds.length === 0) return;
// 2. Chuẩn bị dữ liệu cập nhật đồng bộ cho toàn bộ chuỗi
const updateFields = { privacy };
const updateQuery = { $set: updateFields };
if (privacy === 'shared') {
// Chỉ gán nếu có giá trị, nếu không thì xóa hẳn để tránh lỗi Duplicate Key Null
if (shareToken) {
updateFields.shareToken = shareToken;
} else {
if (!updateQuery.$unset) updateQuery.$unset = {};
updateQuery.$unset.shareToken = 1;
}
updateFields.shareTokenExpires = shareTokenExpires || undefined;
updateFields.sharedWith = sharedWith || [];
updateFields.sharedEmails = sharedEmails || [];
} else {
// [BẢO MẬT] Xóa hoàn toàn token cho mọi chế độ không phải 'shared' để tránh lỗi Duplicate Key Null
if (!updateQuery.$unset) updateQuery.$unset = {};
updateQuery.$unset.shareToken = 1;
updateQuery.$unset.shareTokenExpires = 1;
// Nếu là private hoặc public, xóa luôn danh sách thành viên được chia sẻ
if (privacy !== 'member') {
updateFields.sharedWith = [];
updateFields.sharedEmails = [];
}
}
// 3. Cập nhật hàng loạt cho tất cả các scene con được tìm thấy
await Scene.updateMany(
{ _id: { $in: allChildIds } },
updateQuery
);
await logActivity('PROPAGATE_PRIVACY_DEEP', { parentSceneId, childCount: allChildIds.length, privacy }, 'System');
};
module.exports = { deleteSceneCascade, propagateScenePrivacy };