diff --git a/backend/routes/apiRoutes.js b/backend/routes/apiRoutes.js index a372c32..3778edb 100644 --- a/backend/routes/apiRoutes.js +++ b/backend/routes/apiRoutes.js @@ -23,6 +23,7 @@ const assetRoutes = require('./assetRoutes'); // Ở đây tôi gắn các route còn lại trực tiếp để không làm gián đoạn hệ thống router.use('/admin', adminRoutes); router.use('/auth', authRoutes); // Tích hợp API Đăng ký/Đăng nhập +router.get('/share/:id', sceneRoutes.shareScene); // Route hỗ trợ Open Graph router.use('/tours', tourRoutes); // Thêm các route cho Tour router.use('/scenes', sceneRoutes); router.use('/users', userRoutes); diff --git a/backend/routes/sceneRoutes.js b/backend/routes/sceneRoutes.js index fd6d35e..ec7d066 100644 --- a/backend/routes/sceneRoutes.js +++ b/backend/routes/sceneRoutes.js @@ -168,9 +168,11 @@ router.get('/', optionalAuth, async (req, res) => { } }); -// @route GET /api/share/:id -// @desc Trang trung gian hỗ trợ Open Graph (Facebook, Zalo,...) -router.get('/share/:id', async (req, res) => { +/** + * @route GET /api/share/:id + * @desc Trang trung gian hỗ trợ Open Graph (Facebook, Zalo,...) + */ +const shareScene = async (req, res) => { try { const scene = await Scene.findById(req.params.id).populate('tourId'); if (!scene) return res.status(404).send('Không tìm thấy cảnh 3D'); @@ -179,19 +181,21 @@ router.get('/share/:id', async (req, res) => { const title = tour ? tour.name : (scene.name || 'Virtual Tour 3D'); const description = tour ? tour.description : (scene.description || 'Khám phá không gian 360 độ chân thực'); - // Xác định token (ưu tiên query token, sau đó là token của tour/scene nếu có) + // Lấy token chia sẻ (nếu có) const token = req.query.token || scene.shareToken || (tour && tour.shareToken) || ''; - // Xử lý Protocol/Host để tạo URL tuyệt đối + // Xác định host của hệ thống const protocol = req.headers['x-forwarded-proto'] || req.protocol; - const host = req.get('host'); - const baseUrl = `${protocol}://${host}`; + const host = process.env.SYSTEM_HOST || `${protocol}://${req.get('host')}`; - // URL ảnh thumbnail gọi sang Asset API với cờ watermark - const imageUrl = `${baseUrl}/api/assets/view/${scene.assetId}?watermark=true${token ? '&token=' + token : ''}`; + // URL ảnh thumbnail gọi sang Asset API với cờ watermark (đã được xử lý trong assetRoutes.js) + const imageUrl = `${host}/api/assets/view/${scene.assetId}?watermark=true${token ? '&token=' + token : ''}`; // URL thực tế của ứng dụng để redirect người dùng - const appUrl = `${baseUrl}/?sceneId=${scene._id}${token ? '&token=' + token : ''}`; + const appUrl = `${host}/?sceneId=${scene._id}${token ? '&token=' + token : ''}`; + + // URL Canonical của chính trang chia sẻ này (Dùng cho og:url) + const shareUrl = `${host}/api/share/${scene._id}${token ? '?token=' + token : ''}`; res.send(` @@ -200,13 +204,17 @@ router.get('/share/:id', async (req, res) => { ${title} + + - + + + @@ -230,7 +238,10 @@ router.get('/share/:id', async (req, res) => { console.error("[Share Error]", error); res.status(500).send('Lỗi máy chủ'); } -}); +}; + +// Đăng ký route phụ trợ trong router này +router.get('/share/:id', shareScene); // @route GET /api/scenes/:id router.get('/:id', optionalAuth, async (req, res) => { @@ -458,4 +469,5 @@ router.delete('/:id', protect, async (req, res) => { } }); +router.shareScene = shareScene; // Xuất hàm để apiRoutes sử dụng module.exports = router; \ No newline at end of file