From 2adc618c9d8758e9d1cdfebc35941da199371806 Mon Sep 17 00:00:00 2001
From: Guillaume Heurtier <guillaume.heurtier@maarch.org>
Date: Wed, 2 Dec 2020 13:28:47 +0100
Subject: [PATCH] FEAT #12026 TIME 5:30 added route to convert document page to
 image

---
 rest/index.php                                |   2 +
 .../controllers/ActionMethodController.php    |   9 +-
 .../controllers/AttachmentController.php      |  67 +++++++++++
 .../ConvertThumbnailController.php            | 104 ++++++++++++++++++
 .../resource/controllers/ResController.php    |  66 ++++++++++-
 5 files changed, 242 insertions(+), 6 deletions(-)

diff --git a/rest/index.php b/rest/index.php
index 7ea9bb7a45f..790dfe8e4fe 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -87,6 +87,7 @@ $app->delete('/attachments/{id}', \Attachment\controllers\AttachmentController::
 $app->get('/attachments/{id}/content', \Attachment\controllers\AttachmentController::class . ':getFileContent');
 $app->get('/attachments/{id}/originalContent', \Attachment\controllers\AttachmentController::class . ':getOriginalFileContent');
 $app->get('/attachments/{id}/thumbnail', \Attachment\controllers\AttachmentController::class . ':getThumbnailContent');
+$app->get('/attachments/{id}/thumbnail/{page}', \Attachment\controllers\AttachmentController::class . ':getThumbnailContentByPage');
 $app->put('/attachments/{id}/inSendAttachment', \Attachment\controllers\AttachmentController::class . ':setInSendAttachment');
 $app->put('/attachments/{id}/inSignatureBook', \Attachment\controllers\AttachmentController::class . ':setInSignatureBook');
 $app->put('/attachments/{id}/sign', \SignatureBook\controllers\SignatureBookController::class . ':signAttachment');
@@ -400,6 +401,7 @@ $app->get('/resources/{resId}/versionsInformations', \Resource\controllers\ResCo
 $app->get('/resources/{resId}/content/{version}', \Resource\controllers\ResController::class . ':getVersionFileContent');
 $app->get('/resources/{resId}/originalContent', \Resource\controllers\ResController::class . ':getOriginalFileContent');
 $app->get('/resources/{resId}/thumbnail', \Resource\controllers\ResController::class . ':getThumbnailContent');
+$app->get('/resources/{resId}/thumbnail/{page}', \Resource\controllers\ResController::class . ':getThumbnailContentByPage');
 $app->get('/resources/{resId}/isAllowed', \Resource\controllers\ResController::class . ':isAllowedForCurrentUser');
 $app->get('/resources/{resId}/items', \Resource\controllers\ResController::class . ':getItems');
 $app->get('/resources/{resId}/attachments', \Attachment\controllers\AttachmentController::class . ':getByResId');
diff --git a/src/app/action/controllers/ActionMethodController.php b/src/app/action/controllers/ActionMethodController.php
index 0a5fadb1f03..acc6df8ec39 100644
--- a/src/app/action/controllers/ActionMethodController.php
+++ b/src/app/action/controllers/ActionMethodController.php
@@ -327,17 +327,16 @@ class ActionMethodController
         return true;
     }
 
-    public function sendSignatureBook(array $args)
+    public static function sendSignatureBook(array $args)
     {
         ValidatorModel::notEmpty($args, ['resId']);
         ValidatorModel::intVal($args, ['resId']);
 
         $circuit = ListInstanceModel::get([
-            'select'    => ['requested_signature'],
+            'select'    => ['requested_signature', 'item_mode'],
             'where'     => ['res_id = ?', 'difflist_type = ?', 'process_date is null'],
             'data'      => [$args['resId'], 'VISA_CIRCUIT'],
-            'orderBy'   => ['listinstance_id'],
-            'limit'     => 1
+            'orderBy'   => ['listinstance_id']
         ]);
         if (empty($circuit)) {
             return ['errors' => ['No available circuit']];
@@ -400,7 +399,7 @@ class ActionMethodController
         return true;
     }
 
-    public function continueVisaCircuit(array $args)
+    public static function continueVisaCircuit(array $args)
     {
         ValidatorModel::notEmpty($args, ['resId']);
         ValidatorModel::intVal($args, ['resId']);
diff --git a/src/app/attachment/controllers/AttachmentController.php b/src/app/attachment/controllers/AttachmentController.php
index 4a1cc4a3686..7a9c799408f 100755
--- a/src/app/attachment/controllers/AttachmentController.php
+++ b/src/app/attachment/controllers/AttachmentController.php
@@ -31,6 +31,7 @@ use Resource\controllers\WatermarkController;
 use Resource\models\ResModel;
 use Resource\models\ResourceContactModel;
 use Respect\Validation\Validator;
+use setasign\Fpdi\Tcpdf\Fpdi;
 use SignatureBook\controllers\SignatureBookController;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -481,6 +482,72 @@ class AttachmentController
 
         return $response->withHeader('Content-Type', $mimeType);
     }
+
+    public function getThumbnailContentByPage(Request $request, Response $response, array $args)
+    {
+        if (!Validator::intVal()->validate($args['id'])) {
+            return $response->withStatus(403)->withJson(['errors' => 'id param is not an integer']);
+        }
+
+        $document = AttachmentModel::getById(['select' => [1], 'id' => $args['id']]);
+        if (empty($document)) {
+            return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
+        }
+
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => 'TNL_ATTACH', 'select' => ['path_template']]);
+        if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
+        }
+
+        $adr = AdrModel::getAttachments([
+            'select'  => ['path', 'filename'],
+            'where'   => ['res_id = ?', 'type = ?'],
+            'data'    => [$args['id'], 'TNL' . $args['page']]
+        ]);
+
+        $pathToThumbnail = $docserver['path_template'] . $adr[0]['path'] . $adr[0]['filename'];
+        if (!is_file($pathToThumbnail) || !is_readable($pathToThumbnail)) {
+            $control = ConvertThumbnailController::convertOnePage(['type' => 'attachment', 'resId' => $args['id'], 'page' => $args['page']]);
+            if (!empty($control['errors'])) {
+                return $response->withStatus(400)->withJson(['errors' => $control['errors']]);
+            }
+            $adr = AdrModel::getAttachments([
+                'select'  => ['path', 'filename'],
+                'where'   => ['res_id = ?', 'type = ?'],
+                'data'    => [$args['id'], 'TNL' . $args['page']]
+            ]);
+            $pathToThumbnail = $docserver['path_template'] . $adr[0]['path'] . $adr[0]['filename'];
+            if (!is_file($pathToThumbnail) || !is_readable($pathToThumbnail)) {
+                return $response->withStatus(400)->withJson(['errors' => 'Thumbnail not found on docserver or not readable', 'lang' => 'thumbnailNotFound']);
+            }
+        }
+        $pathToThumbnail = str_replace('#', '/', $pathToThumbnail);
+
+        $fileContent = file_get_contents($pathToThumbnail);
+        if ($fileContent === false) {
+            return $response->withStatus(404)->withJson(['errors' => 'Page not found on docserver']);
+        }
+
+        $base64Content = base64_encode($fileContent);
+
+        $adrPdf = AdrModel::getAttachments([
+            'select'  => ['path', 'filename', 'docserver_id'],
+            'where'   => ['res_id = ?', 'type = ?'],
+            'data'    => [$args['id'], 'PDF']
+        ]);
+
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => $adrPdf[0]['docserver_id'], 'select' => ['path_template']]);
+        if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
+        }
+        $pathToPdf = $docserver['path_template'] . $adrPdf[0]['path'] . $adrPdf[0]['filename'];
+        $pathToPdf = str_replace('#', '/', $pathToPdf);
+
+        $pdf = new Fpdi('P', 'pt');
+        $pageCount = $pdf->setSourceFile($pathToPdf);
+
+        return $response->withJson(['fileContent' => $base64Content, 'pageCount' => $pageCount]);
+    }
     
     public function getFileContent(Request $request, Response $response, array $args)
     {
diff --git a/src/app/convert/controllers/ConvertThumbnailController.php b/src/app/convert/controllers/ConvertThumbnailController.php
index 86360b16ad1..20e3e224406 100755
--- a/src/app/convert/controllers/ConvertThumbnailController.php
+++ b/src/app/convert/controllers/ConvertThumbnailController.php
@@ -154,4 +154,108 @@ class ConvertThumbnailController
 
         return true;
     }
