misuzu/src/MisuzuContext.php

337 lines
13 KiB
PHP

<?php
namespace Misuzu;
use Misuzu\Template;
use Misuzu\Auth\LoginAttempts;
use Misuzu\Auth\RecoveryTokens;
use Misuzu\AuditLog\AuditLog;
use Misuzu\Changelog\Changelog;
use Misuzu\Comments\Comments;
use Misuzu\Config\IConfig;
use Misuzu\Emoticons\Emotes;
use Misuzu\News\News;
use Misuzu\SharpChat\SharpChatRoutes;
use Misuzu\Users\Bans;
use Misuzu\Users\BanInfo;
use Misuzu\Users\ModNotes;
use Misuzu\Users\User;
use Misuzu\Users\Warnings;
use Index\Data\IDbConnection;
use Index\Data\Migration\IDbMigrationRepo;
use Index\Data\Migration\DbMigrationManager;
use Index\Data\Migration\FsDbMigrationRepo;
use Index\Http\HttpFx;
use Index\Http\HttpRequest;
use Index\Routing\Router;
// this class should function as the root for everything going forward
// no more magical static classes that are just kind of assumed to exist
// it currently looks Pretty Messy, but most everything else will be holding instances of other classes
// instances of certain classes should only be made as needed,
// dunno if i want null checks some maybe some kind of init func should be called first like is the case
// with the http shit
class MisuzuContext {
private IDbConnection $dbConn;
private IConfig $config;
private HttpFx $router;
private AuditLog $auditLog;
private Emotes $emotes;
private Changelog $changelog;
private News $news;
private Comments $comments;
private LoginAttempts $loginAttempts;
private RecoveryTokens $recoveryTokens;
private ModNotes $modNotes;
private Bans $bans;
private Warnings $warnings;
public function __construct(IDbConnection $dbConn, IConfig $config) {
$this->dbConn = $dbConn;
$this->config = $config;
$this->auditLog = new AuditLog($this->dbConn);
$this->emotes = new Emotes($this->dbConn);
$this->changelog = new Changelog($this->dbConn);
$this->news = new News($this->dbConn);
$this->comments = new Comments($this->dbConn);
$this->loginAttempts = new LoginAttempts($this->dbConn);
$this->recoveryTokens = new RecoveryTokens($this->dbConn);
$this->modNotes = new ModNotes($this->dbConn);
$this->bans = new Bans($this->dbConn);
$this->warnings = new Warnings($this->dbConn);
}
public function getDbConn(): IDbConnection {
return $this->dbConn;
}
public function getDbQueryCount(): int {
$result = $this->dbConn->query('SHOW SESSION STATUS LIKE "Questions"');
return $result->next() ? $result->getInteger(1) : 0;
}
public function createMigrationManager(): DbMigrationManager {
return new DbMigrationManager($this->dbConn, 'msz_' . DbMigrationManager::DEFAULT_TABLE);
}
public function createMigrationRepo(): IDbMigrationRepo {
return new FsDbMigrationRepo(MSZ_MIGRATIONS);
}
public function getConfig(): IConfig {
return $this->config;
}
public function getRouter(): Router {
return $this->router->getRouter();
}
public function getEmotes(): Emotes {
return $this->emotes;
}
public function getChangelog(): Changelog {
return $this->changelog;
}
public function getNews(): News {
return $this->news;
}
public function getComments(): Comments {
return $this->comments;
}
public function getAuditLog(): AuditLog {
return $this->auditLog;
}
public function getLoginAttempts(): LoginAttempts {
return $this->loginAttempts;
}
public function getRecoveryTokens(): RecoveryTokens {
return $this->recoveryTokens;
}
public function getModNotes(): ModNotes {
return $this->modNotes;
}
public function getBans(): Bans {
return $this->bans;
}
public function getWarnings(): Warnings {
return $this->warnings;
}
private array $activeBansCache = [];
public function tryGetActiveBan(User|string|null $userInfo = null): ?BanInfo {
if($userInfo === null) {
if(User::hasCurrent())
$userInfo = User::getCurrent();
else return null;
}
$userId = (string)$userInfo->getId();
if(array_key_exists($userId, $this->activeBansCache))
return $this->activeBansCache[$userId];
return $this->activeBansCache[$userId] = $this->bans->tryGetActiveBan($userId);
}
public function hasActiveBan(User|string|null $userInfo = null): bool {
return $this->tryGetActiveBan($userInfo) !== null;
}
public function createAuditLog(string $action, array $params = [], User|string|null $userInfo = null): void {
if($userInfo === null && User::hasCurrent())
$userInfo = User::getCurrent();
$this->auditLog->createLog(
$userInfo,
$action,
$params,
$_SERVER['REMOTE_ADDR'] ?? '::1',
$_SERVER['COUNTRY_CODE'] ?? 'XX'
);
}
public function setUpHttp(bool $legacy = false): void {
$this->router = new HttpFx;
$this->router->use('/', function($response) {
$response->setPoweredBy('Misuzu');
});
$this->registerErrorPages();
if($legacy)
$this->registerLegacyRedirects();
else
$this->registerHttpRoutes();
}
public function dispatchHttp(?HttpRequest $request = null): void {
$this->router->dispatch($request);
}
private function registerErrorPages(): void {
$this->router->addErrorHandler(400, function($response) {
$response->setContent(Template::renderRaw('errors.400'));
});
$this->router->addErrorHandler(403, function($response) {
$response->setContent(Template::renderRaw('errors.403'));
});
$this->router->addErrorHandler(404, function($response) {
$response->setContent(Template::renderRaw('errors.404'));
});
$this->router->addErrorHandler(500, function($response) {
$response->setContent(file_get_contents(MSZ_TEMPLATES . '/500.html'));
});
$this->router->addErrorHandler(503, function($response) {
$response->setContent(file_get_contents(MSZ_TEMPLATES . '/503.html'));
});
}
private function registerHttpRoutes(): void {
$mszCompatHandler = fn($className, $method) => fn(...$args) => (new ("\\Misuzu\\Http\\Handlers\\{$className}Handler")($this))->{$method}(...$args);
$this->router->get('/', $mszCompatHandler('Home', 'index'));
$this->router->get('/assets/avatar/:filename', $mszCompatHandler('Assets', 'serveAvatar'));
$this->router->get('/assets/profile-background/:filename', $mszCompatHandler('Assets', 'serveProfileBackground'));
$this->router->get('/info', $mszCompatHandler('Info', 'index'));
$this->router->get('/info/:name', $mszCompatHandler('Info', 'page'));
$this->router->get('/info/:project/:name', $mszCompatHandler('Info', 'page'));
$this->router->get('/changelog', $mszCompatHandler('Changelog', 'index'));
$this->router->get('/changelog.rss', $mszCompatHandler('Changelog', 'feedRss'));
$this->router->get('/changelog.atom', $mszCompatHandler('Changelog', 'feedAtom'));
$this->router->get('/changelog/change/:id', $mszCompatHandler('Changelog', 'change'));
$this->router->get('/news', $mszCompatHandler('News', 'index'));
$this->router->get('/news.rss', $mszCompatHandler('News', 'feedIndexRss'));
$this->router->get('/news.atom', $mszCompatHandler('News', 'feedIndexAtom'));
$this->router->get('/news/:category', $mszCompatHandler('News', 'viewCategory'));
$this->router->get('/news/post/:id', $mszCompatHandler('News', 'viewPost'));
$this->router->get('/forum/mark-as-read', $mszCompatHandler('Forum', 'markAsReadGET'));
$this->router->post('/forum/mark-as-read', $mszCompatHandler('Forum', 'markAsReadPOST'));
new SharpChatRoutes($this->router, $this->config->scopeTo('sockChat'), $this->bans, $this->emotes);
}
private function registerLegacyRedirects(): void {
$this->router->get('/index.php', function($response) {
$response->redirect(url('index'), true);
});
$this->router->get('/info.php', function($response) {
$response->redirect(url('info'), true);
});
$this->router->get('/settings.php', function($response) {
$response->redirect(url('settings-index'), true);
});
$this->router->get('/changelog.php', function($response, $request) {
$changeId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
if($changeId) {
$response->redirect(url('changelog-change', ['change' => $changeId]), true);
return;
}
$response->redirect(url('changelog-index', [
'date' => $request->getParam('d'),
'user' => $request->getParam('u', FILTER_SANITIZE_NUMBER_INT),
]), true);
});
$infoRedirect = function($response, $request, string ...$parts) {
$response->redirect(url('info', ['title' => implode('/', $parts)]), true);
};
$this->router->get('/info.php/:name', $infoRedirect);
$this->router->get('/info.php/:project/:name', $infoRedirect);
$this->router->get('/auth.php', function($response, $request) {
$response->redirect(url([
'logout' => 'auth-logout',
'reset' => 'auth-reset',
'forgot' => 'auth-forgot',
'register' => 'auth-register',
][$request->getParam('m')] ?? 'auth-login'), true);
});
$this->router->get('/news.php', function($response, $request) {
$postId = $request->getParam('n', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('p', FILTER_SANITIZE_NUMBER_INT);
if($postId > 0)
$location = url('news-post', ['post' => $postId]);
else {
$catId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$pageId = $request->getParam('page', FILTER_SANITIZE_NUMBER_INT);
$location = url($catId > 0 ? 'news-category' : 'news-index', ['category' => $catId, 'page' => $pageId]);
}
$response->redirect($location, true);
});
$this->router->get('/news.php/rss', function($response, $request) {
$catId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$location = url($catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss', ['category' => $catId]);
$response->redirect($location, true);
});
$this->router->get('/news.php/atom', function($response, $request) {
$catId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$location = url($catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom', ['category' => $catId]);
$response->redirect($location, true);
});
$this->router->get('/news/index.php', function($response, $request) {
$response->redirect(url('news-index', [
'page' => $request->getParam('page', FILTER_SANITIZE_NUMBER_INT),
]), true);
});
$this->router->get('/news/category.php', function($response, $request) {
$response->redirect(url('news-category', [
'category' => $request->getParam('c', FILTER_SANITIZE_NUMBER_INT),
'page' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT),
]), true);
});
$this->router->get('/news/post.php', function($response, $request) {
$response->redirect(url('news-post', [
'post' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT),
]), true);
});
$this->router->get('/news/feed.php', function() {
return 400;
});
$this->router->get('/news/feed.php/rss', function($response, $request) {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$response->redirect(url(
$catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss',
['category' => $catId]
), true);
});
$this->router->get('/news/feed.php/atom', function($response, $request) {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$response->redirect(url(
$catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom',
['category' => $catId]
), true);
});
$this->router->get('/user-assets.php', function($response, $request) {
return (new \Misuzu\Http\Handlers\AssetsHandler($this))->serveLegacy($response, $request);
});
}
}