114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import { Router } from 'express';
|
|
import {
|
|
getAllRecipes, getRecipeById, createRecipe,
|
|
updateRecipe, deleteRecipe, getCategories, getDb
|
|
} from '../db.js';
|
|
import { getTikTokData } from '../services/tiktok.js';
|
|
import { isAiAvailable, extractRecipe } from '../services/ai.js';
|
|
import { trackEvent } from '../analytics-db.js';
|
|
|
|
const router = Router();
|
|
|
|
router.get('/', (req, res) => {
|
|
const { search, category, user_id } = req.query;
|
|
const recipes = getAllRecipes(search, category, user_id);
|
|
res.json(recipes.map(r => ({
|
|
...r,
|
|
ingredients: JSON.parse(r.ingredients),
|
|
steps: JSON.parse(r.steps),
|
|
})));
|
|
});
|
|
|
|
router.get('/categories', (req, res) => {
|
|
res.json(getCategories());
|
|
});
|
|
|
|
router.get('/authors', (req, res) => {
|
|
const db = getDb();
|
|
const authorIds = [...new Set(db.recipes.filter(r => r.user_id).map(r => r.user_id))];
|
|
const authors = authorIds.map(id => {
|
|
const user = db.users.find(u => u.id === id);
|
|
return { id, username: user ? user.username : `User #${id}` };
|
|
}).sort((a, b) => a.username.localeCompare(b.username));
|
|
res.json(authors);
|
|
});
|
|
|
|
router.get('/ai-status', async (req, res) => {
|
|
const available = await isAiAvailable();
|
|
res.json({ ai: available });
|
|
});
|
|
|
|
router.get('/:id', (req, res) => {
|
|
const recipe = getRecipeById(req.params.id);
|
|
if (!recipe) return res.status(404).json({ error: 'Rezept nicht gefunden' });
|
|
res.json({
|
|
...recipe,
|
|
ingredients: JSON.parse(recipe.ingredients),
|
|
steps: JSON.parse(recipe.steps),
|
|
});
|
|
});
|
|
|
|
router.post('/', (req, res) => {
|
|
const recipe = createRecipe(req.body);
|
|
const userId = req.body.user_id || null;
|
|
trackEvent('recipe_created', userId, { recipe_id: recipe.id, recipe_name: recipe.name });
|
|
res.status(201).json(recipe);
|
|
});
|
|
|
|
router.put('/:id', (req, res) => {
|
|
const existing = getRecipeById(req.params.id);
|
|
if (!existing) return res.status(404).json({ error: 'Rezept nicht gefunden' });
|
|
const updated = updateRecipe(req.params.id, req.body);
|
|
trackEvent('recipe_updated', req.body.user_id || null, { recipe_id: Number(req.params.id), recipe_name: updated.name });
|
|
res.json(updated);
|
|
});
|
|
|
|
router.delete('/:id', (req, res) => {
|
|
const existing = getRecipeById(req.params.id);
|
|
if (!existing) return res.status(404).json({ error: 'Rezept nicht gefunden' });
|
|
deleteRecipe(req.params.id);
|
|
trackEvent('recipe_deleted', null, { recipe_id: Number(req.params.id) });
|
|
res.json({ success: true });
|
|
});
|
|
|
|
router.post('/from-tiktok', async (req, res) => {
|
|
try {
|
|
const { url } = req.body;
|
|
if (!url) return res.status(400).json({ error: 'URL erforderlich' });
|
|
|
|
const tiktokData = await getTikTokData(url);
|
|
|
|
const aiAvailable = await isAiAvailable();
|
|
let extracted = null;
|
|
let aiStatus = aiAvailable ? 'available' : 'unavailable';
|
|
|
|
let aiMessage = '';
|
|
if (aiAvailable && tiktokData.title) {
|
|
try {
|
|
extracted = await extractRecipe(tiktokData.title);
|
|
aiStatus = 'success';
|
|
} catch (e) {
|
|
console.error('KI Extraktion fehlgeschlagen:', e.message);
|
|
aiStatus = 'error';
|
|
aiMessage = e.message;
|
|
}
|
|
} else if (!aiAvailable) {
|
|
aiMessage = 'KI-Service nicht erreichbar';
|
|
} else if (!tiktokData.title) {
|
|
aiMessage = 'Kein Titel im Video gefunden';
|
|
}
|
|
|
|
res.json({
|
|
tiktok: tiktokData,
|
|
ai: aiAvailable,
|
|
aiStatus,
|
|
aiMessage,
|
|
extracted,
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
export default router;
|