From 90acf38f9d06aecc4a6c8e0c7fd607bde4a3d417 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Wed, 14 Feb 2018 23:08:28 +0000
Subject: [PATCH] Add json support to search action! :D

---
 Changelog.md                  |  1 +
 build/index.php               | 35 ++++++++++++----
 core.php                      |  5 ++-
 docs/RestApi/api_data.js      | 76 ++++++++++++++++++++---------------
 docs/RestApi/api_data.json    | 76 ++++++++++++++++++++---------------
 docs/RestApi/api_project.js   |  2 +-
 docs/RestApi/api_project.json |  2 +-
 module_index.json             |  6 +--
 modules/feature-search.php    | 24 +++++++++--
 9 files changed, 143 insertions(+), 84 deletions(-)

diff --git a/Changelog.md b/Changelog.md
index 9df95eb..403e604 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -6,6 +6,7 @@ This file holds the changelog for Pepperminty Wiki. This is the master list of t
 ### Added
  - [Rest API] Added support for the `mode` parameter to the `random` action.
  - Fixed various issues with both the module api & the rest api docs.
+ - Add json support to search action :D
 
 ### Fixed
  - Properly escaped content of short code box on file pages
diff --git a/build/index.php b/build/index.php
index 0dc2410..29be47d 100644
--- a/build/index.php
+++ b/build/index.php
@@ -501,8 +501,11 @@ if($env->is_logged_in)
 // APIDoc strings //
 ////////////////////
 /**
- * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+ * @apiDefine Admin	Only the wiki administrator may use this call.
  */
+ /**
+  * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+  */
 /**
 * @apiDefine User		Only users loggged in may use this call.
 */
