From 7f5e682a8267dce077d7e7c69f0265eb406f40ba Mon Sep 17 00:00:00 2001
From: Damien <damien.burel@maarch.org>
Date: Fri, 31 Jan 2020 11:32:05 +0100
Subject: [PATCH] FEAT #12346 TIME 0:30 Check if resource is signed when update

---
 .../resource/controllers/ResController.php    | 432 +---------------
 .../controllers/ResourceControlController.php | 471 ++++++++++++++++++
 2 files changed, 474 insertions(+), 429 deletions(-)
 create mode 100644 src/app/resource/controllers/ResourceControlController.php

diff --git a/src/app/resource/controllers/ResController.php b/src/app/resource/controllers/ResController.php
index acd1cbbbcd5..66e15fdaa71 100755
--- a/src/app/resource/controllers/ResController.php
+++ b/src/app/resource/controllers/ResController.php
@@ -19,18 +19,14 @@ use Attachment\models\AttachmentModel;
 use Basket\models\BasketModel;
 use Basket\models\GroupBasketModel;
 use Basket\models\RedirectBasketModel;
-use Contact\models\ContactModel;
 use Convert\controllers\ConvertPdfController;
 use Convert\controllers\ConvertThumbnailController;
 use Convert\models\AdrModel;
-use CustomField\models\CustomFieldModel;
 use Docserver\models\DocserverModel;
 use Docserver\models\DocserverTypeModel;
-use Doctype\models\DoctypeModel;
 use Email\models\EmailModel;
 use Entity\models\EntityModel;
 use Entity\models\ListInstanceModel;
-use Folder\controllers\FolderController;
 use Folder\models\FolderModel;
 use Folder\models\ResourceFolderModel;
 use Group\controllers\GroupController;
@@ -38,7 +34,6 @@ use Group\controllers\PrivilegeController;
 use Group\models\GroupModel;
 use History\controllers\HistoryController;
 use IndexingModel\models\IndexingModelFieldModel;
-use IndexingModel\models\IndexingModelModel;
 use Note\models\NoteModel;
 use Priority\models\PriorityModel;
 use Resource\models\ResModel;
@@ -51,12 +46,10 @@ use SrcCore\controllers\PreparedClauseController;
 use SrcCore\models\CoreConfigModel;
 use SrcCore\models\ValidatorModel;
 use Status\models\StatusModel;
-use Tag\models\TagModel;
 use Tag\models\TagResModel;
-use User\models\UserGroupModel;
 use User\models\UserModel;
 
-class ResController
+class ResController extends ResourceControlController
 {
     public function create(Request $request, Response $response)
     {
@@ -66,7 +59,7 @@ class ResController
 
         $body = $request->getParsedBody();
 
-        $control = ResController::controlResource(['body' => $body]);
+        $control = ResourceControlController::controlResource(['body' => $body]);
         if (!empty($control['errors'])) {
             return $response->withStatus(400)->withJson(['errors' => $control['errors']]);
         }
@@ -257,7 +250,7 @@ class ResController
             unset($body['diffusionList']);
         }
 
-        $control = ResController::controlUpdateResource(['body' => $body, 'resId' => $args['resId'], 'isProcessing' => $isProcessing]);
+        $control = ResourceControlController::controlUpdateResource(['body' => $body, 'resId' => $args['resId'], 'isProcessing' => $isProcessing]);
         if (!empty($control['errors'])) {
             return $response->withStatus(400)->withJson(['errors' => $control['errors']]);
         }
@@ -957,425 +950,6 @@ class ResController
         return true;
     }
 
