misuzu/src/Forum/ForumCategoriesRoutes.php

232 lines
9.8 KiB
PHP
Raw Normal View History

<?php
namespace Misuzu\Forum;
2024-12-18 23:58:53 +00:00
use stdClass;
use RuntimeException;
use Index\Http\{HttpRequest,HttpResponseBuilder};
2024-12-18 23:58:53 +00:00
use Index\Http\Routing\{HttpGet,HttpPost,RouteHandler,RouteHandlerTrait};
use Index\Urls\{UrlFormat,UrlSource,UrlSourceTrait};
2024-12-18 23:58:53 +00:00
use Misuzu\{CSRF,Perm,Template};
use Misuzu\Auth\AuthInfo;
2024-12-18 23:58:53 +00:00
use Misuzu\Users\UsersContext;
class ForumCategoriesRoutes implements RouteHandler, UrlSource {
use RouteHandlerTrait, UrlSourceTrait;
public function __construct(
private ForumContext $forum,
2024-12-18 23:58:53 +00:00
private UsersContext $usersCtx,
private AuthInfo $authInfo,
) {}
2024-12-18 23:58:53 +00:00
#[HttpGet('/forum')]
#[UrlFormat('forum-index', '/forum')]
public function getIndex() {
$cats = $this->forum->categories->getCategories(hidden: false, asTree: true);
// Filtering! This really needs cleaning up...
foreach($cats as $catId => $category) {
$perms = $this->authInfo->getPerms('forum', $category->info);
// Check if we're allowed to list this category, separate from viewing for some reason...
if(!$perms->check(Perm::F_CATEGORY_LIST)) {
unset($cats[$catId]);
continue;
}
$unread = false;
// This is not fully recursive, idk why... probably shove this into ForumContext?
if($category->info->mayHaveChildren && !$unread)
foreach($category->children as $childId => $child) {
$childPerms = $this->authInfo->getPerms('forum', $child->info);
if(!$childPerms->check(Perm::F_CATEGORY_LIST)) {
unset($category->children[$childId]);
continue;
}
$childUnread = false;
if($category->info->isListing) {
if($child->info->mayHaveChildren) {
foreach($child->children as $grandChildId => $grandChild) {
$grandChildPerms = $this->authInfo->getPerms('forum', $grandChild->info);
if(!$grandChildPerms->check(Perm::F_CATEGORY_LIST)) {
unset($child->children[$grandChildId]);
continue;
}
$grandChildUnread = false;
if($grandChild->info->mayHaveTopics) {
$catIds = [$grandChild->info->id];
foreach($grandChild->childIds as $greatGrandChildId) {
$greatGrandChildPerms = $this->authInfo->getPerms('forum', $greatGrandChildId);
if($greatGrandChildPerms->check(Perm::F_CATEGORY_LIST))
$catIds[] = $greatGrandChildId;
}
$grandChildUnread = $this->forum->categories->checkCategoryUnread($catIds, $this->authInfo->userInfo);
if($grandChildUnread)
$childUnread = true;
}
$grandChild->perms = $grandChildPerms;
$grandChild->unread = $grandChildUnread;
}
}
if($child->info->mayHaveChildren || $child->info->mayHaveTopics) {
$catIds = [$child->info->id];
foreach($child->childIds as $grandChildId) {
$grandChildPerms = $this->authInfo->getPerms('forum', $grandChildId);
if($grandChildPerms->check(Perm::F_CATEGORY_LIST))
$catIds[] = $grandChildId;
}
try {
$lastPostInfo = $this->forum->posts->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
} catch(RuntimeException $ex) {
$lastPostInfo = null;
}
if($lastPostInfo !== null) {
$child->lastPost = new stdClass;
$child->lastPost->info = $lastPostInfo;
$child->lastPost->topicInfo = $this->forum->topics->getTopic(postInfo: $lastPostInfo);
if($lastPostInfo->userId !== null) {
$child->lastPost->user = $this->usersCtx->getUserInfo($lastPostInfo->userId);
$child->lastPost->colour = $this->usersCtx->getUserColour($child->lastPost->user);
}
}
}
}
if($child->info->mayHaveTopics && !$childUnread) {
$childUnread = $this->forum->categories->checkCategoryUnread($child->info, $this->authInfo->userInfo);
if($childUnread)
$unread = true;
}
$child->perms = $childPerms;
$child->unread = $childUnread;
}
// This is listed second despite being less expensive because the subcategories listed also need to show unread :sob:
if($category->info->mayHaveTopics)
$unread = $this->forum->categories->checkCategoryUnread($category->info, $this->authInfo->userInfo);
// Create virtual root category if we need to list non-listing categories in root
if(!$category->info->isListing) {
if(!array_key_exists('0', $cats)) {
$cats['0'] = $root = new stdClass;
$root->info = null;
$root->perms = 0;
$root->unread = false;
$root->colour = null;
$root->children = [];
}
$cats['0']->children[$categoryId] = $category;
unset($cats[$categoryId]);
if($category->info->mayHaveChildren || $category->info->mayHaveTopics) {
$catIds = [$category->info->id];
foreach($category->childIds as $childId) {
$childPerms = $this->authInfo->getPerms('forum', $childId);
if($childPerms->check(Perm::F_CATEGORY_LIST))
$catIds[] = $childId;
}
try {
$lastPostInfo = $this->forum->posts->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
} catch(RuntimeException $ex) {
$lastPostInfo = null;
}
if($lastPostInfo !== null) {
$category->lastPost = new stdClass;
$category->lastPost->info = $lastPostInfo;
$category->lastPost->topicInfo = $this->forum->topics->getTopic(postInfo: $lastPostInfo);
if($lastPostInfo->userId !== null) {
$category->lastPost->user = $this->usersCtx->getUserInfo($lastPostInfo->userId);
$category->lastPost->colour = $this->usersCtx->getUserColour($category->lastPost->user);
}
}
}
}
$category->perms = $perms;
$category->unread = $unread;
}
return Template::renderRaw('forum.index', [
'forum_categories' => $cats,
'forum_empty' => empty($cats),
'forum_show_mark_as_read' => $this->authInfo->isLoggedIn,
]);
}
#[HttpPost('/forum/mark-as-read')]
#[UrlFormat('forum-mark-as-read', '/forum/mark-as-read', ['cat' => '<category>', 'rec' => '<recursive>'])]
public function postMarkAsRead(HttpResponseBuilder $response, HttpRequest $request) {
if(!$this->authInfo->isLoggedIn)
return 401;
if(!CSRF::validate($request->getHeaderLine('X-CSRF-token')))
return 403;
$response->setHeader('X-CSRF-Token', CSRF::token());
$catId = (string)$request->getParam('cat', FILTER_SANITIZE_NUMBER_INT);
$recursive = !empty($request->getParam('rec'));
// root category purge must be recursive
if($categoryId === '')
return 400;
if($catId === '')
$cats = $this->forum->categories->getCategories();
elseif($recursive)
$cats = $this->forum->categories->getCategoryChildren(parentInfo: $catId, includeSelf: true);
else
try {
$cats = [$this->forum->categories->getCategory(categoryId: $catId)];
} catch(RuntimeException $ex) {
$cats = [];
}
if(empty($cats)) {
$response->setStatusCode(404);
return [
'error' => [
'name' => 'forum:category:none',
'text' => "Couldn't find that forum category.",
],
];
}
$success = false;
foreach($cats as $category) {
$perms = $this->authInfo->getPerms('forum', $category);
if($perms->check(Perm::F_CATEGORY_LIST)) {
$this->forum->categories->updateUserReadCategory($this->authInfo->userInfo, $category);
$success = true;
}
}
if(!$success) {
$response->setStatusCode(403);
return [
'error' => [
'name' => 'forum:category:access',
'text' => "You're not allowed to access this forum category.",
],
];
}
return 204;
}
}