import BlogService from '../services/blogService.js'; import SocialNetworkService from '../services/socialnetworkService.js'; const blogService = new BlogService(); const socialService = new SocialNetworkService(); export const createBlog = async (req, res) => { try { const { userid } = req.headers; // creator must be logged in const blog = await blogService.createBlog(userid, req.body || {}); res.json(blog); } catch (e) { res.status(e.status || 400).json({ error: e.message }); } }; export const updateBlog = async (req, res) => { try { const { userid } = req.headers; const { id } = req.params; const blog = await blogService.updateBlog(userid, id, req.body || {}); res.json(blog); } catch (e) { res.status(e.status || 400).json({ error: e.message }); } }; export const listBlogs = async (req, res) => { try { const { userid } = req.headers; // optional for access checks const blogs = await blogService.listBlogsForViewer(userid || null); res.json(blogs); } catch (e) { res.status(400).json({ error: e.message }); } }; export const getBlog = async (req, res) => { try { const { userid } = req.headers; const { id } = req.params; const blog = await blogService.getBlog(id, userid || null); res.json(blog); } catch (e) { res.status(e.status || 404).json({ error: e.message }); } }; export const createPost = async (req, res) => { try { const { userid } = req.headers; const { id } = req.params; const post = await blogService.createPost(userid, id, req.body || {}); res.json(post); } catch (e) { res.status(e.status || 400).json({ error: e.message }); } }; export const listPosts = async (req, res) => { try { const { userid } = req.headers; const { id } = req.params; const page = Math.max(1, parseInt(req.query.page || '1', 10)); const pageSize = Math.min(50, Math.max(1, parseInt(req.query.pageSize || '10', 10))); const all = await blogService.listPosts(id, userid || null); const total = all.length; const start = (page - 1) * pageSize; const posts = all.slice(start, start + pageSize); res.json({ items: posts, page, pageSize, total }); } catch (e) { res.status(e.status || 400).json({ error: e.message }); } }; export const listBlogImages = async (req, res) => { try { const { userid } = req.headers; const user = await blogService.getUserByHashedId(userid); const blogFolder = await blogService.ensureBlogFolder(user.id); const images = await socialService.getFolderImageList(userid, blogFolder.id); res.json({ folderId: blogFolder.id, images }); } catch (e) { res.status(400).json({ error: e.message }); } }; export const uploadBlogImage = async (req, res) => { try { const { userid } = req.headers; const user = await blogService.getUserByHashedId(userid); const blogFolder = await blogService.ensureBlogFolder(user.id); // Default visibility mirrors blog folder visibilities (already applied) const formData = { title: req.body?.title || 'Blog Image', description: req.body?.description || '', folderId: blogFolder.id, visibility: JSON.stringify([]) }; const file = req.file; const image = await socialService.uploadImage(userid, file, formData); res.status(201).json(image); } catch (e) { res.status(400).json({ error: e.message }); } }; export const getPublicBlogImageByHash = async (req, res) => { try { const { hash } = req.params; const filePath = await socialService.getImageFilePathPublicByHash(hash); res.sendFile(filePath, err => { if (err) { console.error('Error sending file:', err); res.status(500).json({ error: 'Error sending file' }); } }); } catch (e) { res.status(e.status || 403).json({ error: e.message || 'Access denied or image not found' }); } }; export const shareBlog = async (req, res) => { try { const { userid } = req.headers; const { id } = req.params; const { toFriends = false, emails = [] } = req.body || {}; // Prefer configured frontend base for public links; fallback to request origin const feBase = process.env.FRONTEND_BASE_URL; const proto = (req.headers['x-forwarded-proto'] || req.protocol || 'http').split(',')[0].trim(); const host = (req.headers['x-forwarded-host'] || req.get('host')); const origin = (feBase && feBase.trim()) ? feBase.replace(/\/$/, '') : `${proto}://${host}`; // Compute slug from username + title (no spaces, remove unsafe chars) const { user, blog } = await blogService.assertOwner(userid, id); const titleNoSpaces = (blog.title || '').toString().replace(/\s+/g, ''); const base = `${user.username || 'user'}${titleNoSpaces}`; const slug = base.replace(/[^a-zA-Z0-9_-]/g, ''); // Pretty public URL under frontend: /blogs/:slug const url = `${origin}/blogs/${encodeURIComponent(slug)}`; const result = await blogService.shareBlog(userid, id, { toFriends, emails }, url); res.json(result); } catch (e) { res.status(e.status || 400).json({ error: e.message }); } }; export const resolveBlogSlug = async (req, res) => { try { const { slug } = req.params; const blogId = await blogService.resolveSlug(slug); if (!blogId) return res.status(404).json({ error: 'Not found' }); // Redirect to SPA history route so the client router loads the blog const feBase = process.env.FRONTEND_BASE_URL; const proto = (req.headers['x-forwarded-proto'] || req.protocol || 'http').split(',')[0].trim(); const host = (req.headers['x-forwarded-host'] || req.get('host')); const origin = (feBase && feBase.trim()) ? feBase.replace(/\/$/, '') : `${proto}://${host}`; return res.redirect(302, `${origin}/blogs/${blogId}/${encodeURIComponent(slug)}`); } catch (e) { res.status(400).json({ error: e.message }); } }; export const resolveBlogSlugId = async (req, res) => { try { const { slug } = req.params; const blogId = await blogService.resolveSlug(slug); if (!blogId) return res.status(404).json({ error: 'Not found' }); res.json({ id: blogId }); } catch (e) { res.status(400).json({ error: e.message }); } };