Files
tykkaa.fi/api.php
2026-03-08 00:57:31 +02:00

242 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* tykkää.fi — API backend
* Tallentaa julkaisut, kommentit, tykkäykset ja kategoriat JSON-tiedostoihin.
*/
session_start();
header('Content-Type: application/json; charset=UTF-8');
// ─── VAIHDA TÄMÄ SALASANA! ──────────────────────────────────────
define('ADMIN_PASSWORD', 'passus');
// ────────────────────────────────────────────────────────────────
define('DATA_DIR', __DIR__ . '/data/');
if (!is_dir(DATA_DIR)) mkdir(DATA_DIR, 0755, true);
$action = $_GET['action'] ?? '';
$body = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw = file_get_contents('php://input');
$body = json_decode($raw, true) ?? [];
if (!$action) $action = $body['action'] ?? '';
}
// ─── Apufunktiot ───────────────────────────────────────────────
function readData(string $file, $default = []) {
$path = DATA_DIR . $file;
if (!file_exists($path)) return $default;
$d = json_decode(file_get_contents($path), true);
return $d !== null ? $d : $default;
}
function writeData(string $file, $data): void {
file_put_contents(
DATA_DIR . $file,
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
);
}
function ok($data = []): void {
echo json_encode(array_merge(['ok' => true], $data));
exit;
}
function err(string $msg, int $code = 400): void {
http_response_code($code);
echo json_encode(['error' => $msg]);
exit;
}
function isAdmin(): bool {
return !empty($_SESSION['tykkaafi_admin']);
}
// ─── Oletusdata ────────────────────────────────────────────────
function defaultCategories(): array {
return [
['id' => 'recipes', 'fi' => 'Reseptit', 'en' => 'Recipes', 'emoji' => '🍳'],
['id' => 'knitting', 'fi' => 'Neulominen', 'en' => 'Knitting', 'emoji' => '🧶'],
['id' => 'tips', 'fi' => 'Vinkit', 'en' => 'Tips', 'emoji' => '💡'],
];
}
function defaultPosts(): array {
return [
[
'id' => 'pancakes', 'emoji' => '🥞', 'title' => 'Kuohkeat letut',
'category' => 'recipes', 'author' => 'Admin',
'time' => '20 min', 'servings' => '4 annosta', 'type' => 'recipe',
'desc' => 'Kultaisia, voisia lettuja, jotka sulavat suuhun. Täydellisiä laiskaan sunnuntaiaamuun.',
'ingredients' => ['1½ dl vehnäjauhoja','3½ tl leivinjauhetta','1 tl suolaa','1 rkl sokeria','3 dl maitoa','1 muna','3 rkl sulatettua voita','Voita tai öljyä paistamiseen'],
'steps' => ['Sekoita kulhossa jauhot, leivinjauhe, suola ja sokeri.','Tee keskelle kuoppa ja kaada sekaan maito, muna ja sulatettu voi.','Sekoita tasaiseksi — pienet paakut ovat ok.','Kuumenna pannua keskilämmöllä.','Kaada noin ¼ dl taikinaa per lettu.','Paista kunnes pintaan nousee kuplia, käännä ja paista kullanruskeaksi.','Tarjoile vaahterasiirapilla ja marjoilla.'],
],
[
'id' => 'bolognese', 'emoji' => '🍝', 'title' => 'Klassinen spagetti bolognese',
'category' => 'recipes', 'author' => 'Admin',
'time' => '1 t 20 min', 'servings' => '6 annosta', 'type' => 'recipe',
'desc' => 'Runsas, hitaasti haudutettu lihamauste al dente -spagetin päällä. Ajaton italialainen klassikko.',
'ingredients' => ['500 g jauhelihaa','400 g spagettia','1 sipuli, hienonnettuna','3 valkosipulinkynttä','800 g murskattuja tomaatteja','2 dl punaviiniä','2 rkl tomaattipyrettä','Suolaa, pippuria, basilikaa, oreganoa','Parmesaanijuustoa tarjoiluun'],
'steps' => ['Kuullota sipuli ja valkosipuli oliiviöljyssä.','Ruskista jauheliha.','Lisää viini ja anna pelkistyä (5 min).','Lisää tomaatit ja mausteet.','Hauduta miedolla lämmöllä 1 tunti.','Keitä spagetti al denteksi.','Tarjoile parmesaanin kera.'],
],
[
'id' => 'cookies', 'emoji' => '🍪', 'title' => 'Suklaahippukeksit',
'category' => 'recipes', 'author' => 'Admin',
'time' => '30 min', 'servings' => '24 keksiä', 'type' => 'recipe',
'desc' => 'Sitkeä sisältä, rapea reunoilta — täydellinen kotitekoinen keksi.',
'ingredients' => ['5½ dl vehnäjauhoja','1 tl ruokasoodaa','1 tl suolaa','225 g pehmeää voita','1½ dl sokeria','1½ dl ruskeaa sokeria','2 munaa','2 tl vaniljauutetta','4 dl suklaahippuja'],
'steps' => ['Kuumenna uuni 190°C.','Sekoita jauhot, sooda ja suola.','Vatkaa voi ja sokerit kuohkeaksi.','Lisää munat ja vanilja.','Yhdistä aineet ja lisää suklaa.','Lusikoi pellille.','Paista 911 min kullanruskeaksi.'],
],
[
'id' => 'soup', 'emoji' => '🍲', 'title' => 'Täyttävä kasviskeitto',
'category' => 'recipes', 'author' => 'Admin',
'time' => '45 min', 'servings' => '4 annosta', 'type' => 'recipe',
'desc' => 'Lämmittävä kulhollinen paksuja kasviksia rikkaassa yrttiliemessä.',
'ingredients' => ['2 rkl oliiviöljyä','1 sipuli','3 valkosipulia','3 porkkanaa, siivuina','2 perunaa, kuutioina','1 kesäkurpitsa','400 g tomaattimurskaa','1½ l kasvislientä','Timjami, rosmariini, suola, pippuri'],
'steps' => ['Kuullota sipuli ja valkosipuli.','Lisää kasvikset ja sekoittele 5 min.','Kaada liemi ja tomaatit, lisää yrtit.','Hauduta 25 min.','Lisää kesäkurpitsa, keitä 10 min.','Mausta ja tarjoile.'],
],
[
'id' => 'knitting_scarf', 'emoji' => '🧶', 'title' => 'Helppo huivi aloittelijalle',
'category' => 'knitting', 'author' => 'Admin', 'type' => 'post',
'desc' => 'Neulo kaunis huivi muutamassa tunnissa — täydellinen ensimmäinen projekti!',
'body' => '<p><strong>Tarvitset:</strong></p><ul><li>Paksu lanka (noin 200 g)</li><li>Pyöröneulat nro 68</li></ul><p><strong>Ohje:</strong> Luo 20 silmukkaa. Neulo suoraan (edestakaisin oikein silmukoin) kunnes huivi on noin 150 cm pitkä. Päättele silmukat ja viimeistele päät. Valmis! 🎉</p><p>Vinkki: Paksuilla langoilla ja suurilla neuloilla saat huivista nopeasti valmiin, vaikka olisit aloittelija.</p>',
],
[
'id' => 'tip_morning', 'emoji' => '💡', 'title' => 'Rauhallinen aamurutiini',
'category' => 'tips', 'author' => 'Admin', 'type' => 'post',
'desc' => 'Pienet muutokset aamurutiiniin tekevät koko päivästä paremman.',
'body' => '<p>Kokeile näitä vinkkejä parempaan aamuun:</p><ul><li>🌅 Herää 15 minuuttia aiemmin kuin tarvitset</li><li>💧 Juo lasi vettä ennen kahvia</li><li>📵 Älä katso puhelinta heti herätessä</li><li>🚶 Pieni lenkki tai venyttely ennen päivää</li></ul><p>Pienet muutokset, iso vaikutus!</p>',
],
];
}
function getOrInitPosts(): array {
if (!file_exists(DATA_DIR . 'posts.json')) {
$posts = defaultPosts();
writeData('posts.json', $posts);
return $posts;
}
return readData('posts.json', []);
}
function getOrInitCategories(): array {
if (!file_exists(DATA_DIR . 'categories.json')) {
$cats = defaultCategories();
writeData('categories.json', $cats);
return $cats;
}
return readData('categories.json', []);
}
// ─── Routing ───────────────────────────────────────────────────
switch ($action) {
case 'posts':
ok(['posts' => getOrInitPosts()]);
case 'categories':
ok(['categories' => getOrInitCategories()]);
case 'likes':
$likes = readData('likes.json', new stdClass());
$userLikes = $_SESSION['user_likes'] ?? [];
ok(['likes' => $likes, 'userLikes' => $userLikes]);
case 'toggle_like':
$postId = $body['postId'] ?? '';
if (!$postId) err('Missing postId');
$likes = readData('likes.json', []);
$userLikes = $_SESSION['user_likes'] ?? [];
$idx = array_search($postId, $userLikes, true);
if ($idx === false) {
$likes[$postId] = ($likes[$postId] ?? 0) + 1;
$userLikes[] = $postId;
$liked = true;
} else {
$likes[$postId] = max(0, ($likes[$postId] ?? 1) - 1);
array_splice($userLikes, $idx, 1);
$liked = false;
}
$_SESSION['user_likes'] = array_values($userLikes);
writeData('likes.json', $likes);
ok(['liked' => $liked, 'count' => $likes[$postId] ?? 0]);
case 'comments':
$postId = $_GET['postId'] ?? '';
$comments = readData('comments.json', []);
ok(['comments' => $comments[$postId] ?? []]);
case 'add_comment':
$postId = $body['postId'] ?? '';
$name = trim($body['name'] ?? '');
$text = trim($body['text'] ?? '');
if (!$postId || !$name || !$text) err('Missing fields');
$now = time();
$win = 10 * 60;
$times = array_values(array_filter($_SESSION['comment_times'] ?? [], fn($t) => $now - $t < $win));
if (count($times) >= 3) err('Liian monta kommenttia. Odota hetki.');
$times[] = $now;
$_SESSION['comment_times'] = $times;
$comments = readData('comments.json', []);
if (!isset($comments[$postId])) $comments[$postId] = [];
$comment = [
'name' => htmlspecialchars($name, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
'text' => htmlspecialchars($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
'time' => date('d.m.Y'),
];
$comments[$postId][] = $comment;
writeData('comments.json', $comments);
ok(['comment' => $comment]);
case 'add_post':
$post = $body['post'] ?? [];
if (empty($post['title'])) err('Missing title');
$post['id'] = preg_replace('/[^a-z0-9_]/', '', strtolower($post['id'] ?? '')) ?: 'post_' . time();
$posts = getOrInitPosts();
$posts[] = $post;
writeData('posts.json', $posts);
ok();
case 'update_post':
if (!isAdmin()) err('Unauthorized', 403);
$post = $body['post'] ?? [];
if (empty($post['id'])) err('Missing id');
$posts = getOrInitPosts();
foreach ($posts as &$p) {
if ($p['id'] === $post['id']) { $p = $post; break; }
}
unset($p);
writeData('posts.json', $posts);
ok();
case 'delete_post':
if (!isAdmin()) err('Unauthorized', 403);
$id = $body['id'] ?? '';
if (!$id) err('Missing id');
$posts = array_values(array_filter(getOrInitPosts(), fn($p) => ($p['id'] ?? '') !== $id));
writeData('posts.json', $posts);
ok();
case 'save_categories':
if (!isAdmin()) err('Unauthorized', 403);
writeData('categories.json', $body['categories'] ?? []);
ok();
case 'admin_login':
if (($body['password'] ?? '') === ADMIN_PASSWORD) {
$_SESSION['tykkaafi_admin'] = true;
ok();
}
err('Väärä salasana');
case 'admin_logout':
$_SESSION['tykkaafi_admin'] = false;
ok();
case 'admin_check':
ok(['loggedIn' => isAdmin()]);
default:
err('Unknown action');
}