+
+    public static function convertOnePage(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['resId', 'page', 'type']);
+        ValidatorModel::intVal($args, ['resId', 'page']);
+        ValidatorModel::stringType($args, ['type']);
+
+        if ($args['type'] == 'resource') {
+            $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['filename', 'version']]);
+        } elseif ($args['type'] == 'attachment') {
+            $resource = AttachmentModel::getById(['id' => $args['resId'], 'select' => ['filename']]);
+        }
+
+        if (empty($resource)) {
+            return ['errors' => '[ConvertThumbnail] Resource does not exist'];
+        }
+        if (empty($resource['filename'])) {
+            return true;
+        }
+
+        if ($args['type'] == 'resource') {
+            $convertedDocument = AdrModel::getDocuments([
+                'select'    => ['id', 'docserver_id', 'path', 'filename', 'fingerprint'],
+                'where'     => ['res_id = ?', 'type in (?)', 'version = ?'],
+                'data'      => [$args['resId'], ['PDF', 'SIGN'], $resource['version']],
+                'orderBy'   => ["type='SIGN' DESC"],
+                'limit'     => 1
+            ]);
+            $convertedDocument = $convertedDocument[0] ?? null;
+        } elseif ($args['type'] == 'attachment') {
+            $convertedDocument = AdrModel::getConvertedDocumentById([
+                'select'    => ['id', 'docserver_id','path', 'filename', 'fingerprint'],
+                'resId'     => $args['resId'],
+                'collId'    => 'attachment',
+                'type'      => 'PDF'
+            ]);
+        }
+
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => $convertedDocument['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]);
+        if (empty($docserver['path_template']) || !is_dir($docserver['path_template'])) {
+            return ['errors' => 'Docserver does not exist'];
+        }
+
+        $pathToDocument = $docserver['path_template'] . $convertedDocument['path'] . $convertedDocument['filename'];
+        if (!is_file($pathToDocument) || !is_readable($pathToDocument)) {
+            return ['errors' => 'Document not found on docserver or not readable'];
+        }
+
+        $filename = pathinfo($pathToDocument, PATHINFO_FILENAME);
+        $tmpPath = CoreConfigModel::getTmpPath();
+
+        $img = new \Imagick();
+        $img->pingImage($pathToDocument);
+        $pageCount = $img->getNumberImages();
+        if ($pageCount < $args['page']) {
+            return ['errors' => 'Page does not exist'];
+        }
+
+        $fileNameOnTmp = rand() . $filename;
+
+        $convertPage = $args['page'] - 1;
+        $command = "convert -density 500x500 -quality 100 -background white -alpha remove "
+            . escapeshellarg($pathToDocument) . "[{$convertPage}] " . escapeshellarg("{$tmpPath}{$fileNameOnTmp}.png");
+        exec($command.' 2>&1', $output, $return);
+
+        if ($return !== 0) {
+            return ['errors' => "[ConvertThumbnail] Convert command failed for page {$args['page']} : ".implode(" ", $output)];
+        }
+
+        $content = file_get_contents("{$tmpPath}{$fileNameOnTmp}.png");
+
+        $storeResult = DocserverController::storeResourceOnDocServer([
+            'collId'            => $args['type'] == 'resource' ? 'letterbox_coll' : 'attachments_coll',
+            'docserverTypeId'   => 'TNL',
+            'encodedResource'   => base64_encode($content),
+            'format'            => 'png'
+        ]);
+        if (!empty($storeInfos['errors'])) {
+            return ['errors' => $storeInfos['errors']];
+        }
+
+        unlink("{$tmpPath}{$fileNameOnTmp}.png");
+
+        if ($args['type'] == 'resource') {
+            AdrModel::createDocumentAdr([
+                'resId'         => $args['resId'],
+                'type'          => 'TNL' . $args['page'],
+                'docserverId'   => $storeResult['docserver_id'],
+                'path'          => $storeResult['destination_dir'],
+                'filename'      => $storeResult['file_destination_name'],
+                'version'       => $resource['version']
+            ]);
+        } else {
+            AdrModel::createAttachAdr([
+                'resId'         => $args['resId'],
+                'type'          => 'TNL' . $args['page'],
+                'docserverId'   => $storeResult['docserver_id'],
+                'path'          => $storeResult['destination_dir'],
+                'filename'      => $storeResult['file_destination_name']
+            ]);
+        }
+
+        return true;
+    }
 }