-    private static function controlResource(array $args)
-    {
-        $currentUser = UserModel::getById(['id' => $GLOBALS['id'], 'select' => ['loginmode']]);
-        $isWebServiceUser = $currentUser['loginmode'] == 'restMode';
-
-        $body = $args['body'];
-
-        if (empty($body)) {
-            return ['errors' => 'Body is not set or empty'];
-        } elseif (!Validator::intVal()->notEmpty()->validate($body['doctype'])) {
-            return ['errors' => 'Body doctype is empty or not an integer'];
-        } elseif (!Validator::intVal()->notEmpty()->validate($body['modelId'])) {
-            return ['errors' => 'Body modelId is empty or not an integer'];
-        } elseif ($isWebServiceUser && !Validator::stringType()->notEmpty()->validate($body['status'])) {
-            return ['errors' => 'Body status is empty or not a string'];
-        }
-
-        $doctype = DoctypeModel::getById(['id' => $body['doctype'], 'select' => [1]]);
-        if (empty($doctype)) {
-            return ['errors' => 'Body doctype does not exist'];
-        }
-
-        $indexingModel = IndexingModelModel::getById(['id' => $body['modelId'], 'select' => ['master', 'enabled']]);
-        if (empty($indexingModel)) {
-            return ['errors' => 'Body modelId does not exist'];
-        } elseif (!$indexingModel['enabled']) {
-            return ['errors' => 'Body modelId is disabled'];
-        } elseif (!empty($indexingModel['master'])) {
-            return ['errors' => 'Body modelId is not public'];
-        }
-
-        $control = ResController::controlFileData(['body' => $body]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        $control = ResController::controlAdjacentData(['body' => $body, 'isWebServiceUser' => $isWebServiceUser]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        if (!$isWebServiceUser) {
-            $control = ResController::controlIndexingModelFields(['body' => $body]);
-            if (!empty($control['errors'])) {
-                return ['errors' => $control['errors']];
-            }
-
-            if (!empty($body['initiator'])) {
-                $userEntities = UserModel::getEntitiesByLogin(['login' => $GLOBALS['userId']]);
-                $userEntities = array_column($userEntities, 'id');
-                if (!in_array($body['initiator'], $userEntities)) {
-                    return ['errors' => "Body initiator does not belong to your entities"];
-                }
-            }
-        }
-
-        $control = ResController::controlDestination(['body' => $body]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-        $control = ResController::controlDates(['body' => $body]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        if (!empty($body['status'])) {
-            $status = StatusModel::getById(['id' => $body['status'], 'select' => [1]]);
-            if (empty($status)) {
-                return ['errors' => 'Body status does not exist'];
-            }
-        }
-
-        if (!empty($body['linkedResources'])) {
-            if (!ResController::hasRightByResId(['resId' => [$body['linkedResources']], 'userId' => $GLOBALS['id']])) {
-                return ['errors' => 'Body linkedResources out of perimeter'];
-            }
-        }
-
-        return true;
-    }
-
-    private static function controlUpdateResource(array $args)
-    {
-        $body = $args['body'];
-
-        $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['status', 'model_id', 'external_signatory_book_id']]);
-        if (empty($resource['status'])) {
-            return ['errors' => 'Resource status is empty. It can not be modified'];
-        }
-        $status = StatusModel::getById(['id' => $resource['status'], 'select' => ['can_be_modified']]);
-        if ($status['can_be_modified'] != 'Y') {
-            return ['errors' => 'Resource can not be modified because of status'];
-        }
-
-        if (empty($body)) {
-            return ['errors' => 'Body is not set or empty'];
-        } elseif (!Validator::intVal()->notEmpty()->validate($body['doctype'])) {
-            return ['errors' => 'Body doctype is empty or not an integer'];
-        } elseif (!empty($body['encodedFile']) && !empty($resource['external_signatory_book_id'])) {
-            return ['errors' => 'Resource is in external signature book, file can not be modified'];
-        }
-
-        $doctype = DoctypeModel::getById(['id' => $body['doctype'], 'select' => [1]]);
-        if (empty($doctype)) {
-            return ['errors' => 'Body doctype does not exist'];
-        }
-
-        $control = ResController::controlFileData(['body' => $body]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        $control = ResController::controlAdjacentData(['body' => $body, 'isWebServiceUser' => false]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        $body['modelId'] = $resource['model_id'];
-        $control = ResController::controlIndexingModelFields(['body' => $body, 'isProcessing' => $args['isProcessing']]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        if (!empty($body['initiator'])) {
-            $userEntities = UserModel::getEntitiesByLogin(['login' => $GLOBALS['userId']]);
-            $userEntities = array_column($userEntities, 'id');
-            if (!in_array($body['initiator'], $userEntities)) {
-                return ['errors' => "Body initiator does not belong to your entities"];
-            }
-        }
-
-        $control = ResController::controlDestination(['body' => $body]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-        $control = ResController::controlDates(['body' => $body, 'resId' => $args['resId']]);
-        if (!empty($control['errors'])) {
-            return ['errors' => $control['errors']];
-        }
-
-        return true;
-    }
-
-    private static function controlFileData(array $args)
-    {
-        $body = $args['body'];
-
-        if (!empty($body['encodedFile'])) {
-            if (!Validator::stringType()->notEmpty()->validate($body['format'])) {
-                return ['errors' => 'Body format is empty or not a string'];
-            }
-
-            $file     = base64_decode($body['encodedFile']);
-            $finfo    = new \finfo(FILEINFO_MIME_TYPE);
-            $mimeType = $finfo->buffer($file);
-            if (!StoreController::isFileAllowed(['extension' => $body['format'], 'type' => $mimeType])) {
-                return ['errors' => "Format with this mimeType is not allowed : {$body['format']} {$mimeType}"];
-            }
-        }
-
-        return true;
-    }
-
-    private static function controlAdjacentData(array $args)
-    {
-        $body = $args['body'];
-
-        if (!empty($body['customFields'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['customFields'])) {
-                return ['errors' => 'Body customFields is not an array'];
-            }
-            $customFields = CustomFieldModel::get(['select' => ['count(1)'], 'where' => ['id in (?)'], 'data' => [array_keys($body['customFields'])]]);
-            if (count($body['customFields']) != $customFields[0]['count']) {
-                return ['errors' => 'Body customFields : One or more custom fields do not exist'];
-            }
-        }
-        if (!empty($body['folders'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['folders'])) {
-                return ['errors' => 'Body folders is not an array'];
-            }
-            if (!FolderController::hasFolders(['folders' => $body['folders'], 'userId' => $GLOBALS['id']])) {
-                return ['errors' => 'Body folders : One or more folders do not exist or are out of perimeter'];
-            }
-        }
-        if (!empty($body['tags'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['tags'])) {
-                return ['errors' => 'Body tags is not an array'];
-            }
-            $tags = TagModel::get(['select' => ['count(1)'], 'where' => ['id in (?)'], 'data' => [$body['tags']]]);
-            if (count($body['tags']) != $tags[0]['count']) {
-                return ['errors' => 'Body tags : One or more tags do not exist'];
-            }
-        }
-        if (!empty($body['senders'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['senders'])) {
-                return ['errors' => 'Body senders is not an array'];
-            }
-            foreach ($body['senders'] as $key => $sender) {
-                if (!Validator::arrayType()->notEmpty()->validate($sender)) {
-                    return ['errors' => "Body senders[{$key}] is not an array"];
-                }
-                if ($sender['type'] == 'contact') {
-                    $senderItem = ContactModel::getById(['id' => $sender['id'], 'select' => [1]]);
-                } elseif ($sender['type'] == 'user') {
-                    $senderItem = UserModel::getById(['id' => $sender['id'], 'select' => [1]]);
-                } elseif ($sender['type'] == 'entity') {
-                    $senderItem = EntityModel::getById(['id' => $sender['id'], 'select' => [1]]);
-                } else {
-                    return ['errors' => "Body senders[{$key}] type is not valid"];
-                }
-                if (empty($senderItem)) {
-                    return ['errors' => "Body senders[{$key}] id does not exist"];
-                }
-            }
-        }
-        if (!empty($body['recipients'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['recipients'])) {
-                return ['errors' => 'Body recipients is not an array'];
-            }
-            foreach ($body['recipients'] as $key => $recipient) {
-                if (!Validator::arrayType()->notEmpty()->validate($recipient)) {
-                    return ['errors' => "Body recipients[{$key}] is not an array"];
-                }
-                if ($recipient['type'] == 'contact') {
-                    $recipientItem = ContactModel::getById(['id' => $recipient['id'], 'select' => [1]]);
-                } elseif ($recipient['type'] == 'user') {
-                    $recipientItem = UserModel::getById(['id' => $recipient['id'], 'select' => [1]]);
-                } elseif ($recipient['type'] == 'entity') {
-                    $recipientItem = EntityModel::getById(['id' => $recipient['id'], 'select' => [1]]);
-                } else {
-                    return ['errors' => "Body recipients[{$key}] type is not valid"];
-                }
-                if (empty($recipientItem)) {
-                    return ['errors' => "Body recipients[{$key}] id does not exist"];
-                }
-            }
-        }
-        if (!empty($body['diffusionList'])) {
-            if (!Validator::arrayType()->notEmpty()->validate($body['diffusionList'])) {
-                return ['errors' => 'Body diffusionList is not an array'];
-            }
-            $destFound = false;
-            foreach ($body['diffusionList'] as $key => $diffusion) {
-                if ($diffusion['mode'] == 'dest') {
-                    if ($destFound) {
-                        return ['errors' => "Body diffusionList has multiple dest"];
-                    }
-                    $destFound = true;
-                }
-                if ($diffusion['type'] == 'user' || $diffusion['mode'] == 'dest') {
-                    $item = UserModel::getById(['id' => $diffusion['id'], 'select' => [1]]);
-                } else {
-                    $item = EntityModel::getById(['id' => $diffusion['id'], 'select' => [1]]);
-                }
-                if (empty($item)) {
-                    return ['errors' => "Body diffusionList[{$key}] id does not exist"];
-                }
-            }
-            if (!$destFound) {
-                return ['errors' => 'Body diffusion has no dest'];
-            }
-        }
-        if (!$args['isWebServiceUser'] && !empty($body['destination']) && empty($destFound)) {
-            return ['errors' => 'Body diffusion has no dest'];
-        }
-
-        return true;
-    }
-
-    private static function controlIndexingModelFields(array $args)
-    {
-        $body = $args['body'];
-
-        $indexingModelFields = IndexingModelFieldModel::get(['select' => ['identifier', 'mandatory'], 'where' => ['model_id = ?'], 'data' => [$body['modelId']]]);
-        foreach ($indexingModelFields as $indexingModelField) {
-            if (strpos($indexingModelField['identifier'], 'indexingCustomField_') !== false) {
-                $customFieldId = explode('_', $indexingModelField['identifier'])[1];
-                if ($indexingModelField['mandatory'] && empty($body['customFields'][$customFieldId])) {
-                    return ['errors' => "Body customFields[{$customFieldId}] is empty"];
-                }
-                if (!empty($body['customFields'][$customFieldId])) {
-                    $customField = CustomFieldModel::getById(['id' => $customFieldId, 'select' => ['type', 'values']]);
-                    $possibleValues = empty($customField['values']) ? [] : json_decode($customField['values']);
-                    if (($customField['type'] == 'select' || $customField['type'] == 'radio') && !in_array($body['customFields'][$customFieldId], $possibleValues)) {
-                        return ['errors' => "Body customFields[{$customFieldId}] has wrong value"];
-                    } elseif ($customField['type'] == 'checkbox') {
-                        if (!is_array($body['customFields'][$customFieldId])) {
-                            return ['errors' => "Body customFields[{$customFieldId}] is not an array"];
-                        }
-                        foreach ($body['customFields'][$customFieldId] as $value) {
-                            if (!in_array($value, $possibleValues)) {
-                                return ['errors' => "Body customFields[{$customFieldId}] has wrong value"];
-                            }
-                        }
-                    } elseif ($customField['type'] == 'string' && !Validator::stringType()->notEmpty()->validate($body['customFields'][$customFieldId])) {
-                        return ['errors' => "Body customFields[{$customFieldId}] is not a string"];
-                    } elseif ($customField['type'] == 'integer' && !Validator::intVal()->notEmpty()->validate($body['customFields'][$customFieldId])) {
-                        return ['errors' => "Body customFields[{$customFieldId}] is not an integer"];
-                    } elseif ($customField['type'] == 'date' && !Validator::date()->notEmpty()->validate($body['customFields'][$customFieldId])) {
-                        return ['errors' => "Body customFields[{$customFieldId}] is not a date"];
-                    }
-                }
-            } elseif ($indexingModelField['identifier'] == 'destination' && !empty($args['isProcessing'])) {
-                continue;
-            } elseif ($indexingModelField['mandatory'] && !isset($body[$indexingModelField['identifier']])) {
-                return ['errors' => "Body {$indexingModelField['identifier']} is not set"];
-            }
-        }
-
-        return true;
-    }
-
-    private static function controlDates(array $args)
-    {
-        $body = $args['body'];
-
-        if (!empty($body['documentDate'])) {
-            if (!Validator::date()->notEmpty()->validate($body['documentDate'])) {
-                return ['errors' => "Body documentDate is not a date"];
-            }
-
-            $documentDate = new \DateTime($body['documentDate']);
-            $tmr = new \DateTime('tomorrow');
-            if ($documentDate > $tmr) {
-                return ['errors' => "Body documentDate is not a valid date"];
-            }
-        }
-        if (!empty($body['arrivalDate'])) {
-            if (!Validator::date()->notEmpty()->validate($body['arrivalDate'])) {
-                return ['errors' => "Body arrivalDate is not a date"];
-            }
-
-            $arrivalDate = new \DateTime($body['arrivalDate']);
-            $tmr = new \DateTime('tomorrow');
-            if ($arrivalDate > $tmr) {
-                return ['errors' => "Body arrivalDate is not a valid date"];
-            }
-        }
-        if (!empty($body['departureDate'])) {
-            if (!Validator::date()->notEmpty()->validate($body['departureDate'])) {
-                return ['errors' => "Body departureDate is not a date"];
-            }
-            $departureDate = new \DateTime($body['departureDate']);
-            if (!empty($documentDate) && $departureDate < $documentDate) {
-                return ['errors' => "Body departureDate is not a valid date"];
-            }
-        }
-        if (!empty($body['processLimitDate'])) {
-            if (!Validator::date()->notEmpty()->validate($body['processLimitDate'])) {
-                return ['errors' => "Body processLimitDate is not a date"];
-            }
-
-            if (!empty($args['resId'])) {
-                $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['process_limit_date']]);
-                if (!empty($resource['process_limit_date'])) {
-                    $originProcessLimitDate = new \DateTime($resource['process_limit_date']);
-                }
-            }
-            $processLimitDate = new \DateTime($body['processLimitDate']);
-            if (empty($originProcessLimitDate) || $originProcessLimitDate != $processLimitDate) {
-                $today = new \DateTime();
-                $today->setTime(00, 00, 00);
-                if ($processLimitDate < $today) {
-                    return ['errors' => "Body processLimitDate is not a valid date"];
-                }
-            }
-        } elseif (!empty($body['priority'])) {
-            $priority = PriorityModel::getById(['id' => $body['priority'], 'select' => [1]]);
-            if (empty($priority)) {
-                return ['errors' => "Body priority does not exist"];
-            }
-        }
-
-        return true;
-    }
-
-    private static function controlDestination(array $args)
-    {
-        $body = $args['body'];
-
-        if (!empty($body['destination'])) {
-            $groups = UserGroupModel::getWithGroups([
-                'select'    => ['usergroups.indexation_parameters'],
-                'where'     => ['usergroup_content.user_id = ?', 'usergroups.can_index = ?'],
-                'data'      => [$GLOBALS['id'], true]
-            ]);
-
-            $clauseToProcess = '';
-            $allowedEntities = [];
-            foreach ($groups as $group) {
-                $group['indexation_parameters'] = json_decode($group['indexation_parameters'], true);
-                foreach ($group['indexation_parameters']['keywords'] as $keywordValue) {
-                    if (strpos($clauseToProcess, IndexingController::KEYWORDS[$keywordValue]) === false) {
-                        if (!empty($clauseToProcess)) {
-                            $clauseToProcess .= ', ';
-                        }
-                        $clauseToProcess .= IndexingController::KEYWORDS[$keywordValue];
-                    }
-                }
-                $allowedEntities = array_merge($allowedEntities, $group['indexation_parameters']['entities']);
-                $allowedEntities = array_unique($allowedEntities);
-            }
-
-            if (!empty($clauseToProcess)) {
-                $preparedClause = PreparedClauseController::getPreparedClause(['clause' => $clauseToProcess, 'login' => $GLOBALS['userId']]);
-                $preparedEntities = EntityModel::get(['select' => ['id'], 'where' => ['enabled = ?', "entity_id in {$preparedClause}"], 'data' => ['Y']]);
-                $preparedEntities = array_column($preparedEntities, 'id');
-                $allowedEntities = array_merge($allowedEntities, $preparedEntities);
-                $allowedEntities = array_unique($allowedEntities);
-            }
-
-            if (!in_array($body['destination'], $allowedEntities)) {
-                return ['errors' => "Body destination is out of your indexing parameters"];
-            }
-        }
-
-        return true;
-    }
-
     public function getList(Request $request, Response $response)
     {
         $data = $request->getParams();
diff --git a/src/app/resource/controllers/ResourceControlController.php b/src/app/resource/controllers/ResourceControlController.php
new file mode 100644
index 00000000000..bc78ea41c1e
--- /dev/null
+++ b/src/app/resource/controllers/ResourceControlController.php
@@ -0,0 +1,471 @@
+<?php
+
+/**
+* Copyright Maarch since 2008 under licence GPLv3.
+* See LICENCE.txt file at the root folder for more details.
+* This file is part of Maarch software.
+*
+*/
+
+/**
+* @brief Resource Control Controller
+* @author dev@maarch.org
+*/
+
+namespace Resource\controllers;
+
+use Contact\models\ContactModel;
+use Convert\models\AdrModel;
+use CustomField\models\CustomFieldModel;
+use Doctype\models\DoctypeModel;
+use Entity\models\EntityModel;
+use Folder\controllers\FolderController;
+use IndexingModel\models\IndexingModelFieldModel;
+use IndexingModel\models\IndexingModelModel;
+use Priority\models\PriorityModel;
+use Resource\models\ResModel;
+use Respect\Validation\Validator;
+use SrcCore\controllers\PreparedClauseController;
+use Status\models\StatusModel;
+use Tag\models\TagModel;
+use User\models\UserGroupModel;
+use User\models\UserModel;
+
+class ResourceControlController
+{
+    protected static function controlResource(array $args)
+    {
+        $currentUser = UserModel::getById(['id' => $GLOBALS['id'], 'select' => ['loginmode']]);
+        $isWebServiceUser = $currentUser['loginmode'] == 'restMode';
+
+        $body = $args['body'];
+
+        if (empty($body)) {
+            return ['errors' => 'Body is not set or empty'];
+        } elseif (!Validator::intVal()->notEmpty()->validate($body['doctype'])) {
+            return ['errors' => 'Body doctype is empty or not an integer'];
+        } elseif (!Validator::intVal()->notEmpty()->validate($body['modelId'])) {
+            return ['errors' => 'Body modelId is empty or not an integer'];
+        } elseif ($isWebServiceUser && !Validator::stringType()->notEmpty()->validate($body['status'])) {
+            return ['errors' => 'Body status is empty or not a string'];
+        }
+
+        $doctype = DoctypeModel::getById(['id' => $body['doctype'], 'select' => [1]]);
+        if (empty($doctype)) {
+            return ['errors' => 'Body doctype does not exist'];
+        }
+
+        $indexingModel = IndexingModelModel::getById(['id' => $body['modelId'], 'select' => ['master', 'enabled']]);
+        if (empty($indexingModel)) {
+            return ['errors' => 'Body modelId does not exist'];
+        } elseif (!$indexingModel['enabled']) {
+            return ['errors' => 'Body modelId is disabled'];
+        } elseif (!empty($indexingModel['master'])) {
+            return ['errors' => 'Body modelId is not public'];
+        }
+
+        $control = ResourceControlController::controlFileData(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        $control = ResourceControlController::controlAdjacentData(['body' => $body, 'isWebServiceUser' => $isWebServiceUser]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        if (!$isWebServiceUser) {
+            $control = ResourceControlController::controlIndexingModelFields(['body' => $body]);
+            if (!empty($control['errors'])) {
+                return ['errors' => $control['errors']];
+            }
+
+            if (!empty($body['initiator'])) {
+                $userEntities = UserModel::getEntitiesByLogin(['login' => $GLOBALS['userId']]);
+                $userEntities = array_column($userEntities, 'id');
+                if (!in_array($body['initiator'], $userEntities)) {
+                    return ['errors' => "Body initiator does not belong to your entities"];
+                }
+            }
+        }
+
+        $control = ResourceControlController::controlDestination(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+        $control = ResourceControlController::controlDates(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        if (!empty($body['status'])) {
+            $status = StatusModel::getById(['id' => $body['status'], 'select' => [1]]);
+            if (empty($status)) {
+                return ['errors' => 'Body status does not exist'];
+            }
+        }
+
+        if (!empty($body['linkedResources'])) {
+            if (!ResController::hasRightByResId(['resId' => [$body['linkedResources']], 'userId' => $GLOBALS['id']])) {
+                return ['errors' => 'Body linkedResources out of perimeter'];
+            }
+        }
+
+        return true;
+    }
+
+    protected static function controlUpdateResource(array $args)
+    {
+        $body = $args['body'];
+
+        $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['status', 'model_id', 'external_signatory_book_id']]);
+        if (empty($resource['status'])) {
+            return ['errors' => 'Resource status is empty. It can not be modified'];
+        }
+        $status = StatusModel::getById(['id' => $resource['status'], 'select' => ['can_be_modified']]);
+        if ($status['can_be_modified'] != 'Y') {
+            return ['errors' => 'Resource can not be modified because of status'];
+        }
+
+        if (empty($body)) {
+            return ['errors' => 'Body is not set or empty'];
+        } elseif (!Validator::intVal()->notEmpty()->validate($body['doctype'])) {
+            return ['errors' => 'Body doctype is empty or not an integer'];
+        } elseif (!empty($body['encodedFile']) && !empty($resource['external_signatory_book_id'])) {
+            return ['errors' => 'Resource is in external signature book, file can not be modified'];
+        } elseif (!empty($body['encodedFile']) && ResourceControlController::isSigned(['resId' => $args['resId']])) {
+            return ['errors' => 'Resource is signed, file can not be modified'];
+        }
+
+        $doctype = DoctypeModel::getById(['id' => $body['doctype'], 'select' => [1]]);
+        if (empty($doctype)) {
+            return ['errors' => 'Body doctype does not exist'];
+        }
+
+        $control = ResourceControlController::controlFileData(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        $control = ResourceControlController::controlAdjacentData(['body' => $body, 'isWebServiceUser' => false]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        $body['modelId'] = $resource['model_id'];
+        $control = ResourceControlController::controlIndexingModelFields(['body' => $body, 'isProcessing' => $args['isProcessing']]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        if (!empty($body['initiator'])) {
+            $userEntities = UserModel::getEntitiesByLogin(['login' => $GLOBALS['userId']]);
+            $userEntities = array_column($userEntities, 'id');
+            if (!in_array($body['initiator'], $userEntities)) {
+                return ['errors' => "Body initiator does not belong to your entities"];
+            }
+        }
+
+        $control = ResourceControlController::controlDestination(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+        $control = ResourceControlController::controlDates(['body' => $body, 'resId' => $args['resId']]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        return true;
+    }
+
+    private static function isSigned(array $args)
+    {
+        $signedDocument = AdrModel::getDocuments([
+            'select'    => [1],
+            'where'     => ['res_id = ?', 'type = ?'],
+            'data'      => [$args['resId'], 'SIGN']
+        ]);
+
+        if (empty($signedDocument)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private static function controlFileData(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['encodedFile'])) {
+            if (!Validator::stringType()->notEmpty()->validate($body['format'])) {
+                return ['errors' => 'Body format is empty or not a string'];
+            }
+
+            $file     = base64_decode($body['encodedFile']);
+            $finfo    = new \finfo(FILEINFO_MIME_TYPE);
+            $mimeType = $finfo->buffer($file);
+            if (!StoreController::isFileAllowed(['extension' => $body['format'], 'type' => $mimeType])) {
+                return ['errors' => "Format with this mimeType is not allowed : {$body['format']} {$mimeType}"];
+            }
+        }
+
+        return true;
+    }
+
+    private static function controlAdjacentData(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['customFields'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['customFields'])) {
+                return ['errors' => 'Body customFields is not an array'];
+            }
+            $customFields = CustomFieldModel::get(['select' => ['count(1)'], 'where' => ['id in (?)'], 'data' => [array_keys($body['customFields'])]]);
+            if (count($body['customFields']) != $customFields[0]['count']) {
+                return ['errors' => 'Body customFields : One or more custom fields do not exist'];
+            }
+        }
+        if (!empty($body['folders'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['folders'])) {
+                return ['errors' => 'Body folders is not an array'];
+            }
+            if (!FolderController::hasFolders(['folders' => $body['folders'], 'userId' => $GLOBALS['id']])) {
+                return ['errors' => 'Body folders : One or more folders do not exist or are out of perimeter'];
+            }
+        }
+        if (!empty($body['tags'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['tags'])) {
+                return ['errors' => 'Body tags is not an array'];
+            }
+            $tags = TagModel::get(['select' => ['count(1)'], 'where' => ['id in (?)'], 'data' => [$body['tags']]]);
+            if (count($body['tags']) != $tags[0]['count']) {
+                return ['errors' => 'Body tags : One or more tags do not exist'];
+            }
+        }
+        if (!empty($body['senders'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['senders'])) {
+                return ['errors' => 'Body senders is not an array'];
+            }
+            foreach ($body['senders'] as $key => $sender) {
+                if (!Validator::arrayType()->notEmpty()->validate($sender)) {
+                    return ['errors' => "Body senders[{$key}] is not an array"];
+                }
+                if ($sender['type'] == 'contact') {
+                    $senderItem = ContactModel::getById(['id' => $sender['id'], 'select' => [1]]);
+                } elseif ($sender['type'] == 'user') {
+                    $senderItem = UserModel::getById(['id' => $sender['id'], 'select' => [1]]);
+                } elseif ($sender['type'] == 'entity') {
+                    $senderItem = EntityModel::getById(['id' => $sender['id'], 'select' => [1]]);
+                } else {
+                    return ['errors' => "Body senders[{$key}] type is not valid"];
+                }
+                if (empty($senderItem)) {
+                    return ['errors' => "Body senders[{$key}] id does not exist"];
+                }
+            }
+        }
+        if (!empty($body['recipients'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['recipients'])) {
+                return ['errors' => 'Body recipients is not an array'];
+            }
+            foreach ($body['recipients'] as $key => $recipient) {
+                if (!Validator::arrayType()->notEmpty()->validate($recipient)) {
+                    return ['errors' => "Body recipients[{$key}] is not an array"];
+                }
+                if ($recipient['type'] == 'contact') {
+                    $recipientItem = ContactModel::getById(['id' => $recipient['id'], 'select' => [1]]);
+                } elseif ($recipient['type'] == 'user') {
+                    $recipientItem = UserModel::getById(['id' => $recipient['id'], 'select' => [1]]);
+                } elseif ($recipient['type'] == 'entity') {
+                    $recipientItem = EntityModel::getById(['id' => $recipient['id'], 'select' => [1]]);
+                } else {
+                    return ['errors' => "Body recipients[{$key}] type is not valid"];
+                }
+                if (empty($recipientItem)) {
+                    return ['errors' => "Body recipients[{$key}] id does not exist"];
+                }
+            }
+        }
+        if (!empty($body['diffusionList'])) {
+            if (!Validator::arrayType()->notEmpty()->validate($body['diffusionList'])) {
+                return ['errors' => 'Body diffusionList is not an array'];
+            }
+            $destFound = false;
+            foreach ($body['diffusionList'] as $key => $diffusion) {
+                if ($diffusion['mode'] == 'dest') {
+                    if ($destFound) {
+                        return ['errors' => "Body diffusionList has multiple dest"];
+                    }
+                    $destFound = true;
+                }
+                if ($diffusion['type'] == 'user' || $diffusion['mode'] == 'dest') {
+                    $item = UserModel::getById(['id' => $diffusion['id'], 'select' => [1]]);
+                } else {
+                    $item = EntityModel::getById(['id' => $diffusion['id'], 'select' => [1]]);
+                }
+                if (empty($item)) {
+                    return ['errors' => "Body diffusionList[{$key}] id does not exist"];
+                }
+            }
+            if (!$destFound) {
+                return ['errors' => 'Body diffusion has no dest'];
+            }
+        }
+        if (!$args['isWebServiceUser'] && !empty($body['destination']) && empty($destFound)) {
+            return ['errors' => 'Body diffusion has no dest'];
+        }
+
+        return true;
+    }
+
+    private static function controlIndexingModelFields(array $args)
+    {
+        $body = $args['body'];
+
+        $indexingModelFields = IndexingModelFieldModel::get(['select' => ['identifier', 'mandatory'], 'where' => ['model_id = ?'], 'data' => [$body['modelId']]]);
+        foreach ($indexingModelFields as $indexingModelField) {
+            if (strpos($indexingModelField['identifier'], 'indexingCustomField_') !== false) {
+                $customFieldId = explode('_', $indexingModelField['identifier'])[1];
+                if ($indexingModelField['mandatory'] && empty($body['customFields'][$customFieldId])) {
+                    return ['errors' => "Body customFields[{$customFieldId}] is empty"];
+                }
+                if (!empty($body['customFields'][$customFieldId])) {
+                    $customField = CustomFieldModel::getById(['id' => $customFieldId, 'select' => ['type', 'values']]);
+                    $possibleValues = empty($customField['values']) ? [] : json_decode($customField['values']);
+                    if (($customField['type'] == 'select' || $customField['type'] == 'radio') && !in_array($body['customFields'][$customFieldId], $possibleValues)) {
+                        return ['errors' => "Body customFields[{$customFieldId}] has wrong value"];
+                    } elseif ($customField['type'] == 'checkbox') {
+                        if (!is_array($body['customFields'][$customFieldId])) {
+                            return ['errors' => "Body customFields[{$customFieldId}] is not an array"];
+                        }
+                        foreach ($body['customFields'][$customFieldId] as $value) {
+                            if (!in_array($value, $possibleValues)) {
+                                return ['errors' => "Body customFields[{$customFieldId}] has wrong value"];
+                            }
+                        }
+                    } elseif ($customField['type'] == 'string' && !Validator::stringType()->notEmpty()->validate($body['customFields'][$customFieldId])) {
+                        return ['errors' => "Body customFields[{$customFieldId}] is not a string"];
+                    } elseif ($customField['type'] == 'integer' && !Validator::intVal()->notEmpty()->validate($body['customFields'][$customFieldId])) {
+                        return ['errors' => "Body customFields[{$customFieldId}] is not an integer"];
+                    } elseif ($customField['type'] == 'date' && !Validator::date()->notEmpty()->validate($body['customFields'][$customFieldId])) {
+                        return ['errors' => "Body customFields[{$customFieldId}] is not a date"];
+                    }
+                }
+            } elseif ($indexingModelField['identifier'] == 'destination' && !empty($args['isProcessing'])) {
+                continue;
+            } elseif ($indexingModelField['mandatory'] && !isset($body[$indexingModelField['identifier']])) {
+                return ['errors' => "Body {$indexingModelField['identifier']} is not set"];
+            }
+        }
+
+        return true;
+    }
+
+    private static function controlDates(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['documentDate'])) {
+            if (!Validator::date()->notEmpty()->validate($body['documentDate'])) {
+                return ['errors' => "Body documentDate is not a date"];
+            }
+
+            $documentDate = new \DateTime($body['documentDate']);
+            $tmr = new \DateTime('tomorrow');
+            if ($documentDate > $tmr) {
+                return ['errors' => "Body documentDate is not a valid date"];
+            }
+        }
+        if (!empty($body['arrivalDate'])) {
+            if (!Validator::date()->notEmpty()->validate($body['arrivalDate'])) {
+                return ['errors' => "Body arrivalDate is not a date"];
+            }
+
+            $arrivalDate = new \DateTime($body['arrivalDate']);
+            $tmr = new \DateTime('tomorrow');
+            if ($arrivalDate > $tmr) {
+                return ['errors' => "Body arrivalDate is not a valid date"];
+            }
+        }
+        if (!empty($body['departureDate'])) {
+            if (!Validator::date()->notEmpty()->validate($body['departureDate'])) {
+                return ['errors' => "Body departureDate is not a date"];
+            }
+            $departureDate = new \DateTime($body['departureDate']);
+            if (!empty($documentDate) && $departureDate < $documentDate) {
+                return ['errors' => "Body departureDate is not a valid date"];
+            }
+        }
+        if (!empty($body['processLimitDate'])) {
+            if (!Validator::date()->notEmpty()->validate($body['processLimitDate'])) {
+                return ['errors' => "Body processLimitDate is not a date"];
+            }
+
+            if (!empty($args['resId'])) {
+                $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['process_limit_date']]);
+                if (!empty($resource['process_limit_date'])) {
+                    $originProcessLimitDate = new \DateTime($resource['process_limit_date']);
+                }
+            }
+            $processLimitDate = new \DateTime($body['processLimitDate']);
+            if (empty($originProcessLimitDate) || $originProcessLimitDate != $processLimitDate) {
+                $today = new \DateTime();
+                $today->setTime(00, 00, 00);
+                if ($processLimitDate < $today) {
+                    return ['errors' => "Body processLimitDate is not a valid date"];
+                }
+            }
+        } elseif (!empty($body['priority'])) {
+            $priority = PriorityModel::getById(['id' => $body['priority'], 'select' => [1]]);
+            if (empty($priority)) {
+                return ['errors' => "Body priority does not exist"];
+            }
+        }
+
+        return true;
+    }
+
+    private static function controlDestination(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['destination'])) {
+            $groups = UserGroupModel::getWithGroups([
+                'select'    => ['usergroups.indexation_parameters'],
+                'where'     => ['usergroup_content.user_id = ?', 'usergroups.can_index = ?'],
+                'data'      => [$GLOBALS['id'], true]
+            ]);
+
+            $clauseToProcess = '';
+            $allowedEntities = [];
+            foreach ($groups as $group) {
+                $group['indexation_parameters'] = json_decode($group['indexation_parameters'], true);
+                foreach ($group['indexation_parameters']['keywords'] as $keywordValue) {
+                    if (strpos($clauseToProcess, IndexingController::KEYWORDS[$keywordValue]) === false) {
+                        if (!empty($clauseToProcess)) {
+                            $clauseToProcess .= ', ';
+                        }
+                        $clauseToProcess .= IndexingController::KEYWORDS[$keywordValue];
+                    }
+                }
+                $allowedEntities = array_merge($allowedEntities, $group['indexation_parameters']['entities']);
+                $allowedEntities = array_unique($allowedEntities);
+            }
+
+            if (!empty($clauseToProcess)) {
+                $preparedClause = PreparedClauseController::getPreparedClause(['clause' => $clauseToProcess, 'login' => $GLOBALS['userId']]);
+                $preparedEntities = EntityModel::get(['select' => ['id'], 'where' => ['enabled = ?', "entity_id in {$preparedClause}"], 'data' => ['Y']]);
+                $preparedEntities = array_column($preparedEntities, 'id');
+                $allowedEntities = array_merge($allowedEntities, $preparedEntities);
+                $allowedEntities = array_unique($allowedEntities);
+            }
+
+            if (!in_array($body['destination'], $allowedEntities)) {
+                return ['errors' => "Body destination is out of your indexing parameters"];
+            }
+        }
+
+        return true;
+    }
+}
-- 
GitLab