Files
Tiktok-Rezepte/backend/dist/db.js
2026-11-01 20:14:25 +01:00

148 lines
6.6 KiB
JavaScript

import Database from 'better-sqlite3';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const DB_FILE = process.env.DB_PATH || join(__dirname, 'recipes.db');
const db = new Database(DB_FILE);
db.pragma('journal_mode = WAL');
function now() {
return new Date().toISOString().replace('T', ' ').slice(0, 19);
}
export function getDb() {
return db;
}
export function getAllRecipes(search, category, userId) {
let query = 'SELECT * FROM recipes WHERE 1=1';
const params = [];
if (search) {
query += ' AND (LOWER(name) LIKE ? OR LOWER(description) LIKE ? OR LOWER(ingredients) LIKE ?)';
const term = `%${search.toLowerCase()}%`;
params.push(term, term, term);
}
if (category && category !== 'Alle') {
query += ' AND category = ?';
params.push(category);
}
if (userId) {
query += ' AND user_id = ?';
params.push(Number(userId));
}
query += ' ORDER BY created_at DESC';
return db.prepare(query).all(...params);
}
export function getRecipeById(id) {
return db.prepare('SELECT * FROM recipes WHERE id = ?').get(Number(id));
}
export function createRecipe(recipe) {
const nowStr = now();
const stmt = db.prepare(`
INSERT INTO recipes (
name, description, ingredients, steps, category,
source, source_url, source_author, tiktok_url, tiktok_author,
thumbnail_url, user_id, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const info = stmt.run(recipe.name, recipe.description || '', typeof recipe.ingredients === 'string' ? recipe.ingredients : JSON.stringify(recipe.ingredients || []), typeof recipe.steps === 'string' ? recipe.steps : JSON.stringify(recipe.steps || []), recipe.category || 'Sonstiges', recipe.source || 'tiktok', recipe.source_url || recipe.tiktok_url || null, recipe.source_author || recipe.tiktok_author || null, recipe.tiktok_url || recipe.source_url || null, recipe.tiktok_author || recipe.source_author || null, recipe.thumbnail_url || null, recipe.user_id || null, nowStr, nowStr);
return getRecipeById(info.lastInsertRowid);
}
export function updateRecipe(id, recipe) {
const existing = getRecipeById(id);
if (!existing)
return undefined;
const nowStr = now();
const stmt = db.prepare(`
UPDATE recipes SET
name = ?, description = ?, ingredients = ?, steps = ?, category = ?,
source = ?, source_url = ?, source_author = ?, tiktok_url = ?, tiktok_author = ?,
thumbnail_url = ?, updated_at = ?
WHERE id = ?
`);
stmt.run(recipe.name !== undefined ? recipe.name : existing.name, recipe.description !== undefined ? recipe.description : existing.description, recipe.ingredients !== undefined ? (typeof recipe.ingredients === 'string' ? recipe.ingredients : JSON.stringify(recipe.ingredients)) : existing.ingredients, recipe.steps !== undefined ? (typeof recipe.steps === 'string' ? recipe.steps : JSON.stringify(recipe.steps)) : existing.steps, recipe.category || existing.category, recipe.source || existing.source, recipe.source_url || recipe.tiktok_url || existing.source_url, recipe.source_author || recipe.tiktok_author || existing.source_author, recipe.tiktok_url || recipe.source_url || existing.tiktok_url, recipe.tiktok_author || recipe.source_author || existing.tiktok_author, recipe.thumbnail_url !== undefined ? recipe.thumbnail_url : existing.thumbnail_url, nowStr, Number(id));
return getRecipeById(id);
}
export function deleteRecipe(id) {
db.prepare('DELETE FROM recipes WHERE id = ?').run(Number(id));
}
export function getCategories() {
return db.prepare(`
SELECT category, COUNT(*) as count
FROM recipes
GROUP BY category
ORDER BY count DESC
`).all();
}
export function getUserByUsername(username) {
return db.prepare('SELECT * FROM users WHERE username = ?').get(username);
}
export function getUserById(id) {
return db.prepare('SELECT * FROM users WHERE id = ?').get(Number(id));
}
export function createUser(username, hashedPassword, isAdmin = false) {
const nowStr = now();
const stmt = db.prepare('INSERT INTO users (username, password, is_admin, created_at) VALUES (?, ?, ?, ?)');
const info = stmt.run(username, hashedPassword, isAdmin ? 1 : 0, nowStr);
return { id: info.lastInsertRowid, username, is_admin: isAdmin ? 1 : 0, created_at: nowStr };
}
export function updateUserCredentials(userId, { username, password }) {
const user = getUserById(userId);
if (!user)
return null;
let query = 'UPDATE users SET ';
const params = [];
const updates = [];
if (username) {
updates.push('username = ?');
params.push(username);
}
if (password) {
updates.push('password = ?');
params.push(password);
}
if (updates.length === 0)
return { id: user.id, username: user.username, is_admin: user.is_admin, created_at: user.created_at };
query += updates.join(', ') + ' WHERE id = ?';
params.push(Number(userId));
db.prepare(query).run(...params);
return getUserById(userId) || null;
}
export function createInviteToken(token, createdBy) {
const nowStr = now();
db.prepare('INSERT INTO invite_tokens (token, created_by, created_at) VALUES (?, ?, ?)').run(token, Number(createdBy), nowStr);
}
export function getInviteToken(token) {
return db.prepare('SELECT * FROM invite_tokens WHERE token = ?').get(token);
}
export function useInviteToken(token, userId) {
const nowStr = now();
db.prepare('UPDATE invite_tokens SET used_by = ?, used_at = ? WHERE token = ?').run(Number(userId), nowStr, token);
}
export function getInvitesByUser(userId) {
return db.prepare(`
SELECT i.*, u.username as used_by_username
FROM invite_tokens i
LEFT JOIN users u ON i.used_by = u.id
WHERE i.created_by = ?
ORDER BY i.created_at DESC
`).all(Number(userId));
}
export function getAllUsers() {
return db.prepare('SELECT id, username, is_admin, created_at FROM users ORDER BY created_at DESC').all();
}
export function deleteUser(id) {
const userId = Number(id);
const user = getUserById(userId);
if (!user)
return false;
const deleteTrans = db.transaction(() => {
db.prepare('DELETE FROM users WHERE id = ?').run(userId);
db.prepare('DELETE FROM invite_tokens WHERE created_by = ?').run(userId);
});
deleteTrans();
return true;
}
export function getInviteStats() {
const total = db.prepare('SELECT COUNT(*) as count FROM invite_tokens').get().count;
const used = db.prepare('SELECT COUNT(*) as count FROM invite_tokens WHERE used_by IS NOT NULL').get().count;
return { total, used, available: total - used };
}