<?php namespace Misuzu\Changelog; use ErrorException; use RuntimeException; use Index\Http\{HttpRequest,HttpResponseBuilder}; use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerCommon}; use Index\Syndication\FeedBuilder; use Index\Urls\{UrlFormat,UrlRegistry,UrlSource,UrlSourceCommon}; use Misuzu\{Pagination,SiteInfo,Template}; use Misuzu\Auth\AuthInfo; use Misuzu\Comments\CommentsContext; use Misuzu\Users\UsersContext; final class ChangelogRoutes implements RouteHandler, UrlSource { use RouteHandlerCommon, UrlSourceCommon; public function __construct( private SiteInfo $siteInfo, private UrlRegistry $urls, private ChangelogData $changelog, private UsersContext $usersCtx, private CommentsContext $commentsCtx, private AuthInfo $authInfo, ) {} #[HttpGet('/changelog')] #[UrlFormat('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])] public function getIndex(HttpResponseBuilder $response, HttpRequest $request): int|string { $filterDate = (string)$request->getParam('date'); $filterUser = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT); $filterTags = (string)$request->getParam('tags'); if(empty($filterDate)) $filterDate = null; else try { $dateParts = explode('-', $filterDate, 3); $filterDate = gmmktime(12, 0, 0, (int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[0]); } catch(ErrorException $ex) { return 404; } if(empty($filterUser)) $filterUser = null; else try { $filterUser = $this->usersCtx->getUserInfo($filterUser); } catch(RuntimeException $ex) { return 404; } if(empty($filterTags)) $filterTags = null; else { $filterTags = explode(',', $filterTags); foreach($filterTags as &$tag) $tag = trim($tag); } $count = $this->changelog->countChanges($filterUser, $filterDate, $filterTags); $pagination = Pagination::fromRequest($request, $count, 30, 'p'); if(!$pagination->validOffset) return 404; $changes = []; $changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination); $commentsCategoryName = null; foreach($changeInfos as $changeInfo) { $userInfo = $changeInfo->userId !== null ? $this->usersCtx->getUserInfo($changeInfo->userId) : null; if($commentsCategoryName === null) $commentsCategoryName = $changeInfo->commentsCategoryName; $changes[] = [ 'change' => $changeInfo, 'user' => $userInfo, 'user_colour' => $this->usersCtx->getUserColour($userInfo), ]; } if(empty($changes)) return 404; if(empty($filterDate)) $commentsCategoryName = null; elseif($commentsCategoryName) // should this be run here? $this->commentsCtx->categories->ensureCategoryExists($commentsCategoryName); return Template::renderRaw('changelog.index', [ 'changelog_infos' => $changes, 'changelog_date' => $filterDate, 'changelog_user' => $filterUser, 'changelog_tags' => $filterTags, 'changelog_pagination' => $pagination, 'comments_category_name' => $commentsCategoryName, ]); } #[HttpGet('/changelog/change/([0-9]+)')] #[UrlFormat('changelog-change', '/changelog/change/<change>')] #[UrlFormat('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')] public function getChange(HttpResponseBuilder $response, HttpRequest $request, string $changeId): int|string { try { $changeInfo = $this->changelog->getChange($changeId); } catch(RuntimeException $ex) { return 404; } $tagInfos = $this->changelog->getTags(changeInfo: $changeInfo); $userInfo = $changeInfo->userId !== null ? $this->usersCtx->getUserInfo($changeInfo->userId) : null; // should this be run here? $this->commentsCtx->categories->ensureCategoryExists($changeInfo->commentsCategoryName); return Template::renderRaw('changelog.change', [ 'change_info' => $changeInfo, 'change_tags' => $tagInfos, 'change_user_info' => $userInfo, 'change_user_colour' => $this->usersCtx->getUserColour($userInfo), ]); } #[HttpGet('/changelog.(xml|rss|atom)')] #[UrlFormat('changelog-feed', '/changelog.xml')] public function getFeed(HttpResponseBuilder $response): string { $response->setContentType('application/rss+xml; charset=utf-8'); $siteName = $this->siteInfo->name; $siteUrl = $this->siteInfo->url; $changes = $this->changelog->getChanges(pagination: new Pagination(10)); $feed = new FeedBuilder; $feed->title = sprintf('%s ยป Changelog', $siteName); $feed->description = sprintf('Live feed of changes to %s.', $siteName); $feed->contentUrl = $siteUrl . $this->urls->format('changelog-index'); $feed->feedUrl = $siteUrl . $this->urls->format('changelog-feed'); foreach($changes as $change) $feed->createEntry(function($item) use ($change, $siteUrl) { $item->title = sprintf('%s: %s', $change->actionText, $change->summary); $item->createdAt = $change->createdTime; $item->contentUrl = $siteUrl . $this->urls->format('changelog-change', ['change' => $change->id]); $item->commentsUrl = $siteUrl . $this->urls->format('changelog-change-comments', ['change' => $change->id]); }); return $feed->toXmlString(); } }