diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php b/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php index 5eee5fe..975cbd1 100644 --- a/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php +++ b/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php @@ -86,7 +86,8 @@ class SearchAndDisplaceOriginalDocumentController extends Controller try { $handler = new SearchAndDisplaceOriginalDocument(); - return $handler->streamFile($id); + return response()->download($handler->getDownloadPath($id)) + ->deleteFileAfterSend(true); } catch (\Exception $exception) { abort(404); } diff --git a/app/SearchDisplace/Ingest/HandleReceivedDocument.php b/app/SearchDisplace/Ingest/HandleReceivedDocument.php index ff61389..36df47c 100644 --- a/app/SearchDisplace/Ingest/HandleReceivedDocument.php +++ b/app/SearchDisplace/Ingest/HandleReceivedDocument.php @@ -4,6 +4,8 @@ namespace App\SearchDisplace\Ingest; use App\Events\IngestDocumentReceived; use App\SearchDisplace\SearchAndDisplaceOriginalDocument; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\ClientException; use Illuminate\Support\Facades\Storage; class HandleReceivedDocument @@ -21,6 +23,9 @@ class HandleReceivedDocument $this->status = $payload['data']['status']; } + /** + * @throws \Exception + */ public function handle() { if ($this->fileResultType === 'md') { @@ -29,6 +34,12 @@ class HandleReceivedDocument return; } + if ($this->fileResultType === 'document-recreated') { + $this->downloadDocumentFromIngest(); + + return; + } + $this->handleDocumentJson(); } @@ -67,6 +78,37 @@ class HandleReceivedDocument } } + protected function downloadDocumentFromIngest() + { + $storage = Storage::disk('local'); + + + if ($this->status === 'fail') { + $storage->deleteDirectory("contracts/$this->id"); + + return; + } + + $filePath = 'document.docx'; + $fullPath = 'contracts/' . $this->id . '-' . $filePath; + + $url = env('SD_INGEST_URL') . '/recreate-document/' . $this->id . '?file_path=' . $filePath; + + $client = new Client(); + + try { + $client->request('GET', $url, [ + 'sink' => $storage->path($fullPath), + ]); + } catch (ClientException $clientException) { + $error = json_decode($clientException->getResponse()->getBody()->getContents(), true); + + throw new \Exception($error['message']); + } finally { + $storage->deleteDirectory("contracts/$this->id"); + } + } + protected function handleDocumentJson() { $handler = new SearchAndDisplaceOriginalDocument(); diff --git a/app/SearchDisplace/Ingest/SendDataToRecreateDocument.php b/app/SearchDisplace/Ingest/SendDataToRecreateDocument.php new file mode 100644 index 0000000..1c501f9 --- /dev/null +++ b/app/SearchDisplace/Ingest/SendDataToRecreateDocument.php @@ -0,0 +1,73 @@ +url = env('SD_INGEST_URL') . '/recreate-document'; + } + + /** + * + * @param $id + * @param $data + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Exception + */ + public function execute($id, $data) + { + $response = $this->sendRequest($id, $data); + + if ( ! array_key_exists('status', $response)) { + throw new \Exception('Something went wrong.'); + } + + if ($response['status'] === 'fail') { + $message = array_key_exists('message', $response) + ? $response['message'] + : 'Something went wrong.'; + + throw new \Exception($message); + } + } + + /** + * Send request to Ingest to recreate document. + * + * @param $id + * @param $data + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Exception + */ + public function sendRequest($id, $data) + { + $client = new Client(); + + try { + $response = $client->request('post', $this->url, [ + 'headers' => [ + 'Accept' => 'application/json', + ], + + 'form_params' => [ + 'id' => $id, + 'data' => json_encode($data), + ], + ]); + + return json_decode($response->getBody()->getContents(), true); + } catch (ClientException $clientException) { + $error = json_decode($clientException->getResponse()->getBody()->getContents(), true); + + throw new \Exception($error['message']); + } + } +} diff --git a/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php b/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php index b45e239..b082d3b 100644 --- a/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php +++ b/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php @@ -2,6 +2,7 @@ namespace App\SearchDisplace; +use App\SearchDisplace\Ingest\SendDataToRecreateDocument; use App\SearchDisplace\Ingest\SendDocument; use Illuminate\Support\Facades\Storage; @@ -21,6 +22,11 @@ class SearchAndDisplaceOriginalDocument return $id; } + /** + * @param $id + * @param $contents + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function applySD($id, $contents) { $data = json_decode($contents['document'], true); @@ -37,14 +43,12 @@ class SearchAndDisplaceOriginalDocument $result = $searchAndDisplace->execute(); // Update text. - $data['contents'] = $this->applyResultsOnIngestData($data['contents'], $result); + $x = $this->applyResultsOnIngestData($data['contents'], $result); + $data['contents'] = $x; - \Illuminate\Support\Facades\Log::info($data['contents']); - - // Send to Ingest to recreate doc. + $this->sendDataToIngestToRebuild($id, $data); } catch (\Exception $exception) { \Illuminate\Support\Facades\Log::info($exception->getMessage()); - \Illuminate\Support\Facades\Log::info($exception->getTraceAsString()); } } @@ -59,34 +63,36 @@ class SearchAndDisplaceOriginalDocument public function hasFailed($id) { $storage = Storage::disk('local'); - $directory = "contracts/$id"; + $basePath = "contracts/$id"; + $filePath = $basePath . '-document.docx'; - return ! $storage->exists($directory); + return ! $storage->exists($basePath) && ! $storage->exists($filePath); } public function isInProgress($id) { $storage = Storage::disk('local'); - $directory = "contracts/$id"; + $basePath = "contracts/$id"; - return ! $storage->exists("$directory/document"); + // @TODO Set document extension. + return $storage->exists($basePath) && ! $storage->exists($basePath . '-document.docx'); } /** * @param $id - * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @return string * @throws \Exception */ - public function streamFile($id) + public function getDownloadPath($id) { $storage = Storage::disk('local'); - $directory = "contracts/$id"; if ($this->hasFailed($id) || $this->isInProgress($id)) { throw new \Exception('Document is not processed.'); } - return $storage->download("$directory/document"); + // @TODO Set document extension. + return $storage->path('contracts/' . $id . '-document.docx'); } protected function applyResultsOnIngestData($ingestData, $sdResult) @@ -103,15 +109,10 @@ class SearchAndDisplaceOriginalDocument } } - // 0 - 20 - // 21 - 32 - // 33 - 174 - // - - $startOffset = 0; + $lastOffset = 0; - foreach ($ingestData['elements'] as $element) { - $currentStartOffset = 0; + foreach ($ingestData['elements'] as $elementIndex => $element) { + $currentOffset = 0; foreach ($indexes as $i => $index) { if ($index['original_start'] > $element['range_end']) { @@ -126,18 +127,20 @@ class SearchAndDisplaceOriginalDocument $index['original_start'] >= $element['range_start'] && $index['original_end'] <= $element['range_end'] ) { - $endDifference = $index['end'] - $index['original_end']; + $endDifference = ($index['end'] - $index['original_end']) - + ($index['start'] - $index['original_start']); - $element['range_end'] += $endDifference; - $currentStartOffset += $endDifference; + $ingestData['elements'][$elementIndex]['range_end'] += $endDifference; + $currentOffset += $endDifference; unset($indexes[$i]); } } - $element['range_start'] += $startOffset; + $ingestData['elements'][$elementIndex]['range_start'] += $lastOffset; + $ingestData['elements'][$elementIndex]['range_end'] += $lastOffset; - $startOffset += $currentStartOffset; + $lastOffset += $currentOffset; } return $ingestData; @@ -188,4 +191,17 @@ class SearchAndDisplaceOriginalDocument 'name' => $document->getClientOriginalName() ], 'original'); } + + /** + * + * @param $id + * @param $data + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function sendDataToIngestToRebuild($id, $data) + { + $handler = new SendDataToRecreateDocument(); + + $handler->execute($id, $data); + } } diff --git a/public/js/app.js b/public/js/app.js index d18d03a..3443e0e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -4374,7 +4374,7 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { clearInterval(this.intervalId); if (!(response.status === 'fail')) { - _context4.next = 9; + _context4.next = 10; break; } @@ -4384,9 +4384,10 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { detail: 'Document could not have been processed.', life: 7000 }); + this.applyingOnOriginalDocument = false; return _context4.abrupt("return"); - case 9: + case 10: this.$toast.add({ severity: 'success', summary: 'File loaded', @@ -4394,8 +4395,9 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { life: 7000 }); this.downloadFinishedOriginalDocument(id); + this.applyingOnOriginalDocument = false; // @TODO Send request to backend to delete file if no other way.. - case 11: + case 13: case "end": return _context4.stop(); } @@ -4412,7 +4414,13 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { }, { key: "downloadFinishedOriginalDocument", value: function downloadFinishedOriginalDocument(id) { - window.open("".concat(window.location.origin, "/search-and-displace/original-document/").concat(id, "/download")); + var url = "".concat(window.location.origin, "/search-and-displace/original-document/").concat(id, "/download"); + var link = window.document.createElement('a'); + link.setAttribute('download', 'Document.doxc'); + link.href = url; + window.document.body.appendChild(link); + link.click(); + link.remove(); } /** * diff --git a/resources/js/components/ProcessFile/ProcessFile.ts b/resources/js/components/ProcessFile/ProcessFile.ts index 6d8ae78..ef77c41 100644 --- a/resources/js/components/ProcessFile/ProcessFile.ts +++ b/resources/js/components/ProcessFile/ProcessFile.ts @@ -277,6 +277,8 @@ export default class ProcessFile extends Vue { life: 7000, }); + this.applyingOnOriginalDocument = false; + return; } @@ -288,10 +290,21 @@ export default class ProcessFile extends Vue { }); this.downloadFinishedOriginalDocument(id); + + this.applyingOnOriginalDocument = false; + + // @TODO Send request to backend to delete file if no other way.. } private downloadFinishedOriginalDocument(id: string) { - window.open(`${window.location.origin}/search-and-displace/original-document/${id}/download`); + const url = `${window.location.origin}/search-and-displace/original-document/${id}/download`; + + const link = window.document.createElement('a'); + link.setAttribute('download', 'Document.doxc'); + link.href = url; + window.document.body.appendChild(link); + link.click(); + link.remove(); } /**