diff --git a/ProcessMaker/Events/CaseDeleted.php b/ProcessMaker/Events/CaseDeleted.php new file mode 100644 index 0000000000..8c3abb6049 --- /dev/null +++ b/ProcessMaker/Events/CaseDeleted.php @@ -0,0 +1,65 @@ +caseNumber = $caseNumber; + $this->caseTitle = $caseTitle; + } + + /** + * Get specific data related to the event + * + * @return array + */ + public function getData(): array + { + return [ + 'name' => $this->caseTitle, + 'case_number' => $this->caseNumber, + 'deleted_at' => Carbon::now(), + ]; + } + + /** + * Get specific data related to the event + * + * @return array + */ + public function getChanges(): array + { + return [ + 'case_number' => $this->caseNumber, + ]; + } + + /** + * Get the Event name + * + * @return string + */ + public function getEventName(): string + { + return 'CaseDeleted'; + } +} diff --git a/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeleteCase.php b/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeleteCase.php index 4a81bd5d7a..d98f39e703 100644 --- a/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeleteCase.php +++ b/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeleteCase.php @@ -3,23 +3,16 @@ namespace ProcessMaker\Http\Controllers\Api\Actions\Cases; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Schema; -use ProcessMaker\Models\CaseNumber; -use ProcessMaker\Models\CaseParticipated; +use ProcessMaker\Events\CaseDeleted; use ProcessMaker\Models\CaseStarted; -use ProcessMaker\Models\Comment; -use ProcessMaker\Models\InboxRule; -use ProcessMaker\Models\InboxRuleLog; -use ProcessMaker\Models\Media; -use ProcessMaker\Models\ProcessAbeRequestToken; use ProcessMaker\Models\ProcessRequest; -use ProcessMaker\Models\ProcessRequestLock; use ProcessMaker\Models\ProcessRequestToken; -use ProcessMaker\Models\ScheduledTask; use ProcessMaker\Models\TaskDraft; class DeleteCase { + use DeletesCaseRecords; + public function __invoke(string $caseNumber): void { $requestIds = $this->getRequestIds($caseNumber); @@ -28,6 +21,7 @@ public function __invoke(string $caseNumber): void abort(404); } + $caseTitle = $this->getCaseTitle($caseNumber); $tokenIds = $this->getRequestTokenIds($requestIds); DB::transaction(function () use ($caseNumber, $requestIds, $tokenIds) { @@ -49,6 +43,8 @@ public function __invoke(string $caseNumber): void $this->deleteProcessRequests($requestIds); }); + CaseDeleted::dispatch($caseNumber, $caseTitle); + $this->dispatchSavedSearchRecount(); } @@ -60,6 +56,25 @@ private function getRequestIds(string $caseNumber): array ->all(); } + private function getCaseTitle(string $caseNumber): string + { + $caseStarted = CaseStarted::query() + ->where('case_number', $caseNumber) + ->first(); + + if ($caseStarted) { + return $caseStarted->case_title ?? "Case #{$caseNumber}"; + } else { + // If CaseStarted doesn't exist, get case title from the first ProcessRequest + $firstRequest = ProcessRequest::query() + ->where('case_number', $caseNumber) + ->whereNull('parent_request_id') + ->first(); + + return $firstRequest?->case_title ?? "Case #{$caseNumber}"; + } + } + private function getRequestTokenIds(array $requestIds): array { if ($requestIds === []) { @@ -84,186 +99,6 @@ private function getTaskDraftIds(array $tokenIds): array ->all(); } - private function deleteCasesStarted(string $caseNumber): void - { - CaseStarted::query() - ->where('case_number', $caseNumber) - ->delete(); - } - - private function deleteCasesParticipated(string $caseNumber): void - { - CaseParticipated::query() - ->where('case_number', $caseNumber) - ->delete(); - } - - private function deleteCaseNumbers(array $requestIds): void - { - if ($requestIds === []) { - return; - } - - CaseNumber::query() - ->whereIn('process_request_id', $requestIds) - ->delete(); - } - - private function deleteProcessRequests(array $requestIds): void - { - if ($requestIds === []) { - return; - } - - ProcessRequest::query() - ->whereIn('id', $requestIds) - ->get() - ->each - ->delete(); - } - - private function deleteProcessRequestTokens(array $requestIds): void - { - if ($requestIds === []) { - return; - } - - ProcessRequestToken::query() - ->whereIn('process_request_id', $requestIds) - ->delete(); - } - - private function deleteProcessRequestLocks(array $requestIds, array $tokenIds): void - { - ProcessRequestLock::query() - ->whereIn('process_request_id', $requestIds) - ->delete(); - - if ($tokenIds !== []) { - ProcessRequestLock::query() - ->whereIn('process_request_token_id', $tokenIds) - ->delete(); - } - } - - private function deleteProcessAbeRequestTokens(array $requestIds, array $tokenIds): void - { - ProcessAbeRequestToken::query() - ->whereIn('process_request_id', $requestIds) - ->delete(); - - if ($tokenIds !== []) { - ProcessAbeRequestToken::query() - ->whereIn('process_request_token_id', $tokenIds) - ->delete(); - } - } - - private function deleteScheduledTasks(array $requestIds, array $tokenIds): void - { - ScheduledTask::query() - ->whereIn('process_request_id', $requestIds) - ->delete(); - - if ($tokenIds !== []) { - ScheduledTask::query() - ->whereIn('process_request_token_id', $tokenIds) - ->delete(); - } - } - - private function deleteInboxRules(array $tokenIds): void - { - if ($tokenIds === []) { - return; - } - - InboxRule::query() - ->whereIn('process_request_token_id', $tokenIds) - ->get() - ->each - ->delete(); - } - - private function deleteInboxRuleLogs(array $tokenIds): void - { - if ($tokenIds === []) { - return; - } - - InboxRuleLog::query() - ->whereIn('process_request_token_id', $tokenIds) - ->delete(); - } - - private function deleteEllucianEthosSyncTasks(array $tokenIds): void - { - if ($tokenIds === [] || !Schema::hasTable('ellucian_ethos_sync_global_task_list')) { - return; - } - - DB::table('ellucian_ethos_sync_global_task_list') - ->whereIn('process_request_token_id', $tokenIds) - ->delete(); - } - - private function deleteTaskDrafts(array $tokenIds): void - { - if ($tokenIds === []) { - return; - } - - TaskDraft::query() - ->whereIn('task_id', $tokenIds) - ->delete(); - } - - private function deleteTaskDraftMedia(array $draftIds): void - { - if ($draftIds === []) { - return; - } - - Media::query() - ->where('model_type', TaskDraft::class) - ->whereIn('model_id', $draftIds) - ->get() - ->each - ->delete(); - } - - private function deleteRequestMedia(array $requestIds): void - { - if ($requestIds === []) { - return; - } - - Media::query() - ->where('model_type', ProcessRequest::class) - ->whereIn('model_id', $requestIds) - ->get() - ->each - ->delete(); - } - - private function deleteComments(string $caseNumber, array $requestIds, array $tokenIds): void - { - Comment::query() - ->where('case_number', $caseNumber) - ->orWhere(function ($query) use ($requestIds, $tokenIds) { - $query->where('commentable_type', ProcessRequest::class) - ->whereIn('commentable_id', $requestIds); - - if ($tokenIds !== []) { - $query->orWhere(function ($nestedQuery) use ($tokenIds) { - $nestedQuery->where('commentable_type', ProcessRequestToken::class) - ->whereIn('commentable_id', $tokenIds); - }); - } - }) - ->delete(); - } - private function dispatchSavedSearchRecount(): void { if (!config('savedsearch.count', false)) { diff --git a/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeletesCaseRecords.php b/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeletesCaseRecords.php new file mode 100644 index 0000000000..d8b3493ccf --- /dev/null +++ b/ProcessMaker/Http/Controllers/Api/Actions/Cases/DeletesCaseRecords.php @@ -0,0 +1,202 @@ +where('case_number', $caseNumber) + ->delete(); + } + + private function deleteCasesParticipated(string $caseNumber): void + { + CaseParticipated::query() + ->where('case_number', $caseNumber) + ->delete(); + } + + private function deleteCaseNumbers(array $requestIds): void + { + if ($requestIds === []) { + return; + } + + CaseNumber::query() + ->whereIn('process_request_id', $requestIds) + ->delete(); + } + + private function deleteProcessRequests(array $requestIds): void + { + if ($requestIds === []) { + return; + } + + ProcessRequest::query() + ->whereIn('id', $requestIds) + ->get() + ->each + ->delete(); + } + + private function deleteProcessRequestTokens(array $requestIds): void + { + if ($requestIds === []) { + return; + } + + ProcessRequestToken::query() + ->whereIn('process_request_id', $requestIds) + ->delete(); + } + + private function deleteProcessRequestLocks(array $requestIds, array $tokenIds): void + { + ProcessRequestLock::query() + ->whereIn('process_request_id', $requestIds) + ->delete(); + + if ($tokenIds !== []) { + ProcessRequestLock::query() + ->whereIn('process_request_token_id', $tokenIds) + ->delete(); + } + } + + private function deleteProcessAbeRequestTokens(array $requestIds, array $tokenIds): void + { + ProcessAbeRequestToken::query() + ->whereIn('process_request_id', $requestIds) + ->delete(); + + if ($tokenIds !== []) { + ProcessAbeRequestToken::query() + ->whereIn('process_request_token_id', $tokenIds) + ->delete(); + } + } + + private function deleteScheduledTasks(array $requestIds, array $tokenIds): void + { + ScheduledTask::query() + ->whereIn('process_request_id', $requestIds) + ->delete(); + + if ($tokenIds !== []) { + ScheduledTask::query() + ->whereIn('process_request_token_id', $tokenIds) + ->delete(); + } + } + + private function deleteInboxRules(array $tokenIds): void + { + if ($tokenIds === []) { + return; + } + + InboxRule::query() + ->whereIn('process_request_token_id', $tokenIds) + ->get() + ->each + ->delete(); + } + + private function deleteInboxRuleLogs(array $tokenIds): void + { + if ($tokenIds === []) { + return; + } + + InboxRuleLog::query() + ->whereIn('process_request_token_id', $tokenIds) + ->delete(); + } + + private function deleteEllucianEthosSyncTasks(array $tokenIds): void + { + if ($tokenIds === [] || !Schema::hasTable('ellucian_ethos_sync_global_task_list')) { + return; + } + + DB::table('ellucian_ethos_sync_global_task_list') + ->whereIn('process_request_token_id', $tokenIds) + ->delete(); + } + + private function deleteTaskDrafts(array $tokenIds): void + { + if ($tokenIds === []) { + return; + } + + TaskDraft::query() + ->whereIn('task_id', $tokenIds) + ->delete(); + } + + private function deleteTaskDraftMedia(array $draftIds): void + { + if ($draftIds === []) { + return; + } + + Media::query() + ->where('model_type', TaskDraft::class) + ->whereIn('model_id', $draftIds) + ->get() + ->each + ->delete(); + } + + private function deleteRequestMedia(array $requestIds): void + { + if ($requestIds === []) { + return; + } + + Media::query() + ->where('model_type', ProcessRequest::class) + ->whereIn('model_id', $requestIds) + ->get() + ->each + ->delete(); + } + + private function deleteComments(string $caseNumber, array $requestIds, array $tokenIds): void + { + Comment::query() + ->where('case_number', $caseNumber) + ->orWhere(function ($query) use ($requestIds, $tokenIds) { + $query->where('commentable_type', ProcessRequest::class) + ->whereIn('commentable_id', $requestIds); + + if ($tokenIds !== []) { + $query->orWhere(function ($nestedQuery) use ($tokenIds) { + $nestedQuery->where('commentable_type', ProcessRequestToken::class) + ->whereIn('commentable_id', $tokenIds); + }); + } + }) + ->delete(); + } +} diff --git a/ProcessMaker/Providers/EventServiceProvider.php b/ProcessMaker/Providers/EventServiceProvider.php index f2cc0c0832..1ee0c13b57 100644 --- a/ProcessMaker/Providers/EventServiceProvider.php +++ b/ProcessMaker/Providers/EventServiceProvider.php @@ -9,6 +9,7 @@ use ProcessMaker\Events\AuthClientCreated; use ProcessMaker\Events\AuthClientDeleted; use ProcessMaker\Events\AuthClientUpdated; +use ProcessMaker\Events\CaseDeleted; use ProcessMaker\Events\CategoryCreated; use ProcessMaker\Events\CategoryDeleted; use ProcessMaker\Events\CategoryUpdated; @@ -139,6 +140,7 @@ public function boot() $this->app['events']->listen(AuthClientCreated::class, SecurityLogger::class); $this->app['events']->listen(AuthClientDeleted::class, SecurityLogger::class); $this->app['events']->listen(AuthClientUpdated::class, SecurityLogger::class); + $this->app['events']->listen(CaseDeleted::class, SecurityLogger::class); $this->app['events']->listen(CategoryCreated::class, SecurityLogger::class); $this->app['events']->listen(CategoryDeleted::class, SecurityLogger::class); $this->app['events']->listen(CategoryUpdated::class, SecurityLogger::class); diff --git a/tests/Feature/Api/SecurityLogsTest.php b/tests/Feature/Api/SecurityLogsTest.php index d4fa5b6290..3ba3db3a9f 100644 --- a/tests/Feature/Api/SecurityLogsTest.php +++ b/tests/Feature/Api/SecurityLogsTest.php @@ -49,6 +49,7 @@ use ProcessMaker\Models\Permission; use ProcessMaker\Models\Process; use ProcessMaker\Models\ProcessCategory; +use ProcessMaker\Models\ProcessRequest; use ProcessMaker\Models\ProcessTemplates; use ProcessMaker\Models\Screen; use ProcessMaker\Models\Script; @@ -248,6 +249,24 @@ public function checkAssertsSegurityLog(string $event, $date = 'created_at', $to } } + /** + * This tests Case Deleted + */ + public function testCaseDeleted() + { + $caseNumber = 12345; + + ProcessRequest::factory() + ->withCaseNumber($caseNumber) + ->create(); + + $response = $this->apiCall('DELETE', route('api.cases.destroy', ['case_number' => $caseNumber])); + + $response->assertStatus(204); + + $this->checkAssertsSegurityLog('CaseDeleted', 'deleted_at'); + } + /** * This test Category Created */