refactor: split API routes into separate files
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 15s
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 15s
Reorganize routes following design-to-pack pattern: - routes/markers.php: CRUD operations for markers - routes/position.php: Position update (single mode) - routes/image.php: Image capture and regeneration flag management Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9193ac8900
commit
590c842072
5 changed files with 619 additions and 656 deletions
|
|
@ -1,655 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* API Routes for Map Editor Plugin
|
||||
*
|
||||
* Provides CRUD operations for marker subpages
|
||||
*/
|
||||
|
||||
return [
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers',
|
||||
'method' => 'GET',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
// For Panel requests, we trust the session is valid
|
||||
// The Panel itself already requires authentication
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Get the map page
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can read the page
|
||||
if (!$mapPage->isReadable()) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Get all marker subpages, listed only, sorted by num
|
||||
$markerPages = $mapPage
|
||||
->children()
|
||||
->listed()
|
||||
->filterBy('intendedTemplate', 'marker')
|
||||
->sortBy('num', 'asc');
|
||||
|
||||
// Format markers for response
|
||||
$markers = [];
|
||||
foreach ($markerPages as $marker) {
|
||||
// Get custom icon if available
|
||||
$iconFile = $marker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
|
||||
// Get icon size if set
|
||||
$iconSize = $marker->markerIconSize()->isNotEmpty()
|
||||
? (int) $marker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
$markers[] = [
|
||||
'id' => $marker->id(),
|
||||
'slug' => $marker->slug(),
|
||||
'title' => $marker->title()->value(),
|
||||
'position' => [
|
||||
'lat' => (float) $marker->latitude()->value(),
|
||||
'lon' => (float) $marker->longitude()->value()
|
||||
],
|
||||
'num' => $marker->num(),
|
||||
'panelUrl' => (string) $marker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'markers' => $markers
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers',
|
||||
'method' => 'POST',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
// For Panel requests, we trust the session is valid
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Note: CSRF verification skipped for Panel session requests
|
||||
// The Panel session itself is already authenticated and secure
|
||||
|
||||
// Get the map page
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can create children
|
||||
if (!$mapPage->permissions()->can('create')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Get position from request body
|
||||
// Use data() instead of body() - Kirby automatically parses JSON
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['position']['lat']) || !isset($data['position']['lon'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Position (lat, lon) is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['position']['lat'];
|
||||
$lon = (float) $data['position']['lon'];
|
||||
|
||||
// Validate coordinates
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Get existing markers to determine next num
|
||||
$existingMarkers = $mapPage
|
||||
->children()
|
||||
->filterBy('intendedTemplate', 'marker');
|
||||
$nextNum = $existingMarkers->count() + 1;
|
||||
|
||||
// Generate title and slug based on title
|
||||
$title = 'Marqueur ' . $nextNum;
|
||||
$slug = Str::slug($title);
|
||||
|
||||
// Create the new marker page
|
||||
$newMarker = $mapPage->createChild([
|
||||
'slug' => $slug,
|
||||
'template' => 'marker',
|
||||
'content' => [
|
||||
'title' => $title,
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]
|
||||
]);
|
||||
|
||||
// Publish the page as listed with the correct num
|
||||
$newMarker->changeStatus('listed', $nextNum);
|
||||
|
||||
// Get custom icon if available (new markers won't have one initially)
|
||||
$iconFile = $newMarker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
$iconSize = $newMarker->markerIconSize()->isNotEmpty()
|
||||
? (int) $newMarker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'marker' => [
|
||||
'id' => $newMarker->id(),
|
||||
'slug' => $newMarker->slug(),
|
||||
'title' => $title,
|
||||
'position' => [
|
||||
'lat' => $lat,
|
||||
'lon' => $lon
|
||||
],
|
||||
'num' => $nextNum,
|
||||
'panelUrl' => (string) $newMarker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers/(:all)',
|
||||
'method' => 'PATCH',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId, string $markerId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Note: CSRF verification skipped for Panel session requests
|
||||
// The Panel session itself is already authenticated and secure
|
||||
|
||||
// Get the marker page
|
||||
$marker = kirby()->page($markerId);
|
||||
if (!$marker) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Marker not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can update the page
|
||||
if (!$marker->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Get position from request body
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['position']['lat']) || !isset($data['position']['lon'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Position (lat, lon) is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['position']['lat'];
|
||||
$lon = (float) $data['position']['lon'];
|
||||
|
||||
// Validate coordinates
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Update the marker position
|
||||
$marker->update([
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]);
|
||||
|
||||
// Get custom icon if available
|
||||
$iconFile = $marker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
$iconSize = $marker->markerIconSize()->isNotEmpty()
|
||||
? (int) $marker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'marker' => [
|
||||
'id' => $marker->id(),
|
||||
'slug' => $marker->slug(),
|
||||
'title' => $marker->title()->value(),
|
||||
'position' => [
|
||||
'lat' => $lat,
|
||||
'lon' => $lon
|
||||
],
|
||||
'num' => $marker->num(),
|
||||
'panelUrl' => (string) $marker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers/(:all)',
|
||||
'method' => 'DELETE',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId, string $markerId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Note: CSRF verification skipped for Panel session requests
|
||||
// The Panel session itself is already authenticated and secure
|
||||
|
||||
// Get the marker page
|
||||
$marker = kirby()->page($markerId);
|
||||
if (!$marker) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Marker not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can delete the page
|
||||
if (!$marker->permissions()->can('delete')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Delete the marker page
|
||||
$marker->delete(true); // true = force delete
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Marker deleted successfully'
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/position',
|
||||
'method' => 'PATCH',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Note: CSRF verification skipped for Panel session requests
|
||||
// The Panel session itself is already authenticated and secure
|
||||
|
||||
// Get the page (marker page in single mode)
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can update the page
|
||||
if (!$page->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Get coordinates from request body
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['latitude']) || !isset($data['longitude'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Latitude and longitude are required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['latitude'];
|
||||
$lon = (float) $data['longitude'];
|
||||
|
||||
// Validate coordinates
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Update the page position
|
||||
$page->update([
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/capture-image',
|
||||
'method' => 'POST',
|
||||
'auth' => false, // Allow Panel session auth
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
// Get user from session (Panel context)
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
// Get the map page
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
// Check if user can update the page
|
||||
if (!$mapPage->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
// Get image data from request
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['image'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Image data is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Extract base64 data (remove data:image/png;base64, prefix)
|
||||
$imageData = $data['image'];
|
||||
if (preg_match('/^data:image\/(png|jpeg|jpg);base64,(.+)$/', $imageData, $matches)) {
|
||||
$imageData = $matches[2];
|
||||
$extension = $matches[1] === 'jpeg' ? 'jpg' : $matches[1];
|
||||
} else {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid image format',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Decode base64
|
||||
$decodedImage = base64_decode($imageData);
|
||||
if ($decodedImage === false) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to decode image',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
// Create temporary file
|
||||
$filename = 'map-static.' . $extension;
|
||||
$tempPath = sys_get_temp_dir() . '/' . uniqid() . '.' . $extension;
|
||||
file_put_contents($tempPath, $decodedImage);
|
||||
|
||||
// Delete existing map-static file if it exists
|
||||
$existingFile = $mapPage->files()->filterBy('name', 'map-static')->first();
|
||||
if ($existingFile) {
|
||||
$existingFile->delete();
|
||||
}
|
||||
|
||||
// Create file using Kirby API (so it's properly indexed)
|
||||
try {
|
||||
$file = $mapPage->createFile([
|
||||
'source' => $tempPath,
|
||||
'filename' => $filename
|
||||
]);
|
||||
|
||||
// Clean up temp file
|
||||
@unlink($tempPath);
|
||||
} catch (Exception $e) {
|
||||
@unlink($tempPath);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Image saved successfully',
|
||||
'filename' => $filename,
|
||||
'path' => $filepath
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/check-regenerate-flag',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
$markerFile = $page->root() . '/.regenerate-map-image';
|
||||
$needsRegeneration = file_exists($markerFile);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'needsRegeneration' => $needsRegeneration
|
||||
]
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/clear-regenerate-flag',
|
||||
'method' => 'DELETE',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
$markerFile = $page->root() . '/.regenerate-map-image';
|
||||
if (file_exists($markerFile)) {
|
||||
unlink($markerFile);
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Flag cleared'
|
||||
]
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
|
|
@ -50,7 +50,11 @@ Kirby::plugin('geoproject/map-editor', [
|
|||
]
|
||||
],
|
||||
'api' => [
|
||||
'routes' => require __DIR__ . '/api/routes.php'
|
||||
'routes' => [
|
||||
require __DIR__ . '/routes/markers.php',
|
||||
require __DIR__ . '/routes/position.php',
|
||||
require __DIR__ . '/routes/image.php',
|
||||
]
|
||||
],
|
||||
'hooks' => [
|
||||
'page.update:after' => function ($newPage, $oldPage) {
|
||||
|
|
|
|||
185
public/site/plugins/map-editor/routes/image.php
Normal file
185
public/site/plugins/map-editor/routes/image.php
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Image Capture Routes
|
||||
* POST for capturing map image, GET/DELETE for regeneration flag
|
||||
*/
|
||||
|
||||
return [
|
||||
// POST capture and save map image
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/capture-image',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$mapPage->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['image'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Image data is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$imageData = $data['image'];
|
||||
if (preg_match('/^data:image\/(png|jpeg|jpg);base64,(.+)$/', $imageData, $matches)) {
|
||||
$imageData = $matches[2];
|
||||
$extension = $matches[1] === 'jpeg' ? 'jpg' : $matches[1];
|
||||
} else {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid image format',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$decodedImage = base64_decode($imageData);
|
||||
if ($decodedImage === false) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to decode image',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$filename = 'map-static.' . $extension;
|
||||
$tempPath = sys_get_temp_dir() . '/' . uniqid() . '.' . $extension;
|
||||
file_put_contents($tempPath, $decodedImage);
|
||||
|
||||
$existingFile = $mapPage->files()->filterBy('name', 'map-static')->first();
|
||||
if ($existingFile) {
|
||||
$existingFile->delete();
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $mapPage->createFile([
|
||||
'source' => $tempPath,
|
||||
'filename' => $filename
|
||||
]);
|
||||
|
||||
@unlink($tempPath);
|
||||
} catch (Exception $e) {
|
||||
@unlink($tempPath);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Image saved successfully',
|
||||
'filename' => $filename,
|
||||
'path' => $file->root()
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// GET check if regeneration flag exists
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/check-regenerate-flag',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
$markerFile = $page->root() . '/.regenerate-map-image';
|
||||
$needsRegeneration = file_exists($markerFile);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'needsRegeneration' => $needsRegeneration
|
||||
]
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// DELETE clear regeneration flag
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/clear-regenerate-flag',
|
||||
'method' => 'DELETE',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
$markerFile = $page->root() . '/.regenerate-map-image';
|
||||
if (file_exists($markerFile)) {
|
||||
unlink($markerFile);
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Flag cleared'
|
||||
]
|
||||
];
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
346
public/site/plugins/map-editor/routes/markers.php
Normal file
346
public/site/plugins/map-editor/routes/markers.php
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Markers CRUD Routes
|
||||
* GET, POST, PATCH, DELETE operations for markers
|
||||
*/
|
||||
|
||||
return [
|
||||
// GET all markers for a map page
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$mapPage->isReadable()) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$markerPages = $mapPage
|
||||
->children()
|
||||
->listed()
|
||||
->filterBy('intendedTemplate', 'marker')
|
||||
->sortBy('num', 'asc');
|
||||
|
||||
$markers = [];
|
||||
foreach ($markerPages as $marker) {
|
||||
$iconFile = $marker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
$iconSize = $marker->markerIconSize()->isNotEmpty()
|
||||
? (int) $marker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
$markers[] = [
|
||||
'id' => $marker->id(),
|
||||
'slug' => $marker->slug(),
|
||||
'title' => $marker->title()->value(),
|
||||
'position' => [
|
||||
'lat' => (float) $marker->latitude()->value(),
|
||||
'lon' => (float) $marker->longitude()->value()
|
||||
],
|
||||
'num' => $marker->num(),
|
||||
'panelUrl' => (string) $marker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'markers' => $markers
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// POST create new marker
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$mapPage = kirby()->page($pageId);
|
||||
if (!$mapPage) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Map page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$mapPage->permissions()->can('create')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['position']['lat']) || !isset($data['position']['lon'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Position (lat, lon) is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['position']['lat'];
|
||||
$lon = (float) $data['position']['lon'];
|
||||
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$existingMarkers = $mapPage
|
||||
->children()
|
||||
->filterBy('intendedTemplate', 'marker');
|
||||
$nextNum = $existingMarkers->count() + 1;
|
||||
|
||||
$title = 'Marqueur ' . $nextNum;
|
||||
$slug = Str::slug($title);
|
||||
|
||||
$newMarker = $mapPage->createChild([
|
||||
'slug' => $slug,
|
||||
'template' => 'marker',
|
||||
'content' => [
|
||||
'title' => $title,
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]
|
||||
]);
|
||||
|
||||
$newMarker->changeStatus('listed', $nextNum);
|
||||
|
||||
$iconFile = $newMarker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
$iconSize = $newMarker->markerIconSize()->isNotEmpty()
|
||||
? (int) $newMarker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'marker' => [
|
||||
'id' => $newMarker->id(),
|
||||
'slug' => $newMarker->slug(),
|
||||
'title' => $title,
|
||||
'position' => [
|
||||
'lat' => $lat,
|
||||
'lon' => $lon
|
||||
],
|
||||
'num' => $nextNum,
|
||||
'panelUrl' => (string) $newMarker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// PATCH update marker position
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers/(:all)',
|
||||
'method' => 'PATCH',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId, string $markerId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$marker = kirby()->page($markerId);
|
||||
if (!$marker) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Marker not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$marker->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['position']['lat']) || !isset($data['position']['lon'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Position (lat, lon) is required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['position']['lat'];
|
||||
$lon = (float) $data['position']['lon'];
|
||||
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$marker->update([
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]);
|
||||
|
||||
$iconFile = $marker->markerIcon()->toFile();
|
||||
$iconUrl = $iconFile ? $iconFile->url() : null;
|
||||
$iconSize = $marker->markerIconSize()->isNotEmpty()
|
||||
? (int) $marker->markerIconSize()->value()
|
||||
: 40;
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'marker' => [
|
||||
'id' => $marker->id(),
|
||||
'slug' => $marker->slug(),
|
||||
'title' => $marker->title()->value(),
|
||||
'position' => [
|
||||
'lat' => $lat,
|
||||
'lon' => $lon
|
||||
],
|
||||
'num' => $marker->num(),
|
||||
'panelUrl' => (string) $marker->panel()->url(),
|
||||
'iconUrl' => $iconUrl,
|
||||
'iconSize' => $iconSize
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// DELETE marker
|
||||
[
|
||||
'pattern' => 'map-editor/pages/(:all)/markers/(:all)',
|
||||
'method' => 'DELETE',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId, string $markerId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$marker = kirby()->page($markerId);
|
||||
if (!$marker) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Marker not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$marker->permissions()->can('delete')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$marker->delete(true);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'message' => 'Marker deleted successfully'
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
83
public/site/plugins/map-editor/routes/position.php
Normal file
83
public/site/plugins/map-editor/routes/position.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Position Update Route
|
||||
* PATCH route for updating page position (single mode)
|
||||
*/
|
||||
|
||||
return [
|
||||
'pattern' => 'map-editor/pages/(:all)/position',
|
||||
'method' => 'PATCH',
|
||||
'auth' => false,
|
||||
'action' => function (string $pageId) {
|
||||
try {
|
||||
$user = kirby()->user();
|
||||
|
||||
if (!$user && !kirby()->option('debug', false)) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Unauthorized',
|
||||
'code' => 401
|
||||
];
|
||||
}
|
||||
|
||||
$page = kirby()->page($pageId);
|
||||
if (!$page) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Page not found',
|
||||
'code' => 404
|
||||
];
|
||||
}
|
||||
|
||||
if (!$page->permissions()->can('update')) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
'code' => 403
|
||||
];
|
||||
}
|
||||
|
||||
$data = kirby()->request()->data();
|
||||
|
||||
if (!isset($data['latitude']) || !isset($data['longitude'])) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Latitude and longitude are required',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$lat = (float) $data['latitude'];
|
||||
$lon = (float) $data['longitude'];
|
||||
|
||||
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid coordinates',
|
||||
'code' => 400
|
||||
];
|
||||
}
|
||||
|
||||
$page->update([
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'latitude' => $lat,
|
||||
'longitude' => $lon
|
||||
]
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 500
|
||||
];
|
||||
}
|
||||
}
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue