From 91859949718c4ecb11e608183b3ee7eda6a8d86b Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Sat, 28 Jan 2017 16:51:52 +0100
Subject: [PATCH] Link.php: Check paged / Paged that the parameter r, table and
 form are given in the right combination.

---
 extension/qfq/qfq/Constants.php            | 15 +++++----
 extension/qfq/qfq/report/Link.php          | 38 +++++++++++++++++-----
 extension/qfq/tests/phpunit/ReportTest.php | 16 ++++-----
 3 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index e67af2f42..444951bbf 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -177,13 +177,14 @@ const ERROR_IO_CHDIR = 1310;
 //Report
 const ERROR_UNKNOWN_LINK_QUALIFIER = 1400;
 const ERROR_UNDEFINED_RENDER_CONTROL_COMBINATION = 1401;
-const ERROR_MISSING_VALUE = 1402;
-const ERROR_INVALID_VALUE = 1403;
-const ERROR_MULTIPLE_DEFINITION = 1404;
-const ERROR_MULTIPLE_URL_PAGE_MAILTO_DEFINITION = 1405;
-const ERROR_UNKNOWN_TOKEN = 1406;
-const ERROR_TOO_FEW_PARAMETER_FOR_SENDMAIL = 1407;
-const ERROR_TOO_MANY_PARAMETER = 1408;
+const ERROR_MISSING_REQUIRED_DELETE_QUALIFIER = 1402;
+const ERROR_MISSING_VALUE = 1403;
+const ERROR_INVALID_VALUE = 1404;
+const ERROR_MULTIPLE_DEFINITION = 1405;
+const ERROR_MULTIPLE_URL_PAGE_MAILTO_DEFINITION = 1406;
+const ERROR_UNKNOWN_TOKEN = 1407;
+const ERROR_TOO_FEW_PARAMETER_FOR_SENDMAIL = 1408;
+const ERROR_TOO_MANY_PARAMETER = 1409;
 
 // Upload
 const ERROR_UPLOAD = 1500;
diff --git a/extension/qfq/qfq/report/Link.php b/extension/qfq/qfq/report/Link.php
index 70f3198bb..23ea0a323 100644
--- a/extension/qfq/qfq/report/Link.php
+++ b/extension/qfq/qfq/report/Link.php
@@ -30,6 +30,7 @@ require_once(__DIR__ . '/Define.php');
 require_once(__DIR__ . '/../store/Store.php');
 require_once(__DIR__ . '/../store/Sip.php');
 require_once(__DIR__ . '/../exceptions/UserReportExtension.php');
+require_once(__DIR__ . '/../helper/KeyValueStringParser.php');
 
 /*
  * u:url
@@ -829,7 +830,7 @@ EOF;
 //            $vars[NAME_URL] = "dummy";
         }
 
-        // Create 'fake' mode for ajax delete
+        // Create 'fake' mode for ajax/html delete
         if ($vars[NAME_DELETE]) {
             $prefix = "2";
         }
@@ -1045,20 +1046,41 @@ EOF;
      */
     private function buildDelete($vars) {
 
-        // TODO: zur Zeit auskommentiert damit die Tests laufen. Aktuell nicht klar ob es sinnvoll ist die spezielle
-        // 'DELETE' Funktionalitet hier an das ICON zu knuepfen. Was ist wenn das Icon benutzt werden soll OHNE die SIP Funktion?
-        // Vermutlich ist es sonnvoller das `_paged` das Flag setzt. Gibt es / soll es eine andere Moeglichkeit geben, ausser _paged,
-        // die Delete Funktionalitaet zu trigger?
-        //
-//        $vars[NAME_DELETE] = true;
-
         $vars[NAME_GLYPH] = GLYPH_ICON_DELETE;
         $vars[NAME_GLYPH_TITLE] = "Delete";
         $vars[NAME_LINK_CLASS_DEFAULT] = NO_CLASS;
 
+        // Minimal check for required parameter.
+        $this->checkDeleteParam($vars[NAME_URL_PARAM]);
+
         return $vars;
     }
 
