146 lines
5.1 KiB
PHP
146 lines
5.1 KiB
PHP
<?php
|
||
require __DIR__ . '/../session.php';
|
||
require __DIR__ . '/../db.php';
|
||
start_app_session();
|
||
|
||
header('Content-Type: application/json');
|
||
|
||
$pdo = getDbConnection();
|
||
enforce_session_version($pdo);
|
||
|
||
if (!isset($_SESSION['user_id'])) {
|
||
http_response_code(401);
|
||
echo json_encode(['error' => 'Not authenticated']);
|
||
exit;
|
||
}
|
||
|
||
function fetchOwnedCritter(PDO $pdo, int $userId, int $critterId): array|false
|
||
{
|
||
$stmt = $pdo->prepare('
|
||
SELECT c.id AS id, c.isFavorite AS isFavorite, c.isArchived AS isArchived,
|
||
c.adjective_id AS adjective_id, c.noun_id AS noun_id, c.verb_id AS verb_id, c.location_id AS location_id,
|
||
a.value AS adjective, n.value AS noun, v.value AS verb, l.value AS location, c.image AS image
|
||
FROM critters c
|
||
JOIN adjectives a ON a.id = c.adjective_id
|
||
JOIN nouns n ON n.id = c.noun_id
|
||
JOIN verbs v ON v.id = c.verb_id
|
||
JOIN locations l ON l.id = c.location_id
|
||
WHERE c.id = :id AND c.author_id = :author_id
|
||
');
|
||
$stmt->execute(['id' => $critterId, 'author_id' => $userId]);
|
||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||
}
|
||
|
||
$method = $_SERVER['REQUEST_METHOD'];
|
||
$critterId = $method === 'POST'
|
||
? filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT)
|
||
: filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
||
|
||
if (!$critterId) {
|
||
http_response_code(400);
|
||
echo json_encode(['error' => 'Invalid critter id']);
|
||
exit;
|
||
}
|
||
|
||
$critter = fetchOwnedCritter($pdo, (int) $_SESSION['user_id'], $critterId);
|
||
|
||
if (!$critter) {
|
||
http_response_code(404);
|
||
echo json_encode(['error' => 'Critter not found']);
|
||
exit;
|
||
}
|
||
|
||
if ($method === 'POST' && !csrf_verify($_POST['csrf_token'] ?? null)) {
|
||
http_response_code(403);
|
||
echo json_encode(['error' => 'Invalid CSRF token']);
|
||
exit;
|
||
}
|
||
|
||
if ($method === 'POST') {
|
||
$action = $_POST['action'] ?? '';
|
||
|
||
if ($action === 'toggle_favorite') {
|
||
$newValue = $critter['isFavorite'] ? 0 : 1;
|
||
$stmt = $pdo->prepare('UPDATE critters SET isFavorite = :value WHERE id = :id');
|
||
$stmt->execute(['value' => $newValue, 'id' => $critterId]);
|
||
$critter['isFavorite'] = $newValue;
|
||
} elseif ($action === 'toggle_archived') {
|
||
$newValue = $critter['isArchived'] ? 0 : 1;
|
||
$stmt = $pdo->prepare('UPDATE critters SET isArchived = :value WHERE id = :id');
|
||
$stmt->execute(['value' => $newValue, 'id' => $critterId]);
|
||
$critter['isArchived'] = $newValue;
|
||
}
|
||
}
|
||
|
||
$flourishes = [
|
||
'Always up for a new adventure!',
|
||
'This one has a real personality.',
|
||
'Ready to make new friends.',
|
||
"There's never a dull moment with this critter.",
|
||
'One of a kind, through and through.',
|
||
'A firm favorite in the collection.',
|
||
'Full of charm and curiosity.',
|
||
];
|
||
$flourish = $flourishes[array_rand($flourishes)];
|
||
$description = 'A ' . $critter['adjective'] . ' ' . $critter['noun'] . ' who ' . $critter['verb'] . ' ' . $critter['location'] . '. ' . $flourish;
|
||
$prompt = "A {$critter['adjective']} {$critter['noun']} {$critter['verb']} {$critter['location']} in a high quality 3d animation art style. The image should be vibrant and colorful, capturing the essence of the action and setting.";
|
||
|
||
$rarityTiers = [
|
||
['label' => 'Common', 'classes' => 'bg-pink-100 text-pink-700'],
|
||
['label' => 'Rare', 'classes' => 'bg-blue-100 text-blue-700'],
|
||
['label' => 'Legendary', 'classes' => 'bg-amber-100 text-amber-700'],
|
||
];
|
||
$rarityRoll = $critter['id'] % 10;
|
||
if ($rarityRoll >= 9) {
|
||
$rarity = $rarityTiers[2];
|
||
} elseif ($rarityRoll >= 6) {
|
||
$rarity = $rarityTiers[1];
|
||
} else {
|
||
$rarity = $rarityTiers[0];
|
||
}
|
||
|
||
$resolution = null;
|
||
$fileSize = null;
|
||
$createdAt = null;
|
||
|
||
if (!empty($critter['image'])) {
|
||
$imagePath = __DIR__ . '/../critter-images/' . $critter['image'];
|
||
if (is_file($imagePath)) {
|
||
$dimensions = @getimagesize($imagePath);
|
||
if ($dimensions) {
|
||
$resolution = $dimensions[0] . ' × ' . $dimensions[1];
|
||
}
|
||
$bytes = @filesize($imagePath);
|
||
if ($bytes !== false) {
|
||
$fileSize = round($bytes / 1024) . ' KB';
|
||
}
|
||
$mtime = @filemtime($imagePath);
|
||
if ($mtime !== false) {
|
||
$createdAt = date('j M Y, H:i', $mtime);
|
||
}
|
||
}
|
||
}
|
||
|
||
echo json_encode([
|
||
'id' => (int) $critter['id'],
|
||
'title' => ucwords($critter['adjective'] . ' ' . $critter['noun']),
|
||
'adjective' => ucfirst($critter['adjective']),
|
||
'noun' => ucfirst($critter['noun']),
|
||
'verb' => ucfirst($critter['verb']),
|
||
'location' => ucfirst($critter['location']),
|
||
'isFavorite' => (bool) $critter['isFavorite'],
|
||
'isArchived' => (bool) $critter['isArchived'],
|
||
'rarity' => $rarity,
|
||
'description' => $description,
|
||
'prompt' => $prompt,
|
||
'createdAt' => $createdAt,
|
||
'resolution' => $resolution,
|
||
'fileSize' => $fileSize,
|
||
'imageUrl' => $critter['image'] ? 'critter-images/' . $critter['image'] : null,
|
||
'shareUrl' => 'single-critter.php?id=' . $critter['id'],
|
||
'createSimilarUrl' => 'create-critter.php?adjective_id=' . $critter['adjective_id']
|
||
. '&noun_id=' . $critter['noun_id']
|
||
. '&verb_id=' . $critter['verb_id']
|
||
. '&location_id=' . $critter['location_id'],
|
||
]);
|