From f778f9505d4f4a0719c78df2b7135e70ca73aea9 Mon Sep 17 00:00:00 2001
From: Damien <damien.burel@maarch.org>
Date: Wed, 19 Feb 2020 15:55:38 +0100
Subject: [PATCH] FEAT #13217 TIME 1:50 update diffusion list in process

---
 migration/20.03/2003.sql                      |  7 ++
 .../controllers/ActionMethodController.php    |  2 +-
 .../controllers/ListInstanceController.php    | 44 ++++++---
 .../group/controllers/PrivilegeController.php | 89 ++++++++++++-------
 src/frontend/lang/lang-en.ts                  |  6 +-
 src/frontend/lang/lang-fr.ts                  |  6 +-
 src/frontend/lang/lang-nl.ts                  |  6 +-
 src/frontend/service/privileges.service.ts    | 12 +++
 8 files changed, 121 insertions(+), 51 deletions(-)

diff --git a/migration/20.03/2003.sql b/migration/20.03/2003.sql
index 8d0fc16bf46..72d7c04e02d 100644
--- a/migration/20.03/2003.sql
+++ b/migration/20.03/2003.sql
@@ -586,6 +586,13 @@ INSERT INTO usergroups_services (group_id, service_id)
 SELECT distinct(group_id), 'update_diffusion_except_recipient_details'
 FROM usergroups_services WHERE service_id = 'update_list_diff_in_details';
 
+INSERT INTO usergroups_services (group_id, service_id)
+SELECT distinct(group_id), 'update_diffusion_process'
+FROM usergroups_services WHERE service_id = 'edit_recipient_in_process';
+INSERT INTO usergroups_services (group_id, service_id)
+SELECT distinct(group_id), 'update_diffusion_except_recipient_process'
+FROM usergroups_services WHERE group_id not in (SELECT distinct(group_id) FROM usergroups_services WHERE service_id = 'edit_recipient_in_process');
+
 INSERT INTO usergroups_services (group_id, service_id)
 SELECT distinct(group_id), 'update_diffusion_except_recipient_indexing'
 FROM usergroups_services WHERE group_id NOT IN (
diff --git a/src/app/action/controllers/ActionMethodController.php b/src/app/action/controllers/ActionMethodController.php
index 8a34efe75b1..2eb8c931111 100644
--- a/src/app/action/controllers/ActionMethodController.php
+++ b/src/app/action/controllers/ActionMethodController.php
@@ -252,7 +252,7 @@ class ActionMethodController
         }
 
         $listInstances = array_merge($listInstances, $args['data']['listInstances']);
-        $controller = ListInstanceController::updateListInstance(['data' => [['resId' => $args['resId'], 'listInstances' => $listInstances]], 'userId' => $GLOBALS['id']]);
+        $controller = ListInstanceController::updateListInstance(['data' => [['resId' => $args['resId'], 'listInstances' => $listInstances]], 'userId' => $GLOBALS['id'], 'fullRight' => true]);
         if (!empty($controller['errors'])) {
             return ['errors' => [$controller['errors']]];
         }
diff --git a/src/app/entity/controllers/ListInstanceController.php b/src/app/entity/controllers/ListInstanceController.php
index 0d2a23084fa..36afc5b8a23 100755
--- a/src/app/entity/controllers/ListInstanceController.php
+++ b/src/app/entity/controllers/ListInstanceController.php
@@ -130,10 +130,16 @@ class ListInstanceController
 
     public function update(Request $request, Response $response)
     {
-        if (!PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_details', 'userId' => $GLOBALS['id']])
-            && !PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_except_recipient_details', 'userId' => $GLOBALS['id']])
-            && !PrivilegeController::hasPrivilege(['privilegeId' => 'admin_users', 'userId' => $GLOBALS['id']])) {
-            return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
+        $fullRight = false;
+
+        if (PrivilegeController::hasPrivilege(['privilegeId' => 'admin_users', 'userId' => $GLOBALS['id']]) || PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_details', 'userId' => $GLOBALS['id']])) {
+            $fullRight = true;
+        } else {
+            if (!PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_except_recipient_details', 'userId' => $GLOBALS['id']])
+                && !PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_process', 'userId' => $GLOBALS['id']])
+                && !PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_except_recipient_process', 'userId' => $GLOBALS['id']])) {
+                return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
+            }
         }
 
         $body = $request->getParsedBody();
@@ -141,7 +147,7 @@ class ListInstanceController
             return $response->withStatus(400)->withJson(['errors' => 'Body is not set or not an array']);
         }
 
-        $controller = ListInstanceController::updateListInstance(['data' => $body, 'userId' => $GLOBALS['id']]);
+        $controller = ListInstanceController::updateListInstance(['data' => $body, 'userId' => $GLOBALS['id'], 'fullRight' => $fullRight]);
         if (!empty($controller['errors'])) {
             return $response->withStatus($controller['code'])->withJson(['errors' => $controller['errors']]);
         }
@@ -178,7 +184,7 @@ class ListInstanceController
                 return ['errors' => 'resId is empty', 'code' => 400];
             }
 
