From 821c06ad9fed235ed68c8d7d2c1c85f4c0783e51 Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Fri, 22 Jul 2022 18:48:57 +0200 Subject: [PATCH] wip #4628 @6 --- .../CompositionOperation.php | 19 +- app/Jobs/FluidbookDocumentUpload.php | 2 - app/Models/FluidbookDocument.php | 80 ++++-- composer.lock | 30 +- .../fields/fluidbook_composition.blade.php | 268 ++++++++++++++---- 5 files changed, 306 insertions(+), 93 deletions(-) diff --git a/app/Http/Controllers/Admin/Operations/FluidbookPublication/CompositionOperation.php b/app/Http/Controllers/Admin/Operations/FluidbookPublication/CompositionOperation.php index 64c6c0daf..192aa738f 100644 --- a/app/Http/Controllers/Admin/Operations/FluidbookPublication/CompositionOperation.php +++ b/app/Http/Controllers/Admin/Operations/FluidbookPublication/CompositionOperation.php @@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin\Operations\FluidbookPublication; use App\Jobs\FluidbookDocumentUpload; use App\Models\FluidbookDocument; use Cubist\Backpack\Http\Controllers\Base\XSendFileController; -use Cubist\Util\Crypt; use Cubist\Util\Files\Files; use Cubist\Util\Str; use Illuminate\Support\Facades\Route; @@ -19,6 +18,7 @@ trait CompositionOperation Route::match(['get'], $segment . '/docs/{doc_id}/thumb_{doc_page}.jpg', $controller . '@getThumb'); Route::match(['post'], $segment . '/uploaddocument', $controller . '@upload'); Route::match(['get'], $segment . '/uploadProgress/{uploadID}', $controller . '@uploadProgress'); + Route::match(['get'], $segment . '/docInfos/{doc_id}', $controller . '@docInfos'); } protected function setupCompositionDefaults() @@ -31,6 +31,15 @@ trait CompositionOperation /** @var FluidbookDocument $doc */ $doc = FluidbookDocument::find($doc_id); $path = $doc->getFile($doc_page, 'jpg', 'thumb', true, true, ''); + if (filesize($path) === 0) { + for ($i = 1; $i <= 8; $i++) { + clearstatcache(); + if (filesize($path) > 0) { + break; + } + sleep($i); + } + } return XSendFileController::sendfile($path); } @@ -48,7 +57,13 @@ trait CompositionOperation FluidbookDocumentUpload::updateProgression($uploadID, __('Mise en file d\'attente du traitement du document'), 1.2); FluidbookDocumentUpload::dispatch($uploadID, $document, backpack_user()); - return response()->json(['uploadID' => $uploadID]); + return response()->json(['uploadID' => $uploadID, 'document' => $document->id]); + } + + protected function docInfos($doc_id) + { + $doc = FluidbookDocument::find($doc_id); + return response()->json(['pages' => $doc->pages, "size" => $doc->pdf_data['size'], 'numbers' => isset($doc->pdf_data['pagenumbers']) ?: range(1, $doc->pages)]); } protected function uploadProgress($uploadID) diff --git a/app/Jobs/FluidbookDocumentUpload.php b/app/Jobs/FluidbookDocumentUpload.php index f2d368c2c..5aea092aa 100644 --- a/app/Jobs/FluidbookDocumentUpload.php +++ b/app/Jobs/FluidbookDocumentUpload.php @@ -31,10 +31,8 @@ class FluidbookDocumentUpload extends Base public function handle() { - FluidbookDocumentUpload::updateProgression($this->uploadID, __('Début du traitement du document'), 1.25); $this->document->processUpload($this->uploadID, $this->isSync()); - } public static function updateProgression($id, $message, $progress) diff --git a/app/Models/FluidbookDocument.php b/app/Models/FluidbookDocument.php index cce846fbb..f95777fa7 100644 --- a/app/Models/FluidbookDocument.php +++ b/app/Models/FluidbookDocument.php @@ -20,7 +20,6 @@ class FluidbookDocument extends ToolboxModel 'singular' => 'document', 'plural' => 'documents']; protected static $_permissionBase = 'fluidbook-document'; - protected $_filesData = null; protected $casts = ['bookmarks' => 'array', 'pdf_data' => 'array', 'file_data' => 'array']; public function setFields() @@ -33,7 +32,6 @@ class FluidbookDocument extends ToolboxModel $this->addField('bookmarks', Textarea::class, ['cast' => 'array']); $this->addField('pdf_data', Textarea::class, ['cast' => 'array']); $this->addField('file_data', Textarea::class, ['cast' => 'array']); - $this->addField('pagesnumbers', Text::class); } public function getResolutionRatio() @@ -47,49 +45,77 @@ class FluidbookDocument extends ToolboxModel public function processUpload($uploadID, $sync = false) { - FluidbookDocumentUpload::updateProgression($uploadID, __('Analyse du document'), 1.3); + FluidbookDocumentUpload::updateProgression($uploadID, __('Analyse du document'), 1.1); $this->checkInfos(); - FluidbookDocumentUpload::updateProgression($uploadID, __('Nettoyage du document'), 1.5); + FluidbookDocumentUpload::updateProgression($uploadID, __('Nettoyage du document'), 1.2); $this->fixPDF(); - FluidbookDocumentUpload::updateProgression($uploadID, __('Découpe du document'), 1.8); + FluidbookDocumentUpload::updateProgression($uploadID, __('Découpe du document'), 1.3); $this->splitPDF(); - FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => 0]), 2); + FluidbookDocumentUpload::updateProgression($uploadID, __('Extraction des textes'), 1.75); + $this->extractTexts(); + FluidbookDocumentUpload::updateProgression($uploadID, __('Extraction des liens'), 1.9); + $this->extractLinks(); + FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages'), 2); $jobs = []; $files = [['jpg', 'thumb'], ['jpg', 150]]; - + $nbfiles = count($files); + $delay = 0; for ($i = 1; $i <= $this->pages; $i++) { foreach ($files as $file) { $job = new FluidbookDocumentFileProcess($this, $i, $file[0], $file[1]); if ($sync) { dispatch_sync($job); } else { - dispatch($job); + dispatch($job)->delay($delay); } $jobs[] = $job; + if ($i % 20 === 0) { + $delay++; + } + $this->_checkJobs($uploadID, $jobs, $nbfiles); } } - $nbjobs = count($jobs); - $nbfiles = count($files); - while (true) { - $done = 0; - foreach ($jobs as $job) { - /** @var $job FluidbookDocumentFileProcess */ - if ($job->isDone()) { - $done++; - } - } - $progress = $done / $nbjobs; - FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => round($done / $nbfiles)]), 2 + $progress); - if ($progress === 1) { - break; + if ($this->_checkJobs($uploadID, $jobs, $nbfiles) === 1) { + return; } usleep(0.25 * 1000000); } } + public function extractTexts() + { + PDFTools::extractTexts($this->path('original.pdf'), $this->path(), '', false, true); + PDFTools::extractHighlightsData($this->path('original.pdf'), $this->path()); + } + + public function extractLinks() + { + PDFTools::extractLinks($this->path('original.pdf'), $this->path()); + } + + protected function _checkJobs($uploadID, $jobs, $nbfiles) + { + $nbjobs = $nbfiles * $this->pages; + + $done = 0; + foreach ($jobs as $job) { + /** @var $job FluidbookDocumentFileProcess */ + if ($job->isDone()) { + $done++; + } + } + $progress = $done / $nbjobs; + if ($progress === 1) { + FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion terminée'), 3); + } else { + FluidbookDocumentUpload::updateProgression($uploadID, __('Conversion des pages (:done/:pages)', ['pages' => $this->pages, 'done' => round($done / $nbfiles)]), 2 + $progress); + } + return $progress; + } + public function getMobileFirstRatio() { $this->checkInfos(); @@ -103,7 +129,6 @@ class FluidbookDocument extends ToolboxModel $this->pages = $infos['pages']; $this->pdf_data = $infos['infos']; $this->bookmarks = $infos['bookmarks']; - $this->pagesnumbers = $infos['numberSections']; $this->saveWithoutFlushingCache(); } } @@ -128,7 +153,11 @@ class FluidbookDocument extends ToolboxModel */ public function path($path = ''): string { - return rtrim(self::WS_DOCS . $this->id . ($path ? DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR) : $path), DIRECTORY_SEPARATOR); + $res = rtrim(self::WS_DOCS . $this->id . ($path ? DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR) : $path), DIRECTORY_SEPARATOR); + if (!$path) { + $res .= DIRECTORY_SEPARATOR; + } + return $res; } public function hasFile($page, $format = 'jpg', $resolution = 150, $withText = true, $withGraphics = true, $version = 'html') @@ -147,6 +176,9 @@ class FluidbookDocument extends ToolboxModel if (filesize($path) < $minsize) { return false; } + if (file_exists($path . '.lock')) { + return false; + } if ($format === 'svg') { $reffile = $this->path('/html/fp' . $page . '.svg'); if (!file_exists($reffile) || filemtime($path) < filemtime($reffile)) { diff --git a/composer.lock b/composer.lock index 954a9e5e0..f65d05dc1 100644 --- a/composer.lock +++ b/composer.lock @@ -1596,13 +1596,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/cubist_cms-back.git", - "reference": "5037fafa790b4d6a0157f38f7237c45aa69bf157" + "reference": "f2cddfa7b1a8446ba3430147ec045dd4777a8658" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-bc5679.tar", - "reference": "5037fafa790b4d6a0157f38f7237c45aa69bf157", - "shasum": "0bccb1ee64d0f71da2e451ced0a4c329decbe0ec" + "url": "https://composer.cubedesigners.com/dist/cubist/cms-back/cubist-cms-back-dev-master-4b1d60.tar", + "reference": "f2cddfa7b1a8446ba3430147ec045dd4777a8658", + "shasum": "e2470e1897d0463adc15af5c713ccfbde756bcf2" }, "require": { "backpack/backupmanager": "^3.0", @@ -1683,7 +1683,7 @@ } ], "description": "Cubist Backpack extension", - "time": "2022-07-19T13:22:56+00:00" + "time": "2022-07-21T18:23:21+00:00" }, { "name": "cubist/cms-front", @@ -1939,13 +1939,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/cubist_pdf.git", - "reference": "dfbda143ad4963784a2251af488978d92da79d51" + "reference": "b93a3841c212ca8bf9793da611d90497b4f9a6de" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/cubist/pdf/cubist-pdf-dev-master-1ba061.tar", - "reference": "dfbda143ad4963784a2251af488978d92da79d51", - "shasum": "1fd430d15409cfcc232ded890019e8dcebf061db" + "url": "https://composer.cubedesigners.com/dist/cubist/pdf/cubist-pdf-dev-master-876ad1.tar", + "reference": "b93a3841c212ca8bf9793da611d90497b4f9a6de", + "shasum": "7c956335d1f230f7f7bd313e72dd04115f2fea1f" }, "require": { "cubist/util": "dev-master", @@ -1981,7 +1981,7 @@ "cubist", "pdf" ], - "time": "2022-07-13T16:13:36+00:00" + "time": "2022-07-21T18:23:40+00:00" }, { "name": "cubist/scorm", @@ -4402,16 +4402,16 @@ }, { "name": "laravel/framework", - "version": "v8.83.20", + "version": "v8.83.21", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "aa5908e83fccb18b135ca31aa0342cf4bd6909a8" + "reference": "1b3b06e5f419eef9bc3dfa06376dd60f5de524bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/aa5908e83fccb18b135ca31aa0342cf4bd6909a8", - "reference": "aa5908e83fccb18b135ca31aa0342cf4bd6909a8", + "url": "https://api.github.com/repos/laravel/framework/zipball/1b3b06e5f419eef9bc3dfa06376dd60f5de524bc", + "reference": "1b3b06e5f419eef9bc3dfa06376dd60f5de524bc", "shasum": "" }, "require": { @@ -4571,7 +4571,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-07-19T14:11:02+00:00" + "time": "2022-07-21T19:36:48+00:00" }, { "name": "laravel/serializable-closure", diff --git a/resources/views/fields/fluidbook_composition.blade.php b/resources/views/fields/fluidbook_composition.blade.php index fbbbe3050..6fcd987b6 100644 --- a/resources/views/fields/fluidbook_composition.blade.php +++ b/resources/views/fields/fluidbook_composition.blade.php @@ -3,10 +3,10 @@ @push('crud_fields_scripts') @@ -484,6 +589,7 @@ + @endpush @push('crud_fields_styles') @@ -509,11 +615,17 @@ } #composition_pages .page:hover, #composition_pages .page.selected { - border-color: #467fcf; + border-color: #467fcf !important; } + #composition_pages .page.pdfselected { + border-color: #0ba234; + background-color: #7dde98; + } + + #composition_pages .page.selected { - background-color: #b5cbf5; + background-color: #b5cbf5 !important; } #composition_pages .page .handle { @@ -585,11 +697,67 @@ #compositionProgress div { position: absolute; - top: 50%; - left: 50%; - width: 20%; + top: calc(50% - 65px); + left: calc(50% - 200px); + width: 400px; + height: 130px; padding: 20px; background-color: #fff; + border-radius: 4px; + } + + #compositionProgress span { + display: block; + text-align: center; + font-size: 17px; + } + + #compositionProgress progress { + width: 100%; + margin: 10px auto; + height: 25px; + appearance: none; + border-radius: 2px; + border: 1px solid rgba(0, 40, 100, .12); + } + + #compositionProgress progress::-moz-progress-bar, #compositionProgress progress::-webkit-progress-value { + border-radius: 2px; + } + + #compositionProgress progress[data-step="0"] { + background-color: #fff; + } + + #compositionProgress progress[data-step="0"]::-moz-progress-bar, #compositionProgress progress[data-step="0"]::-webkit-progress-value { + background-color: #3d86ee; + } + + #compositionProgress progress[data-step="1"] { + background-color: #3d86ee; + } + + #compositionProgress progress[data-step="1"]::-moz-progress-bar, #compositionProgress progress[data-step="1"]::-webkit-progress-value { + background-color: #3471c8; + } + + #compositionProgress progress[data-step="2"] { + background-color: #3471c8; + } + + #compositionProgress progress[data-step="2"]::-moz-progress-bar, #compositionProgress progress[data-step="2"]::-webkit-progress-value { + background-color: #20457b; + } + + .pace { + opacity: 0; + } + + #compositionUploadForm { + opacity: 0; + position: absolute; + top: 0; + left: 0; } -- 2.39.5