Files
MSPE/api/portfolio.php
T

270 lines
8.0 KiB
PHP
Executable File

<?php
/**
* MSPE Portfolio API
*/
require_once 'config.php';
$method = $_SERVER['REQUEST_METHOD'];
$id = $_GET['id'] ?? null;
// CSRF protection for write operations
if ($method !== 'GET') {
requireSameOriginRequest();
}
switch ($method) {
case 'GET':
if ($id) {
getProject($id);
} else {
getProjects();
}
break;
case 'POST':
requireAuth();
if (!empty($_POST['id'])) {
updateProject($_POST['id']);
} else {
createProject();
}
break;
case 'PUT':
requireAuth();
if (!$id) {
jsonResponse(['success' => false, 'message' => 'Project ID required'], 400);
}
updateProject($id);
break;
case 'DELETE':
requireAuth();
if (!$id) {
jsonResponse(['success' => false, 'message' => 'Project ID required'], 400);
}
deleteProject($id);
break;
default:
jsonResponse(['success' => false, 'message' => 'Method not allowed'], 405);
}
function getProjects() {
global $db;
$projects = $db->getAll('portfolio');
// Apply filters
$category = $_GET['category'] ?? null;
$featured = $_GET['featured'] ?? null;
$limit = (int)($_GET['limit'] ?? 20);
$offset = (int)($_GET['offset'] ?? 0);
if ($category) {
$projects = array_filter($projects, function($p) use ($category) {
return $p['category'] === $category;
});
}
if ($featured !== null) {
$projects = array_filter($projects, function($p) use ($featured) {
return ($p['featured'] ?? false) == ($featured === 'true' || $featured === '1');
});
}
// Public view: only published/active projects
if (!checkAuth()) {
$projects = array_filter($projects, function($p) {
return ($p['status'] ?? 'published') === 'published';
});
}
// Sort by order or date
usort($projects, function($a, $b) {
$orderA = $a['order'] ?? 999;
$orderB = $b['order'] ?? 999;
if ($orderA !== $orderB) {
return $orderA - $orderB;
}
return strtotime($b['created_at']) - strtotime($a['created_at']);
});
$total = count($projects);
$projects = array_slice(array_values($projects), $offset, $limit);
jsonResponse([
'success' => true,
'data' => $projects,
'total' => $total,
'limit' => $limit,
'offset' => $offset
]);
}
function getProject($id) {
global $db;
$project = $db->get('portfolio', $id);
if (!$project) {
jsonResponse(['success' => false, 'message' => 'Project not found'], 404);
}
jsonResponse([
'success' => true,
'data' => $project
]);
}
function createProject() {
global $db;
// Handle multipart form data or JSON
if (!empty($_FILES)) {
$data = $_POST;
} else {
$data = getRequestBody();
}
// Validate required fields
if (empty($data['title'])) {
jsonResponse(['success' => false, 'message' => 'Title is required'], 400);
}
// Sanitize text fields (allow HTML in description)
$data['title'] = sanitize($data['title']);
$data['category'] = sanitize($data['category'] ?? '');
$data['client'] = sanitize($data['client'] ?? '');
$data['technologies'] = sanitize($data['technologies'] ?? '');
// Sanitize description: allow only safe formatting tags
$data['description'] = sanitizeRichText($data['description'] ?? '');
// Handle image upload
if (!empty($_FILES['image'])) {
$upload = handleFileUpload($_FILES['image'], 'portfolio');
if ($upload['success']) {
$data['image'] = $upload['path'];
}
}
// Parse results JSON (JS sends as a serialised string)
$data['results'] = json_decode($data['results'] ?? '[]', true) ?? [];
// Gallery: merge existing-keep list + newly uploaded files
$gallery = json_decode($_POST['gallery_keep'] ?? '[]', true) ?? [];
if (!empty($_FILES['gallery_images']['tmp_name'])) {
foreach ($_FILES['gallery_images']['tmp_name'] as $key => $tmpName) {
if ($_FILES['gallery_images']['error'][$key] !== UPLOAD_ERR_OK) continue;
$file = [
'name' => $_FILES['gallery_images']['name'][$key],
'type' => $_FILES['gallery_images']['type'][$key],
'tmp_name' => $tmpName,
'error' => $_FILES['gallery_images']['error'][$key],
'size' => $_FILES['gallery_images']['size'][$key],
];
$upload = handleFileUpload($file, 'portfolio');
if ($upload['success']) {
$gallery[] = $upload['path'];
}
}
}
$data['gallery'] = $gallery;
// Set defaults
$data['featured'] = $data['featured'] ?? false;
$data['order'] = (int)($data['order'] ?? 0);
$data['status'] = $data['status'] ?? 'published';
$project = $db->insert('portfolio', $data);
jsonResponse([
'success' => true,
'message' => 'Project created successfully',
'data' => $project
], 201);
}
function updateProject($id) {
global $db;
$existing = $db->get('portfolio', $id);
if (!$existing) {
jsonResponse(['success' => false, 'message' => 'Project not found'], 404);
}
// Handle multipart form data or JSON
if (!empty($_FILES)) {
$data = $_POST;
} else {
$data = getRequestBody();
}
// Handle image upload
if (!empty($_FILES['image'])) {
$upload = handleFileUpload($_FILES['image'], 'portfolio');
if ($upload['success']) {
$data['image'] = $upload['path'];
}
}
// Sanitize editable text fields
if (isset($data['title'])) $data['title'] = sanitize($data['title']);
if (isset($data['category'])) $data['category'] = sanitize($data['category']);
if (isset($data['client'])) $data['client'] = sanitize($data['client']);
if (isset($data['technologies'])) $data['technologies'] = sanitize($data['technologies']);
if (isset($data['description'])) $data['description'] = sanitizeRichText($data['description']);
// Parse results JSON
if (isset($data['results'])) {
$data['results'] = json_decode($data['results'], true) ?? $existing['results'] ?? [];
}
// Gallery: merge existing-keep list + newly uploaded files
if (array_key_exists('gallery_keep', $_POST)) {
$gallery = json_decode($_POST['gallery_keep'], true) ?? [];
if (!empty($_FILES['gallery_images']['tmp_name'])) {
foreach ($_FILES['gallery_images']['tmp_name'] as $key => $tmpName) {
if ($_FILES['gallery_images']['error'][$key] !== UPLOAD_ERR_OK) continue;
$file = [
'name' => $_FILES['gallery_images']['name'][$key],
'type' => $_FILES['gallery_images']['type'][$key],
'tmp_name' => $tmpName,
'error' => $_FILES['gallery_images']['error'][$key],
'size' => $_FILES['gallery_images']['size'][$key],
];
$upload = handleFileUpload($file, 'portfolio');
if ($upload['success']) {
$gallery[] = $upload['path'];
}
}
}
$data['gallery'] = $gallery;
}
$project = $db->update('portfolio', $id, $data);
jsonResponse([
'success' => true,
'message' => 'Project updated successfully',
'data' => $project
]);
}
function deleteProject($id) {
global $db;
$existing = $db->get('portfolio', $id);
if (!$existing) {
jsonResponse(['success' => false, 'message' => 'Project not found'], 404);
}
$db->delete('portfolio', $id);
jsonResponse([
'success' => true,
'message' => 'Project deleted successfully'
]);
}