a370b8f7d8
- Персонаж Зеро: 23 позы (zeroCharacter.js), скрипты генерации - Auto-publish статей в TG: multipart upload, кнопки, режим alternating Zero/cover - Fallback цепочка обложек: aiprimetech gpt-5.5 → Pollinations → local SVG (6 палитр) - Auto-series: Claude haiku определяет серию для каждой статьи автоматически - Channel stats: подписчики, история, delta 24h/7d - Photo-search: Yandex API, профили доменов, Redis лимиты - Scheduled posts runner: backfill, preview, queue, cancel - promptBuilder: author_persona Зеро, голос от первого лица - Fixes: dollar-placeholder bugs в PATCH channels/autogen, listArticles фильтры - AI model: gpt-5.5 для image generation
92 lines
3.2 KiB
JavaScript
92 lines
3.2 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const svc = require('../services/userPosts');
|
|
|
|
const getUserId = (req) => parseInt(req.headers['x-user-id']) || null;
|
|
|
|
// GET /api/user-posts?channel_id=N&status=draft
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
const posts = await svc.listUserPosts({
|
|
userId,
|
|
channelId: req.query.channel_id ? parseInt(req.query.channel_id) : null,
|
|
status: req.query.status || null,
|
|
limit: parseInt(req.query.limit) || 50,
|
|
});
|
|
res.json(posts);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// POST /api/user-posts
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
const { channel_id, content, image_url, image_credit, topic, status, scheduled_at } = req.body;
|
|
if (!channel_id || !content) return res.status(400).json({ error: 'channel_id and content required' });
|
|
const post = await svc.savePost({
|
|
userId, channelId: channel_id, content,
|
|
imageUrl: image_url,
|
|
imageCredit: image_credit ?? null,
|
|
topic,
|
|
status: status || 'draft',
|
|
scheduledAt: scheduled_at,
|
|
});
|
|
res.json(post);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// GET /api/user-posts/:id
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
const post = await svc.getPost(userId, req.params.id);
|
|
if (!post) return res.status(404).json({ error: 'Not found' });
|
|
res.json(post);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// PATCH /api/user-posts/:id
|
|
router.patch('/:id', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
const post = await svc.updatePost(userId, req.params.id, req.body);
|
|
if (!post) return res.status(404).json({ error: 'Not found' });
|
|
res.json(post);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// DELETE /api/user-posts/:id
|
|
router.delete('/:id', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
await svc.deletePost(userId, req.params.id);
|
|
res.json({ ok: true });
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// POST /api/user-posts/:id/publish — опубликовать прямо сейчас
|
|
router.post('/:id/publish', async (req, res) => {
|
|
try {
|
|
const userId = getUserId(req);
|
|
if (!userId) return res.status(401).json({ error: 'Unauthorized' });
|
|
const result = await svc.publishPost(userId, req.params.id);
|
|
res.json(result);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
// POST /api/user-posts/run-scheduled — внутренний endpoint для cron
|
|
router.post('/run-scheduled', async (req, res) => {
|
|
try {
|
|
const result = await svc.runScheduledPublications();
|
|
res.json(result);
|
|
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
});
|
|
|
|
module.exports = router;
|