diff --git a/src/app/resource/controllers/ResController.php b/src/app/resource/controllers/ResController.php
index b6131b12898..b744a1add45 100755
--- a/src/app/resource/controllers/ResController.php
+++ b/src/app/resource/controllers/ResController.php
@@ -19,7 +19,6 @@ use Action\models\ActionModel;
 use Attachment\models\AttachmentModel;
 use Basket\models\BasketModel;
 use Basket\models\GroupBasketModel;
-use Basket\models\RedirectBasketModel;
 use Convert\controllers\ConvertPdfController;
 use Convert\controllers\ConvertThumbnailController;
 use Convert\models\AdrModel;
@@ -45,6 +44,7 @@ use Resource\models\ResourceContactModel;
 use Resource\models\UserFollowedResourceModel;
 use Respect\Validation\Validator;
 use Search\controllers\SearchController;
+use setasign\Fpdi\Tcpdf\Fpdi;
 use Shipping\models\ShippingModel;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -746,6 +746,70 @@ class ResController extends ResourceControlController
         return $response->withHeader('Content-Type', $mimeType);
     }
 
+    public function getThumbnailContentByPage(Request $request, Response $response, array $args)
+    {
+        if (!Validator::intVal()->validate($args['resId'])) {
+            return $response->withStatus(403)->withJson(['errors' => 'resId param is not an integer']);
+        }
+
+        $document = ResModel::getById(['select' => ['filename', 'version'], 'resId' => $args['resId']]);
+        if (empty($document)) {
+            return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
+        }
+
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => 'TNL_MLB', 'select' => ['path_template']]);
+        if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
+        }
+
+        $adr = AdrModel::getDocuments([
+            'select'  => ['path', 'filename'],
+            'where'   => ['res_id = ?', 'type = ?'],
+            'data'    => [$args['resId'], 'TNL' . $args['page']]
+        ]);
+
+        $pathToThumbnail = $docserver['path_template'] . $adr[0]['path'] . $adr[0]['filename'];
+        if (!is_file($pathToThumbnail) || !is_readable($pathToThumbnail)) {
+            $control = ConvertThumbnailController::convertOnePage(['type' => 'resource', 'resId' => $args['resId'], 'page' => $args['page']]);
+            if (!empty($control['errors'])) {
+                return $response->withStatus(400)->withJson(['errors' => $control['errors']]);
+            }
+            $adr = AdrModel::getDocuments([
+                'select'  => ['path', 'filename'],
+                'where'   => ['res_id = ?', 'type = ?'],
+                'data'    => [$args['resId'], 'TNL' . $args['page']]
+            ]);
+            $pathToThumbnail = $docserver['path_template'] . $adr[0]['path'] . $adr[0]['filename'];
+            if (!is_file($pathToThumbnail) || !is_readable($pathToThumbnail)) {
+                return $response->withStatus(400)->withJson(['errors' => 'Thumbnail not found on docserver or not readable', 'lang' => 'thumbnailNotFound']);
+            }
+        }
+
+        $fileContent = file_get_contents($pathToThumbnail);
+        if ($fileContent === false) {
+            return $response->withStatus(404)->withJson(['errors' => 'Page not found on docserver']);
+        }
+
+        $base64Content = base64_encode($fileContent);
+
+        $adrPdf = AdrModel::getDocuments([
+            'select'  => ['path', 'filename', 'docserver_id'],
+            'where'   => ['res_id = ?', 'type = ?'],
+            'data'    => [$args['resId'], 'PDF']
+        ]);
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => $adrPdf[0]['docserver_id'], 'select' => ['path_template']]);
+        if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
+        }
+        $pathToPdf = $docserver['path_template'] . $adrPdf[0]['path'] . $adrPdf[0]['filename'];
+        $pathToPdf = str_replace('#', '/', $pathToPdf);
+
+        $pdf = new Fpdi('P', 'pt');
+        $pageCount = $pdf->setSourceFile($pathToPdf);
+
+        return $response->withJson(['fileContent' => $base64Content, 'pageCount' => $pageCount]);
+    }
+
     public function getItems(Request $request, Response $response, array $args)
     {
         if (!Validator::intVal()->validate($args['resId']) || !ResController::hasRightByResId(['resId' => [$args['resId']], 'userId' => $GLOBALS['id']])) {
-- 
GitLab