added tasks handler
This commit is contained in:
@@ -17,7 +17,7 @@ require_once __DIR__ . '/db.php';
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Read Action Parameter and Route to correct Handler
|
||||
// Reads Action Parameter and Routes to correct Handler
|
||||
// ---------------------------------------------------------------------
|
||||
$input = get_input();
|
||||
$action = $input['action'] ?? '';
|
||||
@@ -59,6 +59,27 @@ switch ($action) {
|
||||
case 'update_comment':
|
||||
handle_update_comment($input);
|
||||
break;
|
||||
case 'read_tasks':
|
||||
handle_read_tasks($input);
|
||||
break;
|
||||
case 'create_task':
|
||||
handle_create_task($input);
|
||||
break;
|
||||
case 'update_task':
|
||||
handle_update_task($input);
|
||||
break;
|
||||
case 'delete_task':
|
||||
handle_delete_task($input);
|
||||
break;
|
||||
case 'complete_task':
|
||||
handle_complete_task($input);
|
||||
break;
|
||||
case 'verify_task':
|
||||
handle_verify_task($input);
|
||||
break;
|
||||
case 'read_leaderboard':
|
||||
handle_read_leaderboard($input);
|
||||
break;
|
||||
default:
|
||||
error_response('Unknown Action. Supported Actions are read, create, update, delete, vote.');
|
||||
}
|
||||
@@ -709,4 +730,387 @@ function handle_update_comment($input) {
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================
|
||||
// Action Handlers for Tasks
|
||||
// =====================================================================
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// READ TASKS: Loads Tasks as GeoJSON FeatureCollection
|
||||
// Required: municipality_id
|
||||
// Optional: status, browser_id
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_read_tasks($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['municipality_id']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
$sql = "SELECT *, ST_AsGeoJSON(geom) AS geojson
|
||||
FROM tasks
|
||||
WHERE municipality_id = :mid";
|
||||
$params = [':mid' => $input['municipality_id']];
|
||||
|
||||
// Status Filter
|
||||
$status = $input['status'] ?? 'visible';
|
||||
if ($status === 'visible') {
|
||||
$sql .= " AND status IN ('open', 'completed', 'verified')";
|
||||
} elseif ($status !== 'all') {
|
||||
$sql .= " AND status = :status";
|
||||
$params[':status'] = $status;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY created_at DESC";
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$rows = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
|
||||
// Builds GeoJSON FeatureCollection
|
||||
$features = [];
|
||||
foreach ($rows as $row) {
|
||||
$geometry = json_decode($row['geojson']);
|
||||
unset($row['geom'], $row['geojson']);
|
||||
$features[] = [
|
||||
'type' => 'Feature',
|
||||
'geometry' => $geometry,
|
||||
'properties' => $row
|
||||
];
|
||||
}
|
||||
|
||||
$result = [
|
||||
'type' => 'FeatureCollection',
|
||||
'features' => $features
|
||||
];
|
||||
|
||||
// User Votes for Tasks
|
||||
$browser_id = $input['browser_id'] ?? '';
|
||||
if ($browser_id !== '') {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT task_id, vote_type FROM votes
|
||||
WHERE browser_id = :bid AND task_id IS NOT NULL
|
||||
");
|
||||
$stmt->execute([':bid' => $browser_id]);
|
||||
$user_votes = [];
|
||||
foreach ($stmt->fetchAll() as $v) {
|
||||
$user_votes[$v['task_id']] = $v['vote_type'];
|
||||
}
|
||||
$result['user_votes'] = $user_votes;
|
||||
}
|
||||
|
||||
json_response($result);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// CREATE TASK: Inserts new Task with optional Photo
|
||||
// Required: municipality_id, geom, geom_type, category, title, author_name
|
||||
// Optional: description, browser_id, photo
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_create_task($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, [
|
||||
'municipality_id', 'geom', 'geom_type', 'category', 'title', 'author_name'
|
||||
]);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
$valid_geom_types = ['point', 'line', 'polygon'];
|
||||
if (!in_array($input['geom_type'], $valid_geom_types)) {
|
||||
error_response('Invalid Geometry Type.');
|
||||
}
|
||||
|
||||
$geojson = json_decode($input['geom']);
|
||||
if (!$geojson || !isset($geojson->type)) {
|
||||
error_response('Invalid GeoJSON.');
|
||||
}
|
||||
|
||||
// Handles optional Photo Upload
|
||||
$photo_path = null;
|
||||
if (isset($_FILES['photo']) && $_FILES['photo']['error'] === UPLOAD_ERR_OK) {
|
||||
$photo_path = handle_photo_upload($_FILES['photo']);
|
||||
if (!$photo_path) {
|
||||
error_response('Photo Upload failed. JPG, PNG, GIF and WebP up to 5 MB.');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO tasks
|
||||
(municipality_id, geom, geom_type, category, title, description, author_name, browser_id, photo_path)
|
||||
VALUES
|
||||
(:mid, ST_SetSRID(ST_GeomFromGeoJSON(:geom), 4326), :geom_type,
|
||||
:category, :title, :description, :author_name, :browser_id, :photo_path)
|
||||
");
|
||||
$stmt->execute([
|
||||
':mid' => $input['municipality_id'],
|
||||
':geom' => $input['geom'],
|
||||
':geom_type' => $input['geom_type'],
|
||||
':category' => $input['category'],
|
||||
':title' => $input['title'],
|
||||
':description' => $input['description'] ?? '',
|
||||
':author_name' => $input['author_name'],
|
||||
':browser_id' => $input['browser_id'] ?? null,
|
||||
':photo_path' => $photo_path
|
||||
]);
|
||||
|
||||
json_response([
|
||||
'message' => 'Task created successfully.',
|
||||
'task_id' => (int) $pdo->lastInsertId()
|
||||
], 201);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// UPDATE TASK: Updates existing Tasks or Status
|
||||
// Required: task_id
|
||||
// Optional: category, title, description, status, address
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_update_task($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['task_id']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
$updatable = ['category', 'title', 'description', 'status', 'address'];
|
||||
$set = [];
|
||||
$params = [':id' => $input['task_id']];
|
||||
|
||||
foreach ($updatable as $field) {
|
||||
if (isset($input[$field]) && $input[$field] !== '') {
|
||||
$set[] = "$field = :$field";
|
||||
$params[":$field"] = $input[$field];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($set)) {
|
||||
error_response('No Fields to update.');
|
||||
}
|
||||
|
||||
if (isset($params[':status'])) {
|
||||
$valid = ['pending', 'rejected', 'open', 'completed', 'verified'];
|
||||
if (!in_array($params[':status'], $valid)) {
|
||||
error_response('Invalid Status.');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE tasks SET " . implode(', ', $set) . " WHERE task_id = :id");
|
||||
$stmt->execute($params);
|
||||
json_response(['message' => 'Task updated successfully.']);
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// DELETE TASK: Removes existing Tasks
|
||||
// Required: task_id
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_delete_task($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['task_id']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM tasks WHERE task_id = :id");
|
||||
$stmt->execute([':id' => $input['task_id']]);
|
||||
json_response(['message' => 'Task deleted successfully.']);
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// COMPLETE TASK: Completes existing Tasks with Photo Proof
|
||||
// Required: task_id, author_name, browser_id
|
||||
// Required File: completion_photo
|
||||
// Optional: completion_comment
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_complete_task($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['task_id', 'author_name', 'browser_id']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
// Checks if Task exists and is open
|
||||
$stmt = $pdo->prepare("SELECT task_id, status FROM tasks WHERE task_id = :id");
|
||||
$stmt->execute([':id' => $input['task_id']]);
|
||||
$task = $stmt->fetch();
|
||||
|
||||
if (!$task) {
|
||||
error_response('Task not found.', 404);
|
||||
}
|
||||
if ($task['status'] !== 'open') {
|
||||
error_response('Task is not available for Completion.');
|
||||
}
|
||||
|
||||
// Handles required Completion Photo
|
||||
if (!isset($_FILES['completion_photo']) || $_FILES['completion_photo']['error'] !== UPLOAD_ERR_OK) {
|
||||
error_response('Completion Photo is required.');
|
||||
}
|
||||
|
||||
$photo_path = handle_photo_upload($_FILES['completion_photo']);
|
||||
if (!$photo_path) {
|
||||
error_response('Photo Upload failed. JPG, PNG, GIF and WebP up to 5 MB.');
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE tasks SET
|
||||
status = 'completed',
|
||||
completed_by_name = :name,
|
||||
completed_by_browser = :browser,
|
||||
completion_photo = :photo,
|
||||
completion_comment = :comment,
|
||||
completed_at = NOW()
|
||||
WHERE task_id = :id
|
||||
");
|
||||
$stmt->execute([
|
||||
':id' => $input['task_id'],
|
||||
':name' => $input['author_name'],
|
||||
':browser' => $input['browser_id'],
|
||||
':photo' => $photo_path,
|
||||
':comment' => $input['completion_comment'] ?? ''
|
||||
]);
|
||||
|
||||
json_response(['message' => 'Task Completion submitted for Review.']);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// VERIFY TASK: Moderator confirms or rejects Completions
|
||||
// Required: task_id, action
|
||||
// Awards Points and sets Status if verified
|
||||
// Clears Completion Fields, resets Status if rejected
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_verify_task($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['task_id', 'verify_action']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
// Loads Task
|
||||
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE task_id = :id");
|
||||
$stmt->execute([':id' => $input['task_id']]);
|
||||
$task = $stmt->fetch();
|
||||
|
||||
if (!$task) {
|
||||
error_response('Task not found.', 404);
|
||||
}
|
||||
if ($task['status'] !== 'completed') {
|
||||
error_response('Task is not in completed State.');
|
||||
}
|
||||
|
||||
try {
|
||||
if ($input['verify_action'] === 'verify') {
|
||||
// Accepts Completion and Awards Points
|
||||
$stmt = $pdo->prepare("UPDATE tasks SET status = 'verified' WHERE task_id = :id");
|
||||
$stmt->execute([':id' => $input['task_id']]);
|
||||
|
||||
// Awards Points to User
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO user_points (municipality_id, user_name, points, task_id)
|
||||
VALUES (:mid, :name, :points, :tid)
|
||||
");
|
||||
$stmt->execute([
|
||||
':mid' => $task['municipality_id'],
|
||||
':name' => $task['completed_by_name'],
|
||||
':points' => $task['points_reward'],
|
||||
':tid' => $input['task_id']
|
||||
]);
|
||||
|
||||
json_response(['message' => 'Task verified. Points awarded.']);
|
||||
|
||||
} elseif ($input['verify_action'] === 'reject') {
|
||||
// Rejects Completion and Clears Fields
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE tasks SET
|
||||
status = 'open',
|
||||
completed_by_name = NULL,
|
||||
completed_by_browser = NULL,
|
||||
completion_photo = NULL,
|
||||
completion_comment = NULL,
|
||||
completed_at = NULL
|
||||
WHERE task_id = :id
|
||||
");
|
||||
$stmt->execute([':id' => $input['task_id']]);
|
||||
|
||||
json_response(['message' => 'Completion rejected. Task is open again.']);
|
||||
|
||||
} else {
|
||||
error_response('Invalid Action. Must be: verify or reject.');
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// READ LEADERBOARD: Returns Citizen Leaderboard
|
||||
// Required: municipality_id
|
||||
// Optional: limit
|
||||
// ---------------------------------------------------------------------
|
||||
function handle_read_leaderboard($input) {
|
||||
$pdo = get_db();
|
||||
|
||||
$missing = validate_required($input, ['municipality_id']);
|
||||
if (!empty($missing)) {
|
||||
error_response('Missing Fields: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
$limit = min((int)($input['limit'] ?? 10), 50);
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT user_name,
|
||||
SUM(points) AS total_points,
|
||||
COUNT(*) AS tasks_completed
|
||||
FROM user_points
|
||||
WHERE municipality_id = :mid
|
||||
GROUP BY user_name
|
||||
ORDER BY total_points DESC
|
||||
LIMIT :lim
|
||||
");
|
||||
$stmt->bindValue(':mid', $input['municipality_id'], PDO::PARAM_INT);
|
||||
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
json_response(['leaderboard' => $stmt->fetchAll()]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_response('Database Error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user