added bootstar, font awsome, and the project is in a useable state, bit needs some manual setup.
This commit is contained in:
321
ProjectKiln/api/version.php
Normal file
321
ProjectKiln/api/version.php
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user