-            if (!Validator::intVal()->validate($ListInstanceByRes['resId']) || !ResController::hasRightByResId(['resId' => [$ListInstanceByRes['resId']], 'userId' => $GLOBALS['id']])) {
+            if (!Validator::intVal()->validate($ListInstanceByRes['resId']) || !ResController::hasRightByResId(['resId' => [$ListInstanceByRes['resId']], 'userId' => $args['userId']])) {
                 DatabaseModel::rollbackTransaction();
                 return ['errors' => 'Document out of perimeter', 'code' => 403];
             }
@@ -192,10 +198,6 @@ class ListInstanceController
                 'where'     => ['res_id = ?', 'difflist_type = ?'],
                 'data'      => [$ListInstanceByRes['resId'], 'entity_id']
             ]);
-            ListInstanceModel::delete([
-                'where' => ['res_id = ?', 'difflist_type = ?'],
-                'data'  => [$ListInstanceByRes['resId'], 'entity_id']
-            ]);
 
             $recipientFound = false;
             foreach ($ListInstanceByRes['listInstances'] as $instance) {
@@ -204,9 +206,15 @@ class ListInstanceController
                 }
             }
             if (!$recipientFound) {
+                DatabaseModel::rollbackTransaction();
                 return ['errors' => 'Dest is missing', 'code' => 403];
             }
 
