_binary From 76673937af870e6f5c9d14dc36ca086f81273401 Mon Sep 17 00:00:00 2001
From: Yashi Kamboj <yashi.kamboj@gmail.com>
Date: Sat, 22 Oct 2016 00:40:23 -0700
Subject: [PATCH] Fixes Issue 182: What relates here, a=chris

---
 src/controllers/components/SocialComponent.php |  28 +++++++
 src/library/WikiParser.php                     |  18 ++++-
 src/locale/en_US/configure.ini                 |   9 +++
 src/models/GroupModel.php                      | 104 +++++++++++++++++++++++--
 src/views/WikiView.php                         |   9 ++-
 src/views/elements/WikiElement.php             |  34 +++++++-
 6 files changed, 188 insertions(+), 14 deletions(-)

diff --git a/src/controllers/components/SocialComponent.php b/src/controllers/components/SocialComponent.php
index 4feefe3..c2dfeff 100644
--- a/src/controllers/components/SocialComponent.php
+++ b/src/controllers/components/SocialComponent.php
@@ -2062,6 +2062,33 @@ class SocialComponent extends Component implements CrawlConstants
                         $page_name = $data["FILTER"];
                     }
                     break;
+                case 'relationships':
+                    $data["MODE"] = "relationships";
+                    $data["PAGE_NAME"] = "related";
+                    if (empty($page_id)) {
+                        continue;
+                    }
+                    $page_info = $group_model->getPageInfoByPageId(
+                        $page_id);
+                    if (!isset($page_name)) {
+                        $page_name = empty($page_info['PAGE_NAME'])
+                            ? "links" : $page_info['PAGE_NAME'];
+                    }
+                    $limit = isset($limit) ? $limit : 0;
+                    $num = (isset($_SESSION["MAX_PAGES_TO_SHOW"])) ?
+                        $_SESSION["MAX_PAGES_TO_SHOW"] :
+                        C\DEFAULT_ADMIN_PAGING_NUM;
+                    $data["PAGE_ID"] = $page_id;
+                    $data["PAGE_NAME"] = $page_name;
+                    $data["DISCUSS_THREAD"] = empty($page_info["DISCUSS_THREAD"]
+                        ) ? -1 : $page_info['DISCUSS_THREAD'];
+                    $data["GROUP_ID"]=$page_info["GROUP_ID"];
+                    $data["LIMIT"] = $limit;
+                    $data["RESULTS_PER_PAGE"] = $num;
+                    list($data["TOTAL_ROWS"], $data["RELATIONSHIPS"]) =
+                        $group_model->getRelationshipsToFromPage($page_id, $limit,
+                        $num);
+                    break;
                 case 'source':
                     if (isset($_REQUEST['caret']) &&
                        isset($_REQUEST['scroll_top'])
@@ -2285,6 +2312,7 @@ class SocialComponent extends Component implements CrawlConstants
                 }
             }
         }
+        $data['PAGE_HAS_RELATIONSHIPS'] = $group_model->pageHasRelationships($data['PAGE_ID']);
         $this->updateGetWikiImpressionInfo($data, $user_id, $group_id);
         return $data;
     }
