From 1bfef34660347e778fcfd06b23082d5753c1180f Mon Sep 17 00:00:00 2001
From: Damien <damien.burel@maarch.org>
Date: Wed, 8 Jan 2020 17:34:14 +0100
Subject: [PATCH] FEAT #11692 TIME 3:00 Create and delete link

---
 migration/19.12/1912.sql                      |  1 +
 rest/index.php                                |  2 +
 sql/structure.sql                             |  1 +
 .../resource/controllers/ResController.php    | 68 +++++++++++++++++++
 .../resource/controllers/StoreController.php  |  1 +
 5 files changed, 73 insertions(+)

diff --git a/migration/19.12/1912.sql b/migration/19.12/1912.sql
index 6b08fbb66a5..67d69b3f5ab 100644
--- a/migration/19.12/1912.sql
+++ b/migration/19.12/1912.sql
@@ -357,6 +357,7 @@ ALTER TABLE res_letterbox ADD COLUMN IF NOT EXISTS scan_wkstation CHARACTER VARY
 ALTER TABLE res_letterbox ADD COLUMN IF NOT EXISTS scan_batch CHARACTER VARYING (50) DEFAULT NULL::character varying;
 ALTER TABLE res_letterbox ADD COLUMN IF NOT EXISTS scan_postmark CHARACTER VARYING (50) DEFAULT NULL::character varying;
 ALTER TABLE res_letterbox ADD COLUMN IF NOT EXISTS custom_fields jsonb;
+ALTER TABLE res_letterbox ADD COLUMN IF NOT EXISTS linked_resources jsonb NOT NULL DEFAULT '[]';
 
 
 /* USERGROUP_CONTENT */
diff --git a/rest/index.php b/rest/index.php
index 4397f710491..59ca6acbec5 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -351,6 +351,8 @@ $app->get('/resources/{resId}/listInstance', \Entity\controllers\ListInstanceCon
 $app->get('/resources/{resId}/visaCircuit', \Entity\controllers\ListInstanceController::class . ':getVisaCircuitByResId');
 $app->get('/resources/{resId}/opinionCircuit', \Entity\controllers\ListInstanceController::class . ':getOpinionCircuitByResId');
 $app->get('/resources/{resId}/availableCircuits', \Entity\controllers\ListTemplateController::class . ':getAvailableCircuitsByResId');
+$app->post('/resources/{resId}/linkedResources', \Resource\controllers\ResController::class . ':linkResources');
+$app->delete('/resources/{resId}/linkedResources/{id}', \Resource\controllers\ResController::class . ':unlinkResources');
 $app->get('/res/{resId}/acknowledgementReceipt/{id}', \AcknowledgementReceipt\controllers\AcknowledgementReceiptController::class . ':getAcknowledgementReceipt');
 $app->put('/res/resource/status', \Resource\controllers\ResController::class . ':updateStatus');
 $app->post('/res/list', \Resource\controllers\ResController::class . ':getList');
diff --git a/sql/structure.sql b/sql/structure.sql
index 15989b07b75..d30d02eae5a 100755
--- a/sql/structure.sql
+++ b/sql/structure.sql
@@ -977,6 +977,7 @@ CREATE TABLE res_letterbox
   flag_alarm2 char(1) default 'N'::character varying,
   model_id integer NOT NULL,
   custom_fields jsonb,
+  linked_resources jsonb NOT NULL DEFAULT '[]',
   CONSTRAINT res_letterbox_pkey PRIMARY KEY  (res_id)
 )
 WITH (OIDS=FALSE);
diff --git a/src/app/resource/controllers/ResController.php b/src/app/resource/controllers/ResController.php
index d4a8b982a09..4be8a219b77 100755
--- a/src/app/resource/controllers/ResController.php
+++ b/src/app/resource/controllers/ResController.php
@@ -674,6 +674,68 @@ class ResController
         return $response->withJson(['isAllowed' => true]);
     }
 
