misuzu/src/Satori/SatoriRoutes.php

165 lines
6.1 KiB
PHP

<?php
namespace Misuzu\Satori;
use RuntimeException;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Http\HttpFx;
use Index\Routing\IRouter;
use Misuzu\Pagination;
use Misuzu\Config\IConfig;
use Misuzu\Profile\ProfileFields;
use Misuzu\Users\Users;
final class SatoriRoutes {
private IDbConnection $dbConn;
private IConfig $config;
private Users $users;
private ProfileFields $profileFields;
public function __construct(
IDbConnection $dbConn,
IConfig $config,
IRouter $router,
Users $users,
ProfileFields $profileFields
) {
$this->dbConn = $dbConn;
$this->config = $config;
$this->users = $users;
$this->profileFields = $profileFields;
// Simplify default error pages
if($router instanceof HttpFx)
$router->use('/_satori', function() use($router) {
$router->addErrorHandler(400, function($response) {
$response->setContent('HTTP 400');
});
$router->addErrorHandler(403, function($response) {
$response->setContent('HTTP 403');
});
$router->addErrorHandler(404, function($response) {
$response->setContent('HTTP 404');
});
$router->addErrorHandler(500, function($response) {
$response->setContent('HTTP 500');
});
$router->addErrorHandler(503, function($response) {
$response->setContent('HTTP 503');
});
});
$router->use('/_satori', $this->verifyRequest(...));
$router->get('/_satori/get-profile-field', $this->getProfileField(...));
$router->get('/_satori/get-recent-forum-posts', $this->getRecentForumPosts(...));
$router->get('/_satori/get-recent-registrations', $this->getRecentRegistrations(...));
}
public function verifyRequest($response, $request) {
$secretKey = $this->config->getString('secret');
if(!empty($secretKey)) {
$userTime = (int)$request->getHeaderLine('X-Satori-Time');
$userHash = base64_decode((string)$request->getHeaderLine('X-Satori-Hash'));
$currentTime = time();
if(empty($userHash) || $userTime < $currentTime - 60 || $userTime > $currentTime + 60)
return 403;
$verifyText = (string)$userTime . '#' . $request->getPath() . '?' . $request->getParamString();
$verifyHash = hash_hmac('sha256', $verifyText, $secretKey, true);
if(!hash_equals($verifyHash, $userHash))
return 403;
}
}
public function getProfileField($response, $request): array {
$userId = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
$fieldId = (string)$request->getParam('field', FILTER_SANITIZE_NUMBER_INT);
try {
$fieldValue = $this->profileFields->getFieldValue($fieldId, $userId);
} catch(RuntimeException $ex) {
return ['error' => 105];
}
return [
'field_value' => $fieldValue->getValue(),
];
}
public function getRecentForumPosts($response, $request): array {
$categoryIds = $this->config->getArray('forum.categories');
if(empty($categoryIds))
return [];
$batchSize = $this->config->getInteger('forum.batch', 6);
$backlogDays = $this->config->getInteger('forum.backlog', 7);
$startId = (string)$request->getParam('start', FILTER_SANITIZE_NUMBER_INT);
$args = 0;
$stmt = $this->dbConn->prepare(sprintf(
'SELECT fp.post_id, ft.topic_id, ft.topic_title, fc.forum_id, fc.forum_name, u.user_id, u.username,'
. ' COALESCE(u.user_colour, r.role_colour), (SELECT MIN(post_id) = fp.post_id FROM msz_forum_posts WHERE topic_id = fp.topic_id)'
. ' FROM msz_forum_posts AS fp'
. ' LEFT JOIN msz_users AS u ON u.user_id = fp.user_id'
. ' LEFT JOIN msz_roles AS r ON r.role_id = u.display_role'
. ' LEFT JOIN msz_forum_topics AS ft ON ft.topic_id = fp.topic_id'
. ' LEFT JOIN msz_forum_categories AS fc ON fc.forum_id = fp.forum_id'
. ' WHERE post_id > ? AND post_deleted IS NULL AND post_created >= NOW() - INTERVAL ? DAY'
. ' AND fp.forum_id IN (%s)'
. ' ORDER BY post_id LIMIT ?',
DbTools::prepareListString($categoryIds)
));
$stmt->addParameter(++$args, $startId);
$stmt->addParameter(++$args, $backlogDays);
foreach($categoryIds as $categoryId)
$stmt->addParameter(++$args, $categoryId);
$stmt->addParameter(++$args, $batchSize);
$stmt->execute();
$posts = [];
$result = $stmt->getResult();
while($result->next())
$posts[] = [
'post_id' => $result->getInteger(0),
'topic_id' => $result->getInteger(1),
'topic_title' => $result->getString(2),
'forum_id' => $result->getInteger(3),
'forum_name' => $result->getString(4),
'user_id' => $result->getInteger(5),
'username' => $result->getString(6),
'user_colour' => $result->getInteger(7),
'is_opening_post' => $result->getInteger(8),
];
return $posts;
}
public function getRecentRegistrations($response, $request) {
$batchSize = $this->config->getInteger('users.batch', 10);
$backlogDays = $this->config->getInteger('users.backlog', 7);
$startId = (string)$request->getParam('start', FILTER_SANITIZE_NUMBER_INT);
$userInfos = $this->users->getUsers(
after: $startId,
newerThanDays: $backlogDays,
orderBy: 'id',
pagination: new Pagination($batchSize),
deleted: false
);
$users = [];
foreach($userInfos as $userInfo)
$users[] = [
'user_id' => (int)$userInfo->getId(),
'username' => $userInfo->getName(),
];
return $users;
}
}