This repository has been archived on 2024-09-05. You can view files and clone it, but cannot push or open issues or pull requests.
shimmie2/ext/statistics/main.php

187 lines
7.4 KiB
PHP
Raw Normal View History

2024-03-23 04:17:05 +00:00
<?php
declare(strict_types=1);
namespace Shimmie2;
class Statistics extends Extension
{
/** @var StatisticsTheme */
protected Themelet $theme;
2024-05-03 03:00:04 +00:00
/** @var String[] */
private array $unlisted = ['anonymous', 'ghost', 'hellbanned'];
2024-03-23 04:17:05 +00:00
public function onPageRequest(PageRequestEvent $event): void
{
global $config, $page;
if ($event->page_matches("stats") || $event->page_matches("stats/100")) {
$base_href = get_base_href();
$sitename = $config->get_string(SetupConfig::TITLE);
$theme_name = $config->get_string(SetupConfig::THEME);
2024-05-03 03:00:04 +00:00
$unlisted = "'".implode("','", $this->unlisted)."'";
2024-03-23 04:17:05 +00:00
$limit = 10;
if ($event->page_matches("stats/100")) {
$limit = 100;
}
if (Extension::is_enabled(TagHistoryInfo::KEY)) {
$tallies = $this->get_tag_stats($this->unlisted);
arsort($tallies[0], SORT_NUMERIC);
$stats = [];
foreach ($tallies[0] as $name => $tag_diff) {
$entries = "";
if (isset($tallies[1][$name])) {
$entries = " <span class='tag_count' title='Total edits'>" . $tallies[1][$name] . "</span>";
}
$stats[$name] = "<span title='Tags changed (ignoring aliases)'>$tag_diff</span>$entries";
}
$tag_table = $this->theme->build_table($stats, "Taggers", "Top $limit taggers", $limit);
2024-03-23 04:17:05 +00:00
} else {
$tag_table = null;
}
$upload_tally = [];
2024-05-03 03:00:04 +00:00
foreach ($this->get_upload_stats($unlisted) as $name) {
2024-03-23 04:17:05 +00:00
array_key_exists($name, $upload_tally) ? $upload_tally[$name] += 1 : $upload_tally[$name] = 1;
}
arsort($upload_tally, SORT_NUMERIC);
2024-03-23 04:17:05 +00:00
$upload_table = $this->theme->build_table($upload_tally, "Uploaders", "Top $limit uploaders", $limit);
if (Extension::is_enabled(CommentListInfo::KEY)) {
$comment_tally = [];
2024-05-03 03:00:04 +00:00
foreach ($this->get_comment_stats($unlisted) as $name) {
2024-03-23 04:17:05 +00:00
array_key_exists($name, $comment_tally) ? $comment_tally[$name] += 1 : $comment_tally[$name] = 1;
}
arsort($comment_tally, SORT_NUMERIC);
2024-03-23 04:17:05 +00:00
$comment_table = $this->theme->build_table($comment_tally, "Commenters", "Top $limit commenters", $limit);
} else {
$comment_table = null;
}
if (Extension::is_enabled(FavoritesInfo::KEY)) {
$favorite_tally = [];
2024-05-03 03:00:04 +00:00
foreach ($this->get_favorite_stats($unlisted) as $name) {
2024-03-23 04:17:05 +00:00
array_key_exists($name, $favorite_tally) ? $favorite_tally[$name] += 1 : $favorite_tally[$name] = 1;
}
arsort($favorite_tally, SORT_NUMERIC);
2024-03-23 04:17:05 +00:00
$favorite_table = $this->theme->build_table($favorite_tally, "Favoriters", "Top $limit favoriters", $limit);
} else {
$favorite_table = null;
}
$this->theme->display_page($page, $limit, $tag_table, $upload_table, $comment_table, $favorite_table);
}
}
public function onSetupBuilding(SetupBuildingEvent $event): void
{
$sb = $event->panel->create_new_block("Stats Page");
$sb->add_longtext_option("stats_text", "<br>Page Text:<br>");
}
public function onPageNavBuilding(PageNavBuildingEvent $event): void
{
$event->add_nav_link("stats", new Link('stats'), "Stats");
}
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
{
if ($event->parent == "stats") {
$event->add_nav_link("stats_100", new Link('stats/100'), "Top 100");
}
}
/**
2024-05-03 03:00:04 +00:00
* @param String[] $unlisted
* @return array<array<string, int>>
2024-03-23 04:17:05 +00:00
*/
2024-05-03 03:00:04 +00:00
private function get_tag_stats(array $unlisted): array
2024-03-23 04:17:05 +00:00
{
global $database;
// Returns the username and tags from each tag history entry. This includes Anonymous tag histories to prevent their tagging being ignored and credited to the next user to edit.
$tag_stats = $database->get_all("SELECT users.class,users.name,tag_histories.tags,tag_histories.image_id FROM tag_histories INNER JOIN users ON users.id = tag_histories.user_id WHERE 1=1 ORDER BY tag_histories.id;");
2024-03-23 04:17:05 +00:00
// Group tag history entries by image id
$tag_histories = [];
foreach ($tag_stats as $ts) {
2024-05-03 03:00:04 +00:00
$tag_history = ['class' => $ts['class'], 'name' => $ts['name'], 'tags' => $ts['tags']];
2024-03-23 04:17:05 +00:00
$id = $ts['image_id'];
array_key_exists($id, $tag_histories) ? array_push($tag_histories[$id], $tag_history) : $tag_histories[$id] = [$tag_history];
}
// Grab alias list so we can ignore those changes
// While this strategy may discount some change made before those aliases were implemented, it is preferable over crediting the changes made by an alias to whoever edits the tags next.
$alias_db = $database->get_all(
"
SELECT *
FROM aliases
WHERE 1=1
"
);
$aliases = [];
foreach ($alias_db as $alias) {
$aliases[$alias['oldtag']] = $alias['newtag'];
}
2024-03-23 04:17:05 +00:00
// Count changes made in each tag history and tally tags for users
$tag_tally = [];
$change_tally = [];
2024-03-23 04:17:05 +00:00
foreach ($tag_histories as $i => $image) {
$prev = [];
foreach ($image as $change) {
$curr = explode(' ', $change['tags']);
foreach ($curr as $i => $tag) {
if (array_key_exists($tag, $aliases)) {
$curr[$i] = $aliases[$tag];
}
}
2024-05-03 03:00:04 +00:00
if (!in_array($change['class'], $unlisted)) {
$name = (string)$change['name'];
if (!isset($tag_tally[$name])) {
$tag_tally[$name] = 0;
$change_tally[$name] = 0;
}
$tag_tally[$name] += count(array_diff($curr, $prev));
$change_tally[$name] += 1;
}
2024-03-23 04:17:05 +00:00
$prev = $curr;
}
}
return [$tag_tally, $change_tally];
2024-03-23 04:17:05 +00:00
}
/**
* @return array<string>
*/
2024-05-03 03:00:04 +00:00
private function get_upload_stats(string $unlisted): array
2024-03-23 04:17:05 +00:00
{
global $database;
2024-05-03 03:00:04 +00:00
// Returns the username of each post, as an array.
return $database->get_col("SELECT users.name FROM images INNER JOIN users ON users.id = images.owner_id WHERE users.class NOT IN ($unlisted) ORDER BY users.id;");
2024-03-23 04:17:05 +00:00
}
/**
* @return array<string>
*/
2024-05-03 03:00:04 +00:00
private function get_comment_stats(string $unlisted): array
2024-03-23 04:17:05 +00:00
{
global $database;
2024-05-03 03:00:04 +00:00
// Returns the username of each comment, as an array.
return $database->get_col("SELECT users.name FROM comments INNER JOIN users ON users.id = comments.owner_id WHERE users.class NOT IN ($unlisted) ORDER BY users.id;");
2024-03-23 04:17:05 +00:00
}
/**
* @return array<string>
*/
2024-05-03 03:00:04 +00:00
private function get_favorite_stats(string $unlisted): array
2024-03-23 04:17:05 +00:00
{
global $database;
2024-05-03 03:00:04 +00:00
// Returns the username of each favorite, as an array.
return $database->get_col("SELECT users.name FROM user_favorites INNER JOIN users ON users.id = user_favorites.user_id WHERE users.class NOT IN ($unlisted) ORDER BY users.id;");
2024-03-23 04:17:05 +00:00
}
}