Add some new tag-based stats and a new force param to stats-update

This commit is contained in:
Starbeamrainbowlabs 2017-09-16 17:31:30 +01:00
parent 143e1f847b
commit 425e2854c5
5 changed files with 290 additions and 32 deletions

View File

@ -1459,7 +1459,7 @@ class page_renderer
<footer>
<p>{footer-message}</p>
<p>Powered by Pepperminty Wiki v0.15-dev, which was built by <a href='//starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>. Send bugs to 'bugs at starbeamrainbowlabs dot com' or <a href='//github.com/sbrl/Pepperminty-Wiki' title='Github Issue Tracker'>open an issue</a>.</p>
<p>Your local friendly administrators are {admins-name-list}.</p>
<p>Your local friendly moderators are {admins-name-list}.</p>
<p>This wiki is managed by <a href='mailto:{admin-details-email}'>{admin-details-name}</a>.</p>
</footer>
{navigation-bar-bottom}
@ -4304,19 +4304,21 @@ class search
register_module([
"name" => "Statistics",
"version" => "0.1",
"version" => "0.2",
"author" => "Starbeamrainbowlabs",
"description" => "An extensible statistics calculation system. Comes with a range of built-in statistics, but can be extended by other modules too.",
"id" => "feature-stats",
"code" => function() {
global $settings;
global $settings, $env;
/**
* @api {get|post} ?action=stats-update Recalculate the wiki's statistics
* @apiName UpdateStats
* @api {get} ?action=stats Show wiki statistics
* @apiName Stats
* @apiGroup Utility
* @apiPermission Administrator
*
* @apiParam {string} secret POST only, optional. If you're not logged in, you can specify the wiki's sekret (find it in peppermint.json) using this parameter.
* @apiPermission Anonymous
* @since v0.15
* @apiParam {string} format Specify the format the data should be returned in. Supported formats: html (default), json.
* @apiParam {string} stat HTML format only. If specified the page for the stat with this id is sent instead of the list of scalar stats.
*/
/*
@ -4329,8 +4331,21 @@ register_module([
add_action("stats", function() {
global $settings, $statistic_calculators;
$allowed_formats = [ "html", "json" ];
$format = $_GET["format"] ?? "html";
if(!in_array($format, $allowed_formats)) {
http_response_code(400);
exit(page_renderer::render_main("Format error - $settings->sitename", "<p>Error: The format '$format' is not currently supported by $settings->sitename. Supported formats: " . implode(", ", $allowed_formats) . "."));
}
$stats = stats_load();
if($format == "json") {
header("content-type: application/json");
exit(json_encode($stats, JSON_PRETTY_PRINT));
}
$stat_pages_list = "<a href='?action=stats'>Main</a> | ";
foreach($statistic_calculators as $stat_id => $stat_calculator) {
if($stat_calculator["type"] == "scalar")
@ -4343,12 +4358,24 @@ register_module([
$stat_calculator = $statistic_calculators[$_GET["stat"]];
$content = "<h1>{$stat_calculator["name"]} - Statistics</h1>\n";
$content .= "<p>$stat_pages_list</p>\n";
$content .= $stat_calculator["render"]($stats->{$_GET["stat"]});
switch($stat_calculator["type"]) {
case "page-list":
if(!module_exists("page-list")) {
$content .= "<p>$settings->sitename doesn't current have the page listing module installed, so HTML rendering of this statistic is currently unavailable. Try <a href='mailto:" . hide_email($settings->admindetails_email) . "'>contacting $settings->admindetails_name</a>, $settings->sitename's administrator and asking then to install the <code>page-list</code> module.</p>";
break;
}
$content .= generate_page_list($stats->{$_GET["stat"]}->value);
break;
case "page":
$content .= $stat_calculator["render"]($stats->{$_GET["stat"]});
break;
}
}
else
{
$content = "<h1>Statistics</h1>\n";
$content .= "<p>This page contains a selection of statistics about $settings->sitename's content. They are updated automatically about every " . trim(str_replace(["ago", "1 "], [""], human_time($settings->stats_update_interval))) . ", although $settings->sitename's local friendly moderators may update it earlier (you can see their names at the bottom of every page).</p>\n";
$content .= "<p>This page contains a selection of statistics about $settings->sitename's content. They are updated automatically about every " . trim(str_replace(["ago", "1 "], [""], human_time($settings->stats_update_interval))) . ", although $settings->sitename's local friendly moderators may update them earlier (you can see their names at the bottom of every page).</p>\n";
$content .= "<p>$stat_pages_list</p>\n";
$content .= "<table class='stats-table'>\n";
@ -4365,6 +4392,15 @@ register_module([
exit(page_renderer::render_main("Statistics - $settings->sitename", $content));
});
/**
* @api {get|post} ?action=stats-update Recalculate the wiki's statistics
* @apiName UpdateStats
* @apiGroup Utility
* @apiPermission Administrator
* @since v0.15
* @apiParam {string} secret POST only, optional. If you're not logged in, you can specify the wiki's sekret instead (find it in peppermint.json) using this parameter.
* @apiParam {bool} force Whether the statistics should be recalculated anyway - even if they have already recently been recalculated. Default: no. Supported values: yes, no.
*/
/*
* ███████ ████████ █████ ████████ ███████
@ -4394,7 +4430,7 @@ register_module([
// Delete the old stats cache
unlink($paths->statsindex);
update_statistics(true);
update_statistics(true, ($_GET["force"] ?? "no") == "yes");
header("content-type: application/json");
echo(file_get_contents($paths->statsindex) . "\n");
});
@ -4470,14 +4506,25 @@ register_module([
]);
// Perform an automatic recalculation of the statistics if needed
update_statistics(false);
if($env->action !== "stats-update")
update_statistics(false);
}
]);
function update_statistics($update_all = false)
/**
* Updates the wiki's statistics.
* @package feature-stats
* @param boolean $update_all Whether all the statistics should be checked and recalculated, or just as many as we have time for according to the settings.
* @param boolean $force Whether we should recalculate statistics that don't currently require recalculating anyway.
*/
function update_statistics($update_all = false, $force = false)
{
global $settings, $statistic_calculators;
// Cleart he existing statistics if we are asked to recalculate them all
if($force)
stats_save(new stdClass());
$stats = stats_load();
$start_time = microtime(true);
@ -6475,7 +6522,7 @@ register_module([
register_module([
"name" => "Page list",
"version" => "0.10.3",
"version" => "0.10.4",
"author" => "Starbeamrainbowlabs",
"description" => "Adds a page that lists all the pages in the index along with their metadata.",
"id" => "page-list",
@ -6577,6 +6624,88 @@ register_module([
exit(page_renderer::render("$tag - Tag List - $settings->sitename", $content));
});
statistic_add([
"id" => "tag-count",
"name" => "Number of Tags",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$all_tags = [];
foreach($pageindex as $page_entry) {
if(empty($page_entry->tags))
continue;
foreach($page_entry->tags as $tag) {
if(!in_array($tag, $all_tags)) $all_tags[] = $tag;
}
}
$result = new stdClass(); // value, state, completed
$result->value = count($all_tags);
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "tags-per-page",
"name" => "Average Number of Tags per Page",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$tag_counts = [];
foreach($pageindex as $page_entry)
$tag_counts[] = count($page_entry->tags ?? []);
$result = new stdClass(); // value, state, completed
$result->value = round(array_sum($tag_counts) / count($tag_counts), 3);
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "most-tags",
"name" => "Most tags on a single page",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$highest_tag_count = 0;
$highest_tag_page = "";
foreach($pageindex as $pagename => $page_entry) {
if(count($page_entry->tags ?? []) > $highest_tag_count) {
$highest_tag_count = count($page_entry->tags ?? []);
$highest_tag_page = $pagename;
}
}
$result = new stdClass(); // value, state, completed
$result->value = "$highest_tag_count (<a href='?page=" . rawurlencode($highest_tag_page) . "'>" . htmlentities($highest_tag_page) . "</a>)";
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "untagged-pages",
"name" => "Untagged Pages",
"type" => "page-list",
"update" => function($old_data) {
global $pageindex;
$untagged_pages = [];
foreach($pageindex as $pagename => $page_entry) {
if(empty($page_entry->tags) || count($page_entry->tags ?? []) == 0)
$untagged_pages[] = $pagename;
}
sort($untagged_pages, SORT_STRING | SORT_FLAG_CASE);
$result = new stdClass(); // value, state, completed
$result->value = $untagged_pages;
$result->completed = true;
return $result;
}
]);
add_help_section("30-all-pages-tags", "Listing pages and tags", "<p>All the pages and tags on $settings->sitename are listed on a pair of pages to aid navigation. The list of all pages on $settings->sitename can be found by clicking &quot;All Pages&quot; on the top bar. The list of all the tags currently in use can be found by clicking &quot;All Tags&quot; in the &quot;More...&quot; menu in the top right.</p>
<p>Each tag on either page can be clicked, and leads to a list of all pages that possess that particular tag.</p>
<p>Redirect pages are shown in italics. A page's last known editor is also shown next to each entry on a list of pages, along with the last known size (which should correct, unless it was changed outside of $settings->sitename) and the time since the last modification (hovering over this will show the exact time that the last modification was made in a tooltip).</p>");

View File

@ -1092,7 +1092,7 @@ class page_renderer
<footer>
<p>{footer-message}</p>
<p>Powered by Pepperminty Wiki {version}, which was built by <a href='//starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>. Send bugs to 'bugs at starbeamrainbowlabs dot com' or <a href='//github.com/sbrl/Pepperminty-Wiki' title='Github Issue Tracker'>open an issue</a>.</p>
<p>Your local friendly administrators are {admins-name-list}.</p>
<p>Your local friendly moderators are {admins-name-list}.</p>
<p>This wiki is managed by <a href='mailto:{admin-details-email}'>{admin-details-name}</a>.</p>
</footer>
{navigation-bar-bottom}

View File

@ -109,11 +109,11 @@
},
{
"name": "Statistics",
"version": "0.1",
"version": "0.2",
"author": "Starbeamrainbowlabs",
"description": "An extensible statistics calculation system. Comes with a range of built-in statistics, but can be extended by other modules too.",
"id": "feature-stats",
"lastupdate": 1505564746,
"lastupdate": 1505579268,
"optional": false
},
{
@ -190,11 +190,11 @@
},
{
"name": "Page list",
"version": "0.10.3",
"version": "0.10.4",
"author": "Starbeamrainbowlabs",
"description": "Adds a page that lists all the pages in the index along with their metadata.",
"id": "page-list",
"lastupdate": 1505513005,
"lastupdate": 1505577933,
"optional": false
},
{

View File

@ -1,19 +1,21 @@
<?php
register_module([
"name" => "Statistics",
"version" => "0.1",
"version" => "0.2",
"author" => "Starbeamrainbowlabs",
"description" => "An extensible statistics calculation system. Comes with a range of built-in statistics, but can be extended by other modules too.",
"id" => "feature-stats",
"code" => function() {
global $settings;
global $settings, $env;
/**
* @api {get|post} ?action=stats-update Recalculate the wiki's statistics
* @apiName UpdateStats
* @api {get} ?action=stats Show wiki statistics
* @apiName Stats
* @apiGroup Utility
* @apiPermission Administrator
*
* @apiParam {string} secret POST only, optional. If you're not logged in, you can specify the wiki's sekret (find it in peppermint.json) using this parameter.
* @apiPermission Anonymous
* @since v0.15
* @apiParam {string} format Specify the format the data should be returned in. Supported formats: html (default), json.
* @apiParam {string} stat HTML format only. If specified the page for the stat with this id is sent instead of the list of scalar stats.
*/
/*
@ -26,8 +28,21 @@ register_module([
add_action("stats", function() {
global $settings, $statistic_calculators;
$allowed_formats = [ "html", "json" ];
$format = $_GET["format"] ?? "html";
if(!in_array($format, $allowed_formats)) {
http_response_code(400);
exit(page_renderer::render_main("Format error - $settings->sitename", "<p>Error: The format '$format' is not currently supported by $settings->sitename. Supported formats: " . implode(", ", $allowed_formats) . "."));
}
$stats = stats_load();
if($format == "json") {
header("content-type: application/json");
exit(json_encode($stats, JSON_PRETTY_PRINT));
}
$stat_pages_list = "<a href='?action=stats'>Main</a> | ";
foreach($statistic_calculators as $stat_id => $stat_calculator) {
if($stat_calculator["type"] == "scalar")
@ -40,12 +55,24 @@ register_module([
$stat_calculator = $statistic_calculators[$_GET["stat"]];
$content = "<h1>{$stat_calculator["name"]} - Statistics</h1>\n";
$content .= "<p>$stat_pages_list</p>\n";
$content .= $stat_calculator["render"]($stats->{$_GET["stat"]});
switch($stat_calculator["type"]) {
case "page-list":
if(!module_exists("page-list")) {
$content .= "<p>$settings->sitename doesn't current have the page listing module installed, so HTML rendering of this statistic is currently unavailable. Try <a href='mailto:" . hide_email($settings->admindetails_email) . "'>contacting $settings->admindetails_name</a>, $settings->sitename's administrator and asking then to install the <code>page-list</code> module.</p>";
break;
}
$content .= generate_page_list($stats->{$_GET["stat"]}->value);
break;
case "page":
$content .= $stat_calculator["render"]($stats->{$_GET["stat"]});
break;
}
}
else
{
$content = "<h1>Statistics</h1>\n";
$content .= "<p>This page contains a selection of statistics about $settings->sitename's content. They are updated automatically about every " . trim(str_replace(["ago", "1 "], [""], human_time($settings->stats_update_interval))) . ", although $settings->sitename's local friendly moderators may update it earlier (you can see their names at the bottom of every page).</p>\n";
$content .= "<p>This page contains a selection of statistics about $settings->sitename's content. They are updated automatically about every " . trim(str_replace(["ago", "1 "], [""], human_time($settings->stats_update_interval))) . ", although $settings->sitename's local friendly moderators may update them earlier (you can see their names at the bottom of every page).</p>\n";
$content .= "<p>$stat_pages_list</p>\n";
$content .= "<table class='stats-table'>\n";
@ -62,6 +89,15 @@ register_module([
exit(page_renderer::render_main("Statistics - $settings->sitename", $content));
});
/**
* @api {get|post} ?action=stats-update Recalculate the wiki's statistics
* @apiName UpdateStats
* @apiGroup Utility
* @apiPermission Administrator
* @since v0.15
* @apiParam {string} secret POST only, optional. If you're not logged in, you can specify the wiki's sekret instead (find it in peppermint.json) using this parameter.
* @apiParam {bool} force Whether the statistics should be recalculated anyway - even if they have already recently been recalculated. Default: no. Supported values: yes, no.
*/
/*
* ███████ ████████ █████ ████████ ███████
@ -91,7 +127,7 @@ register_module([
// Delete the old stats cache
unlink($paths->statsindex);
update_statistics(true);
update_statistics(true, ($_GET["force"] ?? "no") == "yes");
header("content-type: application/json");
echo(file_get_contents($paths->statsindex) . "\n");
});
@ -167,14 +203,25 @@ register_module([
]);
// Perform an automatic recalculation of the statistics if needed
update_statistics(false);
if($env->action !== "stats-update")
update_statistics(false);
}
]);
function update_statistics($update_all = false)
/**
* Updates the wiki's statistics.
* @package feature-stats
* @param boolean $update_all Whether all the statistics should be checked and recalculated, or just as many as we have time for according to the settings.
* @param boolean $force Whether we should recalculate statistics that don't currently require recalculating anyway.
*/
function update_statistics($update_all = false, $force = false)
{
global $settings, $statistic_calculators;
// Clear the existing statistics if we are asked to recalculate them all
if($force)
stats_save(new stdClass());
$stats = stats_load();
$start_time = microtime(true);

View File

@ -1,7 +1,7 @@
<?php
register_module([
"name" => "Page list",
"version" => "0.10.3",
"version" => "0.10.4",
"author" => "Starbeamrainbowlabs",
"description" => "Adds a page that lists all the pages in the index along with their metadata.",
"id" => "page-list",
@ -103,6 +103,88 @@ register_module([
exit(page_renderer::render("$tag - Tag List - $settings->sitename", $content));
});
statistic_add([
"id" => "tag-count",
"name" => "Number of Tags",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$all_tags = [];
foreach($pageindex as $page_entry) {
if(empty($page_entry->tags))
continue;
foreach($page_entry->tags as $tag) {
if(!in_array($tag, $all_tags)) $all_tags[] = $tag;
}
}
$result = new stdClass(); // value, state, completed
$result->value = count($all_tags);
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "tags-per-page",
"name" => "Average Number of Tags per Page",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$tag_counts = [];
foreach($pageindex as $page_entry)
$tag_counts[] = count($page_entry->tags ?? []);
$result = new stdClass(); // value, state, completed
$result->value = round(array_sum($tag_counts) / count($tag_counts), 3);
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "most-tags",
"name" => "Most tags on a single page",
"type" => "scalar",
"update" => function($old_data) {
global $pageindex;
$highest_tag_count = 0;
$highest_tag_page = "";
foreach($pageindex as $pagename => $page_entry) {
if(count($page_entry->tags ?? []) > $highest_tag_count) {
$highest_tag_count = count($page_entry->tags ?? []);
$highest_tag_page = $pagename;
}
}
$result = new stdClass(); // value, state, completed
$result->value = "$highest_tag_count (<a href='?page=" . rawurlencode($highest_tag_page) . "'>" . htmlentities($highest_tag_page) . "</a>)";
$result->completed = true;
return $result;
}
]);
statistic_add([
"id" => "untagged-pages",
"name" => "Untagged Pages",
"type" => "page-list",
"update" => function($old_data) {
global $pageindex;
$untagged_pages = [];
foreach($pageindex as $pagename => $page_entry) {
if(empty($page_entry->tags) || count($page_entry->tags ?? []) == 0)
$untagged_pages[] = $pagename;
}
sort($untagged_pages, SORT_STRING | SORT_FLAG_CASE);
$result = new stdClass(); // value, state, completed
$result->value = $untagged_pages;
$result->completed = true;
return $result;
}
]);
add_help_section("30-all-pages-tags", "Listing pages and tags", "<p>All the pages and tags on $settings->sitename are listed on a pair of pages to aid navigation. The list of all pages on $settings->sitename can be found by clicking &quot;All Pages&quot; on the top bar. The list of all the tags currently in use can be found by clicking &quot;All Tags&quot; in the &quot;More...&quot; menu in the top right.</p>
<p>Each tag on either page can be clicked, and leads to a list of all pages that possess that particular tag.</p>
<p>Redirect pages are shown in italics. A page's last known editor is also shown next to each entry on a list of pages, along with the last known size (which should correct, unless it was changed outside of $settings->sitename) and the time since the last modification (hovering over this will show the exact time that the last modification was made in a tooltip).</p>");