init push
This commit is contained in:
202
backend/db.js
Normal file
202
backend/db.js
Normal file
@@ -0,0 +1,202 @@
|
||||
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
||||
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, 'data.json');
|
||||
|
||||
function loadDB() {
|
||||
if (existsSync(DB_FILE)) {
|
||||
return JSON.parse(readFileSync(DB_FILE, 'utf-8'));
|
||||
}
|
||||
return { users: [], recipes: [], invite_tokens: [], _counters: { users: 0, recipes: 0, invite_tokens: 0 } };
|
||||
}
|
||||
|
||||
function saveDB(data) {
|
||||
writeFileSync(DB_FILE, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
let db = loadDB();
|
||||
|
||||
function nextId(table) {
|
||||
db._counters[table] = (db._counters[table] || 0) + 1;
|
||||
return db._counters[table];
|
||||
}
|
||||
|
||||
function now() {
|
||||
return new Date().toISOString().replace('T', ' ').slice(0, 19);
|
||||
}
|
||||
|
||||
export function getDb() {
|
||||
return db;
|
||||
}
|
||||
|
||||
export function getAllRecipes(search, category) {
|
||||
let results = [...db.recipes];
|
||||
|
||||
if (search) {
|
||||
const term = search.toLowerCase();
|
||||
results = results.filter(r =>
|
||||
(r.name && r.name.toLowerCase().includes(term)) ||
|
||||
(r.description && r.description.toLowerCase().includes(term)) ||
|
||||
(r.ingredients && r.ingredients.toLowerCase().includes(term))
|
||||
);
|
||||
}
|
||||
|
||||
if (category && category !== 'Alle') {
|
||||
results = results.filter(r => r.category === category);
|
||||
}
|
||||
|
||||
results.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));
|
||||
return results;
|
||||
}
|
||||
|
||||
export function getRecipeById(id) {
|
||||
return db.recipes.find(r => r.id === Number(id)) || undefined;
|
||||
}
|
||||
|
||||
export function createRecipe(recipe) {
|
||||
const id = nextId('recipes');
|
||||
const nowStr = now();
|
||||
const row = {
|
||||
id,
|
||||
name: recipe.name,
|
||||
description: recipe.description || '',
|
||||
ingredients: JSON.stringify(recipe.ingredients || []),
|
||||
steps: JSON.stringify(recipe.steps || []),
|
||||
category: recipe.category || 'Sonstiges',
|
||||
tiktok_url: recipe.tiktok_url || null,
|
||||
tiktok_author: recipe.tiktok_author || null,
|
||||
thumbnail_url: recipe.thumbnail_url || null,
|
||||
user_id: recipe.user_id || null,
|
||||
created_at: nowStr,
|
||||
updated_at: nowStr,
|
||||
};
|
||||
db.recipes.push(row);
|
||||
saveDB(db);
|
||||
return row;
|
||||
}
|
||||
|
||||
export function updateRecipe(id, recipe) {
|
||||
const idx = db.recipes.findIndex(r => r.id === Number(id));
|
||||
if (idx === -1) return undefined;
|
||||
db.recipes[idx] = {
|
||||
...db.recipes[idx],
|
||||
name: recipe.name,
|
||||
description: recipe.description || '',
|
||||
ingredients: JSON.stringify(recipe.ingredients || []),
|
||||
steps: JSON.stringify(recipe.steps || []),
|
||||
category: recipe.category || 'Sonstiges',
|
||||
tiktok_url: recipe.tiktok_url || null,
|
||||
tiktok_author: recipe.tiktok_author || null,
|
||||
thumbnail_url: recipe.thumbnail_url || null,
|
||||
updated_at: now(),
|
||||
};
|
||||
saveDB(db);
|
||||
return db.recipes[idx];
|
||||
}
|
||||
|
||||
export function deleteRecipe(id) {
|
||||
const idx = db.recipes.findIndex(r => r.id === Number(id));
|
||||
if (idx === -1) return;
|
||||
db.recipes.splice(idx, 1);
|
||||
saveDB(db);
|
||||
}
|
||||
|
||||
export function getCategories() {
|
||||
const counts = {};
|
||||
for (const r of db.recipes) {
|
||||
counts[r.category] = (counts[r.category] || 0) + 1;
|
||||
}
|
||||
return Object.entries(counts)
|
||||
.map(([category, count]) => ({ category, count }))
|
||||
.sort((a, b) => b.count - a.count);
|
||||
}
|
||||
|
||||
export function getUserByUsername(username) {
|
||||
return db.users.find(u => u.username === username) || undefined;
|
||||
}
|
||||
|
||||
export function getUserById(id) {
|
||||
return db.users.find(u => u.id === Number(id)) || undefined;
|
||||
}
|
||||
|
||||
export function createUser(username, hashedPassword, isAdmin = false) {
|
||||
const id = nextId('users');
|
||||
const user = {
|
||||
id,
|
||||
username,
|
||||
password: hashedPassword,
|
||||
is_admin: isAdmin ? 1 : 0,
|
||||
created_at: now(),
|
||||
};
|
||||
db.users.push(user);
|
||||
saveDB(db);
|
||||
return { id, username, is_admin: user.is_admin, created_at: user.created_at };
|
||||
}
|
||||
|
||||
export function updateUserCredentials(userId, { username, password }) {
|
||||
const user = db.users.find(u => u.id === Number(userId));
|
||||
if (!user) return null;
|
||||
if (username) user.username = username;
|
||||
if (password) user.password = password;
|
||||
saveDB(db);
|
||||
return { id: user.id, username: user.username, is_admin: user.is_admin, created_at: user.created_at };
|
||||
}
|
||||
|
||||
export function createInviteToken(token, createdBy) {
|
||||
const id = nextId('invite_tokens');
|
||||
db.invite_tokens.push({
|
||||
id,
|
||||
token,
|
||||
created_by: createdBy,
|
||||
used_by: null,
|
||||
created_at: now(),
|
||||
used_at: null,
|
||||
});
|
||||
saveDB(db);
|
||||
}
|
||||
|
||||
export function getInviteToken(token) {
|
||||
return db.invite_tokens.find(i => i.token === token) || undefined;
|
||||
}
|
||||
|
||||
export function useInviteToken(token, userId) {
|
||||
const inv = db.invite_tokens.find(i => i.token === token);
|
||||
if (inv) {
|
||||
inv.used_by = userId;
|
||||
inv.used_at = now();
|
||||
saveDB(db);
|
||||
}
|
||||
}
|
||||
|
||||
export function getInvitesByUser(userId) {
|
||||
return db.invite_tokens
|
||||
.filter(i => i.created_by === Number(userId))
|
||||
.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''))
|
||||
.map(i => {
|
||||
const usedByUser = i.used_by ? db.users.find(u => u.id === i.used_by) : null;
|
||||
return { ...i, used_by_username: usedByUser ? usedByUser.username : null };
|
||||
});
|
||||
}
|
||||
|
||||
export function getAllUsers() {
|
||||
return db.users
|
||||
.map(u => ({ id: u.id, username: u.username, is_admin: u.is_admin, created_at: u.created_at }))
|
||||
.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));
|
||||
}
|
||||
|
||||
export function deleteUser(id) {
|
||||
const idx = db.users.findIndex(u => u.id === Number(id));
|
||||
if (idx === -1) return false;
|
||||
db.users.splice(idx, 1);
|
||||
db.invite_tokens = db.invite_tokens.filter(i => i.created_by !== Number(id));
|
||||
saveDB(db);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getInviteStats() {
|
||||
const total = db.invite_tokens.length;
|
||||
const used = db.invite_tokens.filter(i => i.used_by !== null).length;
|
||||
return { total, used, available: total - used };
|
||||
}
|
||||
Reference in New Issue
Block a user