c44958ac16
Restores all 27 files changed by the security commit (f8a1310) and later work back to their7d854ffstate (2026-06-16 18:05), as requested. The security rewrite regressed map functionality (tabs, inspection editor, collapsing layers panel) without adding protections the7d854ffversion did not already have (XSS escaping + IDOR checks were already present). Done as a forward commit (no history rewrite / force-push) sof8a1310,a24c8a2and the merge remain in history and are fully recoverable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
109 lines
4.9 KiB
PHP
109 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\PendingSync;
|
|
use App\Models\Phase;
|
|
use App\Models\Inspection;
|
|
use App\Models\Feature;
|
|
use App\Models\Media;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class OfflineSyncController extends Controller
|
|
{
|
|
public function storePending(Request $request)
|
|
{
|
|
$payload = $request->validate([
|
|
'action' => 'required|in:progress_update,inspection,feature_create,media_upload,task_complete',
|
|
'payload' => 'required|array',
|
|
]);
|
|
$pending = PendingSync::create([
|
|
'user_id' => Auth::id() ?? 1,
|
|
'action' => $payload['action'],
|
|
'payload' => $payload['payload'],
|
|
]);
|
|
return response()->json(['queued' => true]);
|
|
}
|
|
|
|
public function sync(Request $request)
|
|
{
|
|
$user = Auth::user();
|
|
$pendings = PendingSync::where('user_id', $user->id)->whereNull('synced_at')->get();
|
|
$results = [];
|
|
foreach ($pendings as $pending) {
|
|
$result = ['id' => $pending->id, 'action' => $pending->action, 'success' => false, 'error' => null];
|
|
try {
|
|
if ($pending->action === 'progress_update') {
|
|
$phase = Phase::find($pending->payload['phase_id']);
|
|
if ($phase) {
|
|
$phase->progress_percent = $pending->payload['progress'];
|
|
$phase->save();
|
|
$phase->progressUpdates()->create([
|
|
'user_id' => $user->id,
|
|
'progress_percent' => $pending->payload['progress'],
|
|
'comment' => $pending->payload['comment'] ?? '',
|
|
'location' => $pending->payload['location'] ?? null,
|
|
]);
|
|
}
|
|
$result['success'] = true;
|
|
} elseif ($pending->action === 'inspection') {
|
|
$inspection = Inspection::create($pending->payload);
|
|
$result['success'] = true;
|
|
$result['data'] = ['inspection_id' => $inspection->id];
|
|
} elseif ($pending->action === 'feature_create') {
|
|
$feature = Feature::create($pending->payload);
|
|
$result['success'] = true;
|
|
$result['data'] = ['feature_id' => $feature->id];
|
|
} elseif ($pending->action === 'media_upload') {
|
|
// Assuming payload has: 'file' (base64), 'path', 'model_type', 'model_id'
|
|
// We'll decode the base64 and store the file
|
|
if (isset($pending->payload['file'], $pending->payload['path'])) {
|
|
$decoded = base64_decode($pending->payload['file']);
|
|
if ($decoded !== false) {
|
|
$path = Storage::put($pending->payload['path'], $decoded);
|
|
// Attach to model if model_type and model_id are provided
|
|
if (isset($pending->payload['model_type'], $pending->payload['model_id'])) {
|
|
$model = new $pending->payload['model_type'];
|
|
$model = $model->find($pending->payload['model_id']);
|
|
if ($model) {
|
|
$model->media()->create([
|
|
'name' => $pending->payload['name'] ?? 'unnamed',
|
|
'path' => $path,
|
|
'mime_type' => $pending->payload['mime_type'] ?? 'application/octet-stream',
|
|
'disk' => 'public',
|
|
]);
|
|
}
|
|
}
|
|
$result['success'] = true;
|
|
$result['data'] = ['path' => $path];
|
|
} else {
|
|
$result['error'] = 'Failed to decode base64 file';
|
|
}
|
|
} else {
|
|
$result['error'] = 'Missing file or path in payload';
|
|
}
|
|
} elseif ($pending->action === 'task_complete') {
|
|
// Example: mark a task as complete (you can adjust as needed)
|
|
// For now, just log and mark as success
|
|
\Log::info('Task completed offline', $pending->payload);
|
|
$result['success'] = true;
|
|
} else {
|
|
$result['error'] = 'Unknown action type';
|
|
}
|
|
} catch (\Exception $e) {
|
|
$result['error'] = $e->getMessage();
|
|
}
|
|
|
|
if ($result['success']) {
|
|
$pending->synced_at = now();
|
|
$pending->save();
|
|
}
|
|
|
|
$results[] = $result;
|
|
}
|
|
return response()->json(['synced' => $results]);
|
|
}
|
|
}
|