@@ -2267,12 +2270,12 @@ register_module([
 	"code" => function() {
 		global $settings;
 		/**
-		 * @api {get} ?action=random Redirects to a random page.
-		 * @apiName RawSource
+		 * @api {get} ?action=random[&mode={modeName}] Redirects to a random page
+		 * @apiName Random
 		 * @apiGroup Page
 		 * @apiPermission Anonymous
 		 *
-		 * @apiParam	{string}	mode	The view mode to redirect to. This parameter is basically just passed through to the direct - it works in the same way as the mode parameter on the _view_ action does.
+		 * @apiParam	{string}	mode	The view mode to redirect to. This parameter is basically just passed through to the direct. It works in the same way as the mode parameter on the view action does.
 		 */
 		
 		add_action("random", function() {
@@ -3596,7 +3599,7 @@ register_module([
 
 register_module([
 	"name" => "Search",
-	"version" => "0.6.1",
+	"version" => "0.6.2",
 	"author" => "Starbeamrainbowlabs",
 	"description" => "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
 	"id" => "feature-search",
@@ -3608,6 +3611,7 @@ register_module([
 		 * @apiName SearchIndex
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
+		 * @apiDescription For debugging purposes. Be warned - the format could change at any time!
 		 * 
 		 * @apiParam {string}	page	The page to generate a word index page.
 		 */
@@ -3690,12 +3694,13 @@ register_module([
 		});
 		
 		/**
-		 * @api {get} ?action=search&query={text}	Search the wiki for a given query string
+		 * @api {get} ?action=search&query={text}[&format={format}]	Search the wiki for a given query string
 		 * @apiName Search
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
 		 * 
 		 * @apiParam {string}	query	The query string to search for.
+		 * @apiParam {string}	format	Optional. Valid values: html, json. In json mode an object is returned with page names as keys, values as search result information - sorted in ranking order.
 		 */
 		
 		/*
@@ -3721,6 +3726,20 @@ register_module([
 			$invindex = search::load_invindex($paths->searchindex);
 			$results = search::query_invindex($_GET["query"], $invindex);
 			$resultCount = count($results);
+			
+			foreach($results as &$result) {
+				$result["context"] = search::extract_context(
+					$_GET["query"],
+					file_get_contents($env->storage_prefix . $result["pagename"] . ".md")
+				);
+			}
+			
+			if(!empty($_GET["format"]) && $_GET["format"] == "json") {
+				header("content-type: application/json");
+				$json_results = new stdClass();
+				foreach($results as $result) $json_results->{$result["pagename"]} = $result;
+				exit(json_encode($json_results));
+			}
 
 			$env->perfdata->search_time = round((microtime(true) - $search_start)*1000, 3);
 
@@ -3788,7 +3807,7 @@ register_module([
 				$pagesource = file_get_contents($env->storage_prefix . $result["pagename"] . ".md");
 				
 				//echo("Extracting context for result " . $result["pagename"] . ".\n");
-				$context = search::extract_context($_GET["query"], $pagesource);
+				$context = $result["context"];
 				if(strlen($context) === 0)
 					$context = substr($pagesource, 0, $settings->search_characters_context * 2);
 				//echo("'Generated search context for " . $result["pagename"] . ": $context'\n");
@@ -3914,7 +3933,7 @@ register_module([
 		
 		
 		/**
-		 * @api {get} ?action=suggest-pages[&type={type}]	Get search suggestions for a query
+		 * @api {get} ?action=suggest-pages[&type={type}]	Get page name suggestions for a query
 		 * @apiName OpenSearchDescription
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
diff --git a/core.php b/core.php
index e6684a5..7388b07 100644
--- a/core.php
+++ b/core.php
@@ -125,8 +125,11 @@ if($env->is_logged_in)
 // APIDoc strings //
 ////////////////////
 /**
- * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+ * @apiDefine Admin	Only the wiki administrator may use this call.
  */
+ /**
+  * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+  */
 /**
 * @apiDefine User		Only users loggged in may use this call.
 */
diff --git a/docs/RestApi/api_data.js b/docs/RestApi/api_data.js
index cda8cec..b69383f 100644
--- a/docs/RestApi/api_data.js
+++ b/docs/RestApi/api_data.js
@@ -584,6 +584,36 @@ define({ "api": [
     "filename": "./modules/action-protect.php",
     "groupTitle": "Page"
   },
+  {
+    "type": "get",
+    "url": "?action=random[&mode={modeName}]",
+    "title": "Redirects to a random page",
+    "name": "Random",
+    "group": "Page",
+    "permission": [
+      {
+        "name": "Anonymous",
+        "title": "Anybody may use this call.",
+        "description": ""
+      }
+    ],
+    "parameter": {
+      "fields": {
+        "Parameter": [
+          {
+            "group": "Parameter",
+            "type": "string",
+            "optional": false,
+            "field": "mode",
+            "description": "<p>The view mode to redirect to. This parameter is basically just passed through to the direct. It works in the same way as the mode parameter on the view action does.</p>"
+          }
+        ]
+      }
+    },
+    "version": "0.0.0",
+    "filename": "./modules/action-random.php",
+    "groupTitle": "Page"
+  },
   {
     "type": "get",
     "url": "?action=raw&page={pageName}",
@@ -614,36 +644,6 @@ define({ "api": [
     "filename": "./modules/action-raw.php",
     "groupTitle": "Page"
   },
-  {
-    "type": "get",
-    "url": "?action=random[&mode={mode}]",
-    "title": "Redirects to a random page.",
-    "name": "RawSource",
-    "group": "Page",
-    "permission": [
-      {
-        "name": "Anonymous",
-        "title": "Anybody may use this call.",
-        "description": ""
-      }
-    ],
-    "parameter": {
-      "fields": {
-        "Parameter": [
-          {
-            "group": "Parameter",
-            "type": "string",
-            "optional": false,
-            "field": "mode",
-            "description": "<p>The view mode to redirect to. This parameter is basically just passed through to the direct - it works in the same way as the mode parameter on the <em>view</em> action does.</p>"
-          }
-        ]
-      }
-    },
-    "version": "0.0.0",
-    "filename": "./modules/action-random.php",
-    "groupTitle": "Page"
-  },
   {
     "type": "get",
     "url": "?action=raw&page={pageName}",
@@ -739,7 +739,7 @@ define({ "api": [
   {
     "type": "get",
     "url": "?action=suggest-pages[&type={type}]",
-    "title": "Get search suggestions for a query",
+    "title": "Get page name suggestions for a query",
     "name": "OpenSearchDescription",
     "group": "Search",
     "permission": [
@@ -792,7 +792,7 @@ define({ "api": [
   },
   {
     "type": "get",
-    "url": "?action=search&query={text}",
+    "url": "?action=search&query={text}[&format={format}]",
     "title": "Search the wiki for a given query string",
     "name": "Search",
     "group": "Search",
@@ -812,6 +812,13 @@ define({ "api": [
             "optional": false,
             "field": "query",
             "description": "<p>The query string to search for.</p>"
+          },
+          {
+            "group": "Parameter",
+            "type": "string",
+            "optional": false,
+            "field": "format",
+            "description": "<p>Optional. Valid values: html, json. In json mode an object is returned with page names as keys, values as search result information - sorted in ranking order.</p>"
           }
         ]
       }
@@ -863,6 +870,7 @@ define({ "api": [
         "description": ""
       }
     ],
+    "description": "<p>For debugging purposes. Be warned - the format could change at any time!</p>",
     "parameter": {
       "fields": {
         "Parameter": [
@@ -889,7 +897,9 @@ define({ "api": [
     "group": "Search",
     "permission": [
       {
-        "name": "Admin"
+        "name": "Admin",
+        "title": "Only the wiki administrator may use this call.",
+        "description": ""
       }
     ],
     "parameter": {
diff --git a/docs/RestApi/api_data.json b/docs/RestApi/api_data.json
index 123f895..575a3ba 100644
--- a/docs/RestApi/api_data.json
+++ b/docs/RestApi/api_data.json
@@ -584,6 +584,36 @@
     "filename": "./modules/action-protect.php",
     "groupTitle": "Page"
   },
+  {
+    "type": "get",
+    "url": "?action=random[&mode={modeName}]",
+    "title": "Redirects to a random page",
+    "name": "Random",
+    "group": "Page",
+    "permission": [
+      {
+        "name": "Anonymous",
+        "title": "Anybody may use this call.",
+        "description": ""
+      }
+    ],
+    "parameter": {
+      "fields": {
+        "Parameter": [
+          {
+            "group": "Parameter",
+            "type": "string",
+            "optional": false,
+            "field": "mode",
+            "description": "<p>The view mode to redirect to. This parameter is basically just passed through to the direct. It works in the same way as the mode parameter on the view action does.</p>"
+          }
+        ]
+      }
+    },
+    "version": "0.0.0",
+    "filename": "./modules/action-random.php",
+    "groupTitle": "Page"
+  },
   {
     "type": "get",
     "url": "?action=raw&page={pageName}",
@@ -614,36 +644,6 @@
     "filename": "./modules/action-raw.php",
     "groupTitle": "Page"
   },
-  {
-    "type": "get",
-    "url": "?action=random[&mode={mode}]",
-    "title": "Redirects to a random page.",
-    "name": "RawSource",
-    "group": "Page",
-    "permission": [
-      {
-        "name": "Anonymous",
-        "title": "Anybody may use this call.",
-        "description": ""
-      }
-    ],
-    "parameter": {
-      "fields": {
-        "Parameter": [
-          {
-            "group": "Parameter",
-            "type": "string",
-            "optional": false,
-            "field": "mode",
-            "description": "<p>The view mode to redirect to. This parameter is basically just passed through to the direct - it works in the same way as the mode parameter on the <em>view</em> action does.</p>"
-          }
-        ]
-      }
-    },
-    "version": "0.0.0",
-    "filename": "./modules/action-random.php",
-    "groupTitle": "Page"
-  },
   {
     "type": "get",
     "url": "?action=raw&page={pageName}",
@@ -739,7 +739,7 @@
   {
     "type": "get",
     "url": "?action=suggest-pages[&type={type}]",
-    "title": "Get search suggestions for a query",
+    "title": "Get page name suggestions for a query",
     "name": "OpenSearchDescription",
     "group": "Search",
     "permission": [
@@ -792,7 +792,7 @@
   },
   {
     "type": "get",
-    "url": "?action=search&query={text}",
+    "url": "?action=search&query={text}[&format={format}]",
     "title": "Search the wiki for a given query string",
     "name": "Search",
     "group": "Search",
@@ -812,6 +812,13 @@
             "optional": false,
             "field": "query",
             "description": "<p>The query string to search for.</p>"
+          },
+          {
+            "group": "Parameter",
+            "type": "string",
+            "optional": false,
+            "field": "format",
+            "description": "<p>Optional. Valid values: html, json. In json mode an object is returned with page names as keys, values as search result information - sorted in ranking order.</p>"
           }
         ]
       }
@@ -863,6 +870,7 @@
         "description": ""
       }
     ],
+    "description": "<p>For debugging purposes. Be warned - the format could change at any time!</p>",
     "parameter": {
       "fields": {
         "Parameter": [
@@ -889,7 +897,9 @@
     "group": "Search",
     "permission": [
       {
-        "name": "Admin"
+        "name": "Admin",
+        "title": "Only the wiki administrator may use this call.",
+        "description": ""
       }
     ],
     "parameter": {
diff --git a/docs/RestApi/api_project.js b/docs/RestApi/api_project.js
index 192597e..a8328a3 100644
--- a/docs/RestApi/api_project.js
+++ b/docs/RestApi/api_project.js
@@ -8,7 +8,7 @@ define({
   "apidoc": "0.3.0",
   "generator": {
     "name": "apidoc",
-    "time": "2018-02-14T22:36:20.697Z",
+    "time": "2018-02-14T23:07:15.949Z",
     "url": "http://apidocjs.com",
     "version": "0.17.6"
   }
diff --git a/docs/RestApi/api_project.json b/docs/RestApi/api_project.json
index 592bc4c..e09a89d 100644
--- a/docs/RestApi/api_project.json
+++ b/docs/RestApi/api_project.json
@@ -8,7 +8,7 @@
   "apidoc": "0.3.0",
   "generator": {
     "name": "apidoc",
-    "time": "2018-02-14T22:36:20.697Z",
+    "time": "2018-02-14T23:07:15.949Z",
     "url": "http://apidocjs.com",
     "version": "0.17.6"
   }
diff --git a/module_index.json b/module_index.json
index 6d7e385..2fe1ac7 100755
--- a/module_index.json
+++ b/module_index.json
@@ -23,7 +23,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds an action called 'random' that redirects you to a random page.",
         "id": "action-random",
-        "lastupdate": 1518647615,
+        "lastupdate": 1518648324,
         "optional": false
     },
     {
@@ -100,11 +100,11 @@
     },
     {
         "name": "Search",
-        "version": "0.6.1",
+        "version": "0.6.2",
         "author": "Starbeamrainbowlabs",
         "description": "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
         "id": "feature-search",
-        "lastupdate": 1517752177,
+        "lastupdate": 1518649628,
         "optional": false
     },
     {
diff --git a/modules/feature-search.php b/modules/feature-search.php
index cf2f089..1643323 100644
--- a/modules/feature-search.php
+++ b/modules/feature-search.php
@@ -1,7 +1,7 @@
 <?php
 register_module([
 	"name" => "Search",
-	"version" => "0.6.1",
+	"version" => "0.6.2",
 	"author" => "Starbeamrainbowlabs",
 	"description" => "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
 	"id" => "feature-search",
@@ -13,6 +13,7 @@ register_module([
 		 * @apiName SearchIndex
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
+		 * @apiDescription For debugging purposes. Be warned - the format could change at any time!
 		 * 
 		 * @apiParam {string}	page	The page to generate a word index page.
 		 */
@@ -95,12 +96,13 @@ register_module([
 		});
 		
 		/**
-		 * @api {get} ?action=search&query={text}	Search the wiki for a given query string
+		 * @api {get} ?action=search&query={text}[&format={format}]	Search the wiki for a given query string
 		 * @apiName Search
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
 		 * 
 		 * @apiParam {string}	query	The query string to search for.
+		 * @apiParam {string}	format	Optional. Valid values: html, json. In json mode an object is returned with page names as keys, values as search result information - sorted in ranking order.
 		 */
 		
 		/*
@@ -126,6 +128,20 @@ register_module([
 			$invindex = search::load_invindex($paths->searchindex);
 			$results = search::query_invindex($_GET["query"], $invindex);
 			$resultCount = count($results);
+			
+			foreach($results as &$result) {
+				$result["context"] = search::extract_context(
+					$_GET["query"],
+					file_get_contents($env->storage_prefix . $result["pagename"] . ".md")
+				);
+			}
+			
+			if(!empty($_GET["format"]) && $_GET["format"] == "json") {
+				header("content-type: application/json");
+				$json_results = new stdClass();
+				foreach($results as $result) $json_results->{$result["pagename"]} = $result;
+				exit(json_encode($json_results));
+			}
 
 			$env->perfdata->search_time = round((microtime(true) - $search_start)*1000, 3);
 
@@ -193,7 +209,7 @@ register_module([
 				$pagesource = file_get_contents($env->storage_prefix . $result["pagename"] . ".md");
 				
 				//echo("Extracting context for result " . $result["pagename"] . ".\n");
-				$context = search::extract_context($_GET["query"], $pagesource);
+				$context = $result["context"];
 				if(strlen($context) === 0)
 					$context = substr($pagesource, 0, $settings->search_characters_context * 2);
 				//echo("'Generated search context for " . $result["pagename"] . ": $context'\n");
@@ -319,7 +335,7 @@ register_module([
 		
 		
 		/**
-		 * @api {get} ?action=suggest-pages[&type={type}]	Get search suggestions for a query
+		 * @api {get} ?action=suggest-pages[&type={type}]	Get page name suggestions for a query
 		 * @apiName OpenSearchDescription
 		 * @apiGroup Search
 		 * @apiPermission Anonymous
