misuzu/src/Http/Handlers/NewsHandler.php
flash 383e2ed0e0 Rewrote the user information class.
This one took multiple days and it pretty invasive into the core of Misuzu so issue might (will) arise, there's also some features that have gone temporarily missing in the mean time and some inefficiencies introduced that will be fixed again at a later time.
The old class isn't gone entirely because I still have to figure out what I'm gonna do about validation, but for the most part this knocks out one of the "layers of backwards compatibility", as I've been referring to it, and is moving us closer to a future where Flashii actually gets real updates.
If you run into anything that's broken and you're inhibited from reporting it through the forum, do it through chat or mail me at flashii-issues@flash.moe.
2023-08-02 22:12:47 +00:00

283 lines
10 KiB
PHP

<?php
namespace Misuzu\Http\Handlers;
use RuntimeException;
use Misuzu\DB;
use Misuzu\Pagination;
use Misuzu\Template;
use Misuzu\Comments\CommentsCategory;
use Misuzu\Comments\CommentsEx;
use Misuzu\Feeds\Feed;
use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\News\NewsCategoryInfo;
use Misuzu\Parsers\Parser;
final class NewsHandler extends Handler {
private function fetchPostInfo(array $postInfos, array $categoryInfos = []): array {
$news = $this->context->getNews();
$users = $this->context->getUsers();
$comments = $this->context->getComments();
$posts = [];
$userInfos = [];
$userColours = [];
foreach($postInfos as $postInfo) {
$userId = $postInfo->getUserId();
$categoryId = $postInfo->getCategoryId();
if(array_key_exists($userId, $userInfos)) {
$userInfo = $userInfos[$userId];
$userColour = $userColours[$userId];
} else {
try {
$userInfo = $users->getUser($userId, 'id');
$userColour = $users->getUserColour($userInfo);
} catch(RuntimeException $ex) {
$userInfo = null;
$userColour = null;
}
$userInfos[$userId] = $userInfo;
$userColours[$userId] = $userColour;
}
if(array_key_exists($categoryId, $categoryInfos))
$categoryInfo = $categoryInfos[$categoryId];
else
$categoryInfos[$categoryId] = $categoryInfo = $news->getCategoryByPost($postInfo);
$commentsCount = $postInfo->hasCommentsCategoryId()
? $comments->countPosts($postInfo->getCommentsCategoryId(), includeReplies: true) : 0;
$posts[] = [
'post' => $postInfo,
'category' => $categoryInfo,
'user' => $userInfo,
'user_colour' => $userColour,
'comments_count' => $commentsCount,
];
}
return $posts;
}
public function index($response, $request) {
$news = $this->context->getNews();
$categories = $news->getAllCategories();
$pagination = new Pagination($news->countAllPosts(onlyFeatured: true), 5);
if(!$pagination->hasValidOffset())
return 404;
$postInfos = $news->getAllPosts(onlyFeatured: true, pagination: $pagination);
$posts = $this->fetchPostInfo($postInfos);
$response->setContent(Template::renderRaw('news.index', [
'news_categories' => $categories,
'news_posts' => $posts,
'news_pagination' => $pagination,
]));
}
public function viewCategory($response, $request, string $fileName) {
$news = $this->context->getNews();
$categoryId = pathinfo($fileName, PATHINFO_FILENAME);
$type = pathinfo($fileName, PATHINFO_EXTENSION);
try {
$categoryInfo = $news->getCategoryById($categoryId);
} catch(RuntimeException $ex) {
return 404;
}
if($type === 'atom')
return $this->feedCategoryAtom($response, $request, $categoryInfo);
elseif($type === 'rss')
return $this->feedCategoryRss($response, $request, $categoryInfo);
elseif($type !== '')
return 404;
$pagination = new Pagination($news->countPostsByCategory($categoryInfo), 5);
if(!$pagination->hasValidOffset())
return 404;
$postInfos = $news->getPostsByCategory($categoryInfo, pagination: $pagination);
$posts = $this->fetchPostInfo($postInfos, [$categoryInfo->getId() => $categoryInfo]);
$response->setContent(Template::renderRaw('news.category', [
'news_category' => $categoryInfo,
'news_posts' => $posts,
'news_pagination' => $pagination,
]));
}
public function viewPost($response, $request, string $postId) {
$news = $this->context->getNews();
$users = $this->context->getUsers();
$comments = $this->context->getComments();
try {
$postInfo = $news->getPostById($postId);
} catch(RuntimeException $ex) {
return 404;
}
if(!$postInfo->isPublished() || $postInfo->isDeleted())
return 404;
$categoryInfo = $news->getCategoryByPost($postInfo);
$comments = $this->context->getComments();
if($postInfo->hasCommentsCategoryId())
try {
$commentsCategory = $comments->getCategoryById($postInfo->getCommentsCategoryId());
} catch(RuntimeException $ex) {}
if(!isset($commentsCategory)) {
$commentsCategory = $comments->ensureCategory($postInfo->getCommentsCategoryName());
$news->updatePostCommentCategory($postInfo, $commentsCategory);
}
$userInfo = null;
$userColour = null;
if($postInfo->hasUserId())
try {
$userInfo = $users->getUser($postInfo->getUserId(), 'id');
$userColour = $users->getUserColour($userInfo);
} catch(RuntimeException $ex) {}
$comments = new CommentsEx($this->context, $comments, $users);
$response->setContent(Template::renderRaw('news.post', [
'post_info' => $postInfo,
'post_category_info' => $categoryInfo,
'post_user_info' => $userInfo,
'post_user_colour' => $userColour,
'comments_info' => $comments->getCommentsForLayout($commentsCategory),
]));
}
private function createFeed(string $feedMode, ?NewsCategoryInfo $categoryInfo, array $posts): Feed {
$hasCategory = $categoryInfo !== null;
$siteName = $this->context->getConfig()->getString('site.name', 'Misuzu');
$feed = (new Feed)
->setTitle($siteName . ' » ' . ($hasCategory ? $categoryInfo->getName() : 'Featured News'))
->setDescription($hasCategory ? $categoryInfo->getDescription() : 'A live featured news feed.')
->setContentUrl(url_prefix(false) . ($hasCategory ? url('news-category', ['category' => $categoryInfo->getId()]) : url('news-index')))
->setFeedUrl(url_prefix(false) . ($hasCategory ? url("news-category-feed-{$feedMode}", ['category' => $categoryInfo->getId()]) : url("news-feed-{$feedMode}")));
foreach($posts as $post) {
$postInfo = $post['post'];
$userInfo = $post['user'];
$userId = 0;
$userName = 'Author';
if($userInfo !== null) {
$userId = $userInfo->getId();
$userName = $userInfo->getName();
}
$postUrl = url_prefix(false) . url('news-post', ['post' => $postInfo->getId()]);
$commentsUrl = url_prefix(false) . url('news-post-comments', ['post' => $postInfo->getId()]);
$authorUrl = url_prefix(false) . url('user-profile', ['user' => $userId]);
$feedItem = (new FeedItem)
->setTitle($postInfo->getTitle())
->setSummary($postInfo->getFirstParagraph())
->setContent(Parser::instance(Parser::MARKDOWN)->parseText($postInfo->getBody()))
->setCreationDate($postInfo->getCreatedTime())
->setUniqueId($postUrl)
->setContentUrl($postUrl)
->setCommentsUrl($commentsUrl)
->setAuthorName($userName)
->setAuthorUrl($authorUrl);
if(!$feed->hasLastUpdate() || $feed->getLastUpdate() < $feedItem->getCreationDate())
$feed->setLastUpdate($feedItem->getCreationDate());
$feed->addItem($feedItem);
}
return $feed;
}
private function fetchPostInfoForFeed(array $postInfos): array {
$news = $this->context->getNews();
$users = $this->context->getUsers();
$posts = [];
$userInfos = [];
foreach($postInfos as $postInfo) {
$userId = $postInfo->getUserId();
if(array_key_exists($userId, $userInfos)) {
$userInfo = $userInfos[$userId];
} else {
try {
$userInfo = $users->getUser($userId, 'id');
} catch(RuntimeException $ex) {
$userInfo = null;
}
$userInfos[$userId] = $userInfo;
}
$posts[] = [
'post' => $postInfo,
'user' => $userInfo,
];
}
return $posts;
}
private function getFeaturedPostsForFeed(): array {
return $this->fetchPostInfoForFeed(
$this->context->getNews()->getAllPosts(
onlyFeatured: true,
pagination: new Pagination(10)
)
);
}
public function feedIndexAtom($response, $request) {
$response->setContentType('application/atom+xml; charset=utf-8');
return (new AtomFeedSerializer)->serializeFeed(
self::createFeed('atom', null, $this->getFeaturedPostsForFeed())
);
}
public function feedIndexRss($response, $request) {
$response->setContentType('application/rss+xml; charset=utf-8');
return (new RssFeedSerializer)->serializeFeed(
self::createFeed('rss', null, $this->getFeaturedPostsForFeed())
);
}
private function getCategoryPostsForFeed(NewsCategoryInfo $categoryInfo): array {
return $this->fetchPostInfoForFeed(
$this->context->getNews()->getPostsByCategory($categoryInfo, pagination: new Pagination(10))
);
}
public function feedCategoryAtom($response, $request, NewsCategoryInfo $categoryInfo) {
$response->setContentType('application/atom+xml; charset=utf-8');
return (new AtomFeedSerializer)->serializeFeed(
self::createFeed('atom', $categoryInfo, $this->getCategoryPostsForFeed($categoryInfo))
);
}
public function feedCategoryRss($response, $request, NewsCategoryInfo $categoryInfo) {
$response->setContentType('application/rss+xml; charset=utf-8');
return (new RssFeedSerializer)->serializeFeed(
self::createFeed('rss', $categoryInfo, $this->getCategoryPostsForFeed($categoryInfo))
);
}
}