+    public function linkResources(Request $request, Response $response, array $args)
+    {
+        if (!Validator::intVal()->validate($args['resId']) || !ResController::hasRightByResId(['resId' => [$args['resId']], 'userId' => $GLOBALS['id']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Resource out of perimeter']);
+        }
+
+        $body = $request->getParsedBody();
+
+        if (!Validator::arrayType()->notEmpty()->validate($body['linkedResources'])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Body linkedResources is empty or not an array']);
+        }
+
+        if (!ResController::hasRightByResId(['resId' => $body['linkedResources'], 'userId' => $GLOBALS['id']])) {
+            return ['errors' => 'Body linkedResources out of perimeter'];
+        }
+
+        $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['linked_resources']]);
+        $linkedResources = json_decode($resource['linked_resources'], true);
+        $linkedResources = array_merge($linkedResources, $body['linkedResources']);
+        $linkedResources = array_unique($linkedResources);
+        foreach ($linkedResources as $key => $value) {
+            $linkedResources[$key] = (string)$value;
+        }
+
+        ResModel::update([
+            'set'       => ['linked_resources' => json_encode($linkedResources)],
+            'where'     => ['res_id = ?'],
+            'data'      => [$args['resId']]
+        ]);
+        ResModel::update([
+            'postSet'   => ['linked_resources' => "jsonb_insert(linked_resources, '{0}', '\"{$args['resId']}\"')"],
+            'where'     => ['res_id in (?)', "(linked_resources @> ?) = false"],
+            'data'      => [$body['linkedResources'], "\"{$args['resId']}\""]
+        ]);
+
+        return $response->withStatus(204);
+    }
+
+    public function unlinkResources(Request $request, Response $response, array $args)
+    {
+        if (!Validator::intVal()->validate($args['resId']) || !ResController::hasRightByResId(['resId' => [$args['resId']], 'userId' => $GLOBALS['id']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Resource out of perimeter']);
+        }
+
+        if (!Validator::intVal()->validate($args['id']) || !ResController::hasRightByResId(['resId' => [$args['id']], 'userId' => $GLOBALS['id']])) {
+            return ['errors' => 'Resource to unlink out of perimeter'];
+        }
+
+        ResModel::update([
+            'postSet'   => ['linked_resources' => "linked_resources - '{$args['id']}'"],
+            'where'     => ['res_id = ?'],
+            'data'      => [$args['resId']]
+        ]);
+        ResModel::update([
+            'postSet'   => ['linked_resources' => "linked_resources - '{$args['resId']}'"],
+            'where'     => ['res_id = ?'],
+            'data'      => [$args['id']]
+        ]);
+
+        return $response->withStatus(204);
+    }
+
     public static function getEncodedDocument(array $aArgs)
     {
         ValidatorModel::notEmpty($aArgs, ['resId']);
@@ -995,6 +1057,12 @@ class ResController
             }
         }
 
+        if (!empty($body['linkedResources'])) {
+            if (!ResController::hasRightByResId(['resId' => [$body['linkedResources']], 'userId' => $GLOBALS['id']])) {
+                return ['errors' => 'Body linkedResources out of perimeter'];
+            }
+        }
+
         return true;
     }
 
diff --git a/src/app/resource/controllers/StoreController.php b/src/app/resource/controllers/StoreController.php
index 25fd8385f4b..084e2d42e88 100755
--- a/src/app/resource/controllers/StoreController.php
+++ b/src/app/resource/controllers/StoreController.php
@@ -203,6 +203,7 @@ class StoreController
             'barcode'               => $args['barcode'] ?? null,
             'origin'                => $args['origin'] ?? null,
             'custom_fields'         => !empty($args['customFields']) ? json_encode($args['customFields']) : null,
+            'linked_resources'      => !empty($args['linkedResources']) ? json_encode($args['linkedResources']) : null,
             'external_id'           => $externalId,
             'creation_date'         => 'CURRENT_TIMESTAMP'
         ];
-- 
GitLab