2022-09-13 13:14:49 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu\Http\Handlers;
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
use RuntimeException;
|
2022-09-13 13:14:49 +00:00
|
|
|
use Misuzu\DB;
|
|
|
|
use Misuzu\Pagination;
|
|
|
|
use Misuzu\Template;
|
2023-07-15 17:02:46 +00:00
|
|
|
use Misuzu\Comments\CommentsCategory;
|
2023-07-15 23:58:17 +00:00
|
|
|
use Misuzu\Comments\CommentsEx;
|
2022-09-13 13:14:49 +00:00
|
|
|
use Misuzu\Feeds\Feed;
|
|
|
|
use Misuzu\Feeds\FeedItem;
|
|
|
|
use Misuzu\Feeds\AtomFeedSerializer;
|
|
|
|
use Misuzu\Feeds\RssFeedSerializer;
|
2023-07-15 17:02:46 +00:00
|
|
|
use Misuzu\News\NewsCategoryInfo;
|
2022-09-13 13:14:49 +00:00
|
|
|
use Misuzu\Parsers\Parser;
|
|
|
|
use Misuzu\Users\User;
|
|
|
|
|
|
|
|
final class NewsHandler extends Handler {
|
2023-07-15 17:02:46 +00:00
|
|
|
private function fetchPostInfo(array $postInfos, array $categoryInfos = []): array {
|
|
|
|
$news = $this->context->getNews();
|
2023-07-15 23:58:17 +00:00
|
|
|
$comments = $this->context->getComments();
|
2023-07-15 17:02:46 +00:00
|
|
|
$posts = [];
|
|
|
|
$userInfos = [];
|
|
|
|
|
|
|
|
foreach($postInfos as $postInfo) {
|
|
|
|
$userId = $postInfo->getUserId();
|
|
|
|
$categoryId = $postInfo->getCategoryId();
|
|
|
|
|
|
|
|
if(array_key_exists($userId, $userInfos)) {
|
|
|
|
$userInfo = $userInfos[$userId];
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
$userInfo = User::byId($userId);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2023-07-15 17:02:46 +00:00
|
|
|
$userInfo = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$userInfos[$userId] = $userInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(array_key_exists($categoryId, $categoryInfos))
|
|
|
|
$categoryInfo = $categoryInfos[$categoryId];
|
|
|
|
else
|
|
|
|
$categoryInfos[$categoryId] = $categoryInfo = $news->getCategoryByPost($postInfo);
|
|
|
|
|
2023-07-15 23:58:17 +00:00
|
|
|
$commentsCount = $postInfo->hasCommentsCategoryId()
|
|
|
|
? $comments->countPosts($postInfo->getCommentsCategoryId(), includeReplies: true) : 0;
|
2023-07-15 17:02:46 +00:00
|
|
|
|
|
|
|
$posts[] = [
|
|
|
|
'post' => $postInfo,
|
|
|
|
'category' => $categoryInfo,
|
|
|
|
'user' => $userInfo,
|
|
|
|
'comments_count' => $commentsCount,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $posts;
|
|
|
|
}
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
public function index($response, $request) {
|
2023-07-15 17:02:46 +00:00
|
|
|
$news = $this->context->getNews();
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
$categories = $news->getAllCategories();
|
|
|
|
$pagination = new Pagination($news->countAllPosts(onlyFeatured: true), 5);
|
|
|
|
|
|
|
|
if(!$pagination->hasValidOffset())
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
$postInfos = $news->getAllPosts(onlyFeatured: true, pagination: $pagination);
|
|
|
|
$posts = $this->fetchPostInfo($postInfos);
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setContent(Template::renderRaw('news.index', [
|
2023-07-15 17:02:46 +00:00
|
|
|
'news_categories' => $categories,
|
|
|
|
'news_posts' => $posts,
|
|
|
|
'news_pagination' => $pagination,
|
2022-09-13 13:14:49 +00:00
|
|
|
]));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function viewCategory($response, $request, string $fileName) {
|
2023-07-15 17:02:46 +00:00
|
|
|
$news = $this->context->getNews();
|
|
|
|
|
|
|
|
$categoryId = pathinfo($fileName, PATHINFO_FILENAME);
|
2022-09-13 13:14:49 +00:00
|
|
|
$type = pathinfo($fileName, PATHINFO_EXTENSION);
|
|
|
|
|
|
|
|
try {
|
2023-07-15 17:02:46 +00:00
|
|
|
$categoryInfo = $news->getCategoryById($categoryId);
|
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
}
|
|
|
|
|
|
|
|
if($type === 'atom')
|
|
|
|
return $this->feedCategoryAtom($response, $request, $categoryInfo);
|
|
|
|
elseif($type === 'rss')
|
|
|
|
return $this->feedCategoryRss($response, $request, $categoryInfo);
|
|
|
|
elseif($type !== '')
|
|
|
|
return 404;
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
$pagination = new Pagination($news->countPostsByCategory($categoryInfo), 5);
|
|
|
|
if(!$pagination->hasValidOffset())
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
$postInfos = $news->getPostsByCategory($categoryInfo, pagination: $pagination);
|
|
|
|
$posts = $this->fetchPostInfo($postInfos, [$categoryInfo->getId() => $categoryInfo]);
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setContent(Template::renderRaw('news.category', [
|
2023-07-15 17:02:46 +00:00
|
|
|
'news_category' => $categoryInfo,
|
|
|
|
'news_posts' => $posts,
|
|
|
|
'news_pagination' => $pagination,
|
2022-09-13 13:14:49 +00:00
|
|
|
]));
|
|
|
|
}
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
public function viewPost($response, $request, string $postId) {
|
|
|
|
$news = $this->context->getNews();
|
2023-07-15 23:58:17 +00:00
|
|
|
$comments = $this->context->getComments();
|
2023-07-15 17:02:46 +00:00
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
try {
|
2023-07-15 17:02:46 +00:00
|
|
|
$postInfo = $news->getPostById($postId);
|
|
|
|
} catch(RuntimeException $ex) {
|
2022-09-13 13:14:49 +00:00
|
|
|
return 404;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$postInfo->isPublished() || $postInfo->isDeleted())
|
|
|
|
return 404;
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
$categoryInfo = $news->getCategoryByPost($postInfo);
|
|
|
|
|
2023-07-15 23:58:17 +00:00
|
|
|
$comments = $this->context->getComments();
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
if($postInfo->hasCommentsCategoryId()) {
|
2023-07-15 23:58:17 +00:00
|
|
|
$commentsCategory = $comments->getCategoryById($postInfo->getCommentsCategoryId());
|
2023-07-15 17:02:46 +00:00
|
|
|
} else {
|
2023-07-15 23:58:17 +00:00
|
|
|
$commentsCategory = $comments->ensureCategory($postInfo->getCommentsCategoryName());
|
|
|
|
$news->updatePostCommentCategory($postInfo, $commentsCategory);
|
2023-07-15 17:02:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$userInfo = null;
|
|
|
|
if($postInfo->hasUserId())
|
|
|
|
try {
|
|
|
|
$userInfo = User::byId($postInfo->getUserId());
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {}
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-07-15 23:58:17 +00:00
|
|
|
$comments = new CommentsEx($comments);
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setContent(Template::renderRaw('news.post', [
|
|
|
|
'post_info' => $postInfo,
|
2023-07-15 17:02:46 +00:00
|
|
|
'post_category_info' => $categoryInfo,
|
|
|
|
'post_user_info' => $userInfo,
|
2023-07-15 23:58:17 +00:00
|
|
|
'comments_info' => $comments->getCommentsForLayout($commentsCategory),
|
2022-09-13 13:14:49 +00:00
|
|
|
]));
|
|
|
|
}
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
private function createFeed(string $feedMode, ?NewsCategoryInfo $categoryInfo, array $posts): Feed {
|
|
|
|
$hasCategory = $categoryInfo !== null;
|
2023-07-18 21:48:44 +00:00
|
|
|
$siteName = $this->context->getConfig()->getString('site.name', 'Misuzu');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
$feed = (new Feed)
|
2023-07-18 21:48:44 +00:00
|
|
|
->setTitle($siteName . ' » ' . ($hasCategory ? $categoryInfo->getName() : 'Featured News'))
|
2022-09-13 13:14:49 +00:00
|
|
|
->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) {
|
2023-07-15 17:02:46 +00:00
|
|
|
$postInfo = $post['post'];
|
|
|
|
$userInfo = $post['user'];
|
|
|
|
|
|
|
|
$userId = 0;
|
|
|
|
$userName = 'Author';
|
|
|
|
if($userInfo !== null) {
|
|
|
|
$userId = $userInfo->getId();
|
|
|
|
$userName = $userInfo->getUsername();
|
|
|
|
}
|
|
|
|
|
|
|
|
$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]);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
$feedItem = (new FeedItem)
|
2023-07-15 17:02:46 +00:00
|
|
|
->setTitle($postInfo->getTitle())
|
|
|
|
->setSummary($postInfo->getFirstParagraph())
|
|
|
|
->setContent(Parser::instance(Parser::MARKDOWN)->parseText($postInfo->getBody()))
|
|
|
|
->setCreationDate($postInfo->getCreatedTime())
|
2022-09-13 13:14:49 +00:00
|
|
|
->setUniqueId($postUrl)
|
|
|
|
->setContentUrl($postUrl)
|
|
|
|
->setCommentsUrl($commentsUrl)
|
2023-07-15 17:02:46 +00:00
|
|
|
->setAuthorName($userName)
|
2022-09-13 13:14:49 +00:00
|
|
|
->setAuthorUrl($authorUrl);
|
|
|
|
|
|
|
|
if(!$feed->hasLastUpdate() || $feed->getLastUpdate() < $feedItem->getCreationDate())
|
|
|
|
$feed->setLastUpdate($feedItem->getCreationDate());
|
|
|
|
|
|
|
|
$feed->addItem($feedItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $feed;
|
|
|
|
}
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
private function fetchPostInfoForFeed(array $postInfos): array {
|
|
|
|
$news = $this->context->getNews();
|
|
|
|
$posts = [];
|
|
|
|
$userInfos = [];
|
|
|
|
|
|
|
|
foreach($postInfos as $postInfo) {
|
|
|
|
$userId = $postInfo->getUserId();
|
|
|
|
|
|
|
|
if(array_key_exists($userId, $userInfos)) {
|
|
|
|
$userInfo = $userInfos[$userId];
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
$userInfo = User::byId($userId);
|
2023-07-22 15:02:41 +00:00
|
|
|
} catch(RuntimeException $ex) {
|
2023-07-15 17:02:46 +00:00
|
|
|
$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)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-13 13:14:49 +00:00
|
|
|
public function feedIndexAtom($response, $request) {
|
|
|
|
$response->setContentType('application/atom+xml; charset=utf-8');
|
|
|
|
return (new AtomFeedSerializer)->serializeFeed(
|
2023-07-15 17:02:46 +00:00
|
|
|
self::createFeed('atom', null, $this->getFeaturedPostsForFeed())
|
2022-09-13 13:14:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function feedIndexRss($response, $request) {
|
|
|
|
$response->setContentType('application/rss+xml; charset=utf-8');
|
|
|
|
return (new RssFeedSerializer)->serializeFeed(
|
2023-07-15 17:02:46 +00:00
|
|
|
self::createFeed('rss', null, $this->getFeaturedPostsForFeed())
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getCategoryPostsForFeed(NewsCategoryInfo $categoryInfo): array {
|
|
|
|
return $this->fetchPostInfoForFeed(
|
|
|
|
$this->context->getNews()->getPostsByCategory($categoryInfo, pagination: new Pagination(10))
|
2022-09-13 13:14:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
public function feedCategoryAtom($response, $request, NewsCategoryInfo $categoryInfo) {
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setContentType('application/atom+xml; charset=utf-8');
|
|
|
|
return (new AtomFeedSerializer)->serializeFeed(
|
2023-07-15 17:02:46 +00:00
|
|
|
self::createFeed('atom', $categoryInfo, $this->getCategoryPostsForFeed($categoryInfo))
|
2022-09-13 13:14:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-07-15 17:02:46 +00:00
|
|
|
public function feedCategoryRss($response, $request, NewsCategoryInfo $categoryInfo) {
|
2022-09-13 13:14:49 +00:00
|
|
|
$response->setContentType('application/rss+xml; charset=utf-8');
|
|
|
|
return (new RssFeedSerializer)->serializeFeed(
|
2023-07-15 17:02:46 +00:00
|
|
|
self::createFeed('rss', $categoryInfo, $this->getCategoryPostsForFeed($categoryInfo))
|
2022-09-13 13:14:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|