diff --git a/src/library/WikiParser.php b/src/library/WikiParser.php
index fadaa9e..a7d065b 100644
--- a/src/library/WikiParser.php
+++ b/src/library/WikiParser.php
@@ -234,6 +234,8 @@ class WikiParser implements CrawlConstants
                 "\n\n$esc<div class='align-right'>\n\n$1\n\n$esc</div>"],
         ];
         $link_substitutions = [
+            ['/\[\[([^\[\]]+?)\|([^\[\]]+?)\|([^\[\]]+?)\]\]/s',
+                "<a href=\"{$base_address}$2\">$1:$3</a>\t"],
             ['/\[\[([^\[\]]+\@[^\[\]]+?)\|([^\[\]]+?)\]\]/s',
                 "<a href=\"@@$1@@\">$2</a>\t"],
             ['/\[\[([^\[\]]+?)\|([^\[\]]+?)\]\]/s',
@@ -712,19 +714,27 @@ class WikiParser implements CrawlConstants
         }
         foreach ($links as $key => $link) {
             $extract = trim($link, "[] \t\n\r\0\x0B");
+            $relationType = null;
             //removing page names with http, .com and .org
-            if(preg_match('/http/',$extract)||
+            if (preg_match('/http/',$extract)||
                 preg_match('/.com/',$extract)||preg_match('/.org/',$extract)) {
                 unset($links[$key]);
                 continue;
             }
-            if(($pos = strpos($extract, '#')) !== false){
+            if (($pos = strpos($extract, '#')) !== false) {
                 $extract = substr($extract, 0, $pos);
                 continue;
             }
-            if(($pos = strpos($extract, '|')) !== false){
-                $extract = substr($extract, 0, $pos);
+            if (($pos = strpos($extract, '|')) !== false) {
+                $nextExtract = substr($extract,$pos+1);
+                if (($nextPos = strpos($nextExtract, '|')) !== false) {
+                    $relationType = substr($extract, 0, $pos);
+                    $extract = substr($nextExtract, 0, $nextPos);
+                }
+                else
+                    $extract = substr($extract, 0, $pos);
             }
+            $extract = $extract."|".$relationType;
             $links[$key] = $extract;
         }
         $links = array_unique($links);
diff --git a/src/locale/en_US/configure.ini b/src/locale/en_US/configure.ini
index 7f7c840..6e49d3d 100644
--- a/src/locale/en_US/configure.ini
+++ b/src/locale/en_US/configure.ini
@@ -4174,6 +4174,9 @@ wiki_view_no_pages = "This group has no pages yet for the %s locale. Search for
 ; WikiElement.php line: 1232
 wiki_element_no_inlinks = "No page links to this page yet!"
 ;
+; WikiElement.php line: 1265
+wiki_element_no_inrelationships = "No page relates to this page yet!"
+;
 ; WikiElement.php line: 1274
 wiki_view_difference = "Difference:"
 ;
@@ -4964,6 +4967,9 @@ wiki_element_page_history = "%s Page History"
 ; WikiView.php line: 111
 wiki_element_page_links = "What links to %s Page"
 ;
+; WikiElement.php line: 194
+wiki_element_page_relationships = "What relates to %s Page"
+;
 ; WikiView.php line: 116
 wiki_element_read_page = "%s Page at %s Group"
 ;
@@ -4976,6 +4982,9 @@ wiki_element_page_history = "%s Page History"
 ; WikiView.php line: 123
 wiki_element_page_links = "What links to %s Page"
 ;
+; WikiElement.php line: 208
+wiki_element_page_relationships = "What relates to %s Page"
+;
 ; WikiView.php line: 129
 wiki_element_page_discuss = "%s Page Discussion"
 ;
diff --git a/src/models/GroupModel.php b/src/models/GroupModel.php
index 5d1c972..7175c1c 100644
--- a/src/models/GroupModel.php
+++ b/src/models/GroupModel.php
@@ -609,6 +609,25 @@ class GroupModel extends Model implements MediaConstants
         return $row;
     }
     /**
+     * Returns the id of the relationship between wiki pages with the given name
+     *
+     * @param string $relationship_type the relationship type to get id about
+     * @return array row from PAGE_RELATIONSHIP table or false (if no access or doesn't
+     *     exist)
+     */
+    public function getRelationshipID($relationship_type)
+    {
+        $db = $this->db;
+        $sql = "SELECT ID AS RELATIONSHIP_ID FROM PAGE_RELATIONSHIP WHERE NAME=? "
+            . $db->limitOffset(1);
+        $result = $db->execute($sql, [$relationship_type]);
+        if (!$result) {
+            return false;
+        }
+        $row = $db->fetchArray($result);
+        return $row['RELATIONSHIP_ID'];
+    }
+    /**
      * Returns an array of user information about users who have contributed
      * to a thread or own the group a thread belongs to
      *
@@ -1004,9 +1023,9 @@ class GroupModel extends Model implements MediaConstants
         $db = $this->db;
         $pubdate = time();
         $parser = new WikiParser($base_address, $additional_substitutions);
-        $fetched_links = $parser->fetchLinks($page);
+        $links_relationships = $parser->fetchLinks($page);
         $parsed_page = $parser->parse($page);
-        if ($page_id = $this->getPageID($group_id, $page_name, $locale_tag)) {
+        if ($page_id = $this->getPageId($group_id, $page_name, $locale_tag)) {
             //can only add and use resources for a page that exists
             $parsed_page = $this->insertResourcesParsePage($group_id, $page_id,
                 $locale_tag, $parsed_page);
@@ -1036,9 +1055,9 @@ class GroupModel extends Model implements MediaConstants
             $db->execute($sql, [C\WIKI_TEMPLATE_LINK, $page_id, $group_id]);
         }
         $sql = "INSERT INTO GROUP_PAGE_LINK (LINK_TYPE_ID, FROM_ID, TO_ID) ".
-            "SELECT ?, FROM_ID, ?  FROM GROUP_PAGE_PRE_LINK ".
+            "SELECT LINK_TYPE_ID, FROM_ID, ?  FROM GROUP_PAGE_PRE_LINK ".
             "WHERE TO_GROUP_ID = ? AND TO_PAGE_NAME = ?";
-        $db->execute($sql, [C\WIKI_STANDARD_LINK, $page_id, $group_id,
+        $db->execute($sql, [$page_id, $group_id,
             $page_name]);
         $sql = "DELETE FROM GROUP_PAGE_PRE_LINK WHERE TO_GROUP_ID = ? AND " .
             "TO_PAGE_NAME = ?";
@@ -1051,15 +1070,34 @@ class GroupModel extends Model implements MediaConstants
             "(LINK_TYPE_ID, FROM_ID, TO_GROUP_ID, TO_PAGE_NAME) ".
             " VALUES (?, ?, ?, ?)";
         //get ID for each of the child links stored in $fetched_links
-        foreach($fetched_links as $fetched_link) {
-            $linked_page_id = $this->getPageID($group_id,
+        foreach ($links_relationships as $links_relationship) {
+            //extract link and relation type from $links_relationship
+            $linkPos = strpos($links_relationship, '|');
+            $fetched_link = substr($links_relationship, 0, $linkPos);
+            $relationship_type = strtolower(substr($links_relationship, $linkPos+1));
+            //get relationship id, if it exists provided relationship type is not null
+            if ($relationship_type == null) {
+                $relationship_id = C\WIKI_STANDARD_LINK;
+            }
+            else {
+                if ($relationship_id = $this->getRelationshipID($relationship_type)) {
+                    //do nothing, already updated relationship_id
+                }
+                else {
+                    $sql = "INSERT INTO PAGE_RELATIONSHIP (NAME) VALUES (?)";
+                    $db->execute($sql, [$relationship_type]);
+                    $relationship_id = $this->getRelationshipID($relationship_type);
+                }
+            }
+            //get page id
+            $linked_page_id = $this->getPageId($group_id,
                 $fetched_link, $locale_tag);
             //insert into GROUP_PAGE_LINK values of parent and child links
             if($linked_page_id === false) {
-                $db->execute($pre_link_sql, [C\WIKI_STANDARD_LINK, $page_id,
+                $db->execute($pre_link_sql, [$relationship_id, $page_id,
                     $group_id, $fetched_link]);
             } else {
-                $db->execute($link_sql, [C\WIKI_STANDARD_LINK, $page_id,
+                $db->execute($link_sql, [$relationship_id, $page_id,
                     $linked_page_id]);
             }
         }
@@ -1153,6 +1191,56 @@ class GroupModel extends Model implements MediaConstants
         return [$total,$pages];
     }
     /**
+     * Gets all the relationship types between this particular wiki page
+     * and all other pages that it is linked to.
+     *
+     * @param int $page_id identifier for the current page
+     * @param string $limit first row we want from the result set
+     * @param string $num number of rows we want starting from the
+     *     first row in the result set
+     * @return array of relationship types which represent all relationships
+     *     between the given wiki page and all other linked wiki pages
+     */
+    public function getRelationshipsToFromPage($page_id, $limit, $num)
+    {
+        $total = $this->PageHasRelationships($page_id);
+        $db = $this->db;
+        $i = 0;
+        $relationships = [];
+        $sql = "SELECT DISTINCT R.NAME AS RELATIONSHIP_TYPE
+            FROM PAGE_RELATIONSHIP R, GROUP_PAGE_LINK G
+            where (G.FROM_ID = ? OR G.TO_ID = ?) AND
+            (R.ID = G.LINK_TYPE_ID)".$db->limitOffset($limit, $num);
+        $result = $db->execute($sql, [$page_id, $page_id]);
+        if ($result) {
+            while ($relationships[$i] = $db->fetchArray($result)) {
+                $i++;
+            }
+            unset($relationships[$i]);
+            $i--;
+        }
+        return [$total,$relationships];
+    }
+    /**
+     * Gets if there is any page related to this particular wiki page.
+     *
+     * @param int $page_id identifier for the current page
+     */
+    public function pageHasRelationships($page_id){
+        if($page_id == NULL){
+            return -1;
+        }
+        $db = $this->db;
+        $sql = "SELECT COUNT(DISTINCT LINK_TYPE_ID) AS NUM FROM GROUP_PAGE_LINK
+            WHERE TO_ID = ? OR FROM_ID = ?";
+        $result = $db->execute($sql, [$page_id, $page_id]);
+        if ($result) {
+            $row = $db->fetchArray($result);
+            $total = $row['NUM'];
+        }
+        return $total;
+    }
+    /**
      * Return the page id, page string, and discussion thread id of the
      * most recent revision of a wiki page
      *
diff --git a/src/views/WikiView.php b/src/views/WikiView.php
index a8834c8..a981361 100644
--- a/src/views/WikiView.php
+++ b/src/views/WikiView.php
@@ -125,6 +125,13 @@ class WikiView extends View
                             $human_page_name),
                     ];
                 }
+                if ($data['PAGE_HAS_RELATIONSHIPS'] > 0) {
+                    $relationship_mode = [
+                        "relationships" => tl('wiki_element_page_relationships',
+                            $human_page_name),
+                    ];
+                    $modes = array_merge($modes, $relationship_mode);
+                }
                 $modes[htmlentities(B\feedsUrl("thread",
                     $data['DISCUSS_THREAD'], true, $data['CONTROLLER'])) .
                     $token_string] = tl('wiki_element_page_discuss',
@@ -142,7 +149,7 @@ class WikiView extends View
                 $page_name = ($name == 'pages') ?
                     'pages' : $data['PAGE_NAME'];
                 $arg = '&amp;arg=' . $name ;
-                if ($name == 'history' || $name == 'links') {
+                if ($name == 'history' || $name == 'links' || $name == 'relationships') {
                     $page_id = (empty($data['PAGE_ID'])) ? "" :
                         $data['PAGE_ID'];
                     $append .= "&amp;page_id=" . $page_id;
diff --git a/src/views/elements/WikiElement.php b/src/views/elements/WikiElement.php
index 2300e8d..dc9134d 100644
--- a/src/views/elements/WikiElement.php
+++ b/src/views/elements/WikiElement.php
@@ -205,6 +205,13 @@ class WikiElement extends Element implements CrawlConstants
                             $human_page_name),
                     ];
                 }
+                if ($data['PAGE_HAS_RELATIONSHIPS'] > 0) {
+                    $relationship_mode = [
+                        "relationships" => tl('wiki_element_page_relationships',
+                            $human_page_name),
+                    ];
+                    $modes = array_merge($modes, $relationship_mode);
+                }
                 $modes[htmlentities(B\feedsUrl("thread",
                     $data['DISCUSS_THREAD'], true, $data['CONTROLLER'])) .
                     $csrf_token] = tl('wiki_element_page_discuss',
@@ -222,7 +229,7 @@ class WikiElement extends Element implements CrawlConstants
                 $page_name = ($name == 'pages') ?
                     'pages' : $data['PAGE_NAME'];
                 $arg = '&amp;arg=' . $name ;
-                if ($name == 'history' || $name == 'links') {
+                if ($name == 'history' || $name == 'links' || $name == 'relationships') {
                     $page_id = (empty($data['PAGE_ID'])) ? "" :
                         $data['PAGE_ID'];
                     $append .= "&amp;page_id=" . $page_id;
@@ -272,6 +279,9 @@ class WikiElement extends Element implements CrawlConstants
             case "links":
                 $this->renderLinkPage($data);
                 break;
+            case "relationships":
+                $this->renderRelationshipPage($data);
+                break;
             case "read":
                 // no break
             case "show":
@@ -1253,6 +1263,28 @@ class WikiElement extends Element implements CrawlConstants
         }
     }
     /**
+     * Used to draw the page which displays all relationship types
+     *    that link a wiki page to other wiki pages
+     *
+     * @param array $data fields contain info about all relationship types
+     */
+    public function renderRelationshipPage($data)
+    {
+        $logged_in = !empty($data["ADMIN"]);
+        if ($logged_in) {
+            $csrf_token = C\CSRF_TOKEN."=".$data[C\CSRF_TOKEN];
+        }
+        if($data["RELATIONSHIPS"]==null){
+            e('<div class="red">' . tl('wiki_element_no_inrelationships') . '</div>');
+            return;
+        }
+        foreach ($data["RELATIONSHIPS"] as $key => $value) {
+            $var = $data["RELATIONSHIPS"][$key]["RELATIONSHIP_TYPE"];
+            e($var);
+            e("<br />");
+        }
+    }
+    /**
      * Used to draw the revision history page for a wiki document
      * Has a form that can be used to draw the diff of two revisions
      *
-- 
1.9.5.msysgit.0

