misuzu/src/Home/HomeRoutes.php

241 lines
8.8 KiB
PHP

<?php
namespace Misuzu\Home;
use RuntimeException;
use Index\DateTime;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Syokuhou\IConfig;
use Misuzu\Pagination;
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo;
use Misuzu\Changelog\Changelog;
use Misuzu\Comments\Comments;
use Misuzu\Counters\Counters;
use Misuzu\News\News;
use Misuzu\URLs\URLInfo;
use Misuzu\Users\UsersContext;
class HomeRoutes extends RouteHandler {
public function __construct(
private IConfig $config,
private IDbConnection $dbConn,
private SiteInfo $siteInfo,
private AuthInfo $authInfo,
private Changelog $changelog,
private Comments $comments,
private Counters $counters,
private News $news,
private UsersContext $usersCtx
) {}
private function getStats(): array {
return $this->counters->get([
'users:active',
'users:online:recent',
'users:online:today',
'comments:posts:visible',
'forum:topics:visible',
'forum:posts:visible',
]);
}
private function getOnlineUsers(): iterable {
return $this->usersCtx->getUsers()->getUsers(
lastActiveInMinutes: 5,
deleted: false,
orderBy: 'random',
);
}
private array $newsCategoryInfos = [];
private function getFeaturedNewsPosts(int $amount, bool $decorate): array {
$postInfos = $this->news->getPosts(
onlyFeatured: true,
pagination: new Pagination($amount)
);
if(!$decorate)
return $postInfos;
$posts = [];
foreach($postInfos as $postInfo) {
$categoryId = $postInfo->getCategoryId();
$userInfo = $postInfo->hasUserId() ? $this->usersCtx->getUserInfo($postInfo->getUserId()) : null;
if(array_key_exists($categoryId, $this->newsCategoryInfos))
$categoryInfo = $this->newsCategoryInfos[$categoryId];
else
$this->newsCategoryInfos[$categoryId] = $categoryInfo = $this->news->getCategory(postInfo: $postInfo);
$commentsCount = $postInfo->hasCommentsCategoryId()
? $this->comments->countPosts(categoryInfo: $postInfo->getCommentsCategoryId(), deleted: false) : 0;
$posts[] = [
'post' => $postInfo,
'category' => $categoryInfo,
'user' => $userInfo,
'user_colour' => $this->usersCtx->getUserColour($userInfo),
'comments_count' => $commentsCount,
];
}
return $posts;
}
public function getPopularForumTopics(array $categoryIds): array {
$args = 0;
$stmt = $this->dbConn->prepare(
'SELECT t.topic_id, c.forum_id, t.topic_title, c.forum_icon, t.topic_count_views'
. ', (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
. ' FROM msz_forum_topics AS t'
. ' LEFT JOIN msz_forum_categories AS c ON c.forum_id = t.forum_id'
. ' WHERE c.forum_id IN (' . DbTools::prepareListString($categoryIds) . ') AND topic_deleted IS NULL AND topic_locked IS NULL'
. ' ORDER BY (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL AND post_created > NOW() - INTERVAL 3 MONTH) DESC'
. ' LIMIT 10'
);
foreach($categoryIds as $categoryId)
$stmt->addParameter(++$args, (string)$categoryId);
$stmt->execute();
$topics = [];
$result = $stmt->getResult();
while($result->next())
$topics[] = [
'topic_id' => $result->getInteger(0),
'forum_id' => $result->getInteger(1),
'topic_title' => $result->getString(2),
'forum_icon' => $result->getString(3),
'topic_count_views' => $result->getInteger(4),
'topic_count_posts' => $result->getInteger(5),
];
return $topics;
}
public function getActiveForumTopics(array $categoryIds): array {
$args = 0;
$stmt = $this->dbConn->prepare(
'SELECT t.topic_id, c.forum_id, t.topic_title, c.forum_icon, t.topic_count_views'
. ', (SELECT COUNT(*) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
. ', (SELECT MAX(post_id) FROM msz_forum_posts AS p WHERE p.topic_id = t.topic_id AND post_deleted IS NULL)'
. ' FROM msz_forum_topics AS t'
. ' LEFT JOIN msz_forum_categories AS c ON c.forum_id = t.forum_id'
. ' WHERE c.forum_id IN (' . DbTools::prepareListString($categoryIds) . ') AND topic_deleted IS NULL AND topic_locked IS NULL'
. ' ORDER BY topic_bumped DESC'
. ' LIMIT 10'
);
foreach($categoryIds as $categoryId)
$stmt->addParameter(++$args, (string)$categoryId);
$stmt->execute();
$topics = [];
$result = $stmt->getResult();
while($result->next())
$topics[] = [
'topic_id' => $result->getInteger(0),
'forum_id' => $result->getInteger(1),
'topic_title' => $result->getString(2),
'forum_icon' => $result->getString(3),
'topic_count_views' => $result->getInteger(4),
'topic_count_posts' => $result->getInteger(5),
'latest_post_id' => $result->getInteger(6),
];
return $topics;
}
#[Route('GET', '/')]
#[URLInfo('index', '/')]
public function getIndex(...$args) {
return $this->authInfo->isLoggedIn()
? $this->getHome(...$args)
: $this->getLanding(...$args);
}
public function getHome() {
$stats = $this->getStats();
$onlineUserInfos = iterator_to_array($this->getOnlineUsers());
$featuredNews = $this->getFeaturedNewsPosts(5, true);
$changelog = iterator_to_array($this->changelog->getChanges(pagination: new Pagination(10)));
$stats['users:online:recent'] = count($onlineUserInfos);
$birthdays = [];
$birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: DateTime::now(), orderBy: 'random');
foreach($birthdayInfos as $birthdayInfo)
$birthdays[] = [
'info' => $birthdayInfo,
'colour' => $this->usersCtx->getUserColour($birthdayInfo),
];
$newestMember = [];
if(empty($birthdays)) {
$newestMemberId = $this->config->getString('users.newest');
if(!empty($newestMemberId))
try {
$newestMember['info'] = $this->usersCtx->getUserInfo($newestMemberId);
$newestMember['colour'] = $this->usersCtx->getUserColour($newestMemberId);
} catch(RuntimeException $ex) {
$newestMember = [];
$this->config->removeValues('users.newest');
}
}
return Template::renderRaw('home.home', [
'statistics' => $stats,
'newest_member' => $newestMember,
'online_users' => $onlineUserInfos,
'birthdays' => $birthdays,
'featured_changelog' => $changelog,
'featured_news' => $featuredNews,
]);
}
#[Route('GET', '/_landing')]
public function getLanding($response, $request) {
$config = $this->config->getValues([
['social.embed_linked:b'],
['landing.forum_categories:a'],
'social.linked:a'
]);
if($config['social.embed_linked']) {
$linkedData = [
'@context' => 'http://schema.org',
'@type' => 'Organization',
'name' => $this->siteInfo->getName(),
'url' => $this->siteInfo->getURL(),
'logo' => $this->siteInfo->getExternalLogo(),
'same_as' => $config['social.linked'],
];
} else $linkedData = null;
$stats = $this->getStats();
$onlineUserInfos = $this->getOnlineUsers();
$featuredNews = $this->getFeaturedNewsPosts(3, false);
$popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']);
$activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']);
$stats['users:online:recent'] = count($onlineUserInfos);
return Template::renderRaw('home.landing', [
'statistics' => $stats,
'online_users' => $onlineUserInfos,
'featured_news' => $featuredNews,
'linked_data' => $linkedData,
'forum_popular' => $popularTopics,
'forum_active' => $activeTopics,
]);
}
}