diff --git a/app/Http/Controllers/SearchAndDisplaceController.php b/app/Http/Controllers/SearchAndDisplaceController.php index 6b0482b..5644470 100644 --- a/app/Http/Controllers/SearchAndDisplaceController.php +++ b/app/Http/Controllers/SearchAndDisplaceController.php @@ -15,7 +15,7 @@ class SearchAndDisplaceController extends Controller $result = $handler->getAfterIngest($id); if ($result['status'] !== 'processing') { -// $handler->destroy($id); + $handler->destroy($id); } return response()->json($result, 200); @@ -33,7 +33,7 @@ class SearchAndDisplaceController extends Controller 'searchers' => 'required|array', 'searchers.*.key' => 'required', 'searchers.*.type' => 'required|in:replace,displace', - 'searchers.*.vale' => 'nullable', + 'searchers.*.value' => 'nullable', 'searchOnly' => 'nullable|boolean' ]); diff --git a/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php b/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php new file mode 100644 index 0000000..5eee5fe --- /dev/null +++ b/app/Http/Controllers/SearchAndDisplaceOriginalDocumentController.php @@ -0,0 +1,94 @@ +validate([ + 'document' => [ + 'required', + 'file', + 'max:10000', + 'mimes:doc,dot,docx,dotx,docm,dotm,odt,rtf,pdf,txt', + ], + + // Searchers is encoded. +// 'searchers' => 'required|array', +// 'searchers.*.key' => 'required', +// 'searchers.*.type' => 'required|in:replace,displace', +// 'searchers.*.value' => 'nullable', + ]); + + // Send document to Ingest to be processed as docx in order to get original data. + + // After we get the response from Ingest apply S&D on the result. + // After that send back to Ingest to recreate the original document. + // After that Ingest will send webhook that it is done. + // Download file from Ingest. + // The interface will keep asking if the file is ready. + // Once is ready return the response with the file. + + try { + $handler = new SearchAndDisplaceOriginalDocument(); + + $id = $handler->start(request()->file('document'), json_decode(request()->get('searchers'), true)); + + return response()->json([ + 'status' => 'ok', + 'id' => $id, + ]); + } catch (BadResponseException $e) { + return response()->json([ + 'message' => $e->getMessage(), + 'response' => $e->getResponse() + ], 400); + } catch (\Exception $e) { + return response()->json([ + 'message' => $e->getMessage(), + ], 400); + } + } + + public function show($id) + { + try { + $handler = new SearchAndDisplaceOriginalDocument(); + + if ($handler->hasFailed($id)) { + return response()->json([ + 'status' => 'fail', + ], 200); + } + + if ($handler->isInProgress($id)) { + return response()->json([ + 'status' => 'processing', + ], 200); + } + + return response()->json([ + 'status' => 'success', + ], 200); + } catch (\Exception $exception) { + return response()->json([ + 'message' => $exception->getMessage(), + ], 400); + } + } + + public function download($id) + { + try { + $handler = new SearchAndDisplaceOriginalDocument(); + + return $handler->streamFile($id); + } catch (\Exception $exception) { + abort(404); + } + } +} diff --git a/app/SearchDisplace/Ingest/HandleReceivedDocument.php b/app/SearchDisplace/Ingest/HandleReceivedDocument.php index 147b1d5..ff61389 100644 --- a/app/SearchDisplace/Ingest/HandleReceivedDocument.php +++ b/app/SearchDisplace/Ingest/HandleReceivedDocument.php @@ -3,22 +3,36 @@ namespace App\SearchDisplace\Ingest; use App\Events\IngestDocumentReceived; +use App\SearchDisplace\SearchAndDisplaceOriginalDocument; use Illuminate\Support\Facades\Storage; class HandleReceivedDocument { protected $id; protected $content; + protected $fileResultType; protected $status; public function __construct($payload) { $this->id = $payload['data']['id']; $this->content = $payload['data']['content']; + $this->fileResultType = $payload['data']['file_result_type']; $this->status = $payload['data']['status']; } public function handle() + { + if ($this->fileResultType === 'md') { + $this->handleDocumentMD(); + + return; + } + + $this->handleDocumentJson(); + } + + protected function handleDocumentMD() { $storage = Storage::disk('local'); @@ -46,9 +60,23 @@ class HandleReceivedDocument $storage->put("$dir/$name.$type", base64_decode($contents)); } + // Emit event so other sections of the app can work on it. IngestDocumentReceived::dispatch($this->id); } catch (\Exception $exception) { \Illuminate\Support\Facades\Log::info('Exception: ' . $exception->getTraceAsString()); } } + + protected function handleDocumentJson() + { + $handler = new SearchAndDisplaceOriginalDocument(); + + if ($this->status !== 'success') { + $handler->onIngestFail($this->id); + + return; + } + + $handler->applySD($this->id, $this->content); + } } diff --git a/app/SearchDisplace/Ingest/SendDocument.php b/app/SearchDisplace/Ingest/SendDocument.php index d36a4eb..a978032 100644 --- a/app/SearchDisplace/Ingest/SendDocument.php +++ b/app/SearchDisplace/Ingest/SendDocument.php @@ -14,10 +14,10 @@ class SendDocument $this->url = env('SD_INGEST_URL') . '/ingest'; } - public function execute($id, $document) + public function execute($id, $document, $fileResultType = 'md') { try { - $response = $this->sendRequest($id, $document); + $response = $this->sendRequest($id, $document, $fileResultType); if ($response['status'] === 'fail') { $message = array_key_exists('message', $response) @@ -41,7 +41,7 @@ class SendDocument * @return mixed * @throws \GuzzleHttp\Exception\GuzzleException */ - public function sendRequest($id, $document) + public function sendRequest($id, $document, $fileResultType) { $client = new Client(); @@ -57,6 +57,16 @@ class SendDocument 'contents' => $id, ], + [ + 'name' => 'file_result_type', + 'contents' => $fileResultType, + ], + + [ + 'name' => 'mime_type', + 'contents' => $document['type'], + ], + [ 'name' => 'document', 'contents' => fopen($document['path'], 'r'), diff --git a/app/SearchDisplace/SearchAndDisplace.php b/app/SearchDisplace/SearchAndDisplace.php index be86846..a3ad06b 100644 --- a/app/SearchDisplace/SearchAndDisplace.php +++ b/app/SearchDisplace/SearchAndDisplace.php @@ -85,6 +85,9 @@ class SearchAndDisplace $replacementIndexes[$searcherItem['searcher']][] = [ 'start' => $start, 'end' => $end, + + 'original_start' => $searcherItem['start'], + 'original_end' => $searcherItem['end'], ]; } diff --git a/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php b/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php new file mode 100644 index 0000000..b45e239 --- /dev/null +++ b/app/SearchDisplace/SearchAndDisplaceOriginalDocument.php @@ -0,0 +1,191 @@ +getClientOriginalName(), PATHINFO_FILENAME); + + $this->storeSearchers($id, $searchers); + $this->sendDocumentToIngest($id, $document); + + return $id; + } + + public function applySD($id, $contents) + { + $data = json_decode($contents['document'], true); + + try { + $searchAndDisplace = new SearchAndDisplace( + $data['contents']['text'], + + [ + 'searchers' => $this->getSearchers($id), + ] + ); + + $result = $searchAndDisplace->execute(); + + // Update text. + $data['contents'] = $this->applyResultsOnIngestData($data['contents'], $result); + + \Illuminate\Support\Facades\Log::info($data['contents']); + + // Send to Ingest to recreate doc. + } catch (\Exception $exception) { + \Illuminate\Support\Facades\Log::info($exception->getMessage()); + \Illuminate\Support\Facades\Log::info($exception->getTraceAsString()); + } + } + + public function onIngestFail($id) + { + $storage = Storage::disk('local'); + $directory = "contracts/$id"; + + $storage->deleteDirectory($directory); + } + + public function hasFailed($id) + { + $storage = Storage::disk('local'); + $directory = "contracts/$id"; + + return ! $storage->exists($directory); + } + + public function isInProgress($id) + { + $storage = Storage::disk('local'); + $directory = "contracts/$id"; + + return ! $storage->exists("$directory/document"); + } + + /** + * @param $id + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @throws \Exception + */ + public function streamFile($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"); + } + + protected function applyResultsOnIngestData($ingestData, $sdResult) + { + $ingestData['text'] = $sdResult['content']; + + // Update index ranges. + $indexes = []; + + // Use original start for key in order to have the indexes sorted ASC. + foreach ($sdResult['indexes'] as $searcher => $searcherIndexes) { + foreach ($searcherIndexes as $index) { + $indexes[$index['original_start']] = $index; + } + } + + // 0 - 20 + // 21 - 32 + // 33 - 174 + // + + $startOffset = 0; + + foreach ($ingestData['elements'] as $element) { + $currentStartOffset = 0; + + foreach ($indexes as $i => $index) { + if ($index['original_start'] > $element['range_end']) { + break; + } + + if ($index['original_end'] < $element['range_start']) { + continue; + } + + if ( + $index['original_start'] >= $element['range_start'] && + $index['original_end'] <= $element['range_end'] + ) { + $endDifference = $index['end'] - $index['original_end']; + + $element['range_end'] += $endDifference; + $currentStartOffset += $endDifference; + + unset($indexes[$i]); + } + } + + $element['range_start'] += $startOffset; + + $startOffset += $currentStartOffset; + } + + return $ingestData; + } + + protected function storeSearchers($id, $searchers) + { + $storage = Storage::disk('local'); + $directory = "contracts/$id"; + $storage->makeDirectory($directory); + + $storage->put("$directory/searchers.json", json_encode($searchers)); + } + + /** + * + * @param $id + * @return string + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + protected function getSearchers($id) + { + $storage = Storage::disk('local'); + $directory = "contracts/$id"; + + $searchers = $storage->get("$directory/searchers.json"); + + if ( ! $searchers) { + throw new \Exception('Searchers do not exist.'); + } + + return json_decode($searchers, true); + } + + /** + * + * @param $id + * @param $document + * @throws \Exception + */ + protected function sendDocumentToIngest($id, $document) + { + $sendDocument = new SendDocument(); + + $sendDocument->execute($id, [ + 'path' => $document->getRealPath(), + 'type' => $document->getMimeType(), + 'name' => $document->getClientOriginalName() + ], 'original'); + } +} diff --git a/public/js/app.js b/public/js/app.js index 28a339a..d18d03a 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -3800,6 +3800,7 @@ var Home = /*#__PURE__*/function (_Vue) { _this.uiBlocked = false; _this.uploading = false; _this.fileUploaded = false; + _this.document = null; _this.uploadResult = { id: '', file_name: '' @@ -3877,53 +3878,54 @@ var Home = /*#__PURE__*/function (_Vue) { response = _context2.sent; this.fileUploaded = true; this.uploadResult = response; - _context2.next = 25; + this.document = file; + _context2.next = 26; break; - case 11: - _context2.prev = 11; + case 12: + _context2.prev = 12; _context2.t0 = _context2["catch"](3); this.uploading = false; this.fileUploaded = false; if (!(0,_SearchDisplace_helpers__WEBPACK_IMPORTED_MODULE_2__.isServerError)(_context2.t0)) { - _context2.next = 24; + _context2.next = 25; break; } if (!_context2.t0.response.data.hasOwnProperty('errors')) { - _context2.next = 21; + _context2.next = 22; break; } errors = _context2.t0.response.data.errors; if (!errors.hasOwnProperty('file')) { - _context2.next = 21; + _context2.next = 22; break; } this.error = errors.file[0]; return _context2.abrupt("return"); - case 21: + case 22: if (!_context2.t0.response.data.hasOwnProperty('message')) { - _context2.next = 24; + _context2.next = 25; break; } this.error = _context2.t0.response.data.message; return _context2.abrupt("return"); - case 24: + case 25: this.error = 'There was an error uploading your file. Please try again later.'; - case 25: + case 26: case "end": return _context2.stop(); } } - }, _callee2, this, [[3, 11]]); + }, _callee2, this, [[3, 12]]); })); function uploadNewFile(_x2) { @@ -3976,13 +3978,14 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ }); /* harmony import */ var _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/regenerator */ "./node_modules/@babel/runtime/regenerator/index.js"); /* harmony import */ var _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.js"); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.js"); /* harmony import */ var marked__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! marked */ "./node_modules/marked/lib/marked.js"); /* harmony import */ var marked__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(marked__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue-property-decorator */ "./node_modules/vue-property-decorator/lib/vue-property-decorator.js"); /* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/app */ "./resources/js/app.ts"); /* harmony import */ var _Searchers_DefineSearcher_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Searchers/DefineSearcher.vue */ "./resources/js/components/Searchers/DefineSearcher.vue"); /* harmony import */ var primevue_radiobutton__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primevue/radiobutton */ "./node_modules/primevue/radiobutton/index.js"); +/* harmony import */ var _SearchDisplace_helpers__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/SearchDisplace/helpers */ "./resources/js/SearchDisplace/helpers.ts"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } @@ -4024,6 +4027,7 @@ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.g + var ProcessFile = /*#__PURE__*/function (_Vue) { _inherits(ProcessFile, _Vue); @@ -4064,6 +4068,7 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { _this.newlySelectedSearchers = []; _this.showDefineSearcher = false; _this.searcherToDefineText = ''; + _this.applyingOnOriginalDocument = false; return _this; } /** @@ -4343,6 +4348,72 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { return waitForFile; }() + }, { + key: "verifySdOnOriginalDocumentIsDone", + value: function () { + var _verifySdOnOriginalDocumentIsDone = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee4(id) { + var response; + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee4$(_context4) { + while (1) { + switch (_context4.prev = _context4.next) { + case 0: + _context4.next = 2; + return this.$api.verifySdOnOriginalDocumentIsDone(id); + + case 2: + response = _context4.sent; + + if (!(response.status === 'processing')) { + _context4.next = 5; + break; + } + + return _context4.abrupt("return"); + + case 5: + clearInterval(this.intervalId); + + if (!(response.status === 'fail')) { + _context4.next = 9; + break; + } + + this.$toast.add({ + severity: 'error', + summary: 'Something went wrong.', + detail: 'Document could not have been processed.', + life: 7000 + }); + return _context4.abrupt("return"); + + case 9: + this.$toast.add({ + severity: 'success', + summary: 'File loaded', + detail: 'The file has been processed by ingest.', + life: 7000 + }); + this.downloadFinishedOriginalDocument(id); + + case 11: + case "end": + return _context4.stop(); + } + } + }, _callee4, this); + })); + + function verifySdOnOriginalDocumentIsDone(_x3) { + return _verifySdOnOriginalDocumentIsDone.apply(this, arguments); + } + + return verifySdOnOriginalDocumentIsDone; + }() + }, { + key: "downloadFinishedOriginalDocument", + value: function downloadFinishedOriginalDocument(id) { + window.open("".concat(window.location.origin, "/search-and-displace/original-document/").concat(id, "/download")); + } /** * * @param $event @@ -4365,13 +4436,13 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { }, { key: "runSearchers", value: function () { - var _runSearchers = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee4() { + var _runSearchers = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee5() { var _this4 = this; var searchers, response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee4$(_context4) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee5$(_context5) { while (1) { - switch (_context4.prev = _context4.next) { + switch (_context5.prev = _context5.next) { case 0: this.processing = true; this.processedFileContent = ''; @@ -4383,32 +4454,32 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { value: _this4.searchersOptions[searcher.id].value || '' }); }); - _context4.prev = 4; - _context4.next = 7; + _context5.prev = 4; + _context5.next = 7; return this.$api.filterDocument(this.fileContent, searchers); case 7: - response = _context4.sent; + response = _context5.sent; this.processedFileContent = response.content; this.documentDiffIndexes = response.indexes; this.createDiffPreview(); this.processing = false; - _context4.next = 17; + _context5.next = 17; break; case 14: - _context4.prev = 14; - _context4.t0 = _context4["catch"](4); + _context5.prev = 14; + _context5.t0 = _context5["catch"](4); this.$emit('error', 'Server error.'); // if (isServerError(e)) { // this.$emit('error', getServerErrorMessage(e)); // } case 17: case "end": - return _context4.stop(); + return _context5.stop(); } } - }, _callee4, this, [[4, 14]]); + }, _callee5, this, [[4, 14]]); })); function runSearchers() { @@ -4420,13 +4491,13 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { }, { key: "runSearchersWithoutDisplacing", value: function () { - var _runSearchersWithoutDisplacing = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee5() { + var _runSearchersWithoutDisplacing = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee6() { var _this5 = this; var searchers, response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee5$(_context5) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee6$(_context6) { while (1) { - switch (_context5.prev = _context5.next) { + switch (_context6.prev = _context6.next) { case 0: this.processing = true; this.processedFileContent = ''; @@ -4438,32 +4509,32 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { value: _this5.searchersOptions[searcher.id].value || '' }); }); - _context5.prev = 4; - _context5.next = 7; + _context6.prev = 4; + _context6.next = 7; return this.$api.filterDocument(this.fileContent, searchers, true); case 7: - response = _context5.sent; + response = _context6.sent; this.processedFileContent = this.fileContent; this.documentDiffIndexes = response; this.createDiffPreview(); this.processing = false; - _context5.next = 17; + _context6.next = 17; break; case 14: - _context5.prev = 14; - _context5.t0 = _context5["catch"](4); + _context6.prev = 14; + _context6.t0 = _context6["catch"](4); this.$emit('error', 'Server error.'); // if (isServerError(e)) { // this.$emit('error', getServerErrorMessage(e)); // } case 17: case "end": - return _context5.stop(); + return _context6.stop(); } } - }, _callee5, this, [[4, 14]]); + }, _callee6, this, [[4, 14]]); })); function runSearchersWithoutDisplacing() { @@ -4505,25 +4576,25 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { }, { key: "downloadOdt", value: function () { - var _downloadOdt = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee6() { + var _downloadOdt = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee7() { var response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee6$(_context6) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee7$(_context7) { while (1) { - switch (_context6.prev = _context6.next) { + switch (_context7.prev = _context7.next) { case 0: - _context6.next = 2; + _context7.next = 2; return this.$api.convertFile(this.processedFileContent, this.file.id); case 2: - response = _context6.sent; + response = _context7.sent; window.open("".concat(window.location.origin, "/file/download/") + response.path); case 4: case "end": - return _context6.stop(); + return _context7.stop(); } } - }, _callee6, this); + }, _callee7, this); })); function downloadOdt() { @@ -4532,6 +4603,118 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { return downloadOdt; }() + }, { + key: "downloadOriginal", + value: function () { + var _downloadOriginal = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee8() { + var _this6 = this; + + var searchers, data, errors; + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee8$(_context8) { + while (1) { + switch (_context8.prev = _context8.next) { + case 0: + if (this.document) { + _context8.next = 2; + break; + } + + return _context8.abrupt("return"); + + case 2: + this.applyingOnOriginalDocument = true; + this.$toast.add({ + severity: 'info', + summary: 'Processing...', + detail: 'This operation may take a while..', + life: 7000 + }); + searchers = []; + Object.values(this.selectedSearchers).forEach(function (searcher) { + searchers.push({ + key: searcher.id, + type: _this6.searchersOptions[searcher.id].type, + value: _this6.searchersOptions[searcher.id].value || '' + }); + }); + _context8.prev = 6; + _context8.next = 9; + return this.$api.sdOnOriginalDocument(this.document, searchers); + + case 9: + data = _context8.sent; + this.intervalId = setInterval(function () { + _this6.verifySdOnOriginalDocumentIsDone(data.id); + }, 5000); + _context8.next = 26; + break; + + case 13: + _context8.prev = 13; + _context8.t0 = _context8["catch"](6); + this.applyingOnOriginalDocument = false; + + if (!(0,_SearchDisplace_helpers__WEBPACK_IMPORTED_MODULE_6__.isServerError)(_context8.t0)) { + _context8.next = 25; + break; + } + + if (!_context8.t0.response.data.hasOwnProperty('errors')) { + _context8.next = 22; + break; + } + + errors = _context8.t0.response.data.errors; + + if (!errors.hasOwnProperty('file')) { + _context8.next = 22; + break; + } + + this.$toast.add({ + severity: 'error', + summary: errors.file[0], + detail: 'There was an error processing your file. Please try again later.', + life: 7000 + }); + return _context8.abrupt("return"); + + case 22: + if (!_context8.t0.response.data.hasOwnProperty('message')) { + _context8.next = 25; + break; + } + + this.$toast.add({ + severity: 'error', + summary: _context8.t0.response.data.message, + detail: 'There was an error processing your file. Please try again later.', + life: 7000 + }); + return _context8.abrupt("return"); + + case 25: + this.$toast.add({ + severity: 'error', + summary: 'Something went wrong.', + detail: 'There was an error processing your file. Please try again later.', + life: 7000 + }); + + case 26: + case "end": + return _context8.stop(); + } + } + }, _callee8, this, [[6, 13]]); + })); + + function downloadOriginal() { + return _downloadOriginal.apply(this, arguments); + } + + return downloadOriginal; + }() }, { key: "canRunSearchers", value: function canRunSearchers() { @@ -4618,7 +4801,7 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { }, { key: "onSelectedSearchersChanged", value: function onSelectedSearchersChanged() { - var _this6 = this; + var _this7 = this; var selectedIds = Object.keys(this.selectedSearchers); var optionsIds = Object.keys(this.searchersOptions); @@ -4627,9 +4810,9 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { return; } - _this6.$set(_this6.searchersOptions, selectedId, { - type: _this6.selectedSearchers[selectedId].tag ? 'displace' : 'replace', - value: _this6.selectedSearchers[selectedId].tag ? _this6.selectedSearchers[selectedId].tag : '' + _this7.$set(_this7.searchersOptions, selectedId, { + type: _this7.selectedSearchers[selectedId].tag ? 'displace' : 'replace', + value: _this7.selectedSearchers[selectedId].tag ? _this7.selectedSearchers[selectedId].tag : '' }); }); optionsIds.forEach(function (optionId) { @@ -4637,7 +4820,7 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { return; } - _this6.$delete(_this6.selectedSearchers, optionId); + _this7.$delete(_this7.selectedSearchers, optionId); }); } }]); @@ -4645,7 +4828,7 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { return ProcessFile; }(vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Vue); -(0,tslib__WEBPACK_IMPORTED_MODULE_6__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Prop)({ +(0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Prop)({ default: { id: -1, file: '', @@ -4653,17 +4836,21 @@ var ProcessFile = /*#__PURE__*/function (_Vue) { } })], ProcessFile.prototype, "file", void 0); -(0,tslib__WEBPACK_IMPORTED_MODULE_6__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Prop)({ +(0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Prop)({ default: [] })], ProcessFile.prototype, "searchers", void 0); -(0,tslib__WEBPACK_IMPORTED_MODULE_6__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Watch)('showDiffHighlight')], ProcessFile.prototype, "onDiffHighlightChanged", null); +(0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Prop)({ + default: null +})], ProcessFile.prototype, "document", void 0); -(0,tslib__WEBPACK_IMPORTED_MODULE_6__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Watch)('selectedSearchers', { +(0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Watch)('showDiffHighlight')], ProcessFile.prototype, "onDiffHighlightChanged", null); + +(0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Watch)('selectedSearchers', { deep: true })], ProcessFile.prototype, "onSelectedSearchersChanged", null); -ProcessFile = (0,tslib__WEBPACK_IMPORTED_MODULE_6__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Component)({ +ProcessFile = (0,tslib__WEBPACK_IMPORTED_MODULE_7__.__decorate)([(0,vue_property_decorator__WEBPACK_IMPORTED_MODULE_2__.Component)({ components: { RadioButton: primevue_radiobutton__WEBPACK_IMPORTED_MODULE_5__.default, DefineSearcher: _Searchers_DefineSearcher_vue__WEBPACK_IMPORTED_MODULE_4__.default @@ -4741,7 +4928,8 @@ var ApiService = /*#__PURE__*/function () { file: this.baseUrl + '/api/file', fileDownload: this.baseUrl + '/api/file/convert', fileDiscard: this.baseUrl + '/api/file/', - searchAndDisplace: this.baseUrl + '/search-and-displace' + searchAndDisplace: this.baseUrl + '/search-and-displace', + sdOnOriginalDocument: "".concat(this.baseUrl, "/search-and-displace/original-document") }; } /** @@ -4798,6 +4986,91 @@ var ApiService = /*#__PURE__*/function () { return uploadFile; }() + /** + * + * @param document + * @param searchers + */ + + }, { + key: "sdOnOriginalDocument", + value: function () { + var _sdOnOriginalDocument = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee2(document, searchers) { + var formData, response; + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + formData = new FormData(); + formData.append('document', document); + formData.append('searchers', JSON.stringify(searchers)); + _context2.prev = 3; + _context2.next = 6; + return axios__WEBPACK_IMPORTED_MODULE_1___default().post(this.apiRoutes.sdOnOriginalDocument, formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }); + + case 6: + response = _context2.sent; + return _context2.abrupt("return", response.data); + + case 10: + _context2.prev = 10; + _context2.t0 = _context2["catch"](3); + throw _context2.t0; + + case 13: + case "end": + return _context2.stop(); + } + } + }, _callee2, this, [[3, 10]]); + })); + + function sdOnOriginalDocument(_x2, _x3) { + return _sdOnOriginalDocument.apply(this, arguments); + } + + return sdOnOriginalDocument; + }() + }, { + key: "verifySdOnOriginalDocumentIsDone", + value: function () { + var _verifySdOnOriginalDocumentIsDone = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee3(id) { + var response; + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + _context3.prev = 0; + _context3.next = 3; + return axios__WEBPACK_IMPORTED_MODULE_1___default().get("".concat(this.apiRoutes.sdOnOriginalDocument, "/").concat(id)); + + case 3: + response = _context3.sent; + return _context3.abrupt("return", response.data); + + case 7: + _context3.prev = 7; + _context3.t0 = _context3["catch"](0); + throw _context3.t0; + + case 10: + case "end": + return _context3.stop(); + } + } + }, _callee3, this, [[0, 7]]); + })); + + function verifySdOnOriginalDocumentIsDone(_x4) { + return _verifySdOnOriginalDocumentIsDone.apply(this, arguments); + } + + return verifySdOnOriginalDocumentIsDone; + }() /** * Get data for a file from the server. * Throws an error if the response wasn't successful @@ -4812,34 +5085,34 @@ var ApiService = /*#__PURE__*/function () { }, { key: "getFileData", value: function () { - var _getFileData = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee2(fileId) { + var _getFileData = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee4(fileId) { var response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee2$(_context2) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee4$(_context4) { while (1) { - switch (_context2.prev = _context2.next) { + switch (_context4.prev = _context4.next) { case 0: - _context2.prev = 0; - _context2.next = 3; + _context4.prev = 0; + _context4.next = 3; return axios__WEBPACK_IMPORTED_MODULE_1___default().get(this.apiRoutes.searchAndDisplace + "/".concat(fileId)); case 3: - response = _context2.sent; - return _context2.abrupt("return", response.data); + response = _context4.sent; + return _context4.abrupt("return", response.data); case 7: - _context2.prev = 7; - _context2.t0 = _context2["catch"](0); - throw _context2.t0; + _context4.prev = 7; + _context4.t0 = _context4["catch"](0); + throw _context4.t0; case 10: case "end": - return _context2.stop(); + return _context4.stop(); } } - }, _callee2, this, [[0, 7]]); + }, _callee4, this, [[0, 7]]); })); - function getFileData(_x2) { + function getFileData(_x5) { return _getFileData.apply(this, arguments); } @@ -4856,17 +5129,17 @@ var ApiService = /*#__PURE__*/function () { }, { key: "filterDocument", value: function () { - var _filterDocument = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee3(content, searchers) { + var _filterDocument = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee5(content, searchers) { var searchOnly, response, - _args3 = arguments; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee3$(_context3) { + _args5 = arguments; + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee5$(_context5) { while (1) { - switch (_context3.prev = _context3.next) { + switch (_context5.prev = _context5.next) { case 0: - searchOnly = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : false; - _context3.prev = 1; - _context3.next = 4; + searchOnly = _args5.length > 2 && _args5[2] !== undefined ? _args5[2] : false; + _context5.prev = 1; + _context5.next = 4; return axios__WEBPACK_IMPORTED_MODULE_1___default().post(this.apiRoutes.searchAndDisplace, { 'content': content, 'searchers': searchers, @@ -4874,23 +5147,23 @@ var ApiService = /*#__PURE__*/function () { }); case 4: - response = _context3.sent; - return _context3.abrupt("return", response.data); + response = _context5.sent; + return _context5.abrupt("return", response.data); case 8: - _context3.prev = 8; - _context3.t0 = _context3["catch"](1); - throw _context3.t0; + _context5.prev = 8; + _context5.t0 = _context5["catch"](1); + throw _context5.t0; case 11: case "end": - return _context3.stop(); + return _context5.stop(); } } - }, _callee3, this, [[1, 8]]); + }, _callee5, this, [[1, 8]]); })); - function filterDocument(_x3, _x4) { + function filterDocument(_x6, _x7) { return _filterDocument.apply(this, arguments); } @@ -4908,37 +5181,37 @@ var ApiService = /*#__PURE__*/function () { }, { key: "convertFile", value: function () { - var _convertFile = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee4(content, fileId) { + var _convertFile = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee6(content, fileId) { var response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee4$(_context4) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee6$(_context6) { while (1) { - switch (_context4.prev = _context4.next) { + switch (_context6.prev = _context6.next) { case 0: - _context4.prev = 0; - _context4.next = 3; + _context6.prev = 0; + _context6.next = 3; return axios__WEBPACK_IMPORTED_MODULE_1___default().post(this.apiRoutes.fileDownload, { 'file_id': fileId, 'content': content }); case 3: - response = _context4.sent; - return _context4.abrupt("return", response.data); + response = _context6.sent; + return _context6.abrupt("return", response.data); case 7: - _context4.prev = 7; - _context4.t0 = _context4["catch"](0); - throw _context4.t0; + _context6.prev = 7; + _context6.t0 = _context6["catch"](0); + throw _context6.t0; case 10: case "end": - return _context4.stop(); + return _context6.stop(); } } - }, _callee4, this, [[0, 7]]); + }, _callee6, this, [[0, 7]]); })); - function convertFile(_x5, _x6) { + function convertFile(_x8, _x9) { return _convertFile.apply(this, arguments); } @@ -4953,34 +5226,34 @@ var ApiService = /*#__PURE__*/function () { }, { key: "discardFile", value: function () { - var _discardFile = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee5(fileId) { + var _discardFile = _asyncToGenerator( /*#__PURE__*/_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().mark(function _callee7(fileId) { var response; - return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee5$(_context5) { + return _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default().wrap(function _callee7$(_context7) { while (1) { - switch (_context5.prev = _context5.next) { + switch (_context7.prev = _context7.next) { case 0: - _context5.prev = 0; - _context5.next = 3; + _context7.prev = 0; + _context7.next = 3; return axios__WEBPACK_IMPORTED_MODULE_1___default().delete(this.apiRoutes.fileDiscard + fileId); case 3: - response = _context5.sent; - return _context5.abrupt("return", response.data); + response = _context7.sent; + return _context7.abrupt("return", response.data); case 7: - _context5.prev = 7; - _context5.t0 = _context5["catch"](0); - throw _context5.t0; + _context7.prev = 7; + _context7.t0 = _context7["catch"](0); + throw _context7.t0; case 10: case "end": - return _context5.stop(); + return _context7.stop(); } } - }, _callee5, this, [[0, 7]]); + }, _callee7, this, [[0, 7]]); })); - function discardFile(_x7) { + function discardFile(_x10) { return _discardFile.apply(this, arguments); } @@ -30033,6 +30306,7 @@ var render = function() { _c("process-file", { attrs: { file: _vm.uploadResult, + document: _vm.document, searchers: _vm.availableSearchers }, on: { @@ -30262,6 +30536,21 @@ var render = function() { on: { click: _vm.downloadOdt } }), _vm._v(" "), + _c("Button", { + staticClass: + "p-button-secondary p-button-outlined p-button-sm", + attrs: { + label: "Download original", + icon: !_vm.applyingOnOriginalDocument + ? "pi pi-download" + : "pi pi-loading", + disabled: + _vm.processedFileContent == "" || + _vm.applyingOnOriginalDocument + }, + on: { click: _vm.downloadOriginal } + }), + _vm._v(" "), _c("Button", { staticClass: "p-button-success p-button-outlined p-button-sm", diff --git a/resources/js/components/Home/Home.ts b/resources/js/components/Home/Home.ts index 54de59e..24c430d 100644 --- a/resources/js/components/Home/Home.ts +++ b/resources/js/components/Home/Home.ts @@ -10,6 +10,7 @@ export default class Home extends Vue { public uiBlocked = false; public uploading = false; public fileUploaded: boolean = false; + public document: File | null = null; public uploadResult: FileUploadResponse = { id: '', file_name: '', @@ -33,6 +34,7 @@ export default class Home extends Vue { */ public async uploadFile(event: any): Promise { let file = event.files[0]; + return this.uploadNewFile(file); } @@ -52,6 +54,8 @@ export default class Home extends Vue { this.fileUploaded = true; this.uploadResult = response; + + this.document = file; } catch (e) { this.uploading = false; this.fileUploaded = false; diff --git a/resources/js/components/Home/Home.vue b/resources/js/components/Home/Home.vue index f504134..f131599 100644 --- a/resources/js/components/Home/Home.vue +++ b/resources/js/components/Home/Home.vue @@ -32,6 +32,7 @@ + @@ -71,6 +72,12 @@ :disabled="processedFileContent == ''" @click="downloadOdt"/> +