added bootstar, font awsome, and the project is in a useable state, bit needs some manual setup.

This commit is contained in:
2026-06-13 23:11:54 +02:00
parent 4cf12c378e
commit 9045841645
5886 changed files with 538083 additions and 99 deletions

321
ProjectKiln/api/version.php Normal file
View File

@@ -0,0 +1,321 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../auth.php';
header('Content-Type: application/json; charset=utf-8');
function jsonResponse(array $data, int $status = 200): void
{
http_response_code($status);
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
function getInputData(): array
{
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (str_contains($contentType, 'application/json')) {
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
return is_array($data) ? $data : [];
}
return $_POST;
}
function normalizeDateValue(mixed $value, string $fieldName): ?string
{
$value = trim((string)$value);
if ($value === '') {
return null;
}
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
jsonResponse([
'success' => false,
'error' => "Invalid {$fieldName}. Use YYYY-MM-DD."
], 400);
}
return $value;
}
function requireProjectAccess(string $projectId, int $userId): void
{
requireProjectAccessForUser($userId, $projectId);
}
$user = requireApiAuth();
$api = $_GET['api'] ?? '';
switch ($api) {
case 'ListVersions': {
$projectId = strtoupper(trim($_GET['project_id'] ?? ''));
if ($projectId === '') {
jsonResponse([
'success' => false,
'error' => 'Missing project_id.'
], 400);
}
requireProjectAccess($projectId, (int)$user['id']);
$stmt = db()->prepare(
'SELECT id
FROM versions
WHERE project = ?
ORDER BY created_date DESC, id DESC'
);
$stmt->execute([$projectId]);
jsonResponse([
'success' => true,
'versions' => array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN))
]);
}
case 'VersionInfo': {
$versionId = (int)($_GET['version_id'] ?? 0);
if ($versionId <= 0) {
jsonResponse([
'success' => false,
'error' => 'Missing or invalid version_id.'
], 400);
}
$stmt = db()->prepare(
'SELECT
versions.id,
versions.name,
versions.description,
versions.created_date,
versions.due_date,
versions.released_date,
versions.project
FROM versions
INNER JOIN projects ON projects.id = versions.project
WHERE versions.id = ?
LIMIT 1'
);
$stmt->execute([$versionId]);
$version = $stmt->fetch();
if (!$version) {
jsonResponse([
'success' => false,
'error' => 'Version not found.'
], 404);
}
requireProjectAccessForUser((int)$user['id'], (string)$version['project']);
jsonResponse([
'success' => true,
'version' => $version
]);
}
case 'Create': {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonResponse([
'success' => false,
'error' => 'Create requires POST.'
], 405);
}
$data = getInputData();
$projectId = strtoupper(trim($data['project_id'] ?? $data['project'] ?? ''));
$name = trim($data['name'] ?? '');
$description = array_key_exists('description', $data) ? trim((string)$data['description']) : null;
$dueDate = array_key_exists('due_date', $data) ? normalizeDateValue($data['due_date'], 'due_date') : null;
$releasedDate = array_key_exists('released_date', $data) ? normalizeDateValue($data['released_date'], 'released_date') : null;
if ($projectId === '') {
jsonResponse([
'success' => false,
'error' => 'Project id is required.'
], 400);
}
requireProjectRight((int)$user['id'], $projectId, 'Create Versions');
if ($name === '') {
jsonResponse([
'success' => false,
'error' => 'Version name is required.'
], 400);
}
if (strlen($name) > 128) {
jsonResponse([
'success' => false,
'error' => 'Version name is too long.'
], 400);
}
$stmt = db()->prepare(
'INSERT INTO versions
(name, description, created_date, due_date, released_date, project)
VALUES (?, ?, CURDATE(), ?, ?, ?)'
);
$stmt->execute([
$name,
$description,
$dueDate,
$releasedDate,
$projectId
]);
jsonResponse([
'success' => true,
'version_id' => (int)db()->lastInsertId()
], 201);
}
case 'Edit': {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonResponse([
'success' => false,
'error' => 'Edit requires POST.'
], 405);
}
$versionId = (int)($_GET['version_id'] ?? 0);
if ($versionId <= 0) {
jsonResponse([
'success' => false,
'error' => 'Missing or invalid version_id.'
], 400);
}
$data = getInputData();
$projectStmt = db()->prepare(
'SELECT project
FROM versions
WHERE id = ?
LIMIT 1'
);
$projectStmt->execute([$versionId]);
$versionProject = $projectStmt->fetchColumn();
if (!$versionProject) {
jsonResponse([
'success' => false,
'error' => 'Version not found.'
], 404);
}
requireProjectRight((int)$user['id'], (string)$versionProject, 'Edit Versions');
$fields = [];
$values = [];
if (array_key_exists('name', $data)) {
$name = trim((string)$data['name']);
if ($name === '') {
jsonResponse([
'success' => false,
'error' => 'Version name cannot be empty.'
], 400);
}
if (strlen($name) > 128) {
jsonResponse([
'success' => false,
'error' => 'Version name is too long.'
], 400);
}
$fields[] = 'versions.name = ?';
$values[] = $name;
}
if (array_key_exists('description', $data)) {
$description = trim((string)$data['description']);
$fields[] = 'versions.description = ?';
$values[] = $description !== '' ? $description : null;
}
if (array_key_exists('due_date', $data)) {
$fields[] = 'versions.due_date = ?';
$values[] = normalizeDateValue($data['due_date'], 'due_date');
}
if (array_key_exists('released_date', $data)) {
$fields[] = 'versions.released_date = ?';
$values[] = normalizeDateValue($data['released_date'], 'released_date');
}
if (empty($fields)) {
jsonResponse([
'success' => false,
'error' => 'No editable fields provided.'
], 400);
}
$values[] = $versionId;
$stmt = db()->prepare(
'UPDATE versions
INNER JOIN projects ON projects.id = versions.project
SET ' . implode(', ', $fields) . '
WHERE versions.id = ?'
);
$stmt->execute($values);
if ($stmt->rowCount() === 0) {
$existsStmt = db()->prepare(
'SELECT versions.id
FROM versions
INNER JOIN projects ON projects.id = versions.project
WHERE versions.id = ?
LIMIT 1'
);
$existsStmt->execute([$versionId]);
if ($existsStmt->fetch()) {
jsonResponse([
'success' => true,
'version_id' => $versionId
]);
}
jsonResponse([
'success' => false,
'error' => 'Version not found.'
], 404);
}
jsonResponse([
'success' => true,
'version_id' => $versionId
]);
}
default: {
jsonResponse([
'success' => false,
'error' => 'Unknown API action.'
], 404);
}
}