From bac889787afc9870519a495346c73dd1a9d120d9 Mon Sep 17 00:00:00 2001 From: flashwave <me@flash.moe> Date: Sun, 9 Feb 2025 17:39:48 +0000 Subject: [PATCH] Moved database methods into own context class. --- misuzu.php | 14 +------- public-legacy/auth/password.php | 2 ++ public-legacy/forum/posting.php | 6 ++-- public-legacy/manage/users/user.php | 1 + public-legacy/settings/data.php | 2 +- src/DatabaseContext.php | 46 ++++++++++++++++++++++++ src/MisuzuContext.php | 35 ++++++++---------- src/TemplatingExtension.php | 2 +- src/Users/Assets/UserAvatarAsset.php | 8 ++--- src/Users/Assets/UserBackgroundAsset.php | 12 +++---- src/Users/UserNameHistoryInfo.php | 4 +-- tools/cron | 16 ++++----- tools/migrate | 4 +-- tools/new-migration | 4 +-- 14 files changed, 94 insertions(+), 62 deletions(-) create mode 100644 src/DatabaseContext.php diff --git a/misuzu.php b/misuzu.php index 73b4532b..d6e42fa6 100644 --- a/misuzu.php +++ b/misuzu.php @@ -1,8 +1,6 @@ <?php namespace Misuzu; -use Index\Db\DbBackends; -use Index\Config\Db\DbConfig; use Index\Config\Fs\FsConfig; define('MSZ_STARTUP', microtime(true)); @@ -37,14 +35,4 @@ if($env->hasValues('sentry:dsn')) }); })($env->scopeTo('sentry')); -$db = DbBackends::create($env->getString('database:dsn', 'null:')); -$db->execute(<<<SQL - SET SESSION time_zone = '+00:00', - sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; -SQL); - -$cfg = new DbConfig($db, 'msz_config'); - -Mailer::init($cfg->scopeTo('mail')); - -$msz = new MisuzuContext($db, $cfg, $env); +$msz = new MisuzuContext($env); diff --git a/public-legacy/auth/password.php b/public-legacy/auth/password.php index 2c3936ff..a59b8f7e 100644 --- a/public-legacy/auth/password.php +++ b/public-legacy/auth/password.php @@ -114,6 +114,8 @@ while($canResetPassword) { } catch(RuntimeException $ex) { $tokenInfo = $msz->authCtx->recoveryTokens->createToken($forgotUser, $ipAddress); + $msz->initMailer(); + $recoveryMessage = Mailer::template('password-recovery', [ 'username' => $forgotUser->name, 'token' => $tokenInfo->code, diff --git a/public-legacy/forum/posting.php b/public-legacy/forum/posting.php index 58f24a73..531bb8cc 100644 --- a/public-legacy/forum/posting.php +++ b/public-legacy/forum/posting.php @@ -153,7 +153,7 @@ if(!empty($_POST)) { $isEditingTopic = empty($topicInfo) || ($mode === 'edit' && $originalPostInfo->id == $postInfo->id); if($mode === 'create') { - $postTimeout = $cfg->getInteger('forum.posting.timeout', 5); + $postTimeout = $msz->config->getInteger('forum.posting.timeout', 5); if($postTimeout > 0) { $postTimeoutThreshold = new CarbonImmutable(sprintf('-%d seconds', $postTimeout)); $lastPostCreatedAt = $msz->forumCtx->posts->getUserLastPostCreatedAt($currentUser); @@ -173,7 +173,7 @@ if(!empty($_POST)) { $originalTopicType = $topicInfo?->typeString ?? 'discussion'; // @phpstan-ignore-line: this also $topicTypeChanged = $topicType !== null && $topicType !== $originalTopicType; - $topicTitleLengths = $cfg->getValues([ + $topicTitleLengths = $msz->config->getValues([ ['forum.topic.minLength:i', 3], ['forum.topic.maxLength:i', 100], ]); @@ -191,7 +191,7 @@ if(!empty($_POST)) { } } - $postTextLengths = $cfg->getValues([ + $postTextLengths = $msz->config->getValues([ ['forum.post.minLength:i', 1], ['forum.post.maxLength:i', 60000], ]); diff --git a/public-legacy/manage/users/user.php b/public-legacy/manage/users/user.php index 3e09b65d..992d9de2 100644 --- a/public-legacy/manage/users/user.php +++ b/public-legacy/manage/users/user.php @@ -81,6 +81,7 @@ if(CSRF::validateRequest() && $canEdit) { } elseif(!is_string($_POST['send_test_email']) || $_POST['send_test_email'] !== 'yes_send_it') { $notices[] = 'Invalid request thing shut the fuck up.'; } else { + $msz->initMailer(); $testMail = Mailer::sendMessage( [$userInfo->emailAddress => $userInfo->name], 'Flashii Test E-mail', diff --git a/public-legacy/settings/data.php b/public-legacy/settings/data.php index 50f7efc0..f338ed23 100644 --- a/public-legacy/settings/data.php +++ b/public-legacy/settings/data.php @@ -11,7 +11,7 @@ if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext)) if(!$msz->authInfo->loggedIn) Template::throwError(401); -$dbConn = $msz->dbConn; +$dbConn = $msz->dbCtx->conn; /** @param string[] $fieldInfos */ function db_to_zip( diff --git a/src/DatabaseContext.php b/src/DatabaseContext.php new file mode 100644 index 00000000..805343bb --- /dev/null +++ b/src/DatabaseContext.php @@ -0,0 +1,46 @@ +<?php +namespace Misuzu; + +use Index\Config\Config; +use Index\Db\{DbBackends,DbConnection}; +use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo}; +use Index\Http\Routing\{HttpMiddleware,RouteHandler,RouteHandlerCommon}; + +class DatabaseContext implements RouteHandler { + use RouteHandlerCommon; + + public private(set) DbConnection $conn; + + public function __construct(Config $config) { + $this->conn = DbBackends::create($config->getString('dsn', 'null:')); + $this->conn->execute(<<<SQL + SET SESSION + time_zone = '+00:00', + sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; + SQL); + } + + public function getQueryCount(): int { + $result = $this->conn->query("SHOW SESSION STATUS LIKE 'Questions'"); + return $result->next() ? $result->getInteger(1) : 0; + } + + public function createMigrationManager(): DbMigrationManager { + return new DbMigrationManager($this->conn, sprintf('msz_%s', DbMigrationManager::DEFAULT_TABLE)); + } + + public function createMigrationRepo(): DbMigrationRepo { + return new FsDbMigrationRepo(MSZ_MIGRATIONS); + } + + public function getMigrateLockPath(): string { + return sys_get_temp_dir() . '/misuzu-migration-' . hash('sha256', MSZ_ROOT) . '.lock'; + } + + /** @return void|int */ + #[HttpMiddleware('/')] + public function middleware() { + if(is_file($this->getMigrateLockPath())) + return 503; + } +} diff --git a/src/MisuzuContext.php b/src/MisuzuContext.php index 3389f773..b568d9ff 100644 --- a/src/MisuzuContext.php +++ b/src/MisuzuContext.php @@ -3,6 +3,7 @@ namespace Misuzu; use Index\Dependencies; use Index\Config\Config; +use Index\Config\Db\DbConfig; use Index\Db\DbConnection; use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo}; use Index\Http\HttpRequest; @@ -16,6 +17,7 @@ use RPCii\Server\{HttpRpcServer,RpcServer}; class MisuzuContext { public private(set) Dependencies $deps; + public private(set) Config $config; public private(set) TplEnvironment $templating; public private(set) AuditLog\AuditLogData $auditLog; @@ -26,6 +28,7 @@ class MisuzuContext { public private(set) News\NewsData $news; public private(set) Comments\CommentsData $comments; + public private(set) DatabaseContext $dbCtx; public private(set) Apps\AppsContext $appsCtx; public private(set) Auth\AuthContext $authCtx; public private(set) Forum\ForumContext $forumCtx; @@ -43,28 +46,29 @@ class MisuzuContext { public private(set) UrlRegistry $urls; public function __construct( - public private(set) DbConnection $dbConn, - public private(set) Config $config, public private(set) Config $env ) { $this->deps = new Dependencies; $this->deps->register($this->deps); - $this->deps->register($this->dbConn); - $this->deps->register($this->config); $this->deps->register($this->env); - $this->deps->register($this->perms = new Perms\PermissionsData($dbConn)); + $this->deps->register($this->dbCtx = new DatabaseContext($this->env->scopeTo('database'))); + $this->deps->register($this->dbCtx->conn); + + $this->deps->register($this->config = $this->deps->constructLazy(DbConfig::class, tableName: 'msz_config')); + + $this->deps->register($this->perms = $this->deps->constructLazy(Perms\PermissionsData::class)); $this->deps->register($this->authInfo = $this->deps->constructLazy(Auth\AuthInfo::class)); - $this->deps->register($this->siteInfo = $this->deps->constructLazy(SiteInfo::class, config: $config->scopeTo('site'))); + $this->deps->register($this->siteInfo = $this->deps->constructLazy(SiteInfo::class, config: $this->config->scopeTo('site'))); $this->deps->register($this->appsCtx = $this->deps->constructLazy(Apps\AppsContext::class)); - $this->deps->register($this->authCtx = $this->deps->constructLazy(Auth\AuthContext::class, config: $config->scopeTo('auth'))); + $this->deps->register($this->authCtx = $this->deps->constructLazy(Auth\AuthContext::class, config: $this->config->scopeTo('auth'))); $this->deps->register($this->forumCtx = $this->deps->constructLazy(Forum\ForumContext::class)); $this->deps->register($this->messagesCtx = $this->deps->constructLazy(Messages\MessagesContext::class)); - $this->deps->register($this->oauth2Ctx = $this->deps->constructLazy(OAuth2\OAuth2Context::class, config: $config->scopeTo('oauth2'))); + $this->deps->register($this->oauth2Ctx = $this->deps->constructLazy(OAuth2\OAuth2Context::class, config: $this->config->scopeTo('oauth2'))); $this->deps->register($this->profileCtx = $this->deps->constructLazy(Profile\ProfileContext::class)); $this->deps->register($this->usersCtx = $this->deps->constructLazy(Users\UsersContext::class)); - $this->deps->register($this->redirectsCtx = $this->deps->constructLazy(Redirects\RedirectsContext::class, config: $config->scopeTo('redirects'))); + $this->deps->register($this->redirectsCtx = $this->deps->constructLazy(Redirects\RedirectsContext::class, config: $this->config->scopeTo('redirects'))); $this->deps->register($this->auditLog = $this->deps->constructLazy(AuditLog\AuditLogData::class)); $this->deps->register($this->changelog = $this->deps->constructLazy(Changelog\ChangelogData::class)); @@ -74,17 +78,8 @@ class MisuzuContext { $this->deps->register($this->news = $this->deps->constructLazy(News\NewsData::class)); } - 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(): DbMigrationRepo { - return new FsDbMigrationRepo(MSZ_MIGRATIONS); + public function initMailer(): void { + Mailer::init($this->config->scopeTo('mail')); } /** @param mixed[] $params */ diff --git a/src/TemplatingExtension.php b/src/TemplatingExtension.php index f4c91de5..d136773b 100644 --- a/src/TemplatingExtension.php +++ b/src/TemplatingExtension.php @@ -38,7 +38,7 @@ final class TemplatingExtension extends AbstractExtension { new TwigFunction('git_tag', GitInfo::tag(...)), new TwigFunction('git_branch', GitInfo::branch(...)), new TwigFunction('startup_time', fn(float $time = MSZ_STARTUP) => microtime(true) - $time), - new TwigFunction('sql_query_count', $this->ctx->getDbQueryCount(...)), + new TwigFunction('sql_query_count', $this->ctx->dbCtx->getQueryCount(...)), new TwigFunction('msz_header_menu', $this->getHeaderMenu(...)), new TwigFunction('msz_user_menu', $this->getUserMenu(...)), new TwigFunction('msz_manage_menu', $this->getManageMenu(...)), diff --git a/src/Users/Assets/UserAvatarAsset.php b/src/Users/Assets/UserAvatarAsset.php index d47cd816..993b57ae 100644 --- a/src/Users/Assets/UserAvatarAsset.php +++ b/src/Users/Assets/UserAvatarAsset.php @@ -17,15 +17,15 @@ class UserAvatarAsset extends UserImageAsset implements UserAssetScalableInterfa private const MAX_BYTES = 1000000; public function getMaxWidth(): int { - global $cfg; - return $cfg->getInteger('avatar.max_res', self::MAX_RES); + global $msz; + return $msz->config->getInteger('avatar.max_res', self::MAX_RES); } public function getMaxHeight(): int { return $this->getMaxWidth(); } public function getMaxBytes(): int { - global $cfg; - return $cfg->getInteger('avatar.max_size', self::MAX_BYTES); + global $msz; + return $msz->config->getInteger('avatar.max_size', self::MAX_BYTES); } public static function clampDimensions(int $dimensions): int { diff --git a/src/Users/Assets/UserBackgroundAsset.php b/src/Users/Assets/UserBackgroundAsset.php index 055e960a..432d3d39 100644 --- a/src/Users/Assets/UserBackgroundAsset.php +++ b/src/Users/Assets/UserBackgroundAsset.php @@ -12,16 +12,16 @@ class UserBackgroundAsset extends UserImageAsset { private const MAX_BYTES = 1500000; public function getMaxWidth(): int { - global $cfg; - return $cfg->getInteger('background.max_width', self::MAX_WIDTH); + global $msz; + return $msz->config->getInteger('background.max_width', self::MAX_WIDTH); } public function getMaxHeight(): int { - global $cfg; - return $cfg->getInteger('background.max_height', self::MAX_HEIGHT); + global $msz; + return $msz->config->getInteger('background.max_height', self::MAX_HEIGHT); } public function getMaxBytes(): int { - global $cfg; - return $cfg->getInteger('background.max_size', self::MAX_BYTES); + global $msz; + return $msz->config->getInteger('background.max_size', self::MAX_BYTES); } public function getFileName(): string { diff --git a/src/Users/UserNameHistoryInfo.php b/src/Users/UserNameHistoryInfo.php index 4fea1c75..93f6fe58 100644 --- a/src/Users/UserNameHistoryInfo.php +++ b/src/Users/UserNameHistoryInfo.php @@ -14,8 +14,8 @@ class UserNameHistoryInfo { public private(set) int $createdTime ) {} - public static function fromResult(DbResult $result): UserPasswordInfo { - return new UserPasswordInfo( + public static function fromResult(DbResult $result): UserNameHistoryInfo { + return new UserNameHistoryInfo( id: $result->getString(0), userId: $result->getString(1), nameBefore: $result->getString(2), diff --git a/tools/cron b/tools/cron index 0d28187f..1b542358 100755 --- a/tools/cron +++ b/tools/cron @@ -147,7 +147,7 @@ msz_sched_task_func('Resync statistics counters.', true, function() use ($msz) { ]; foreach($stats as $name => $query) { - $result = $msz->dbConn->query($query); + $result = $msz->dbCtx->conn->query($query); $msz->counters->set($name, $result->next() ? $result->getInteger(0) : 0); } }); @@ -166,7 +166,7 @@ msz_sched_task_func('Omega disliking comments...', true, function() use ($msz) { if(!is_array($commentIds)) return; - $stmt = $msz->dbConn->prepare('REPLACE INTO msz_comments_votes (comment_id, user_id, comment_vote) SELECT ?, user_id, -1 FROM msz_users'); + $stmt = $msz->dbCtx->conn->prepare('REPLACE INTO msz_comments_votes (comment_id, user_id, comment_vote) SELECT ?, user_id, -1 FROM msz_users'); foreach($commentIds as $commentId) { $stmt->addParameter(1, $commentId); $stmt->execute(); @@ -178,9 +178,9 @@ msz_sched_task_func('Announcing random topics...', true, function() use ($msz) { if(!is_array($categoryIds)) return; - $stmtRevert = $msz->dbConn->prepare('UPDATE msz_forum_topics SET topic_type = 0 WHERE forum_id = ? AND topic_type = 2'); - $stmtRandom = $msz->dbConn->prepare('SELECT topic_id FROM msz_forum_topics WHERE forum_id = ? AND topic_deleted IS NULL ORDER BY RAND() LIMIT 1'); - $stmtAnnounce = $msz->dbConn->prepare('UPDATE msz_forum_topics SET topic_type = 2 WHERE topic_id = ?'); + $stmtRevert = $msz->dbCtx->conn->prepare('UPDATE msz_forum_topics SET topic_type = 0 WHERE forum_id = ? AND topic_type = 2'); + $stmtRandom = $msz->dbCtx->conn->prepare('SELECT topic_id FROM msz_forum_topics WHERE forum_id = ? AND topic_deleted IS NULL ORDER BY RAND() LIMIT 1'); + $stmtAnnounce = $msz->dbCtx->conn->prepare('UPDATE msz_forum_topics SET topic_type = 2 WHERE topic_id = ?'); foreach($categoryIds as $categoryId) { $stmtRevert->addParameter(1, $categoryId); $stmtRevert->execute(); @@ -201,8 +201,8 @@ msz_sched_task_func('Changing category icons...', false, function() use ($msz) { if(!is_array($categoryIds)) return; - $stmtIcon = $msz->dbConn->prepare('UPDATE msz_forum_categories SET forum_icon = COALESCE(?, forum_icon), forum_name = COALESCE(?, forum_name), forum_colour = ((ROUND(RAND() * 255) << 16) | (ROUND(RAND() * 255) << 8) | ROUND(RAND() * 255)) WHERE forum_id = ?'); - $stmtUnlock = $msz->dbConn->prepare('UPDATE msz_forum_topics SET topic_locked = IF(?, NULL, COALESCE(topic_locked, NOW())) WHERE topic_id = ?'); + $stmtIcon = $msz->dbCtx->conn->prepare('UPDATE msz_forum_categories SET forum_icon = COALESCE(?, forum_icon), forum_name = COALESCE(?, forum_name), forum_colour = ((ROUND(RAND() * 255) << 16) | (ROUND(RAND() * 255) << 8) | ROUND(RAND() * 255)) WHERE forum_id = ?'); + $stmtUnlock = $msz->dbCtx->conn->prepare('UPDATE msz_forum_topics SET topic_locked = IF(?, NULL, COALESCE(topic_locked, NOW())) WHERE topic_id = ?'); foreach($categoryIds as $categoryId) { $scoped = $msz->config->scopeTo(sprintf('forum.rngicon.fc%d', $categoryId)); @@ -247,7 +247,7 @@ foreach($schedTasks as $task) { try { switch($task->type) { case 'sql': - $affected = $msz->dbConn->execute($task->command); + $affected = $msz->dbCtx->conn->execute($task->command); echo $affected . ' rows affected. ' . PHP_EOL; break; diff --git a/tools/migrate b/tools/migrate index 29e1d2b9..73be4e08 100755 --- a/tools/migrate +++ b/tools/migrate @@ -9,13 +9,13 @@ try { chmod(MSZ_ROOT . '/.migrating', 0777); echo 'Creating migration manager...' . PHP_EOL; - $manager = $msz->createMigrationManager(); + $manager = $msz->dbCtx->createMigrationManager(); echo 'Preparing to run migrations...' . PHP_EOL; $manager->init(); echo 'Creating migration repository...' . PHP_EOL; - $repo = $msz->createMigrationRepo(); + $repo = $msz->dbCtx->createMigrationRepo(); echo 'Running migrations...' . PHP_EOL; $completed = $manager->processMigrations($repo); diff --git a/tools/new-migration b/tools/new-migration index 8b0c47fb..b242e052 100755 --- a/tools/new-migration +++ b/tools/new-migration @@ -4,14 +4,14 @@ use Index\Db\Migration\FsDbMigrationRepo; require_once __DIR__ . '/../misuzu.php'; -$repo = $msz->createMigrationRepo(); +$repo = $msz->dbCtx->createMigrationRepo(); if(!($repo instanceof FsDbMigrationRepo)) { echo 'Migration repository type does not support creation of templates.' . PHP_EOL; return; } $baseName = implode(' ', array_slice($argv, 1)); -$manager = $msz->createMigrationManager(); +$manager = $msz->dbCtx->createMigrationManager(); try { $names = $manager->createNames($baseName);