diff --git a/Changelog.md b/Changelog.md index e412e13..e8c5c1b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,6 +18,7 @@ This file holds the changelog for Pepperminty Wiki. This is the master list of t - Fixed that age-old warning in the search results if you have pages with special characters! I learnt a _lot_ about utf8 whilst fixing this one.... (#114) - You'll need to rebuild your search index for this fix to fully take effect (call the `invindex-rebuild` action as a mod or better) - Normalise utf8 text to avoid duplicate ids and missing search results. + - Improved handling of mime types in some places in the API. ### Changed - Disallow uploads if editing is disabled. Previously files could still be uploaded even if editing was disabled - unless `upload_enabled` was set to `false`. diff --git a/build/index.php b/build/index.php index 5cf6ea5..4a9b5f9 100644 --- a/build/index.php +++ b/build/index.php @@ -946,9 +946,14 @@ function system_extension_mime_type($ext) { */ function accept_contains_mime($accept_header, $mime_type) { + $target_mime = explode("/", $mime_type); + $accepted_mimes = explode(",", $accept_header); foreach($accepted_mimes as $accepted_mime) { - if(explode(";", $accepted_mime)[0] == $mime_type) + $next_mime = explode("/", explode(";", $accepted_mime)[0]); + if($next_mime == $mime_type || ($next_mime[0] == "*" && $next_mime[1] == "*")) + return true; + if($next_mime[1] == "*" && $next_mime[0] == $mime_type[0]) return true; } return false; @@ -2363,12 +2368,11 @@ register_module([ "code" => function() { global $settings; /** - * @api {get} ?action=raw&page={pageName} Get the raw source code of a page - * @apiName RawSource - * @apiGroup Page + * @api {get} ?action=status Get the json-formatted status of this wiki + * @apiName Status + * @apiGroup Stats * @apiPermission Anonymous * - * @apiParam {string} page The page to return the source of. */ diff --git a/core.php b/core.php index fd50a5e..ab7d5c4 100644 --- a/core.php +++ b/core.php @@ -569,9 +569,14 @@ function system_extension_mime_type($ext) { */ function accept_contains_mime($accept_header, $mime_type) { + $target_mime = explode("/", $mime_type); + $accepted_mimes = explode(",", $accept_header); foreach($accepted_mimes as $accepted_mime) { - if(explode(";", $accepted_mime)[0] == $mime_type) + $next_mime = explode("/", explode(";", $accepted_mime)[0]); + if($next_mime == $mime_type || ($next_mime[0] == "*" && $next_mime[1] == "*")) + return true; + if($next_mime[1] == "*" && $next_mime[0] == $mime_type[0]) return true; } return false; diff --git a/docs/ModuleApi/classes/PeppermintParsedown.html b/docs/ModuleApi/classes/PeppermintParsedown.html index 15c30ba..3a6003f 100644 --- a/docs/ModuleApi/classes/PeppermintParsedown.html +++ b/docs/ModuleApi/classes/PeppermintParsedown.html @@ -136,10 +136,10 @@
The new pagee name to move the old page name to.
The new page name to move the old page name to.
$settings->sitename has a function that can send you to a random page. To use it, click here. $settings->admindetails_name ($settings->sitename's adminstrator) may have added it to one of the menus.
"); diff --git a/docs/ModuleApi/files/modules/api-status.php.txt b/docs/ModuleApi/files/modules/api-status.php.txt index 03059c4..152ed5d 100644 --- a/docs/ModuleApi/files/modules/api-status.php.txt +++ b/docs/ModuleApi/files/modules/api-status.php.txt @@ -8,12 +8,11 @@ register_module([ "code" => function() { global $settings; /** - * @api {get} ?action=raw&page={pageName} Get the raw source code of a page - * @apiName RawSource - * @apiGroup Page + * @api {get} ?action=status Get the json-formatted status of this wiki + * @apiName Status + * @apiGroup Stats * @apiPermission Anonymous * - * @apiParam {string} page The page to return the source of. */ diff --git a/docs/ModuleApi/files/modules/feature-recent-changes.php.txt b/docs/ModuleApi/files/modules/feature-recent-changes.php.txt index ac98e64..2e86b9a 100644 --- a/docs/ModuleApi/files/modules/feature-recent-changes.php.txt +++ b/docs/ModuleApi/files/modules/feature-recent-changes.php.txt @@ -244,12 +244,17 @@ function render_recent_change($rchange) $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml ($size_display)"; break; - + case "deletion": $resultClasses[] = "deletion"; $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml"; break; + case "move": + $resultClasses[] = "move"; + $result .= "$rchange->oldpage ⭢ $pageDisplayHtml $editorDisplayHtml $timeDisplayHtml"; + break; + case "upload": $resultClasses[] = "upload"; $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml (" . human_filesize($rchange->filesize) . ")"; diff --git a/docs/ModuleApi/files/modules/feature-search.php.txt b/docs/ModuleApi/files/modules/feature-search.php.txt index 2ed0708..3c5974c 100644 --- a/docs/ModuleApi/files/modules/feature-search.php.txt +++ b/docs/ModuleApi/files/modules/feature-search.php.txt @@ -1,7 +1,7 @@ "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. */ @@ -83,7 +84,7 @@ register_module([ /** * @api {get} ?action=idindex-show Show the id index - * @apiDescription Outputs the id index. Useful if you need to verify that it's working as expected. + * @apiDescription Outputs the id index. Useful if you need to verify that it's working as expected. Output is a json object. * @apiName SearchShowIdIndex * @apiGroup Search * @apiPermission Anonymous @@ -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,11 +209,14 @@ 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); - if(strlen($context) === 0) - $context = substr($pagesource, 0, $settings->search_characters_context * 2); + $context = $result["context"]; + if(mb_strlen($context) === 0) + $context = mb_substr($pagesource, 0, $settings->search_characters_context * 2); //echo("'Generated search context for " . $result["pagename"] . ": $context'\n"); - $context = search::highlight_context($_GET["query"], htmlentities($context)); + $context = search::highlight_context( + $_GET["query"], + preg_replace('/page.md", null, null, null, $settings->search_characters_context * 2)); @@ -319,7 +338,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 @@ -493,7 +512,7 @@ class search public static function index($source) { $source = html_entity_decode($source, ENT_QUOTES); - $source_length = strlen($source); + $source_length = mb_strlen($source); $index = []; @@ -527,8 +546,8 @@ class search */ public static function tokenize($source) { - $source = strtolower($source); - $source = str_replace([ '[', ']', '|', '{', '}', '/' ], " ", $source); + $source = Normalizer::normalize(strtolower($source), Normalizer::FORM_C); + $source = preg_replace('/[\[\]\|\{\}\/]/u', " ", $source); return preg_split("/((^\p{P}+)|(\p{P}*\s+\p{P}*)|(\p{P}+$))|\|/u", $source, -1, PREG_SPLIT_NO_EMPTY); } @@ -540,7 +559,7 @@ class search */ public static function strip_markup($source) { - return str_replace([ "[", "]", "\"", "*", "_", " - ", "`" ], "", $source); + return preg_replace('/([\"*_\[\]]| - |`)/u', "", $source); } /** @@ -567,12 +586,12 @@ class search { $page_filename = $env->storage_prefix . $pagedetails->filename; if(!file_exists($page_filename)) { - echo("data: [" . ($i + 1) . " / $max] Error: Can't find $page_filename"); + echo("data: [" . ($i + 1) . " / $max] Error: Can't find $page_filename\n"); flush(); $missing_files++; continue; } - $pagesource = utf8_encode(file_get_contents($page_filename)); + $pagesource = Normalizer::normalize(file_get_contents($page_filename), Normalizer::FORM_C); $index = self::index($pagesource); $pageid = ids::getid($pagename); @@ -883,7 +902,7 @@ class search return ($a[1] > $b[1]) ? +1 : -1; }); - $sourceLength = strlen($source); + $sourceLength = mb_strlen($source); $contexts = []; $basepos = 0; @@ -955,7 +974,8 @@ class search if(in_array($qterm, static::$stop_words)) continue; // From http://stackoverflow.com/a/2483859/1460422 - $context = preg_replace("/" . str_replace("/", "\/", preg_quote($qterm)) . "/i", "$0", $context); + + $context = preg_replace("/" . preg_replace('/\\//u', "\/", preg_quote($qterm)) . "/iu", "$0", $context); } return $context; diff --git a/docs/ModuleApi/files/modules/page-edit.php.txt b/docs/ModuleApi/files/modules/page-edit.php.txt index eb04be0..390f2c6 100644 --- a/docs/ModuleApi/files/modules/page-edit.php.txt +++ b/docs/ModuleApi/files/modules/page-edit.php.txt @@ -424,9 +424,9 @@ DIFFSCRIPT; $pageindex->{$env->page}->size = strlen($_POST["content"]); $pageindex->{$env->page}->lastmodified = time(); if($env->is_logged_in) - $pageindex->{$env->page}->lasteditor = utf8_encode($env->user); + $pageindex->{$env->page}->lasteditor = $env->user; else // TODO: Add an option to record the user's IP here instead - $pageindex->{$env->page}->lasteditor = utf8_encode("anonymous"); + $pageindex->{$env->page}->lasteditor = "anonymous"; $pageindex->{$env->page}->tags = $page_tags; // A hack to resave the pagedata if the preprocessors have diff --git a/docs/ModuleApi/files/modules/page-move.php.txt b/docs/ModuleApi/files/modules/page-move.php.txt index b8eb24d..9b99be6 100644 --- a/docs/ModuleApi/files/modules/page-move.php.txt +++ b/docs/ModuleApi/files/modules/page-move.php.txt @@ -127,6 +127,19 @@ register_module([ ); } + // Add a recent change announcing the move if the recent changes + // module is installed + if(module_exists("feature-recent-changes")) + { + add_recent_change([ + "type" => "move", + "timestamp" => time(), + "oldpage" => $page, + "page" => $new_name, + "user" => $env->user + ]); + } + // Exit with a nice message exit(page_renderer::render_main("Moving " . htmlentities($env->page), "" . htmlentities($env->page) . " has been moved to " . htmlentities($new_name) . " successfully.
")); }); diff --git a/docs/ModuleApi/files/modules/page-view.php.txt b/docs/ModuleApi/files/modules/page-view.php.txt index a086e15..3342e20 100644 --- a/docs/ModuleApi/files/modules/page-view.php.txt +++ b/docs/ModuleApi/files/modules/page-view.php.txt @@ -7,14 +7,14 @@ register_module([ "id" => "page-view", "code" => function() { /** - * @api {get} ?action=view[&page={pageName}][&revision=rid][&printable=yes] View a page + * @api {get} ?action=view[&page={pageName}][&revision=rid][&printable=yes][&mode={mode}] View a page * @apiName View * @apiGroup Page * @apiPermission Anonymous * * @apiUse PageParameter * @apiParam {number} revision The revision number to display. - * @apiParam {string} mode Optional. The display mode to use. Can hld the following values: 'normal' - The default. Sends a normal page. 'printable' - Sends a printable version of the page. 'contentonly' - Sends only the content of the page, not the extra stuff around it. 'parsedsourceonly' - Sends only the raw rendered source of the page, as it appears just after it has come out of the page parser. Useful for writing external tools (see also the `raw` action). + * @apiParam {string} mode Optional. The display mode to use. Can hold the following values: 'normal' - The default. Sends a normal page. 'printable' - Sends a printable version of the page. 'contentonly' - Sends only the content of the page, not the extra stuff around it. 'parsedsourceonly' - Sends only the raw rendered source of the page, as it appears just after it has come out of the page parser. Useful for writing external tools (see also the `raw` action). * * @apiError NonExistentPageError The page doesn't exist and editing is disabled in the wiki's settings. If editing isn't disabled, you will be redirected to the edit page instead. * @apiError NonExistentRevisionError The specified revision was not found. diff --git a/docs/ModuleApi/files/pack.html b/docs/ModuleApi/files/pack.html index 65b7a7c..85d691a 100644 --- a/docs/ModuleApi/files/pack.html +++ b/docs/ModuleApi/files/pack.html @@ -136,10 +136,10 @@The page to return the source of.
" - } - ] - } - }, - "version": "0.0.0", - "filename": "./modules/api-status.php", - "groupTitle": "Page" - }, { "type": "get", "url": "?action=view[&page={pageName}][&revision=rid][&printable=yes][&mode={mode}]", @@ -923,7 +893,7 @@ define({ "api": [ "type": "get", "url": "?action=idindex-show", "title": "Show the id index", - "description": "Outputs the id index. Useful if you need to verify that it's working as expected.
", + "description": "Outputs the id index. Useful if you need to verify that it's working as expected. Output is a json object.
", "name": "SearchShowIdIndex", "group": "Search", "permission": [ @@ -1044,6 +1014,23 @@ define({ "api": [ "filename": "./modules/feature-recent-changes.php", "groupTitle": "Stats" }, + { + "type": "get", + "url": "?action=status", + "title": "Get the json-formatted status of this wiki", + "name": "Status", + "group": "Stats", + "permission": [ + { + "name": "Anonymous", + "title": "Anybody may use this call.", + "description": "" + } + ], + "version": "0.0.0", + "filename": "./modules/api-status.php", + "groupTitle": "Stats" + }, { "type": "get", "url": "?action=avatar&user={username}[&size={size}]", diff --git a/docs/RestApi/api_data.json b/docs/RestApi/api_data.json index 575a3ba..5f43603 100644 --- a/docs/RestApi/api_data.json +++ b/docs/RestApi/api_data.json @@ -644,36 +644,6 @@ "filename": "./modules/action-raw.php", "groupTitle": "Page" }, - { - "type": "get", - "url": "?action=raw&page={pageName}", - "title": "Get the raw source code of a 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": "page", - "description": "The page to return the source of.
" - } - ] - } - }, - "version": "0.0.0", - "filename": "./modules/api-status.php", - "groupTitle": "Page" - }, { "type": "get", "url": "?action=view[&page={pageName}][&revision=rid][&printable=yes][&mode={mode}]", @@ -923,7 +893,7 @@ "type": "get", "url": "?action=idindex-show", "title": "Show the id index", - "description": "Outputs the id index. Useful if you need to verify that it's working as expected.
", + "description": "Outputs the id index. Useful if you need to verify that it's working as expected. Output is a json object.
", "name": "SearchShowIdIndex", "group": "Search", "permission": [ @@ -1044,6 +1014,23 @@ "filename": "./modules/feature-recent-changes.php", "groupTitle": "Stats" }, + { + "type": "get", + "url": "?action=status", + "title": "Get the json-formatted status of this wiki", + "name": "Status", + "group": "Stats", + "permission": [ + { + "name": "Anonymous", + "title": "Anybody may use this call.", + "description": "" + } + ], + "version": "0.0.0", + "filename": "./modules/api-status.php", + "groupTitle": "Stats" + }, { "type": "get", "url": "?action=avatar&user={username}[&size={size}]", diff --git a/docs/RestApi/api_project.js b/docs/RestApi/api_project.js index a8328a3..bf3d291 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-14T23:07:15.949Z", + "time": "2018-03-27T15:57:49.013Z", "url": "http://apidocjs.com", "version": "0.17.6" } diff --git a/docs/RestApi/api_project.json b/docs/RestApi/api_project.json index e09a89d..562e8e5 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-14T23:07:15.949Z", + "time": "2018-03-27T15:57:49.013Z", "url": "http://apidocjs.com", "version": "0.17.6" } diff --git a/module_index.json b/module_index.json index c32bebd..8a54c3f 100755 --- a/module_index.json +++ b/module_index.json @@ -41,7 +41,7 @@ "author": "Starbeamrainbowlabs", "description": "Provides a basic JSON status action that provices a few useful bits of information for API consumption.", "id": "api-status", - "lastupdate": 1498472652, + "lastupdate": 1522166256, "optional": false }, { diff --git a/modules/api-status.php b/modules/api-status.php index a970b98..f68127f 100644 --- a/modules/api-status.php +++ b/modules/api-status.php @@ -8,12 +8,11 @@ register_module([ "code" => function() { global $settings; /** - * @api {get} ?action=raw&page={pageName} Get the raw source code of a page - * @apiName RawSource - * @apiGroup Page + * @api {get} ?action=status Get the json-formatted status of this wiki + * @apiName Status + * @apiGroup Stats * @apiPermission Anonymous * - * @apiParam {string} page The page to return the source of. */