diff --git a/Changelog.md b/Changelog.md
index 51252dd..3b3e368 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -9,6 +9,7 @@ This file holds the changelog for Pepperminty Wiki. This is the master list of t
- Provides new module api functions: `interwiki_pagename_parse`, `interwiki_pagename_resolve`, `interwiki_get_pagename_url`, and `is_interwiki_link`
- Added CSV support to the `recent-changes` action.
- Added `count` and `offset` GET parameters to `recent-changes` action.
+ - Added new `find_revisionid_timestamp()` function to `feature-recent-changes` module.
### Changed
- Completely reworked the README to refactor out the documentation to its [own static site](https://starbeamrainbowlabs.com/labs/peppermint/_docpress/)
diff --git a/build/index.php b/build/index.php
index 7bec4f1..a233a84 100644
--- a/build/index.php
+++ b/build/index.php
@@ -409,7 +409,7 @@ if($settings->sessionprefix == "auto")
/////////////////////////////////////////////////////////////////////////////
/** The version of Pepperminty Wiki currently running. */
$version = "v0.18-dev";
-$commit = "e715c2049f0782f46919fd2b220eac9292183075";
+$commit = "242f197ccf8969c87e18f13d1a525dd01219b03c";
/// Environment ///
/** Holds information about the current request environment. */
$env = new stdClass();
@@ -3708,7 +3708,7 @@ register_module([
*
* @apiParam {number} offset If specified, start returning changes from this many changes in. 0 is the beginning.
* @apiParam {number} count If specified, return at most this many changes. A value of 0 means no limit (the default) - apart from the limit on the number of changes stored by the server (configurable in pepppermint.json).
- * @apiParam {string} format The format to return the recent changes in. Valid values: html, json, csv. Default: html.
+ * @apiParam {string} format The format to return the recent changes in. Valid values: html, json, csv, atom. Default: html.
*/
/*
* ██████ ███████ ██████ ███████ ███ ██ ████████
@@ -3768,7 +3768,18 @@ register_module([
header("content-type: text/csv");
header("content-length: " . fstat($result)["size"]);
- echo(stream_get_contents($result));
+ exit(stream_get_contents($result));
+ break;
+ case "atom":
+ $result = render_recent_change_atom($recent_changes);
+ header("content-type: application/atom+xml");
+ header("content-length: " . strlen($result));
+ exit($result);
+ default:
+ http_response_code(406);
+ header("content-type: text/plain");
+ header("content-length: 42");
+ exit("Error: That format code wasnot recognised.");
}
@@ -3920,6 +3931,24 @@ function render_recent_changes($recent_changes)
return $content;
}
+/**
+ * Given a page name and timestamp, returns the associated page revision number.
+ * @param string $pagename The page name to obtain the revision number for.
+ * @param int $timestamap The timestamp at which the revision was saved.
+ * @return int The revision number of the given page at the given time.
+ */
+function find_revisionid_timestamp($pagename, $timestamap) {
+ if(!isset($pageindex->$pagename) || !isset($pageindex->$pagename->history))
+ return null;
+
+ foreach($pageindex->$pagename->history as $historyEntry){
+ if($historyEntry->timestamp == $timestamp) {
+ return $historyEntry->rid;
+ break;
+ }
+ }
+}
+
/**
* Renders a single recent change
* @package feature-recent-changes
@@ -3933,18 +3962,7 @@ function render_recent_change($rchange)
$editorDisplayHtml = render_editor(page_renderer::render_username($rchange->user));
$timeDisplayHtml = render_timestamp($rchange->timestamp);
- $revisionId = false;
- if(isset($pageindex->{$rchange->page}) && isset($pageindex->{$rchange->page}->history))
- {
- foreach($pageindex->{$rchange->page}->history as $historyEntry)
- {
- if($historyEntry->timestamp == $rchange->timestamp)
- {
- $revisionId = $historyEntry->rid;
- break;
- }
- }
- }
+ $revisionId = find_revisionid_timestamp($rchange->page, $rchange->timestamp);
$result = "";
$resultClasses = [];
@@ -3967,7 +3985,7 @@ function render_recent_change($rchange)
if($rchange_type === "revert")
$resultClasses[] = "reversion";
- $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml ($size_display)";
+ $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml ($size_display)";
break;
case "deletion":
@@ -3995,7 +4013,112 @@ function render_recent_change($rchange)
return $result;
}
-
+/**
+ * Renders a list of recent changes as an Atom 1.0 feed.
+ * Requires the XMLWriter PHP class.
+ * @param array $recent_changes The array of recent changes to render.
+ * @return string The recent changes as an Atom 1.0 feed.
+ */
+function render_recent_change_atom($recent_changes) {
+ global $version, $settings;
+
+ $full_url_stem = full_url();
+ $full_url_stem = substr($full_url_stem, 0, strpos($full_url_stem, "?"));
+
+ $xml = new XMLWriter();
+ $xml->openMemory();
+ $xml->setIndentString("\t");
+ $xml->startDocument("1.0", "utf-8");
+
+ $xml->startElement("feed");
+ $xml->writeAttribute("xmlns", "http://www.w3.org/2005/Atom");
+
+ $xml->startElement("generator");
+ $xml->writeAttribute("uri", "https://github.com/sbrl/Pepperminty-Wiki/");
+ $xml->writeAttribute("version", $version);
+ $xml->text("Pepperminty Wiki");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "self");
+ $xml->writeAttribute("type", "application/atom+xml");
+ $xml->writeAttribute("href", full_url());
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/html");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=html");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "application/json");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=json");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/csv");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=csv");
+ $xml->endElement();
+
+ $xml->writeElement("updated", date(DateTime::ATOM));
+ $xml->writeElement("id", full_url());
+ $xml->writeElement("icon", $settings->favicon);
+ $xml->writeElement("title", "$settings->sitename - Recent Changes");
+ $xml->writeElements("subtitle", "Recent Changes on $settings->sitename");
+
+ foreach($recent_changes as $recent_change) {
+ $xml->startElement("entry");
+
+ // Change types: revert, edit, deletion, move, upload, comment
+ $type = $recent_change->type;
+ $url = "$full_url_stem?page=".rawurlencode($recent_change->page);
+ switch($type) {
+ case "revert":
+ case "edit":
+ $type = ($type == "revert" ? "Reversion of" : "Edit to");
+ $revision_id = find_revisionid_timestamp($recent_change->page, $recent_change->timestamp);
+ if(!empty($revision_id))
+ $url .= "&revision=$revision_id";
+ break;
+ case "deletion": $type = "Deletion of"; break;
+ case "move": $type = "Movement of"; break;
+ case "upload": $type = "Upload of"; break;
+ case "comment":
+ $type = "Comment on";
+ $url .= "#comment-$comment_id";
+ break;
+ }
+ $xml->writeElement("title", "$type $recent_change->page by $recent_change->user");
+ $xml->writeElement("id", $url);
+ $xml->writeElement("updated", date(DateTime::ATOM, $recent_change->timestamp));
+ $xml->startElement("content");
+ $xml->writeCdata("
+ - Page name: $recent_change->page
+ - Timestamp: ".date(DateTime::RFC1123, $recent_change->timestamp)."
+ - Change type: $recent_change->type
+ - User: $recent_change->user
+
");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/html");
+ $xml->writeAttribute("href", $url);
+ $xml->endElement();
+
+ $xml->startElement("author");
+ $xml->writeElement("name", $recent_change->user);
+ $xml->writeElement("uri", "$full_url_stem?page=".rawurlencode("$settings->user_page_prefix/$recent_change->page"));
+ $xml->endElement();
+
+ $xml->endElement();
+ }
+
+ $xml->endElement();
+}
register_module([
diff --git a/module_index.json b/module_index.json
index 00c6def..c7dd83e 100755
--- a/module_index.json
+++ b/module_index.json
@@ -95,7 +95,7 @@
"author": "Starbeamrainbowlabs",
"description": "Adds recent changes. Access through the 'recent-changes' action.",
"id": "feature-recent-changes",
- "lastupdate": 1548354223,
+ "lastupdate": 1548361795,
"optional": false
},
{
diff --git a/modules/feature-recent-changes.php b/modules/feature-recent-changes.php
index 3dc3a57..01fbd46 100644
--- a/modules/feature-recent-changes.php
+++ b/modules/feature-recent-changes.php
@@ -22,7 +22,7 @@ register_module([
*
* @apiParam {number} offset If specified, start returning changes from this many changes in. 0 is the beginning.
* @apiParam {number} count If specified, return at most this many changes. A value of 0 means no limit (the default) - apart from the limit on the number of changes stored by the server (configurable in pepppermint.json).
- * @apiParam {string} format The format to return the recent changes in. Valid values: html, json, csv. Default: html.
+ * @apiParam {string} format The format to return the recent changes in. Valid values: html, json, csv, atom. Default: html.
*/
/*
* ██████ ███████ ██████ ███████ ███ ██ ████████
@@ -82,7 +82,18 @@ register_module([
header("content-type: text/csv");
header("content-length: " . fstat($result)["size"]);
- echo(stream_get_contents($result));
+ exit(stream_get_contents($result));
+ break;
+ case "atom":
+ $result = render_recent_change_atom($recent_changes);
+ header("content-type: application/atom+xml");
+ header("content-length: " . strlen($result));
+ exit($result);
+ default:
+ http_response_code(406);
+ header("content-type: text/plain");
+ header("content-length: 42");
+ exit("Error: That format code wasnot recognised.");
}
@@ -234,6 +245,24 @@ function render_recent_changes($recent_changes)
return $content;
}
+/**
+ * Given a page name and timestamp, returns the associated page revision number.
+ * @param string $pagename The page name to obtain the revision number for.
+ * @param int $timestamap The timestamp at which the revision was saved.
+ * @return int The revision number of the given page at the given time.
+ */
+function find_revisionid_timestamp($pagename, $timestamap) {
+ if(!isset($pageindex->$pagename) || !isset($pageindex->$pagename->history))
+ return null;
+
+ foreach($pageindex->$pagename->history as $historyEntry){
+ if($historyEntry->timestamp == $timestamp) {
+ return $historyEntry->rid;
+ break;
+ }
+ }
+}
+
/**
* Renders a single recent change
* @package feature-recent-changes
@@ -247,18 +276,7 @@ function render_recent_change($rchange)
$editorDisplayHtml = render_editor(page_renderer::render_username($rchange->user));
$timeDisplayHtml = render_timestamp($rchange->timestamp);
- $revisionId = false;
- if(isset($pageindex->{$rchange->page}) && isset($pageindex->{$rchange->page}->history))
- {
- foreach($pageindex->{$rchange->page}->history as $historyEntry)
- {
- if($historyEntry->timestamp == $rchange->timestamp)
- {
- $revisionId = $historyEntry->rid;
- break;
- }
- }
- }
+ $revisionId = find_revisionid_timestamp($rchange->page, $rchange->timestamp);
$result = "";
$resultClasses = [];
@@ -281,7 +299,7 @@ function render_recent_change($rchange)
if($rchange_type === "revert")
$resultClasses[] = "reversion";
- $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml ($size_display)";
+ $result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml ($size_display)";
break;
case "deletion":
@@ -309,4 +327,109 @@ function render_recent_change($rchange)
return $result;
}
-?>
+/**
+ * Renders a list of recent changes as an Atom 1.0 feed.
+ * Requires the XMLWriter PHP class.
+ * @param array $recent_changes The array of recent changes to render.
+ * @return string The recent changes as an Atom 1.0 feed.
+ */
+function render_recent_change_atom($recent_changes) {
+ global $version, $settings;
+
+ $full_url_stem = full_url();
+ $full_url_stem = substr($full_url_stem, 0, strpos($full_url_stem, "?"));
+
+ $xml = new XMLWriter();
+ $xml->openMemory();
+ $xml->setIndentString("\t");
+ $xml->startDocument("1.0", "utf-8");
+
+ $xml->startElement("feed");
+ $xml->writeAttribute("xmlns", "http://www.w3.org/2005/Atom");
+
+ $xml->startElement("generator");
+ $xml->writeAttribute("uri", "https://github.com/sbrl/Pepperminty-Wiki/");
+ $xml->writeAttribute("version", $version);
+ $xml->text("Pepperminty Wiki");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "self");
+ $xml->writeAttribute("type", "application/atom+xml");
+ $xml->writeAttribute("href", full_url());
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/html");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=html");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "application/json");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=json");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/csv");
+ $xml->writeAttribute("href", "$full_url_stem?action=recent-changes&format=csv");
+ $xml->endElement();
+
+ $xml->writeElement("updated", date(DateTime::ATOM));
+ $xml->writeElement("id", full_url());
+ $xml->writeElement("icon", $settings->favicon);
+ $xml->writeElement("title", "$settings->sitename - Recent Changes");
+ $xml->writeElements("subtitle", "Recent Changes on $settings->sitename");
+
+ foreach($recent_changes as $recent_change) {
+ $xml->startElement("entry");
+
+ // Change types: revert, edit, deletion, move, upload, comment
+ $type = $recent_change->type;
+ $url = "$full_url_stem?page=".rawurlencode($recent_change->page);
+ switch($type) {
+ case "revert":
+ case "edit":
+ $type = ($type == "revert" ? "Reversion of" : "Edit to");
+ $revision_id = find_revisionid_timestamp($recent_change->page, $recent_change->timestamp);
+ if(!empty($revision_id))
+ $url .= "&revision=$revision_id";
+ break;
+ case "deletion": $type = "Deletion of"; break;
+ case "move": $type = "Movement of"; break;
+ case "upload": $type = "Upload of"; break;
+ case "comment":
+ $type = "Comment on";
+ $url .= "#comment-$comment_id";
+ break;
+ }
+ $xml->writeElement("title", "$type $recent_change->page by $recent_change->user");
+ $xml->writeElement("id", $url);
+ $xml->writeElement("updated", date(DateTime::ATOM, $recent_change->timestamp));
+ $xml->startElement("content");
+ $xml->writeCdata("
+ - Page name: $recent_change->page
+ - Timestamp: ".date(DateTime::RFC1123, $recent_change->timestamp)."
+ - Change type: $recent_change->type
+ - User: $recent_change->user
+
");
+ $xml->endElement();
+
+ $xml->startElement("link");
+ $xml->writeAttribute("rel", "alternate");
+ $xml->writeAttribute("type", "text/html");
+ $xml->writeAttribute("href", $url);
+ $xml->endElement();
+
+ $xml->startElement("author");
+ $xml->writeElement("name", $recent_change->user);
+ $xml->writeElement("uri", "$full_url_stem?page=".rawurlencode("$settings->user_page_prefix/$recent_change->page"));
+ $xml->endElement();
+
+ $xml->endElement();
+ }
+
+ $xml->endElement();
+}