+    /**
+     * Check that at least SIP_RECORD_ID is given and SIP_TABLE or SIP_FORM.
+     * This check is only processed for COLUMN_PAGED & COLUMN_PPAGED. Not for COLOUMN_LINK, cause it's not known there.
+     * In case of missing parameter, throw an exception.
+     *
+     * @param $urlParam
+     * @throws UserReportException in case parameter is missing.
+     */
+    private function checkDeleteParam($urlParam) {
+
+        // Fill array 'found' with every given token
+        $found = KeyValueStringParser::parse($urlParam, '=', '&');
+
+        $flagRecordId = isset($found[SIP_RECORD_ID]) && $found[SIP_RECORD_ID] != '' && $found[SIP_RECORD_ID] > 0;
+        $flagTable = isset($found[SIP_TABLE]) && $found[SIP_TABLE] != '';
+        $flagForm = isset($found[SIP_FORM]) && $found[SIP_FORM] != '';
+
+        if ($flagRecordId && ($flagTable || $flagForm)) {
+            return;
+        }
+
+        throw new UserReportException ("Missing some qualifier/value for column " . COLUMN_PAGED . '/' . COLUMN_PPAGED . ": " .
+            SIP_RECORD_ID . ", " . SIP_FORM . " or " . SIP_TABLE, ERROR_MISSING_REQUIRED_DELETE_QUALIFIER);
+
+    }
     /**
      * Called by $this->callTable
      *
diff --git a/extension/qfq/tests/phpunit/ReportTest.php b/extension/qfq/tests/phpunit/ReportTest.php
index c84270c37..f66ebf512 100644
--- a/extension/qfq/tests/phpunit/ReportTest.php
+++ b/extension/qfq/tests/phpunit/ReportTest.php
@@ -239,10 +239,6 @@ class ReportTest extends AbstractDatabaseTest {
         $result = $this->report->process("10.sql = SELECT 'p:form&r=123&a=hello&type=5&L=3&final=world|N' AS _page FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="index.php?id=form&type=5&L=3&s=badcaffee1234" class="btn btn-default" title="New" ><span class="glyphicon glyphicon-plus" ></span></a>', $result);
 
-        // page & Delete
-        $result = $this->report->process("10.sql = SELECT 'p:form&r=123&a=hello&type=5&L=3&final=world|D' AS _page FROM Person ORDER BY id LIMIT 1");
-        $this->assertEquals('<a href="index.php?id=form&type=5&L=3&s=badcaffee1234" class="btn btn-default" title="Delete" ><span class="glyphicon glyphicon-trash" ></span></a>', $result);
-
         // page & Help
         $result = $this->report->process("10.sql = SELECT 'p:form&r=123&a=hello&type=5&L=3&final=world|H' AS _page FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="index.php?id=form&type=5&L=3&s=badcaffee1234" class="btn btn-default" title="Help" ><span class="glyphicon glyphicon glyphicon-question-sign" ></span></a>', $result);
@@ -668,7 +664,7 @@ return false;"
 EOF;
 
         // _paged: incl. alert
-        $result = $this->report->process("10.sql = SELECT 'U:table=Person' AS _paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'U:table=Person&r=123' AS _paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span></a>', $result);
 
         // _paged: other than defaults for the alert.
@@ -679,11 +675,11 @@ EOF;
         $js = str_replace('timeout: 0', 'timeout: 10000', $js);
         $js = str_replace('modal: true', 'modal: false', $js);
         $js = str_replace("type: 'warning'", "type: 'success'", $js);
-        $result = $this->report->process("10.sql = SELECT 'U:table=Person|q:Move to trash?:success:yes:no:10:0' AS _paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'U:table=Person&r=123|q:Move to trash?:success:yes:no:10:0' AS _paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span></a>', $result);
 
 
-        $result = $this->report->process("10.sql = SELECT 'U:table=Person|q:Move to trash?:success:yes:no:10:0|t:click me' AS _paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'U:table=Person&r=123|q:Move to trash?:success:yes:no:10:0|t:click me' AS _paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span> click me</a>', $result);
 
     }
@@ -707,7 +703,7 @@ return false;"
 EOF;
 
         // _paged: incl. alert
-        $result = $this->report->process("10.sql = SELECT 'table=Person' AS _Paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'table=Person&r=123' AS _Paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span></a>', $result);
 
         // _paged: other than defaults for the alert.
@@ -718,11 +714,11 @@ EOF;
         $js = str_replace('timeout: 0', 'timeout: 10000', $js);
         $js = str_replace('modal: true', 'modal: false', $js);
         $js = str_replace("type: 'warning'", "type: 'success'", $js);
-        $result = $this->report->process("10.sql = SELECT 'table=Person|||Move to trash?:success:yes:no:10:0' AS _Paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'table=Person&r=123|||Move to trash?:success:yes:no:10:0' AS _Paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span></a>', $result);
 
 
-        $result = $this->report->process("10.sql = SELECT 'table=Person|click me||Move to trash?:success:yes:no:10:0' AS _Paged FROM Person ORDER BY id LIMIT 1");
+        $result = $this->report->process("10.sql = SELECT 'table=Person&r=123|click me||Move to trash?:success:yes:no:10:0' AS _Paged FROM Person ORDER BY id LIMIT 1");
         $this->assertEquals('<a href="' . API_DIR . '/' . API_DELETE_PHP . '?s=badcaffee1234" class="btn btn-default" title="Delete" ' . $js . ' ><span class="glyphicon glyphicon-trash" ></span> click me</a>', $result);
 
     }
-- 
GitLab