+            ListInstanceModel::delete([
+                'where' => ['res_id = ?', 'difflist_type = ?'],
+                'data'  => [$ListInstanceByRes['resId'], 'entity_id']
+            ]);
+
             foreach ($ListInstanceByRes['listInstances'] as $key => $instance) {
                 $listControl = ['item_id', 'item_type', 'item_mode'];
                 foreach ($listControl as $itemControl) {
@@ -245,6 +253,22 @@ class ListInstanceController
                     return ['errors' => 'item_type does not exist', 'code' => 400];
                 }
 
+                if ($instance['item_mode'] == 'dest' && !$args['fullRight']) {
+                    foreach ($listInstances as $listInstance) {
+                        if ($listInstance['item_mode'] == 'dest') {
+                            if ($listInstance['item_type'] != $instance['item_type'] || $listInstance['item_id'] != $instance['item_id']) {
+                                if (!PrivilegeController::hasPrivilege(['privilegeId' => 'update_diffusion_process', 'userId' => $args['userId']])) {
+                                    DatabaseModel::rollbackTransaction();
+                                    return ['errors' => 'Privilege forbidden : update assignee', 'code' => 403];
+                                } elseif (!PrivilegeController::isResourceInProcess(['userId' => $args['userId'], 'resId' => $ListInstanceByRes['resId']])) {
+                                    DatabaseModel::rollbackTransaction();
+                                    return ['errors' => 'Privilege forbidden : update assignee', 'code' => 403];
+                                }
+                            }
+                        }
+                    }
+                }
+
                 ListInstanceModel::create([
                     'res_id'                => $ListInstanceByRes['resId'],
                     'sequence'              => $key,
diff --git a/src/app/group/controllers/PrivilegeController.php b/src/app/group/controllers/PrivilegeController.php
index 4b6928b9613..52cda4c9e8a 100644
--- a/src/app/group/controllers/PrivilegeController.php
+++ b/src/app/group/controllers/PrivilegeController.php
@@ -245,54 +245,75 @@ class PrivilegeController
 
         if (PrivilegeController::hasPrivilege(['privilegeId' => 'edit_resource', 'userId' => $args['userId']])) {
             return ResController::hasRightByResId(['resId' => [$args['resId']], 'userId' => $args['userId']]);
-        } else {
-            $basketsClause = '';
+        }
+
+        return PrivilegeController::isResourceInProcess(['userId' => $args['userId'], 'resId' => $args['resId'], 'canUpdate' => true]);
+    }
+
+    public static function isResourceInProcess(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['resId', 'userId']);
+        ValidatorModel::intVal($args, ['resId', 'userId']);
 
-            $currentUser = UserModel::getById(['id' => $args['userId'], 'select' => ['id', 'user_id']]);
-            $groups = UserGroupModel::get(['select' => ['group_id'], 'where' => ['user_id = ?'], 'data' => [$currentUser['id']]]);
+        $currentUser = UserModel::getById(['id' => $args['userId'], 'select' => ['id', 'user_id']]);
+
+        $basketsClause = '';
+
+        $groups = UserGroupModel::get(['select' => ['group_id'], 'where' => ['user_id = ?'], 'data' => [$currentUser['id']]]);
+        $groups = array_column($groups, 'group_id');
+        if (!empty($groups)) {
+            $groups = GroupModel::get(['select' => ['group_id'], 'where' => ['id in (?)'], 'data' => [$groups]]);
             $groups = array_column($groups, 'group_id');
-            if (!empty($groups)) {
-                $groups = GroupModel::get(['select' => ['group_id'], 'where' => ['id in (?)'], 'data' => [$groups]]);
-                $groups = array_column($groups, 'group_id');
-
-                $baskets = GroupBasketModel::get(['select' => ['basket_id'], 'where' => ['group_id in (?)', 'list_event = ?', "list_event_data->>'canUpdate' = ?"], 'data' => [$groups, 'processDocument', 'true']]);
-                $baskets = array_column($baskets, 'basket_id');
-                if (!empty($baskets)) {
-                    $clauses = BasketModel::get(['select' => ['basket_clause'], 'where' => ['basket_id in (?)'], 'data' => [$baskets]]);
-
-                    foreach ($clauses as $clause) {
-                        $basketClause = PreparedClauseController::getPreparedClause(['clause' => $clause['basket_clause'], 'login' => $currentUser['user_id']]);
-                        if (!empty($basketsClause)) {
-                            $basketsClause .= ' or ';
-                        }
-                        $basketsClause .= "({$basketClause})";
-                    }
-                }
+
+            $where = ['group_id in (?)', 'list_event = ?'];
+            $data = [$groups, 'processDocument'];
+            if (!empty($args['canUpdate'])) {
+                $where[] = "list_event_data->>'canUpdate' = ?";
+                $data[] = 'true';
             }
+            $baskets = GroupBasketModel::get(['select' => ['basket_id'], 'where' => $where, 'data' => $data]);
+            $baskets = array_column($baskets, 'basket_id');
+            if (!empty($baskets)) {
+                $clauses = BasketModel::get(['select' => ['basket_clause'], 'where' => ['basket_id in (?)'], 'data' => [$baskets]]);
 
-            $assignedBaskets = RedirectBasketModel::getAssignedBasketsByUserId(['userId' => $currentUser['id']]);
-            foreach ($assignedBaskets as $basket) {
-                $hasProcessBaskets = GroupBasketModel::get(['select' => [1], 'where' => ['basket_id = ?', 'group_id = ?', 'list_event = ?', "list_event_data->>'canUpdate' = ?"], 'data' => [$basket['basket_id'], $basket['oldGroupId'], 'processDocument', 'true']]);
-                if (!empty($hasProcessBaskets)) {
-                    $basketOwner = UserModel::getById(['id' => $basket['owner_user_id'], 'select' => ['user_id']]);
-                    $basketClause = PreparedClauseController::getPreparedClause(['clause' => $basket['basket_clause'], 'login' => $basketOwner['user_id']]);
+                foreach ($clauses as $clause) {
+                    $basketClause = PreparedClauseController::getPreparedClause(['clause' => $clause['basket_clause'], 'login' => $currentUser['user_id']]);
                     if (!empty($basketsClause)) {
                         $basketsClause .= ' or ';
                     }
                     $basketsClause .= "({$basketClause})";
                 }
             }
+        }
 
-            try {
-                $res = ResModel::getOnView(['select' => [1], 'where' => ['res_id = ?', "({$basketsClause})"], 'data' => [$args['resId']]]);
-                if (empty($res)) {
-                    return false;
+        $assignedBaskets = RedirectBasketModel::getAssignedBasketsByUserId(['userId' => $currentUser['id']]);
+        foreach ($assignedBaskets as $basket) {
+            $where = ['basket_id = ?', 'group_id = ?', 'list_event = ?'];
+            $data = [$basket['basket_id'], $basket['oldGroupId'], 'processDocument'];
+            if (!empty($args['canUpdate'])) {
+                $where[] = "list_event_data->>'canUpdate' = ?";
+                $data[] = 'true';
+            }
+            $hasSB = GroupBasketModel::get(['select' => [1], 'where' => $where, 'data' => $data]);
+            if (!empty($hasSB)) {
+                $basketOwner = UserModel::getById(['id' => $basket['owner_user_id'], 'select' => ['user_id']]);
+                $basketClause = PreparedClauseController::getPreparedClause(['clause' => $basket['basket_clause'], 'login' => $basketOwner['user_id']]);
+                if (!empty($basketsClause)) {
+                    $basketsClause .= ' or ';
                 }
-            } catch (\Exception $e) {
-                return false;
+                $basketsClause .= "({$basketClause})";
             }
+        }
 
-            return true;
+        try {
+            $res = ResModel::getOnView(['select' => [1], 'where' => ['res_id = ?', "({$basketsClause})"], 'data' => [$args['resId']]]);
+            if (empty($res)) {
+                return false;
+            }
+        } catch (\Exception $e) {
+            return false;
         }
+
+        return true;
     }
 }
diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts
index 7a02fd1af0f..5da9cf9e78e 100755
--- a/src/frontend/lang/lang-en.ts
+++ b/src/frontend/lang/lang-en.ts
@@ -1188,8 +1188,10 @@ export const LANG_EN = {
     "manageTagsInApplicationDesc" : "Create tags while indexing, processing and in details",
     "updateDiffusionWhileIndexing" : "Update all parts of diffusion list when indexing.",
     "updateDiffusionExceptRecipientWhileIndexing" : "Update diffusion list except Assignee when indexing.",
-    "updateDiffusionWhileDetails" : "Update all parts of diffusion list when processing.",
-    "updateDiffusionExceptRecipientWhileDetails" : "Update diffusion list except Assignee when processing.",
+    "updateDiffusionWhileProcess" : "Update all parts of diffusion list when processing.",
+    "updateDiffusionExceptRecipientWhileProcess" : "Update diffusion list except Assignee when processing.",
+    "updateDiffusionWhileDetails" : "Update all parts of diffusion list when in details.",
+    "updateDiffusionExceptRecipientWhileDetails" : "Update diffusion list except Assignee when in details.",
     "useMailServices" : "Use emails services as sender",
     "viewDocumentsWithNotes": "View mail with notes",
     "viewDocumentsWithNotesDesc": "View attachments of 'document_with_notes' type",
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index 01a15992218..6661605204a 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -1226,8 +1226,10 @@ export const LANG_FR = {
     "manageTagsInApplicationDesc" : "Créer des mots-clés depuis l'indexation, le traitement et la fiche détaillée",
     "updateDiffusionWhileIndexing" : "Pouvoir modifier toutes les parties de la liste de diffusion lors de l'enregistrement d'un courrier.",
     "updateDiffusionExceptRecipientWhileIndexing" : "Pouvoir modifier la liste de diffusion hormis l'attributaire lors de l'enregistrement d'un courrier.",
-    "updateDiffusionWhileDetails" : "Pouvoir modifier toutes les parties de la liste de diffusion lors du traitement d'un courrier.",
-    "updateDiffusionExceptRecipientWhileDetails" : "Pouvoir modifier la liste de diffusion hormis l'attributaire lors du traitement d'un courrier.",
+    "updateDiffusionWhileProcess" : "Pouvoir modifier toutes les parties de la liste de diffusion lors du traitement d'un courrier.",
+    "updateDiffusionExceptRecipientWhileProcess" : "Pouvoir modifier la liste de diffusion hormis l'attributaire lors du traitement d'un courrier.",
+    "updateDiffusionWhileDetails" : "Pouvoir modifier toutes les parties de la liste de diffusion sur la fiche détaillé d'un courrier.",
+    "updateDiffusionExceptRecipientWhileDetails" : "Pouvoir modifier la liste de diffusion hormis l'attributaire sur la fiche détaillé d'un courrier.",
     "useMailServices" : "Utiliser les courriels de ses services en tant qu'expéditeur",
     "viewDocumentsWithNotes": "Voir les courriers annotés",
     "viewDocumentsWithNotesDesc": "Voir les courriers annotés revenus de Maarch Parapheur",
diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts
index 9570a665b2e..1c3dd5a249f 100755
--- a/src/frontend/lang/lang-nl.ts
+++ b/src/frontend/lang/lang-nl.ts
@@ -1214,8 +1214,10 @@ export const LANG_NL = {
     "manageTagsInApplicationDesc" : "Create tags while indexing, processing and in details", //_TO_TRANSLATE
     "updateDiffusionWhileIndexing" : "Update all parts of diffusion list when indexing.", //_TO_TRANSLATE
     "updateDiffusionExceptRecipientWhileIndexing" : "Update diffusion list except Assignee when indexing.", //_TO_TRANSLATE
-    "updateDiffusionWhileDetails" : "Update all parts of diffusion list when processing.", //_TO_TRANSLATE
-    "updateDiffusionExceptRecipientWhileDetails" : "Update diffusion list except Assignee when processing.", //_TO_TRANSLATE
+    "updateDiffusionWhileProcess" : "Update all parts of diffusion list when processing.", //_TO_TRANSLATE
+    "updateDiffusionExceptRecipientWhileProcess" : "Update diffusion list except Assignee when processing.", //_TO_TRANSLATE
+    "updateDiffusionWhileDetails" : "Update all parts of diffusion list when in details.", //_TO_TRANSLATE
+    "updateDiffusionExceptRecipientWhileDetails" : "Update diffusion list except Assignee when in details.", //_TO_TRANSLATE
     "useMailServices" : "De e-mails van zijn diensten gebruiken als verzender",
     "viewDocumentsWithNotes": "View mail with notes", //_TO_TRANSLATE
     "viewDocumentsWithNotesDesc": "View attachment of 'document_with_notes' type", //_TO_TRANSLATE
diff --git a/src/frontend/service/privileges.service.ts b/src/frontend/service/privileges.service.ts
index aa17fb7f452..802c26708fb 100644
--- a/src/frontend/service/privileges.service.ts
+++ b/src/frontend/service/privileges.service.ts
@@ -350,6 +350,18 @@ export class PrivilegeService {
             "comment": this.lang.updateDiffusionExceptRecipientWhileIndexing,
             "unit": 'diffusionList'
         },
+        {
+            "id": "update_diffusion_process",
+            "label": this.lang.allRoles,
+            "comment": this.lang.updateDiffusionWhileDetails,
+            "unit": 'diffusionList'
+        },
+        {
+            "id": "update_diffusion_except_recipient_process",
+            "label": this.lang.rolesExceptAssignee,
+            "comment": this.lang.updateDiffusionExceptRecipientWhileDetails,
+            "unit": 'diffusionList'
+        },
         {
             "id": "update_diffusion_details",
             "label": this.lang.allRoles,
-- 
GitLab