From 1858009b36ace4b499dfe61ccbbb2c5f12caedb4 Mon Sep 17 00:00:00 2001 From: Eleazar Resendez Date: Thu, 26 Sep 2024 17:43:51 -0600 Subject: [PATCH 1/3] fix: implement Last-Modified header with If-Modified-Since validation for cache control --- .../Controllers/Api/V1_1/TaskController.php | 94 ++++++++++++------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php index f27c538dfc..c25fe4f0a2 100644 --- a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php @@ -4,8 +4,11 @@ namespace ProcessMaker\Http\Controllers\Api\V1_1; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\Request; +use Illuminate\Http\Response; use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Http\Resources\V1_1\TaskInterstitialResource; use ProcessMaker\Http\Resources\V1_1\TaskResource; @@ -59,34 +62,6 @@ public function index() ]; } - private function processFilters(Request $request, Builder $query) - { - if (request()->has('user_id')) { - ProcessRequestToken::scopeWhereUserAssigned($query, request()->get('user_id')); - } - - if ($request->has('process_request_id')) { - $query->where(function ($q) use ($request) { - $q->where('process_request_id', $request->input('process_request_id')); - $this->addSubprocessTasks($request, $q); - }); - } - if ($request->has('status')) { - $query->where('status', $request->input('status')); - } - } - - private function addSubprocessTasks(Request $request, Builder &$q) - { - if ($request->has('include_sub_tasks')) { - $q->orWhereIn( - 'process_request_id', - ProcessRequest::select('id') - ->where('parent_request_id', $request->input('process_request_id')) - ); - } - } - public function show(ProcessRequestToken $task) { $resource = TaskResource::preprocessInclude(request(), ProcessRequestToken::where('id', $task->id)); @@ -94,19 +69,44 @@ public function show(ProcessRequestToken $task) return $resource->toArray(request()); } - public function showScreen($taskId) + /** + * Display the screen for a given task. + * + * @throws ModelNotFoundException If the task is not found. + */ + public function showScreen(Request $request, int $taskId): Response { + // Fetch the task data. $task = ProcessRequestToken::select( array_merge($this->defaultFields, ['process_request_id', 'process_id']) )->findOrFail($taskId); + + // Prepare the response. $response = new TaskScreen($task); - $response = response($response->toArray(request())['screen'], 200); - $now = time(); - // screen cache time + $screen = $response->toArray($request)['screen']; + $now = isset($screen['updated_at']) + ? Carbon::parse($screen['updated_at'])->timestamp + : time(); + + // Create the response object. + $response = response($screen, 200); + + // Set Cache-Control headers. $cacheTime = config('screen_task_cache_time', 86400); - $response->headers->set('Cache-Control', 'max-age=' . $cacheTime . ', must-revalidate, public'); + $response->headers->set('Cache-Control', 'no-cache, must-revalidate, public'); $response->headers->set('Expires', gmdate('D, d M Y H:i:s', $now + $cacheTime) . ' GMT'); + // Set Last-Modified header. + $response->headers->set('Last-Modified', gmdate('D, d M Y H:i:s', $now) . ' GMT'); + + // Return 304 if the resource has not been modified since the provided date. + if ($request->headers->has('If-Modified-Since')) { + $ifModifiedSince = strtotime($request->headers->get('If-Modified-Since')); + if ($ifModifiedSince >= $now) { + return response()->noContent(304); + } + } + return $response; } @@ -125,4 +125,32 @@ public function showInterstitial($taskId) return $response; } + + private function processFilters(Request $request, Builder $query) + { + if (request()->has('user_id')) { + ProcessRequestToken::scopeWhereUserAssigned($query, request()->get('user_id')); + } + + if ($request->has('process_request_id')) { + $query->where(function ($q) use ($request) { + $q->where('process_request_id', $request->input('process_request_id')); + $this->addSubprocessTasks($request, $q); + }); + } + if ($request->has('status')) { + $query->where('status', $request->input('status')); + } + } + + private function addSubprocessTasks(Request $request, Builder &$q) + { + if ($request->has('include_sub_tasks')) { + $q->orWhereIn( + 'process_request_id', + ProcessRequest::select('id') + ->where('parent_request_id', $request->input('process_request_id')) + ); + } + } } From a168f7eb446d26c4e045ca37a1507256bd50f8bd Mon Sep 17 00:00:00 2001 From: Eleazar Resendez Date: Fri, 27 Sep 2024 09:50:12 -0600 Subject: [PATCH 2/3] Revert "fix: implement Last-Modified header with If-Modified-Since validation for cache control" This reverts commit 1858009b36ace4b499dfe61ccbbb2c5f12caedb4. --- .../Controllers/Api/V1_1/TaskController.php | 94 +++++++------------ 1 file changed, 33 insertions(+), 61 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php index c25fe4f0a2..f27c538dfc 100644 --- a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php @@ -4,11 +4,8 @@ namespace ProcessMaker\Http\Controllers\Api\V1_1; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\Request; -use Illuminate\Http\Response; use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Http\Resources\V1_1\TaskInterstitialResource; use ProcessMaker\Http\Resources\V1_1\TaskResource; @@ -62,6 +59,34 @@ public function index() ]; } + private function processFilters(Request $request, Builder $query) + { + if (request()->has('user_id')) { + ProcessRequestToken::scopeWhereUserAssigned($query, request()->get('user_id')); + } + + if ($request->has('process_request_id')) { + $query->where(function ($q) use ($request) { + $q->where('process_request_id', $request->input('process_request_id')); + $this->addSubprocessTasks($request, $q); + }); + } + if ($request->has('status')) { + $query->where('status', $request->input('status')); + } + } + + private function addSubprocessTasks(Request $request, Builder &$q) + { + if ($request->has('include_sub_tasks')) { + $q->orWhereIn( + 'process_request_id', + ProcessRequest::select('id') + ->where('parent_request_id', $request->input('process_request_id')) + ); + } + } + public function show(ProcessRequestToken $task) { $resource = TaskResource::preprocessInclude(request(), ProcessRequestToken::where('id', $task->id)); @@ -69,44 +94,19 @@ public function show(ProcessRequestToken $task) return $resource->toArray(request()); } - /** - * Display the screen for a given task. - * - * @throws ModelNotFoundException If the task is not found. - */ - public function showScreen(Request $request, int $taskId): Response + public function showScreen($taskId) { - // Fetch the task data. $task = ProcessRequestToken::select( array_merge($this->defaultFields, ['process_request_id', 'process_id']) )->findOrFail($taskId); - - // Prepare the response. $response = new TaskScreen($task); - $screen = $response->toArray($request)['screen']; - $now = isset($screen['updated_at']) - ? Carbon::parse($screen['updated_at'])->timestamp - : time(); - - // Create the response object. - $response = response($screen, 200); - - // Set Cache-Control headers. + $response = response($response->toArray(request())['screen'], 200); + $now = time(); + // screen cache time $cacheTime = config('screen_task_cache_time', 86400); - $response->headers->set('Cache-Control', 'no-cache, must-revalidate, public'); + $response->headers->set('Cache-Control', 'max-age=' . $cacheTime . ', must-revalidate, public'); $response->headers->set('Expires', gmdate('D, d M Y H:i:s', $now + $cacheTime) . ' GMT'); - // Set Last-Modified header. - $response->headers->set('Last-Modified', gmdate('D, d M Y H:i:s', $now) . ' GMT'); - - // Return 304 if the resource has not been modified since the provided date. - if ($request->headers->has('If-Modified-Since')) { - $ifModifiedSince = strtotime($request->headers->get('If-Modified-Since')); - if ($ifModifiedSince >= $now) { - return response()->noContent(304); - } - } - return $response; } @@ -125,32 +125,4 @@ public function showInterstitial($taskId) return $response; } - - private function processFilters(Request $request, Builder $query) - { - if (request()->has('user_id')) { - ProcessRequestToken::scopeWhereUserAssigned($query, request()->get('user_id')); - } - - if ($request->has('process_request_id')) { - $query->where(function ($q) use ($request) { - $q->where('process_request_id', $request->input('process_request_id')); - $this->addSubprocessTasks($request, $q); - }); - } - if ($request->has('status')) { - $query->where('status', $request->input('status')); - } - } - - private function addSubprocessTasks(Request $request, Builder &$q) - { - if ($request->has('include_sub_tasks')) { - $q->orWhereIn( - 'process_request_id', - ProcessRequest::select('id') - ->where('parent_request_id', $request->input('process_request_id')) - ); - } - } } From d8186eab8faa876c6419ddf8df88b8636b9b1104 Mon Sep 17 00:00:00 2001 From: Eleazar Resendez Date: Fri, 27 Sep 2024 09:59:02 -0600 Subject: [PATCH 3/3] feat: implement cache-busting with version parameter to ensure screen updates are reflected - Added a version parameter to screen URLs based on the last modified id. - Ensures that changes in the screen trigger a new URL, bypassing cached versions. - Prevents stale data by forcing the browser to fetch the updated resource when changes occur. --- resources/views/tasks/edit.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/tasks/edit.blade.php b/resources/views/tasks/edit.blade.php index d6bc80fe34..80a4691396 100644 --- a/resources/views/tasks/edit.blade.php +++ b/resources/views/tasks/edit.blade.php @@ -55,6 +55,7 @@ class="card border-0" v-model="formData" :initial-task-id="{{ $task->id }}" :initial-request-id="{{ $task->process_request_id }}" + :screen-version="{{ $task->screen['id'] ?? null }}" :user-id="{{ Auth::user()->id }}" csrf-token="{{ csrf_token() }}" initial-loop-context="{{ $task->getLoopContext() }}"