Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
flash | 44a4bb6e6f | ||
flash | ec00cfa176 | ||
flash | 1d295df8da | ||
flash | 6a88ed8b11 | ||
flash | 36bcf1ab1d | ||
flash | 5d3e1d4960 | ||
flash | 9bb943bacf | ||
flash | 107d16cf46 | ||
flash | 0afc5186a7 | ||
flash | 0300bae994 | ||
flash | cb0c64f8ed | ||
flash | 89ef9d9ad1 | ||
flash | c02d922dc6 | ||
flash | 80cd6222c4 | ||
flash | 344a3c9160 | ||
flash | df5dbdf3ad | ||
flash | c0caceed7b | ||
flash | be54ce2c22 | ||
flash | 070dc5e782 | ||
flash | b89621cb1a | ||
flash | 760cca0e5d |
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2017-2023, flashwave <me@flash.moe>
|
Copyright (c) 2017-2024, flashwave <me@flash.moe>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -49,7 +49,6 @@ const MszForumEditor = function(form) {
|
||||||
const uploadTask = eepromClient.create(file);
|
const uploadTask = eepromClient.create(file);
|
||||||
|
|
||||||
uploadTask.onProgress(prog => {
|
uploadTask.onProgress(prog => {
|
||||||
const progress = `}%`;
|
|
||||||
uploadElemProgressBarValue.style.width = `${Math.ceil(prog.progress * 100)}%`;
|
uploadElemProgressBarValue.style.width = `${Math.ceil(prog.progress * 100)}%`;
|
||||||
uploadElemProgressText.textContent = `${prog.progress.toLocaleString(undefined, { style: 'percent' })} (${prog.total - prog.loaded} bytes remaining)`;
|
uploadElemProgressText.textContent = `${prog.progress.toLocaleString(undefined, { style: 'percent' })} (${prog.total - prog.loaded} bytes remaining)`;
|
||||||
});
|
});
|
||||||
|
|
369
composer.lock
generated
369
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\Migration\IDbMigration;
|
||||||
|
|
||||||
|
final class BaseSixtyFourEncodePmsInDb_20240602_194809 implements IDbMigration {
|
||||||
|
public function migrate(IDbConnection $conn): void {
|
||||||
|
$conn->execute('UPDATE msz_messages SET msg_title = TO_BASE64(msg_title), msg_body = TO_BASE64(msg_body)');
|
||||||
|
$conn->execute('
|
||||||
|
ALTER TABLE `msz_messages`
|
||||||
|
CHANGE COLUMN `msg_title` `msg_title` TINYBLOB NOT NULL AFTER `msg_reply_to`,
|
||||||
|
CHANGE COLUMN `msg_body` `msg_body` BLOB NOT NULL AFTER `msg_title`;
|
||||||
|
');
|
||||||
|
}
|
||||||
|
}
|
593
package-lock.json
generated
593
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@swc/core": "^1.3.69",
|
"@swc/core": "^1.5.24",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.19",
|
||||||
"cssnano": "^6.0.1",
|
"cssnano": "^6.1.2",
|
||||||
"postcss": "^8.4.26"
|
"postcss": "^8.4.38"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ $perms = $perms->checkMany([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Template::render('forum.forum', [
|
Template::render('forum.forum', [
|
||||||
'forum_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo),
|
'forum_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($categoryInfo)),
|
||||||
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
|
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
|
||||||
'forum_info' => $categoryInfo,
|
'forum_info' => $categoryInfo,
|
||||||
'forum_children' => $children,
|
'forum_children' => $children,
|
||||||
|
|
|
@ -296,7 +296,7 @@ try {
|
||||||
}
|
}
|
||||||
|
|
||||||
Template::render('forum.posting', [
|
Template::render('forum.posting', [
|
||||||
'posting_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo),
|
'posting_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($categoryInfo)),
|
||||||
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
|
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
|
||||||
'posting_user' => $currentUser,
|
'posting_user' => $currentUser,
|
||||||
'posting_user_colour' => $usersCtx->getUserColour($currentUser),
|
'posting_user_colour' => $usersCtx->getUserColour($currentUser),
|
||||||
|
|
|
@ -291,7 +291,11 @@ $postInfos = $forumPosts->getPosts(
|
||||||
if(empty($postInfos))
|
if(empty($postInfos))
|
||||||
Template::throwError(404);
|
Template::throwError(404);
|
||||||
|
|
||||||
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
|
try {
|
||||||
|
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
|
||||||
|
} catch(RuntimeException $ex) {
|
||||||
|
Template::throwError(404);
|
||||||
|
}
|
||||||
|
|
||||||
$posts = [];
|
$posts = [];
|
||||||
|
|
||||||
|
@ -326,7 +330,7 @@ $perms = $perms->checkMany([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Template::render('forum.topic', [
|
Template::render('forum.topic', [
|
||||||
'topic_breadcrumbs' => $forumCategories->getCategoryAncestry($topicInfo),
|
'topic_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($topicInfo)),
|
||||||
'global_accent_colour' => $forumCategories->getCategoryColour($topicInfo),
|
'global_accent_colour' => $forumCategories->getCategoryColour($topicInfo),
|
||||||
'topic_info' => $topicInfo,
|
'topic_info' => $topicInfo,
|
||||||
'category_info' => $categoryInfo,
|
'category_info' => $categoryInfo,
|
||||||
|
|
|
@ -18,7 +18,7 @@ else
|
||||||
try {
|
try {
|
||||||
$isNew = false;
|
$isNew = false;
|
||||||
$emoteInfo = $emotes->getEmote($emoteId);
|
$emoteInfo = $emotes->getEmote($emoteId);
|
||||||
$emoteStrings = $emotes->getEmoteStrings($emoteInfo);
|
$emoteStrings = iterator_to_array($emotes->getEmoteStrings($emoteInfo));
|
||||||
} catch(RuntimeException $ex) {
|
} catch(RuntimeException $ex) {
|
||||||
Template::throwError(404);
|
Template::throwError(404);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ $pagination = new Pagination($auditLog->countLogs(), 50);
|
||||||
if(!$pagination->hasValidOffset())
|
if(!$pagination->hasValidOffset())
|
||||||
Template::throwError(404);
|
Template::throwError(404);
|
||||||
|
|
||||||
$logs = $auditLog->getLogs(pagination: $pagination);
|
$logs = iterator_to_array($auditLog->getLogs(pagination: $pagination));
|
||||||
$userInfos = [];
|
$userInfos = [];
|
||||||
$userColours = [];
|
$userColours = [];
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ if(CSRF::validateRequest() && $canEdit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$existingRoles = [];
|
$existingRoles = [];
|
||||||
foreach($roles->getRoles(userInfo: $userInfo) as $roleInfo)
|
foreach(iterator_to_array($roles->getRoles(userInfo: $userInfo)) as $roleInfo)
|
||||||
$existingRoles[$roleInfo->getId()] = $roleInfo;
|
$existingRoles[$roleInfo->getId()] = $roleInfo;
|
||||||
|
|
||||||
$removeRoles = [];
|
$removeRoles = [];
|
||||||
|
@ -226,7 +226,7 @@ if(CSRF::validateRequest() && $canEdit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rolesAll = $roles->getRoles();
|
$rolesAll = iterator_to_array($roles->getRoles());
|
||||||
$userRoleIds = $users->hasRoles($userInfo, $rolesAll);
|
$userRoleIds = $users->hasRoles($userInfo, $rolesAll);
|
||||||
|
|
||||||
Template::render('manage.users.user', [
|
Template::render('manage.users.user', [
|
||||||
|
|
|
@ -113,7 +113,7 @@ if($isEditing) {
|
||||||
if(!$perms->edit_profile) {
|
if(!$perms->edit_profile) {
|
||||||
$notices[] = 'You\'re not allowed to edit your profile';
|
$notices[] = 'You\'re not allowed to edit your profile';
|
||||||
} else {
|
} else {
|
||||||
$profileFieldInfos = $profileFields->getFields();
|
$profileFieldInfos = iterator_to_array($profileFields->getFields());
|
||||||
$profileFieldsSetInfos = [];
|
$profileFieldsSetInfos = [];
|
||||||
$profileFieldsSetValues = [];
|
$profileFieldsSetValues = [];
|
||||||
$profileFieldsRemove = [];
|
$profileFieldsRemove = [];
|
||||||
|
@ -299,7 +299,7 @@ $profileStats->forum_post_count = $forumCtx->countTotalUserPosts($userInfo);
|
||||||
$profileStats->comments_count = $msz->getComments()->countPosts(userInfo: $userInfo, deleted: false);
|
$profileStats->comments_count = $msz->getComments()->countPosts(userInfo: $userInfo, deleted: false);
|
||||||
|
|
||||||
if(!$viewingAsGuest) {
|
if(!$viewingAsGuest) {
|
||||||
Template::set('profile_warnings', $usersCtx->getWarnings()->getWarningsWithDefaultBacklog($userInfo));
|
Template::set('profile_warnings', iterator_to_array($usersCtx->getWarnings()->getWarningsWithDefaultBacklog($userInfo)));
|
||||||
|
|
||||||
if((!$isBanned || $canEdit)) {
|
if((!$isBanned || $canEdit)) {
|
||||||
$unranked = $cfg->getValues([
|
$unranked = $cfg->getValues([
|
||||||
|
@ -323,9 +323,9 @@ if(!$viewingAsGuest) {
|
||||||
);
|
);
|
||||||
$activeTopicInfo = $activeTopicStats->success ? $forumTopics->getTopic(topicId: $activeTopicStats->topicId) : null;
|
$activeTopicInfo = $activeTopicStats->success ? $forumTopics->getTopic(topicId: $activeTopicStats->topicId) : null;
|
||||||
|
|
||||||
$profileFieldValues = $profileFields->getFieldValues($userInfo);
|
$profileFieldValues = iterator_to_array($profileFields->getFieldValues($userInfo));
|
||||||
$profileFieldInfos = $profileFieldInfos ?? $profileFields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues);
|
$profileFieldInfos = $profileFieldInfos ?? iterator_to_array($profileFields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues));
|
||||||
$profileFieldFormats = $profileFields->getFieldFormats(fieldValueInfos: $profileFieldValues);
|
$profileFieldFormats = iterator_to_array($profileFields->getFieldFormats(fieldValueInfos: $profileFieldValues));
|
||||||
|
|
||||||
$profileFieldRawValues = [];
|
$profileFieldRawValues = [];
|
||||||
$profileFieldLinkValues = [];
|
$profileFieldLinkValues = [];
|
||||||
|
|
|
@ -116,7 +116,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) {
|
||||||
if($_SERVER['REQUEST_METHOD'] === 'POST' && $isVerifiedRequest)
|
if($_SERVER['REQUEST_METHOD'] === 'POST' && $isVerifiedRequest)
|
||||||
$userInfo = $users->getUser($userInfo->getId(), 'id');
|
$userInfo = $users->getUser($userInfo->getId(), 'id');
|
||||||
|
|
||||||
$userRoles = $roles->getRoles(userInfo: $userInfo);
|
$userRoles = iterator_to_array($roles->getRoles(userInfo: $userInfo));
|
||||||
|
|
||||||
Template::render('settings.account', [
|
Template::render('settings.account', [
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
|
|
|
@ -129,6 +129,7 @@ if(isset($_POST['action']) && is_string($_POST['action'])) {
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_redirects', ['topic_id:s', 'user_id:s:n', 'topic_redir_url:s', 'topic_redir_created:t']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_redirects', ['topic_id:s', 'user_id:s:n', 'topic_redir_url:s', 'topic_redir_created:t']);
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_track', ['user_id:s', 'topic_id:s', 'forum_id:s', 'track_last_read:t']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'forum_topics_track', ['user_id:s', 'topic_id:s', 'forum_id:s', 'track_last_read:t']);
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'login_attempts', ['user_id:s:n', 'attempt_success:b', 'attempt_ip:a', 'attempt_country:s', 'attempt_created:t', 'attempt_user_agent:s']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'login_attempts', ['user_id:s:n', 'attempt_success:b', 'attempt_ip:a', 'attempt_country:s', 'attempt_created:t', 'attempt_user_agent:s']);
|
||||||
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'messages', ['msg_id:s', 'msg_owner_id:s', 'msg_author_id:s:n', 'msg_recipient_id:s:n', 'msg_reply_to:s:n', 'msg_title:s', 'msg_body:s', 'msg_parser:i', 'msg_created:t', 'msg_sent:t:n', 'msg_read:t:n', 'msg_deleted:t:n'], 'msg_owner_id');
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'news_posts', ['post_id:s', 'category_id:s', 'user_id:s:n', 'comment_section_id:s:n', 'post_is_featured:b', 'post_title:s', 'post_text:s', 'post_scheduled:t', 'post_created:t', 'post_updated:t', 'post_deleted:t:n']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'news_posts', ['post_id:s', 'category_id:s', 'user_id:s:n', 'comment_section_id:s:n', 'post_is_featured:b', 'post_title:s', 'post_text:s', 'post_scheduled:t', 'post_created:t', 'post_updated:t', 'post_deleted:t:n']);
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'perms', ['user_id:s:n', 'role_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_allow:i', 'perms_deny:i']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'perms', ['user_id:s:n', 'role_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_allow:i', 'perms_deny:i']);
|
||||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'perms_calculated', ['user_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_calculated:i']);
|
$tmpFiles[] = db_to_zip($archive, $userInfo, 'perms_calculated', ['user_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_calculated:i']);
|
||||||
|
|
|
@ -15,8 +15,8 @@ $auditLog = $msz->getAuditLog();
|
||||||
$loginHistoryPagination = new Pagination($loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp');
|
$loginHistoryPagination = new Pagination($loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp');
|
||||||
$accountLogPagination = new Pagination($auditLog->countLogs(userInfo: $currentUser), 10, 'ap');
|
$accountLogPagination = new Pagination($auditLog->countLogs(userInfo: $currentUser), 10, 'ap');
|
||||||
|
|
||||||
$loginHistory = $loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination);
|
$loginHistory = iterator_to_array($loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination));
|
||||||
$auditLogs = $auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination);
|
$auditLogs = iterator_to_array($auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination));
|
||||||
|
|
||||||
Template::render('settings.logs', [
|
Template::render('settings.logs', [
|
||||||
'login_history_list' => $loginHistory,
|
'login_history_list' => $loginHistory,
|
||||||
|
|
|
@ -61,7 +61,7 @@ class AuditLog {
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
IPAddress|string|null $remoteAddr = null,
|
IPAddress|string|null $remoteAddr = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($remoteAddr instanceof IPAddress)
|
if($remoteAddr instanceof IPAddress)
|
||||||
|
@ -98,13 +98,8 @@ class AuditLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->getResult();
|
|
||||||
$logs = [];
|
|
||||||
|
|
||||||
while($result->next())
|
return $stmt->getResult()->getIterator(AuditLogInfo::fromResult(...));
|
||||||
$logs[] = new AuditLogInfo($result);
|
|
||||||
|
|
||||||
return $logs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createLog(
|
public function createLog(
|
||||||
|
|
|
@ -7,20 +7,24 @@ use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
|
|
||||||
class AuditLogInfo {
|
class AuditLogInfo {
|
||||||
private ?string $userId;
|
public function __construct(
|
||||||
private string $action;
|
private ?string $userId,
|
||||||
private array $params;
|
private string $action,
|
||||||
private int $created;
|
private array $params,
|
||||||
private string $address;
|
private int $created,
|
||||||
private string $country;
|
private string $address,
|
||||||
|
private string $country,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): AuditLogInfo {
|
||||||
$this->userId = $result->isNull(0) ? null : (string)$result->getInteger(0);
|
return new AuditLogInfo(
|
||||||
$this->action = $result->getString(1);
|
userId: $result->getStringOrNull(0),
|
||||||
$this->params = json_decode($result->getString(2));
|
action: $result->getString(1),
|
||||||
$this->created = $result->getInteger(3);
|
params: json_decode($result->getString(2)),
|
||||||
$this->address = $result->isNull(4) ? '::1' : $result->getString(4); // apparently this being NULL is possible?
|
created: $result->getInteger(3),
|
||||||
$this->country = $result->getString(5);
|
address: $result->isNull(4) ? '::1' : $result->getString(4), // apparently this being NULL is possible?
|
||||||
|
country: $result->getString(5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasUserId(): bool {
|
public function hasUserId(): bool {
|
||||||
|
|
|
@ -7,22 +7,26 @@ use Index\Net\IPAddress;
|
||||||
use Misuzu\ClientInfo;
|
use Misuzu\ClientInfo;
|
||||||
|
|
||||||
class LoginAttemptInfo {
|
class LoginAttemptInfo {
|
||||||
private ?string $userId;
|
public function __construct(
|
||||||
private bool $success;
|
private ?string $userId,
|
||||||
private string $remoteAddr;
|
private bool $success,
|
||||||
private string $countryCode;
|
private string $remoteAddr,
|
||||||
private int $created;
|
private string $countryCode,
|
||||||
private string $userAgent;
|
private int $created,
|
||||||
private string $clientInfo;
|
private string $userAgent,
|
||||||
|
private string $clientInfo,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): LoginAttemptInfo {
|
||||||
$this->userId = $result->isNull(0) ? null : (string)$result->getInteger(0);
|
return new LoginAttemptInfo(
|
||||||
$this->success = $result->getInteger(1) !== 0;
|
userId: $result->getStringOrNull(0),
|
||||||
$this->remoteAddr = $result->getString(2);
|
success: $result->getBoolean(1),
|
||||||
$this->countryCode = $result->getString(3);
|
remoteAddr: $result->getString(2),
|
||||||
$this->created = $result->getInteger(4);
|
countryCode: $result->getString(3),
|
||||||
$this->userAgent = $result->getString(5);
|
created: $result->getInteger(4),
|
||||||
$this->clientInfo = $result->getString(6);
|
userAgent: $result->getString(5),
|
||||||
|
clientInfo: $result->getString(6),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasUserId(): bool {
|
public function hasUserId(): bool {
|
||||||
|
|
|
@ -83,7 +83,7 @@ class LoginAttempts {
|
||||||
IPAddress|string|null $remoteAddr = null,
|
IPAddress|string|null $remoteAddr = null,
|
||||||
TimeSpan|int|null $timeRange = null,
|
TimeSpan|int|null $timeRange = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($remoteAddr instanceof IPAddress)
|
if($remoteAddr instanceof IPAddress)
|
||||||
|
@ -127,13 +127,7 @@ class LoginAttempts {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(LoginAttemptInfo::fromResult(...));
|
||||||
$attempts = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$attempts[] = new LoginAttemptInfo($result);
|
|
||||||
|
|
||||||
return $attempts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recordAttempt(
|
public function recordAttempt(
|
||||||
|
|
|
@ -7,32 +7,36 @@ use Index\Net\IPAddress;
|
||||||
use Misuzu\ClientInfo;
|
use Misuzu\ClientInfo;
|
||||||
|
|
||||||
class SessionInfo {
|
class SessionInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $userId;
|
private string $id,
|
||||||
private string $token;
|
private string $userId,
|
||||||
private string $firstRemoteAddr;
|
private string $token,
|
||||||
private ?string $lastRemoteAddr;
|
private string $firstRemoteAddr,
|
||||||
private string $userAgent;
|
private ?string $lastRemoteAddr,
|
||||||
private string $clientInfo;
|
private string $userAgent,
|
||||||
private string $countryCode;
|
private string $clientInfo,
|
||||||
private int $expires;
|
private string $countryCode,
|
||||||
private bool $bumpExpires;
|
private int $expires,
|
||||||
private int $created;
|
private bool $bumpExpires,
|
||||||
private ?int $lastActive;
|
private int $created,
|
||||||
|
private ?int $lastActive,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): SessionInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new SessionInfo(
|
||||||
$this->userId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->token = $result->getString(2);
|
userId: $result->getString(1),
|
||||||
$this->firstRemoteAddr = $result->getString(3);
|
token: $result->getString(2),
|
||||||
$this->lastRemoteAddr = $result->isNull(4) ? null : $result->getString(4);
|
firstRemoteAddr: $result->getString(3),
|
||||||
$this->userAgent = $result->getString(5);
|
lastRemoteAddr: $result->getStringOrNull(4),
|
||||||
$this->clientInfo = $result->getString(6);
|
userAgent: $result->getString(5),
|
||||||
$this->countryCode = $result->getString(7);
|
clientInfo: $result->getString(6),
|
||||||
$this->expires = $result->getInteger(8);
|
countryCode: $result->getString(7),
|
||||||
$this->bumpExpires = $result->getInteger(9) !== 0;
|
expires: $result->getInteger(8),
|
||||||
$this->created = $result->getInteger(10);
|
bumpExpires: $result->getBoolean(9),
|
||||||
$this->lastActive = $result->isNull(11) ? null : $result->getInteger(11);
|
created: $result->getInteger(10),
|
||||||
|
lastActive: $result->getIntegerOrNull(11),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Sessions {
|
||||||
public function getSessions(
|
public function getSessions(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -85,13 +85,7 @@ class Sessions {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(SessionInfo::fromResult(...));
|
||||||
$sessions = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$sessions[] = new SessionInfo($result);
|
|
||||||
|
|
||||||
return $sessions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSession(
|
public function getSession(
|
||||||
|
@ -124,7 +118,7 @@ class Sessions {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Session not found.');
|
throw new RuntimeException('Session not found.');
|
||||||
|
|
||||||
return new SessionInfo($result);
|
return SessionInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createSession(
|
public function createSession(
|
||||||
|
|
|
@ -5,20 +5,24 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ChangeInfo {
|
class ChangeInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private ?string $userId;
|
private string $id,
|
||||||
private int $action;
|
private ?string $userId,
|
||||||
private int $created;
|
private int $action,
|
||||||
private string $summary;
|
private int $created,
|
||||||
private string $body;
|
private string $summary,
|
||||||
|
private string $body,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ChangeInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ChangeInfo(
|
||||||
$this->userId = $result->isNull(1) ? null : (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->action = $result->getInteger(2);
|
userId: $result->getStringOrNull(1),
|
||||||
$this->created = $result->getInteger(3);
|
action: $result->getInteger(2),
|
||||||
$this->summary = $result->getString(4);
|
created: $result->getInteger(3),
|
||||||
$this->body = $result->getString(5);
|
summary: $result->getString(4),
|
||||||
|
body: $result->getString(5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -121,7 +121,7 @@ class Changelog {
|
||||||
DateTime|int|null $dateTime = null,
|
DateTime|int|null $dateTime = null,
|
||||||
?array $tags = null,
|
?array $tags = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($dateTime instanceof DateTime)
|
if($dateTime instanceof DateTime)
|
||||||
|
@ -169,13 +169,7 @@ class Changelog {
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ChangeInfo::fromResult(...));
|
||||||
$changes = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$changes[] = new ChangeInfo($result);
|
|
||||||
|
|
||||||
return $changes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChange(string $changeId): ChangeInfo {
|
public function getChange(string $changeId): ChangeInfo {
|
||||||
|
@ -187,7 +181,7 @@ class Changelog {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No tag with that ID exists.');
|
throw new RuntimeException('No tag with that ID exists.');
|
||||||
|
|
||||||
return new ChangeInfo($result);
|
return ChangeInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createChange(
|
public function createChange(
|
||||||
|
|
|
@ -3,20 +3,12 @@ namespace Misuzu\Changelog;
|
||||||
|
|
||||||
use ErrorException;
|
use ErrorException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\Routing\Route;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\RouteHandler;
|
use Misuzu\{Pagination,SiteInfo,Template};
|
||||||
use Misuzu\Pagination;
|
|
||||||
use Misuzu\SiteInfo;
|
|
||||||
use Misuzu\Template;
|
|
||||||
use Misuzu\Auth\AuthInfo;
|
use Misuzu\Auth\AuthInfo;
|
||||||
use Misuzu\Comments\Comments;
|
use Misuzu\Comments\{Comments,CommentsEx};
|
||||||
use Misuzu\Comments\CommentsEx;
|
use Misuzu\Feeds\{Feed,FeedItem,AtomFeedSerializer,RssFeedSerializer};
|
||||||
use Misuzu\Feeds\Feed;
|
use Misuzu\URLs\{URLInfo,URLRegistry};
|
||||||
use Misuzu\Feeds\FeedItem;
|
|
||||||
use Misuzu\Feeds\AtomFeedSerializer;
|
|
||||||
use Misuzu\Feeds\RssFeedSerializer;
|
|
||||||
use Misuzu\URLs\URLInfo;
|
|
||||||
use Misuzu\URLs\URLRegistry;
|
|
||||||
use Misuzu\Users\UsersContext;
|
use Misuzu\Users\UsersContext;
|
||||||
|
|
||||||
final class ChangelogRoutes extends RouteHandler {
|
final class ChangelogRoutes extends RouteHandler {
|
||||||
|
@ -34,7 +26,7 @@ final class ChangelogRoutes extends RouteHandler {
|
||||||
return $comments->getCommentsForLayout($categoryName);
|
return $comments->getCommentsForLayout($categoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/changelog')]
|
#[HttpGet('/changelog')]
|
||||||
#[URLInfo('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])]
|
#[URLInfo('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])]
|
||||||
public function getIndex($response, $request) {
|
public function getIndex($response, $request) {
|
||||||
$filterDate = (string)$request->getParam('date');
|
$filterDate = (string)$request->getParam('date');
|
||||||
|
@ -73,15 +65,16 @@ final class ChangelogRoutes extends RouteHandler {
|
||||||
if(!$pagination->hasValidOffset())
|
if(!$pagination->hasValidOffset())
|
||||||
return 404;
|
return 404;
|
||||||
|
|
||||||
$changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
|
|
||||||
if(empty($changeInfos))
|
|
||||||
return 404;
|
|
||||||
|
|
||||||
$changes = [];
|
$changes = [];
|
||||||
|
$changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
|
||||||
|
$commentsCategoryName = null;
|
||||||
|
|
||||||
foreach($changeInfos as $changeInfo) {
|
foreach($changeInfos as $changeInfo) {
|
||||||
$userInfo = $changeInfo->hasUserId() ? $this->usersCtx->getUserInfo($changeInfo->getUserId()) : null;
|
$userInfo = $changeInfo->hasUserId() ? $this->usersCtx->getUserInfo($changeInfo->getUserId()) : null;
|
||||||
|
|
||||||
|
if($commentsCategoryName === null)
|
||||||
|
$commentsCategoryName = $changeInfo->getCommentsCategoryName();
|
||||||
|
|
||||||
$changes[] = [
|
$changes[] = [
|
||||||
'change' => $changeInfo,
|
'change' => $changeInfo,
|
||||||
'user' => $userInfo,
|
'user' => $userInfo,
|
||||||
|
@ -89,17 +82,20 @@ final class ChangelogRoutes extends RouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(empty($changes))
|
||||||
|
return 404;
|
||||||
|
|
||||||
return Template::renderRaw('changelog.index', [
|
return Template::renderRaw('changelog.index', [
|
||||||
'changelog_infos' => $changes,
|
'changelog_infos' => $changes,
|
||||||
'changelog_date' => $filterDate,
|
'changelog_date' => $filterDate,
|
||||||
'changelog_user' => $filterUser,
|
'changelog_user' => $filterUser,
|
||||||
'changelog_tags' => $filterTags,
|
'changelog_tags' => $filterTags,
|
||||||
'changelog_pagination' => $pagination,
|
'changelog_pagination' => $pagination,
|
||||||
'comments_info' => empty($filterDate) ? null : $this->getCommentsInfo($changeInfos[0]->getCommentsCategoryName()),
|
'comments_info' => empty($filterDate) && $commentsCategoryName !== null ? null : $this->getCommentsInfo($commentsCategoryName),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/changelog/change/:id')]
|
#[HttpGet('/changelog/change/([0-9]+)')]
|
||||||
#[URLInfo('changelog-change', '/changelog/change/<change>')]
|
#[URLInfo('changelog-change', '/changelog/change/<change>')]
|
||||||
#[URLInfo('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')]
|
#[URLInfo('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')]
|
||||||
public function getChange($response, $request, string $changeId) {
|
public function getChange($response, $request, string $changeId) {
|
||||||
|
@ -148,14 +144,14 @@ final class ChangelogRoutes extends RouteHandler {
|
||||||
return $feed;
|
return $feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/changelog.rss')]
|
#[HttpGet('/changelog.rss')]
|
||||||
#[URLInfo('changelog-feed-rss', '/changelog.rss')]
|
#[URLInfo('changelog-feed-rss', '/changelog.rss')]
|
||||||
public function getFeedRSS($response) {
|
public function getFeedRSS($response) {
|
||||||
$response->setContentType('application/rss+xml; charset=utf-8');
|
$response->setContentType('application/rss+xml; charset=utf-8');
|
||||||
return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss'));
|
return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/changelog.atom')]
|
#[HttpGet('/changelog.atom')]
|
||||||
#[URLInfo('changelog-feed-atom', '/changelog.atom')]
|
#[URLInfo('changelog-feed-atom', '/changelog.atom')]
|
||||||
public function getFeedAtom($response) {
|
public function getFeedAtom($response) {
|
||||||
$response->setContentType('application/atom+xml; charset=utf-8');
|
$response->setContentType('application/atom+xml; charset=utf-8');
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Comments {
|
||||||
public function getCategories(
|
public function getCategories(
|
||||||
UserInfo|string|null $owner = null,
|
UserInfo|string|null $owner = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($owner instanceof UserInfo)
|
if($owner instanceof UserInfo)
|
||||||
$owner = $owner->getId();
|
$owner = $owner->getId();
|
||||||
|
|
||||||
|
@ -72,13 +72,7 @@ class Comments {
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(CommentsCategoryInfo::fromResult(...));
|
||||||
$categories = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$categories[] = new CommentsCategoryInfo($result);
|
|
||||||
|
|
||||||
return $categories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategory(
|
public function getCategory(
|
||||||
|
@ -124,7 +118,7 @@ class Comments {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Comments category not found.');
|
throw new RuntimeException('Comments category not found.');
|
||||||
|
|
||||||
return new CommentsCategoryInfo($result);
|
return CommentsCategoryInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkCategoryNameExists(string $name): bool {
|
public function checkCategoryNameExists(string $name): bool {
|
||||||
|
@ -276,7 +270,7 @@ class Comments {
|
||||||
?bool $deleted = null,
|
?bool $deleted = null,
|
||||||
bool $includeRepliesCount = false,
|
bool $includeRepliesCount = false,
|
||||||
bool $includeVotesCount = false
|
bool $includeVotesCount = false
|
||||||
): array {
|
): iterable {
|
||||||
if($categoryInfo instanceof CommentsCategoryInfo)
|
if($categoryInfo instanceof CommentsCategoryInfo)
|
||||||
$categoryInfo = $categoryInfo->getId();
|
$categoryInfo = $categoryInfo->getId();
|
||||||
if($parentInfo instanceof CommentsPostInfo)
|
if($parentInfo instanceof CommentsPostInfo)
|
||||||
|
@ -330,13 +324,7 @@ class Comments {
|
||||||
$stmt->addParameter(++$args, $userInfo instanceof UserInfo ? $userInfo->getId() : $userInfo);
|
$stmt->addParameter(++$args, $userInfo instanceof UserInfo ? $userInfo->getId() : $userInfo);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$posts = [];
|
return $stmt->getResult()->getIterator(fn($result) => CommentsPostInfo::fromResult($result, $includeRepliesCount, $includeVotesCount));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$posts[] = new CommentsPostInfo($result, $includeRepliesCount, $includeVotesCount);
|
|
||||||
|
|
||||||
return $posts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost(
|
public function getPost(
|
||||||
|
@ -362,7 +350,7 @@ class Comments {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No comment with that ID exists.');
|
throw new RuntimeException('No comment with that ID exists.');
|
||||||
|
|
||||||
return new CommentsPostInfo($result, $includeRepliesCount, $includeVotesCount);
|
return CommentsPostInfo::fromResult($result, $includeRepliesCount, $includeVotesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPost(
|
public function createPost(
|
||||||
|
|
|
@ -6,20 +6,24 @@ use Index\Data\IDbResult;
|
||||||
use Misuzu\Users\UserInfo;
|
use Misuzu\Users\UserInfo;
|
||||||
|
|
||||||
class CommentsCategoryInfo {
|
class CommentsCategoryInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $name;
|
private string $id,
|
||||||
private ?string $ownerId;
|
private string $name,
|
||||||
private int $created;
|
private ?string $ownerId,
|
||||||
private ?int $locked;
|
private int $created,
|
||||||
private int $comments;
|
private ?int $locked,
|
||||||
|
private int $comments,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): CommentsCategoryInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new CommentsCategoryInfo(
|
||||||
$this->name = $result->getString(1);
|
id: $result->getString(0),
|
||||||
$this->ownerId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
name: $result->getString(1),
|
||||||
$this->created = $result->getInteger(3);
|
ownerId: $result->getStringOrNull(2),
|
||||||
$this->locked = $result->isNull(4) ? null : $result->getInteger(4);
|
created: $result->getInteger(3),
|
||||||
$this->comments = $result->getInteger(5);
|
locked: $result->getIntegerOrNull(4),
|
||||||
|
comments: $result->getInteger(5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -5,47 +5,53 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class CommentsPostInfo {
|
class CommentsPostInfo {
|
||||||
private string $id;
|
|
||||||
private string $categoryId;
|
|
||||||
private ?string $userId;
|
|
||||||
private ?string $replyingTo;
|
|
||||||
private string $body;
|
|
||||||
private int $created;
|
|
||||||
private ?int $pinned;
|
|
||||||
private ?int $updated;
|
|
||||||
private ?int $deleted;
|
|
||||||
private int $replies;
|
|
||||||
private int $votesTotal;
|
|
||||||
private int $votesPositive;
|
|
||||||
private int $votesNegative;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
private string $id,
|
||||||
|
private string $categoryId,
|
||||||
|
private ?string $userId,
|
||||||
|
private ?string $replyingTo,
|
||||||
|
private string $body,
|
||||||
|
private int $created,
|
||||||
|
private ?int $pinned,
|
||||||
|
private ?int $updated,
|
||||||
|
private ?int $deleted,
|
||||||
|
private int $replies,
|
||||||
|
private int $votesTotal,
|
||||||
|
private int $votesPositive,
|
||||||
|
private int $votesNegative,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromResult(
|
||||||
IDbResult $result,
|
IDbResult $result,
|
||||||
bool $includeRepliesCount = false,
|
bool $includeRepliesCount = false,
|
||||||
bool $includeVotesCount = false
|
bool $includeVotesCount = false
|
||||||
) {
|
): CommentsPostInfo {
|
||||||
$args = 0;
|
$args = [];
|
||||||
$this->id = (string)$result->getInteger($args);
|
$count = 0;
|
||||||
$this->categoryId = (string)$result->getInteger(++$args);
|
|
||||||
$this->userId = $result->isNull(++$args) ? null : (string)$result->getInteger($args);
|
|
||||||
$this->replyingTo = $result->isNull(++$args) ? null : (string)$result->getInteger($args);
|
|
||||||
$this->body = $result->getString(++$args);
|
|
||||||
$this->created = $result->getInteger(++$args);
|
|
||||||
$this->pinned = $result->isNull(++$args) ? null : $result->getInteger($args);
|
|
||||||
$this->updated = $result->isNull(++$args) ? null : $result->getInteger($args);
|
|
||||||
$this->deleted = $result->isNull(++$args) ? null : $result->getInteger($args);
|
|
||||||
|
|
||||||
$this->replies = $includeRepliesCount ? $result->getInteger(++$args) : 0;
|
$args[] = $result->getString($count); // id
|
||||||
|
$args[] = $result->getString(++$count); // categoryId
|
||||||
|
$args[] = $result->getStringOrNull(++$count); // userId
|
||||||
|
$args[] = $result->getStringOrNull(++$count); // replyingTo
|
||||||
|
$args[] = $result->getString(++$count); // body
|
||||||
|
$args[] = $result->getInteger(++$count); // created
|
||||||
|
$args[] = $result->getIntegerOrNull(++$count); // pinned
|
||||||
|
$args[] = $result->getIntegerOrNull(++$count); // updated
|
||||||
|
$args[] = $result->getIntegerOrNull(++$count); // deleted
|
||||||
|
|
||||||
|
$args[] = $includeRepliesCount ? $result->getInteger(++$count) : 0;
|
||||||
|
|
||||||
if($includeVotesCount) {
|
if($includeVotesCount) {
|
||||||
$this->votesTotal = $result->getInteger(++$args);
|
$args[] = $result->getInteger(++$count); // votesTotal
|
||||||
$this->votesPositive = $result->getInteger(++$args);
|
$args[] = $result->getInteger(++$count); // votesPositive
|
||||||
$this->votesNegative = $result->getInteger(++$args);
|
$args[] = $result->getInteger(++$count); // votesNegative
|
||||||
} else {
|
} else {
|
||||||
$this->votesTotal = 0;
|
$args[] = 0;
|
||||||
$this->votesPositive = 0;
|
$args[] = 0;
|
||||||
$this->votesNegative = 0;
|
$args[] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new CommentsPostInfo(...$args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -5,14 +5,18 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class CounterInfo {
|
class CounterInfo {
|
||||||
private string $name;
|
public function __construct(
|
||||||
private int $value;
|
private string $name,
|
||||||
private int $updated;
|
private int $value,
|
||||||
|
private int $updated,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): CounterInfo {
|
||||||
$this->name = $result->getString(0);
|
return new CounterInfo(
|
||||||
$this->value = $result->getInteger(1);
|
name: $result->getString(0),
|
||||||
$this->updated = $result->getInteger(2);
|
value: $result->getInteger(1),
|
||||||
|
updated: $result->getInteger(2),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): string {
|
public function getName(): string {
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Counters {
|
||||||
public function getCounters(
|
public function getCounters(
|
||||||
?string $orderBy = null,
|
?string $orderBy = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
$hasOrderBy = $orderBy !== null;
|
$hasOrderBy = $orderBy !== null;
|
||||||
$hasPagination = $pagination !== null;
|
$hasPagination = $pagination !== null;
|
||||||
|
|
||||||
|
@ -47,13 +47,7 @@ class Counters {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(CounterInfo::fromResult(...));
|
||||||
$counters = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$counters[] = new CounterInfo($result);
|
|
||||||
|
|
||||||
return $counters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get(array|string $names): array|int {
|
public function get(array|string $names): array|int {
|
||||||
|
|
|
@ -5,16 +5,20 @@ use Stringable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class EmoteInfo implements Stringable {
|
class EmoteInfo implements Stringable {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private int $order;
|
private string $id,
|
||||||
private int $rank;
|
private int $order,
|
||||||
private string $url;
|
private int $rank,
|
||||||
|
private string $url,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): EmoteInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new EmoteInfo(
|
||||||
$this->order = $result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->rank = $result->getInteger(2);
|
order: $result->getInteger(1),
|
||||||
$this->url = $result->getString(3);
|
rank: $result->getInteger(2),
|
||||||
|
url: $result->getString(3),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -5,14 +5,18 @@ use Stringable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class EmoteStringInfo implements Stringable {
|
class EmoteStringInfo implements Stringable {
|
||||||
private string $emoteId;
|
public function __construct(
|
||||||
private int $order;
|
private string $emoteId,
|
||||||
private string $string;
|
private int $order,
|
||||||
|
private string $string,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): EmoteStringInfo {
|
||||||
$this->emoteId = (string)$result->getInteger(0);
|
return new EmoteStringInfo(
|
||||||
$this->order = $result->getInteger(1);
|
emoteId: $result->getString(0),
|
||||||
$this->string = $result->getString(2);
|
order: $result->getInteger(1),
|
||||||
|
string: $result->getString(2),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmoteId(): string {
|
public function getEmoteId(): string {
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Emotes {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No emoticon with that ID exists.');
|
throw new RuntimeException('No emoticon with that ID exists.');
|
||||||
|
|
||||||
return new EmoteInfo($result);
|
return EmoteInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function emoteOrderOptions(): array {
|
public static function emoteOrderOptions(): array {
|
||||||
|
@ -43,7 +43,7 @@ class Emotes {
|
||||||
?int $minRank = null,
|
?int $minRank = null,
|
||||||
?string $orderBy = null,
|
?string $orderBy = null,
|
||||||
?bool $reverse = null
|
?bool $reverse = null
|
||||||
): array {
|
): iterable {
|
||||||
$hasMinRank = $minRank !== null;
|
$hasMinRank = $minRank !== null;
|
||||||
$hasOrderBy = $orderBy !== null;
|
$hasOrderBy = $orderBy !== null;
|
||||||
$hasReverse = $reverse !== null;
|
$hasReverse = $reverse !== null;
|
||||||
|
@ -65,13 +65,7 @@ class Emotes {
|
||||||
$stmt->addParameter(1, $minRank);
|
$stmt->addParameter(1, $minRank);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$emotes = [];
|
return $stmt->getResult()->getIterator(EmoteInfo::fromResult(...));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$emotes[] = new EmoteInfo($result);
|
|
||||||
|
|
||||||
return $emotes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkEmoteUrlInternal(string $url): string {
|
private static function checkEmoteUrlInternal(string $url): string {
|
||||||
|
@ -156,7 +150,7 @@ class Emotes {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmoteStrings(EmoteInfo|string $infoOrId): array {
|
public function getEmoteStrings(EmoteInfo|string $infoOrId): iterable {
|
||||||
if($infoOrId instanceof EmoteInfo)
|
if($infoOrId instanceof EmoteInfo)
|
||||||
$infoOrId = $infoOrId->getId();
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
@ -164,13 +158,7 @@ class Emotes {
|
||||||
$stmt->addParameter(1, $infoOrId);
|
$stmt->addParameter(1, $infoOrId);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$strings = [];
|
return $stmt->getResult()->getIterator(EmoteStringInfo::fromResult(...));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$strings[] = new EmoteStringInfo($result);
|
|
||||||
|
|
||||||
return $strings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkEmoteStringInternal(string $string): string {
|
private static function checkEmoteStringInternal(string $string): string {
|
||||||
|
|
|
@ -12,19 +12,20 @@ use Misuzu\Pagination;
|
||||||
use Misuzu\Users\UserInfo;
|
use Misuzu\Users\UserInfo;
|
||||||
|
|
||||||
class ForumCategories {
|
class ForumCategories {
|
||||||
private IDbConnection $dbConn;
|
|
||||||
private DbStatementCache $cache;
|
private DbStatementCache $cache;
|
||||||
|
|
||||||
public function __construct(IDbConnection $dbConn) {
|
public function __construct(IDbConnection $dbConn) {
|
||||||
$this->dbConn = $dbConn;
|
|
||||||
$this->cache = new DbStatementCache($dbConn);
|
$this->cache = new DbStatementCache($dbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function convertCategoryListToTree(
|
public static function convertCategoryListToTree(
|
||||||
array $catInfos,
|
iterable $catInfos,
|
||||||
ForumCategoryInfo|string|null $parentInfo = null,
|
ForumCategoryInfo|string|null $parentInfo = null,
|
||||||
?Colour $colour = null
|
?Colour $colour = null
|
||||||
): array {
|
): array {
|
||||||
|
if(!is_array($catInfos))
|
||||||
|
$catInfos = iterator_to_array($catInfos);
|
||||||
|
|
||||||
$colour ??= Colour::none();
|
$colour ??= Colour::none();
|
||||||
$tree = [];
|
$tree = [];
|
||||||
$predicate = $parentInfo
|
$predicate = $parentInfo
|
||||||
|
@ -103,7 +104,7 @@ class ForumCategories {
|
||||||
?bool $hidden = null,
|
?bool $hidden = null,
|
||||||
bool $asTree = false,
|
bool $asTree = false,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
$isRootParent = false;
|
$isRootParent = false;
|
||||||
$hasParentInfo = $parentInfo !== false;
|
$hasParentInfo = $parentInfo !== false;
|
||||||
$hasType = $type !== null;
|
$hasType = $type !== null;
|
||||||
|
@ -155,11 +156,7 @@ class ForumCategories {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
$cats = $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
|
||||||
$cats = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$cats[] = new ForumCategoryInfo($result);
|
|
||||||
|
|
||||||
if($asTree)
|
if($asTree)
|
||||||
$cats = self::convertCategoryListToTree($cats);
|
$cats = self::convertCategoryListToTree($cats);
|
||||||
|
@ -216,7 +213,7 @@ class ForumCategories {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Forum category info not found.');
|
throw new RuntimeException('Forum category info not found.');
|
||||||
|
|
||||||
return new ForumCategoryInfo($result);
|
return ForumCategoryInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateCategory(
|
public function updateCategory(
|
||||||
|
@ -261,7 +258,7 @@ class ForumCategories {
|
||||||
|
|
||||||
public function getCategoryAncestry(
|
public function getCategoryAncestry(
|
||||||
ForumCategoryInfo|ForumTopicInfo|ForumPostInfo|string $categoryInfo
|
ForumCategoryInfo|ForumTopicInfo|ForumPostInfo|string $categoryInfo
|
||||||
): array {
|
): iterable {
|
||||||
if($categoryInfo instanceof ForumCategoryInfo)
|
if($categoryInfo instanceof ForumCategoryInfo)
|
||||||
$categoryInfo = $categoryInfo->getId();
|
$categoryInfo = $categoryInfo->getId();
|
||||||
elseif($categoryInfo instanceof ForumTopicInfo || $categoryInfo instanceof ForumPostInfo)
|
elseif($categoryInfo instanceof ForumTopicInfo || $categoryInfo instanceof ForumPostInfo)
|
||||||
|
@ -277,13 +274,7 @@ class ForumCategories {
|
||||||
$stmt->addParameter(1, $categoryInfo);
|
$stmt->addParameter(1, $categoryInfo);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
|
||||||
$cats = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$cats[] = new ForumCategoryInfo($result);
|
|
||||||
|
|
||||||
return $cats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategoryChildren(
|
public function getCategoryChildren(
|
||||||
|
@ -291,7 +282,7 @@ class ForumCategories {
|
||||||
bool $includeSelf = false,
|
bool $includeSelf = false,
|
||||||
?bool $hidden = null,
|
?bool $hidden = null,
|
||||||
bool $asTree = false
|
bool $asTree = false
|
||||||
): array {
|
): iterable {
|
||||||
if($parentInfo instanceof ForumCategoryInfo)
|
if($parentInfo instanceof ForumCategoryInfo)
|
||||||
$parentInfo = $parentInfo->getId();
|
$parentInfo = $parentInfo->getId();
|
||||||
|
|
||||||
|
@ -319,11 +310,7 @@ class ForumCategories {
|
||||||
$stmt->addParameter(++$args, $parentInfo);
|
$stmt->addParameter(++$args, $parentInfo);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
$cats = $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
|
||||||
$cats = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$cats[] = new ForumCategoryInfo($result);
|
|
||||||
|
|
||||||
if($asTree)
|
if($asTree)
|
||||||
$cats = self::convertCategoryListToTree($cats, $parentInfo);
|
$cats = self::convertCategoryListToTree($cats, $parentInfo);
|
||||||
|
|
|
@ -26,38 +26,42 @@ class ForumCategoryInfo {
|
||||||
self::TYPE_DISCUSSION,
|
self::TYPE_DISCUSSION,
|
||||||
];
|
];
|
||||||
|
|
||||||
private string $id;
|
public function __construct(
|
||||||
private int $order;
|
private string $id,
|
||||||
private ?string $parentId;
|
private int $order,
|
||||||
private string $name;
|
private ?string $parentId,
|
||||||
private int $type;
|
private string $name,
|
||||||
private ?string $desc;
|
private int $type,
|
||||||
private ?string $icon;
|
private ?string $desc,
|
||||||
private ?int $colour;
|
private ?string $icon,
|
||||||
private ?string $link;
|
private ?int $colour,
|
||||||
private ?int $clicks;
|
private ?string $link,
|
||||||
private int $created;
|
private ?int $clicks,
|
||||||
private bool $archived;
|
private int $created,
|
||||||
private bool $hidden;
|
private bool $archived,
|
||||||
private int $topicsCount;
|
private bool $hidden,
|
||||||
private int $postsCount;
|
private int $topicsCount,
|
||||||
|
private int $postsCount,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ForumCategoryInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ForumCategoryInfo(
|
||||||
$this->order = $result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->parentId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
order: $result->getInteger(1),
|
||||||
$this->name = $result->getString(3);
|
parentId: $result->getStringOrNull(2),
|
||||||
$this->type = $result->getInteger(4);
|
name: $result->getString(3),
|
||||||
$this->desc = $result->isNull(5) ? null : $result->getString(5);
|
type: $result->getInteger(4),
|
||||||
$this->icon = $result->isNull(6) ? null : $result->getString(6);
|
desc: $result->getStringOrNull(5),
|
||||||
$this->colour = $result->isNull(7) ? null : $result->getInteger(7);
|
icon: $result->getStringOrNull(6),
|
||||||
$this->link = $result->isNull(8) ? null : $result->getString(8);
|
colour: $result->getIntegerOrNull(7),
|
||||||
$this->clicks = $result->isNull(9) ? null : $result->getInteger(9);
|
link: $result->getStringOrNull(8),
|
||||||
$this->created = $result->getInteger(10);
|
clicks: $result->getIntegerOrNull(9),
|
||||||
$this->archived = $result->getInteger(11) !== 0;
|
created: $result->getInteger(10),
|
||||||
$this->hidden = $result->getInteger(12) !== 0;
|
archived: $result->getBoolean(11),
|
||||||
$this->topicsCount = $result->getInteger(13);
|
hidden: $result->getBoolean(12),
|
||||||
$this->postsCount = $result->getInteger(14);
|
topicsCount: $result->getInteger(13),
|
||||||
|
postsCount: $result->getInteger(14),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -7,30 +7,34 @@ use Index\Net\IPAddress;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
|
||||||
class ForumPostInfo {
|
class ForumPostInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $topicId;
|
private string $id,
|
||||||
private string $categoryId;
|
private string $topicId,
|
||||||
private ?string $userId;
|
private string $categoryId,
|
||||||
private string $remoteAddr;
|
private ?string $userId,
|
||||||
private string $body;
|
private string $remoteAddr,
|
||||||
private int $parser;
|
private string $body,
|
||||||
private bool $displaySignature;
|
private int $parser,
|
||||||
private int $created;
|
private bool $displaySignature,
|
||||||
private ?int $edited;
|
private int $created,
|
||||||
private ?int $deleted;
|
private ?int $edited,
|
||||||
|
private ?int $deleted,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ForumPostInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ForumPostInfo(
|
||||||
$this->topicId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->categoryId = (string)$result->getInteger(2);
|
topicId: $result->getString(1),
|
||||||
$this->userId = $result->isNull(3) ? null : (string)$result->getInteger(3);
|
categoryId: $result->getString(2),
|
||||||
$this->remoteAddr = $result->getString(4);
|
userId: $result->getStringOrNull(3),
|
||||||
$this->body = $result->getString(5);
|
remoteAddr: $result->getString(4),
|
||||||
$this->parser = $result->getInteger(6);
|
body: $result->getString(5),
|
||||||
$this->displaySignature = $result->getInteger(7) !== 0;
|
parser: $result->getInteger(6),
|
||||||
$this->created = $result->getInteger(8);
|
displaySignature: $result->getBoolean(7),
|
||||||
$this->edited = $result->isNull(9) ? null : $result->getInteger(9);
|
created: $result->getInteger(8),
|
||||||
$this->deleted = $result->isNull(10) ? null : $result->getInteger(10);
|
edited: $result->getIntegerOrNull(9),
|
||||||
|
deleted: $result->getIntegerOrNull(10),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -84,7 +84,7 @@ class ForumPosts {
|
||||||
?array $searchQuery = null,
|
?array $searchQuery = null,
|
||||||
?bool $deleted = null,
|
?bool $deleted = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
// remove this hack when search server
|
// remove this hack when search server
|
||||||
$hasSearchQuery = $searchQuery !== null;
|
$hasSearchQuery = $searchQuery !== null;
|
||||||
$doSearchOrder = false;
|
$doSearchOrder = false;
|
||||||
|
@ -189,13 +189,7 @@ class ForumPosts {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ForumPostInfo::fromResult(...));
|
||||||
$posts = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$posts[] = new ForumPostInfo($result);
|
|
||||||
|
|
||||||
return $posts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost(
|
public function getPost(
|
||||||
|
@ -267,7 +261,7 @@ class ForumPosts {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Forum post not found.');
|
throw new RuntimeException('Forum post not found.');
|
||||||
|
|
||||||
return new ForumPostInfo($result);
|
return ForumPostInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPost(
|
public function createPost(
|
||||||
|
|
|
@ -17,32 +17,36 @@ class ForumTopicInfo {
|
||||||
'global' => self::TYPE_GLOBAL,
|
'global' => self::TYPE_GLOBAL,
|
||||||
];
|
];
|
||||||
|
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $categoryId;
|
private string $id,
|
||||||
private ?string $userId;
|
private string $categoryId,
|
||||||
private int $type;
|
private ?string $userId,
|
||||||
private string $title;
|
private int $type,
|
||||||
private int $postsCount;
|
private string $title,
|
||||||
private int $deletedPostsCount;
|
private int $postsCount,
|
||||||
private int $viewsCount;
|
private int $deletedPostsCount,
|
||||||
private int $created;
|
private int $viewsCount,
|
||||||
private int $bumped;
|
private int $created,
|
||||||
private ?int $deleted;
|
private int $bumped,
|
||||||
private ?int $locked;
|
private ?int $deleted,
|
||||||
|
private ?int $locked,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ForumTopicInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ForumTopicInfo(
|
||||||
$this->categoryId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->userId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
categoryId: $result->getString(1),
|
||||||
$this->type = $result->getInteger(3);
|
userId: $result->getStringOrNull(2),
|
||||||
$this->title = $result->getString(4);
|
type: $result->getInteger(3),
|
||||||
$this->viewsCount = $result->getInteger(5);
|
title: $result->getString(4),
|
||||||
$this->created = $result->getInteger(6);
|
viewsCount: $result->getInteger(5),
|
||||||
$this->bumped = $result->getInteger(7);
|
created: $result->getInteger(6),
|
||||||
$this->deleted = $result->isNull(8) ? null : $result->getInteger(8);
|
bumped: $result->getInteger(7),
|
||||||
$this->locked = $result->isNull(9) ? null : $result->getInteger(9);
|
deleted: $result->getIntegerOrNull(8),
|
||||||
$this->postsCount = $result->getInteger(10);
|
locked: $result->getIntegerOrNull(9),
|
||||||
$this->deletedPostsCount = $result->getInteger(11);
|
postsCount: $result->getInteger(10),
|
||||||
|
deletedPostsCount: $result->getInteger(11),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -5,16 +5,20 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ForumTopicRedirectInfo {
|
class ForumTopicRedirectInfo {
|
||||||
private string $topicId;
|
public function __construct(
|
||||||
private ?string $userId;
|
private string $topicId,
|
||||||
private string $link;
|
private ?string $userId,
|
||||||
private int $created;
|
private string $link,
|
||||||
|
private int $created,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ForumTopicRedirectInfo {
|
||||||
$this->topicId = (string)$result->getInteger(0);
|
return new ForumTopicRedirectInfo(
|
||||||
$this->userId = $result->isNull(1) ? null : (string)$result->getInteger(1);
|
topicId: $result->getString(0),
|
||||||
$this->link = $result->getString(2);
|
userId: $result->getStringOrNull(1),
|
||||||
$this->created = $result->getInteger(3);
|
link: $result->getString(2),
|
||||||
|
created: $result->getInteger(3),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTopicId(): string {
|
public function getTopicId(): string {
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ForumTopicRedirects {
|
||||||
public function getTopicRedirects(
|
public function getTopicRedirects(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -61,13 +61,7 @@ class ForumTopicRedirects {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ForumTopicRedirectInfo::fromResult(...));
|
||||||
$redirs = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$redirs[] = new ForumTopicRedirectInfo($result);
|
|
||||||
|
|
||||||
return $redirs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasTopicRedirect(ForumTopicInfo|string $topicInfo): bool {
|
public function hasTopicRedirect(ForumTopicInfo|string $topicInfo): bool {
|
||||||
|
@ -97,7 +91,7 @@ class ForumTopicRedirects {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Could not find that forum topic redirect.');
|
throw new RuntimeException('Could not find that forum topic redirect.');
|
||||||
|
|
||||||
return new ForumTopicRedirectInfo($result);
|
return ForumTopicRedirectInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createTopicRedirect(
|
public function createTopicRedirect(
|
||||||
|
|
|
@ -91,7 +91,7 @@ class ForumTopics {
|
||||||
?bool $global = null,
|
?bool $global = null,
|
||||||
?bool $deleted = null,
|
?bool $deleted = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
// remove this hack when search server
|
// remove this hack when search server
|
||||||
$hasSearchQuery = $searchQuery !== null;
|
$hasSearchQuery = $searchQuery !== null;
|
||||||
$hasAfterTopicId = false;
|
$hasAfterTopicId = false;
|
||||||
|
@ -194,13 +194,7 @@ class ForumTopics {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ForumTopicInfo::fromResult(...));
|
||||||
$topics = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$topics[] = new ForumTopicInfo($result);
|
|
||||||
|
|
||||||
return $topics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTopic(
|
public function getTopic(
|
||||||
|
@ -239,7 +233,7 @@ class ForumTopics {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Forum topic not found.');
|
throw new RuntimeException('Forum topic not found.');
|
||||||
|
|
||||||
return new ForumTopicInfo($result);
|
return ForumTopicInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createTopic(
|
public function createTopic(
|
||||||
|
|
|
@ -3,14 +3,10 @@ namespace Misuzu\Home;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use Index\DateTime;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\{DbTools,IDbConnection};
|
||||||
use Index\Data\IDbConnection;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\Route;
|
|
||||||
use Index\Routing\RouteHandler;
|
|
||||||
use Syokuhou\IConfig;
|
use Syokuhou\IConfig;
|
||||||
use Misuzu\Pagination;
|
use Misuzu\{Pagination,SiteInfo,Template};
|
||||||
use Misuzu\SiteInfo;
|
|
||||||
use Misuzu\Template;
|
|
||||||
use Misuzu\Auth\AuthInfo;
|
use Misuzu\Auth\AuthInfo;
|
||||||
use Misuzu\Changelog\Changelog;
|
use Misuzu\Changelog\Changelog;
|
||||||
use Misuzu\Comments\Comments;
|
use Misuzu\Comments\Comments;
|
||||||
|
@ -43,7 +39,7 @@ class HomeRoutes extends RouteHandler {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getOnlineUsers(): array {
|
private function getOnlineUsers(): iterable {
|
||||||
return $this->usersCtx->getUsers()->getUsers(
|
return $this->usersCtx->getUsers()->getUsers(
|
||||||
lastActiveInMinutes: 5,
|
lastActiveInMinutes: 5,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
|
@ -53,14 +49,14 @@ class HomeRoutes extends RouteHandler {
|
||||||
|
|
||||||
private array $newsCategoryInfos = [];
|
private array $newsCategoryInfos = [];
|
||||||
|
|
||||||
private function getFeaturedNewsPosts(int $amount, bool $decorate): array {
|
private function getFeaturedNewsPosts(int $amount, bool $decorate): iterable {
|
||||||
$postInfos = $this->news->getPosts(
|
$postInfos = $this->news->getPosts(
|
||||||
onlyFeatured: true,
|
onlyFeatured: true,
|
||||||
pagination: new Pagination($amount)
|
pagination: new Pagination($amount)
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!$decorate)
|
if(!$decorate)
|
||||||
return $postInfos;
|
return iterator_to_array($postInfos);
|
||||||
|
|
||||||
$posts = [];
|
$posts = [];
|
||||||
|
|
||||||
|
@ -154,7 +150,7 @@ class HomeRoutes extends RouteHandler {
|
||||||
return $topics;
|
return $topics;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/')]
|
#[HttpGet('/')]
|
||||||
#[URLInfo('index', '/')]
|
#[URLInfo('index', '/')]
|
||||||
public function getIndex(...$args) {
|
public function getIndex(...$args) {
|
||||||
return $this->authInfo->isLoggedIn()
|
return $this->authInfo->isLoggedIn()
|
||||||
|
@ -164,9 +160,9 @@ class HomeRoutes extends RouteHandler {
|
||||||
|
|
||||||
public function getHome() {
|
public function getHome() {
|
||||||
$stats = $this->getStats();
|
$stats = $this->getStats();
|
||||||
$onlineUserInfos = $this->getOnlineUsers();
|
$onlineUserInfos = iterator_to_array($this->getOnlineUsers());
|
||||||
$featuredNews = $this->getFeaturedNewsPosts(5, true);
|
$featuredNews = $this->getFeaturedNewsPosts(5, true);
|
||||||
$changelog = $this->changelog->getChanges(pagination: new Pagination(10));
|
$changelog = iterator_to_array($this->changelog->getChanges(pagination: new Pagination(10)));
|
||||||
|
|
||||||
$stats['users:online:recent'] = count($onlineUserInfos);
|
$stats['users:online:recent'] = count($onlineUserInfos);
|
||||||
|
|
||||||
|
@ -201,7 +197,7 @@ class HomeRoutes extends RouteHandler {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_landing')]
|
#[HttpGet('/_landing')]
|
||||||
public function getLanding($response, $request) {
|
public function getLanding($response, $request) {
|
||||||
$config = $this->config->getValues([
|
$config = $this->config->getValues([
|
||||||
['social.embed_linked:b'],
|
['social.embed_linked:b'],
|
||||||
|
@ -221,7 +217,7 @@ class HomeRoutes extends RouteHandler {
|
||||||
} else $linkedData = null;
|
} else $linkedData = null;
|
||||||
|
|
||||||
$stats = $this->getStats();
|
$stats = $this->getStats();
|
||||||
$onlineUserInfos = $this->getOnlineUsers();
|
$onlineUserInfos = iterator_to_array($this->getOnlineUsers());
|
||||||
$featuredNews = $this->getFeaturedNewsPosts(3, false);
|
$featuredNews = $this->getFeaturedNewsPosts(3, false);
|
||||||
$popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']);
|
$popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']);
|
||||||
$activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']);
|
$activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Info;
|
namespace Misuzu\Info;
|
||||||
|
|
||||||
use Index\Routing\Route;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\RouteHandler;
|
|
||||||
use Misuzu\Template;
|
use Misuzu\Template;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
use Misuzu\URLs\URLInfo;
|
use Misuzu\URLs\URLInfo;
|
||||||
|
@ -18,23 +17,16 @@ class InfoRoutes extends RouteHandler {
|
||||||
'index' => 'Index Project » %s',
|
'index' => 'Index Project » %s',
|
||||||
];
|
];
|
||||||
|
|
||||||
private static function checkName(string $name): bool {
|
#[HttpGet('/info')]
|
||||||
return preg_match('#^([A-Za-z0-9_]+)$#', $name) === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('GET', '/info')]
|
|
||||||
#[URLInfo('info-index', '/info')]
|
#[URLInfo('info-index', '/info')]
|
||||||
public function getIndex() {
|
public function getIndex() {
|
||||||
return Template::renderRaw('info.index');
|
return Template::renderRaw('info.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/info/:name')]
|
#[HttpGet('/info/([A-Za-z0-9_]+)')]
|
||||||
#[URLInfo('info', '/info/<title>')]
|
#[URLInfo('info', '/info/<title>')]
|
||||||
#[URLInfo('info-doc', '/info/<title>')]
|
#[URLInfo('info-doc', '/info/<title>')]
|
||||||
public function getDocsPage($response, $request, string $name) {
|
public function getDocsPage($response, $request, string $name) {
|
||||||
if(!self::checkName($name))
|
|
||||||
return 404;
|
|
||||||
|
|
||||||
return $this->serveMarkdownDocument(
|
return $this->serveMarkdownDocument(
|
||||||
sprintf('%s/%s.md', self::DOCS_PATH, $name)
|
sprintf('%s/%s.md', self::DOCS_PATH, $name)
|
||||||
);
|
);
|
||||||
|
@ -78,13 +70,11 @@ class InfoRoutes extends RouteHandler {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/info/:project/:name')]
|
#[HttpGet('/info/([A-Za-z0-9_]+)/([A-Za-z0-9_]+)')]
|
||||||
#[URLInfo('info-project-doc', '/info/<project>/<title>')]
|
#[URLInfo('info-project-doc', '/info/<project>/<title>')]
|
||||||
public function getProjectPage($response, $request, string $project, string $name) {
|
public function getProjectPage($response, $request, string $project, string $name) {
|
||||||
if(!array_key_exists($project, self::PROJECT_PATHS))
|
if(!array_key_exists($project, self::PROJECT_PATHS))
|
||||||
return 404;
|
return 404;
|
||||||
if(!self::checkName($name))
|
|
||||||
return 404;
|
|
||||||
|
|
||||||
$projectPath = self::PROJECT_PATHS[$project];
|
$projectPath = self::PROJECT_PATHS[$project];
|
||||||
$titleSuffix = array_key_exists($project, self::PROJECT_SUFFIXES) ? self::PROJECT_SUFFIXES[$project] : '';
|
$titleSuffix = array_key_exists($project, self::PROJECT_SUFFIXES) ? self::PROJECT_SUFFIXES[$project] : '';
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\Routing\Route;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\RouteHandler;
|
use Misuzu\URLs\{IURLSource,URLInfo,URLRegistry};
|
||||||
use Misuzu\URLs\IURLSource;
|
|
||||||
use Misuzu\URLs\URLInfo;
|
|
||||||
use Misuzu\URLs\URLRegistry;
|
|
||||||
|
|
||||||
class LegacyRoutes extends RouteHandler implements IURLSource {
|
class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -124,27 +121,27 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
$urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']);
|
$urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/index.php')]
|
#[HttpGet('/index.php')]
|
||||||
public function getIndexPHP($response): void {
|
public function getIndexPHP($response): void {
|
||||||
$response->redirect($this->urls->format('index'), true);
|
$response->redirect($this->urls->format('index'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/info.php')]
|
#[HttpGet('/info.php')]
|
||||||
public function getInfoPHP($response): void {
|
public function getInfoPHP($response): void {
|
||||||
$response->redirect($this->urls->format('info'), true);
|
$response->redirect($this->urls->format('info'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/info.php/:name')]
|
#[HttpGet('/info.php/([A-Za-z0-9_]+)')]
|
||||||
public function getInfoDocsPHP($response, $request, string $name): void {
|
public function getInfoDocsPHP($response, $request, string $name): void {
|
||||||
$response->redirect($this->urls->format('info', ['title' => $name]), true);
|
$response->redirect($this->urls->format('info', ['title' => $name]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/info.php/:project/:name')]
|
#[HttpGet('/info.php/([A-Za-z0-9_]+)/([A-Za-z0-9_]+)')]
|
||||||
public function getInfoProjectPHP($response, $request, string $project, string $name): void {
|
public function getInfoProjectPHP($response, $request, string $project, string $name): void {
|
||||||
$response->redirect($this->urls->format('info', ['title' => $project . '/' . $name]), true);
|
$response->redirect($this->urls->format('info', ['title' => $project . '/' . $name]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news.php')]
|
#[HttpGet('/news.php')]
|
||||||
public function getNewsPHP($response, $request): void {
|
public function getNewsPHP($response, $request): void {
|
||||||
$postId = (int)($request->getParam('n', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('p', FILTER_SANITIZE_NUMBER_INT));
|
$postId = (int)($request->getParam('n', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('p', FILTER_SANITIZE_NUMBER_INT));
|
||||||
|
|
||||||
|
@ -159,28 +156,28 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
$response->redirect($location, true);
|
$response->redirect($location, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news.php/rss')]
|
#[HttpGet('/news.php/rss')]
|
||||||
public function getNewsRssPHP($response, $request): void {
|
public function getNewsRssPHP($response, $request): void {
|
||||||
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$location = $this->urls->format($catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss', ['category' => $catId]);
|
$location = $this->urls->format($catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss', ['category' => $catId]);
|
||||||
$response->redirect($location, true);
|
$response->redirect($location, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news.php/atom')]
|
#[HttpGet('/news.php/atom')]
|
||||||
public function getNewsAtomPHP($response, $request): void {
|
public function getNewsAtomPHP($response, $request): void {
|
||||||
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$location = $this->urls->format($catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom', ['category' => $catId]);
|
$location = $this->urls->format($catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom', ['category' => $catId]);
|
||||||
$response->redirect($location, true);
|
$response->redirect($location, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/index.php')]
|
#[HttpGet('/news/index.php')]
|
||||||
public function getNewsIndexPHP($response, $request): void {
|
public function getNewsIndexPHP($response, $request): void {
|
||||||
$response->redirect($this->urls->format('news-index', [
|
$response->redirect($this->urls->format('news-index', [
|
||||||
'page' => $request->getParam('page', FILTER_SANITIZE_NUMBER_INT),
|
'page' => $request->getParam('page', FILTER_SANITIZE_NUMBER_INT),
|
||||||
]), true);
|
]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/category.php')]
|
#[HttpGet('/news/category.php')]
|
||||||
public function getNewsCategoryPHP($response, $request): void {
|
public function getNewsCategoryPHP($response, $request): void {
|
||||||
$response->redirect($this->urls->format('news-category', [
|
$response->redirect($this->urls->format('news-category', [
|
||||||
'category' => $request->getParam('c', FILTER_SANITIZE_NUMBER_INT),
|
'category' => $request->getParam('c', FILTER_SANITIZE_NUMBER_INT),
|
||||||
|
@ -188,19 +185,19 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
]), true);
|
]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/post.php')]
|
#[HttpGet('/news/post.php')]
|
||||||
public function getNewsPostPHP($response, $request): void {
|
public function getNewsPostPHP($response, $request): void {
|
||||||
$response->redirect($this->urls->format('news-post', [
|
$response->redirect($this->urls->format('news-post', [
|
||||||
'post' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT),
|
'post' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT),
|
||||||
]), true);
|
]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/feed.php')]
|
#[HttpGet('/news/feed.php')]
|
||||||
public function getNewsFeedPHP($response, $request): int {
|
public function getNewsFeedPHP($response, $request): int {
|
||||||
return 400;
|
return 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/feed.php/rss')]
|
#[HttpGet('/news/feed.php/rss')]
|
||||||
public function getNewsFeedRssPHP($response, $request): void {
|
public function getNewsFeedRssPHP($response, $request): void {
|
||||||
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$response->redirect($this->urls->format(
|
$response->redirect($this->urls->format(
|
||||||
|
@ -209,7 +206,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
), true);
|
), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/feed.php/atom')]
|
#[HttpGet('/news/feed.php/atom')]
|
||||||
public function getNewsFeedAtomPHP($response, $request): void {
|
public function getNewsFeedAtomPHP($response, $request): void {
|
||||||
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$response->redirect($this->urls->format(
|
$response->redirect($this->urls->format(
|
||||||
|
@ -218,7 +215,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
), true);
|
), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/changelog.php')]
|
#[HttpGet('/changelog.php')]
|
||||||
public function getChangelogPHP($response, $request): void {
|
public function getChangelogPHP($response, $request): void {
|
||||||
$changeId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
$changeId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
|
||||||
if($changeId) {
|
if($changeId) {
|
||||||
|
@ -232,7 +229,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
]), true);
|
]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/auth.php')]
|
#[HttpGet('/auth.php')]
|
||||||
public function getAuthPHP($response, $request): void {
|
public function getAuthPHP($response, $request): void {
|
||||||
$response->redirect($this->urls->format(match($request->getParam('m')) {
|
$response->redirect($this->urls->format(match($request->getParam('m')) {
|
||||||
'logout' => 'auth-logout',
|
'logout' => 'auth-logout',
|
||||||
|
@ -243,44 +240,44 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
|
||||||
}), true);
|
}), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/auth')]
|
#[HttpGet('/auth')]
|
||||||
#[Route('GET', '/auth/index.php')]
|
#[HttpGet('/auth/index.php')]
|
||||||
public function getAuthIndexPHP($response, $request): void {
|
public function getAuthIndexPHP($response, $request): void {
|
||||||
$response->redirect($this->urls->format('auth-login'), true);
|
$response->redirect($this->urls->format('auth-login'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/settings.php')]
|
#[HttpGet('/settings.php')]
|
||||||
public function getSettingsPHP($response): void {
|
public function getSettingsPHP($response): void {
|
||||||
$response->redirect($this->urls->format('settings-index'), true);
|
$response->redirect($this->urls->format('settings-index'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/settings')]
|
#[HttpGet('/settings')]
|
||||||
public function getSettingsIndex($response): void {
|
public function getSettingsIndex($response): void {
|
||||||
$response->redirect($this->urls->format('settings-account'));
|
$response->redirect($this->urls->format('settings-account'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/settings/index.php')]
|
#[HttpGet('/settings/index.php')]
|
||||||
public function getSettingsIndexPHP($response): void {
|
public function getSettingsIndexPHP($response): void {
|
||||||
$response->redirect($this->urls->format('settings-account'), true);
|
$response->redirect($this->urls->format('settings-account'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/manage')]
|
#[HttpGet('/manage')]
|
||||||
#[URLInfo('manage-index', '/manage')]
|
#[URLInfo('manage-index', '/manage')]
|
||||||
public function getManageIndex($response): void {
|
public function getManageIndex($response): void {
|
||||||
$response->redirect($this->urls->format('manage-general-overview'));
|
$response->redirect($this->urls->format('manage-general-overview'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/manage/index.php')]
|
#[HttpGet('/manage/index.php')]
|
||||||
public function getManageIndexPHP($response): void {
|
public function getManageIndexPHP($response): void {
|
||||||
$response->redirect($this->urls->format('manage-general-overview'), true);
|
$response->redirect($this->urls->format('manage-general-overview'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/manage/news')]
|
#[HttpGet('/manage/news')]
|
||||||
public function getManageNewsIndex($response): void {
|
public function getManageNewsIndex($response): void {
|
||||||
$response->redirect($this->urls->format('manage-news-categories'));
|
$response->redirect($this->urls->format('manage-news-categories'));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/manage/news/index.php')]
|
#[HttpGet('/manage/news/index.php')]
|
||||||
public function getManageNewsIndexPHP($response): void {
|
public function getManageNewsIndexPHP($response): void {
|
||||||
$response->redirect($this->urls->format('manage-news-categories'), true);
|
$response->redirect($this->urls->format('manage-news-categories'), true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,32 +6,36 @@ use Index\Data\IDbResult;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
|
||||||
class MessageInfo {
|
class MessageInfo {
|
||||||
private string $messageId;
|
public function __construct(
|
||||||
private string $ownerId;
|
private string $messageId,
|
||||||
private ?string $authorId;
|
private string $ownerId,
|
||||||
private ?string $recipientId;
|
private ?string $authorId,
|
||||||
private ?string $replyTo;
|
private ?string $recipientId,
|
||||||
private string $title;
|
private ?string $replyTo,
|
||||||
private string $body;
|
private string $title,
|
||||||
private int $parser;
|
private string $body,
|
||||||
private int $created;
|
private int $parser,
|
||||||
private ?int $sent;
|
private int $created,
|
||||||
private ?int $read;
|
private ?int $sent,
|
||||||
private ?int $deleted;
|
private ?int $read,
|
||||||
|
private ?int $deleted,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): MessageInfo {
|
||||||
$this->messageId = $result->getString(0);
|
return new MessageInfo(
|
||||||
$this->ownerId = $result->getString(1);
|
messageId: $result->getString(0),
|
||||||
$this->authorId = $result->getStringOrNull(2);
|
ownerId: $result->getString(1),
|
||||||
$this->recipientId = $result->getStringOrNull(3);
|
authorId: $result->getStringOrNull(2),
|
||||||
$this->replyTo = $result->getStringOrNull(4);
|
recipientId: $result->getStringOrNull(3),
|
||||||
$this->title = $result->getString(5);
|
replyTo: $result->getStringOrNull(4),
|
||||||
$this->body = $result->getString(6);
|
title: $result->getString(5),
|
||||||
$this->parser = $result->getInteger(7);
|
body: $result->getString(6),
|
||||||
$this->created = $result->getInteger(8);
|
parser: $result->getInteger(7),
|
||||||
$this->sent = $result->getIntegerOrNull(9);
|
created: $result->getInteger(8),
|
||||||
$this->read = $result->getIntegerOrNull(10);
|
sent: $result->getIntegerOrNull(9),
|
||||||
$this->deleted = $result->getIntegerOrNull(11);
|
read: $result->getIntegerOrNull(10),
|
||||||
|
deleted: $result->getIntegerOrNull(11),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Misuzu\Users\UserInfo;
|
||||||
class MessagesDatabase {
|
class MessagesDatabase {
|
||||||
private DbStatementCache $cache;
|
private DbStatementCache $cache;
|
||||||
|
|
||||||
public function __construct(private IDbConnection $dbConn) {
|
public function __construct(IDbConnection $dbConn) {
|
||||||
$this->cache = new DbStatementCache($dbConn);
|
$this->cache = new DbStatementCache($dbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class MessagesDatabase {
|
||||||
?bool $read = null,
|
?bool $read = null,
|
||||||
?bool $deleted = null,
|
?bool $deleted = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
$hasOwnerInfo = $ownerInfo !== null;
|
$hasOwnerInfo = $ownerInfo !== null;
|
||||||
$hasAuthorInfo = $authorInfo !== null;
|
$hasAuthorInfo = $authorInfo !== null;
|
||||||
$hasRecipientInfo = $recipientInfo !== null;
|
$hasRecipientInfo = $recipientInfo !== null;
|
||||||
|
@ -104,7 +104,7 @@ class MessagesDatabase {
|
||||||
$hasPagination = $pagination !== null;
|
$hasPagination = $pagination !== null;
|
||||||
|
|
||||||
$args = 0;
|
$args = 0;
|
||||||
$query = 'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages';
|
$query = 'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages';
|
||||||
if($hasOwnerInfo) {
|
if($hasOwnerInfo) {
|
||||||
++$args;
|
++$args;
|
||||||
$query .= ' WHERE msg_owner_id = ?';
|
$query .= ' WHERE msg_owner_id = ?';
|
||||||
|
@ -153,13 +153,7 @@ class MessagesDatabase {
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$infos = [];
|
return $stmt->getResult()->getIterator(MessageInfo::fromResult(...));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$infos[] = new MessageInfo($result);
|
|
||||||
|
|
||||||
return $infos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMessageInfo(
|
public function getMessageInfo(
|
||||||
|
@ -168,7 +162,7 @@ class MessagesDatabase {
|
||||||
bool $useReplyTo = false
|
bool $useReplyTo = false
|
||||||
): MessageInfo {
|
): MessageInfo {
|
||||||
$stmt = $this->cache->get(sprintf(
|
$stmt = $this->cache->get(sprintf(
|
||||||
'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages WHERE msg_id = %s AND msg_owner_id = ?',
|
'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, FROM_BASE64(msg_title), FROM_BASE64(msg_body), msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages WHERE msg_id = %s AND msg_owner_id = ?',
|
||||||
!$useReplyTo || $messageInfoOrId instanceof MessageInfo ? '?' : '(SELECT msg_reply_to FROM msz_messages WHERE msg_id = ?)'
|
!$useReplyTo || $messageInfoOrId instanceof MessageInfo ? '?' : '(SELECT msg_reply_to FROM msz_messages WHERE msg_id = ?)'
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -183,7 +177,7 @@ class MessagesDatabase {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Message not found.');
|
throw new RuntimeException('Message not found.');
|
||||||
|
|
||||||
return new MessageInfo($result);
|
return MessageInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createMessage(
|
public function createMessage(
|
||||||
|
@ -198,7 +192,7 @@ class MessagesDatabase {
|
||||||
DateTime|int|null $sentAt = null,
|
DateTime|int|null $sentAt = null,
|
||||||
DateTime|int|null $readAt = null
|
DateTime|int|null $readAt = null
|
||||||
): MessageInfo {
|
): MessageInfo {
|
||||||
$stmt = $this->cache->get('INSERT INTO msz_messages (msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, msg_sent, msg_read) VALUES (?, ?, ?, ?, ?, ?, ?, ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))');
|
$stmt = $this->cache->get('INSERT INTO msz_messages (msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, msg_sent, msg_read) VALUES (?, ?, ?, ?, ?, TO_BASE64(?), TO_BASE64(?), ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))');
|
||||||
$stmt->addParameter(1, $messageId);
|
$stmt->addParameter(1, $messageId);
|
||||||
$stmt->addParameter(2, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
$stmt->addParameter(2, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||||||
$stmt->addParameter(3, $authorInfo instanceof UserInfo ? $authorInfo->getId() : $authorInfo);
|
$stmt->addParameter(3, $authorInfo instanceof UserInfo ? $authorInfo->getId() : $authorInfo);
|
||||||
|
@ -239,12 +233,12 @@ class MessagesDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
if($title !== null) {
|
if($title !== null) {
|
||||||
$setQuery[] = 'msg_title = ?';
|
$setQuery[] = 'msg_title = TO_BASE64(?)';
|
||||||
$setValues[] = $title;
|
$setValues[] = $title;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($body !== null) {
|
if($body !== null) {
|
||||||
$setQuery[] = 'msg_body = ?';
|
$setQuery[] = 'msg_body = TO_BASE64(?)';
|
||||||
$setValues[] = $body;
|
$setValues[] = $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use stdClass;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\XString;
|
use Index\XString;
|
||||||
use Index\Routing\{Route,RouteHandler};
|
use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler};
|
||||||
use Syokuhou\IConfig;
|
use Syokuhou\IConfig;
|
||||||
use Misuzu\{CSRF,Pagination,Perm,Template};
|
use Misuzu\{CSRF,Pagination,Perm,Template};
|
||||||
use Misuzu\Auth\AuthInfo;
|
use Misuzu\Auth\AuthInfo;
|
||||||
|
@ -33,12 +33,16 @@ class MessagesRoutes extends RouteHandler {
|
||||||
|
|
||||||
private bool $canSendMessages;
|
private bool $canSendMessages;
|
||||||
|
|
||||||
#[Route('/messages')]
|
#[HttpMiddleware('/messages')]
|
||||||
public function checkAccess($response, $request) {
|
public function checkAccess($response, $request) {
|
||||||
// should probably be a permission or something too
|
// should probably be a permission or something too
|
||||||
if(!$this->authInfo->isLoggedIn())
|
if(!$this->authInfo->isLoggedIn())
|
||||||
return 401;
|
return 401;
|
||||||
|
|
||||||
|
// do not allow access to PMs when impersonating in production mode
|
||||||
|
if(!MSZ_DEBUG && $this->authInfo->isImpersonating())
|
||||||
|
return 403;
|
||||||
|
|
||||||
$globalPerms = $this->authInfo->getPerms('global');
|
$globalPerms = $this->authInfo->getPerms('global');
|
||||||
if(!$globalPerms->check(Perm::G_MESSAGES_VIEW))
|
if(!$globalPerms->check(Perm::G_MESSAGES_VIEW))
|
||||||
return 403;
|
return 403;
|
||||||
|
@ -72,7 +76,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/messages')]
|
#[HttpGet('/messages')]
|
||||||
#[URLInfo('messages-index', '/messages', ['folder' => '<folder>', 'page' => '<page>'])]
|
#[URLInfo('messages-index', '/messages', ['folder' => '<folder>', 'page' => '<page>'])]
|
||||||
public function getIndex($response, $request, string $folderName = '') {
|
public function getIndex($response, $request, string $folderName = '') {
|
||||||
$folderName = (string)$request->getParam('folder');
|
$folderName = (string)$request->getParam('folder');
|
||||||
|
@ -125,7 +129,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/messages/stats')]
|
#[HttpGet('/messages/stats')]
|
||||||
#[URLInfo('messages-stats', '/messages/stats')]
|
#[URLInfo('messages-stats', '/messages/stats')]
|
||||||
public function getStats() {
|
public function getStats() {
|
||||||
$selfInfo = $this->authInfo->getUserInfo();
|
$selfInfo = $this->authInfo->getUserInfo();
|
||||||
|
@ -142,7 +146,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/recipient')]
|
#[HttpPost('/messages/recipient')]
|
||||||
#[URLInfo('messages-recipient', '/messages/recipient')]
|
#[URLInfo('messages-recipient', '/messages/recipient')]
|
||||||
public function postRecipient($response, $request) {
|
public function postRecipient($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
|
@ -182,7 +186,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/messages/compose')]
|
#[HttpGet('/messages/compose')]
|
||||||
#[URLInfo('messages-compose', '/messages/compose', ['recipient' => '<recipient>'])]
|
#[URLInfo('messages-compose', '/messages/compose', ['recipient' => '<recipient>'])]
|
||||||
public function getEditor($response, $request) {
|
public function getEditor($response, $request) {
|
||||||
if(!$this->canSendMessages)
|
if(!$this->canSendMessages)
|
||||||
|
@ -193,7 +197,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/messages/:message')]
|
#[HttpGet('/messages/([A-Za-z0-9]+)')]
|
||||||
#[URLInfo('messages-view', '/messages/<message>')]
|
#[URLInfo('messages-view', '/messages/<message>')]
|
||||||
public function getView($response, $request, string $messageId) {
|
public function getView($response, $request, string $messageId) {
|
||||||
if(strlen($messageId) !== 8)
|
if(strlen($messageId) !== 8)
|
||||||
|
@ -323,7 +327,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/create')]
|
#[HttpPost('/messages/create')]
|
||||||
#[URLInfo('messages-create', '/messages/create')]
|
#[URLInfo('messages-create', '/messages/create')]
|
||||||
public function postCreate($response, $request) {
|
public function postCreate($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
|
@ -427,7 +431,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/:message')]
|
#[HttpPost('/messages/([A-Za-z0-9]+)')]
|
||||||
#[URLInfo('messages-update', '/messages/<message>')]
|
#[URLInfo('messages-update', '/messages/<message>')]
|
||||||
public function postUpdate($response, $request, string $messageId) {
|
public function postUpdate($response, $request, string $messageId) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
|
@ -518,7 +522,7 @@ class MessagesRoutes extends RouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/mark')]
|
#[HttpPost('/messages/mark')]
|
||||||
#[URLInfo('messages-mark', '/messages/mark')]
|
#[URLInfo('messages-mark', '/messages/mark')]
|
||||||
public function postMark($response, $request) {
|
public function postMark($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
|
@ -549,16 +553,16 @@ class MessagesRoutes extends RouteHandler {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/delete')]
|
#[HttpPost('/messages/delete')]
|
||||||
#[URLInfo('messages-delete', '/messages/delete')]
|
#[URLInfo('messages-delete', '/messages/delete')]
|
||||||
public function postDelete($response, $request) {
|
public function postDelete($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
return 400;
|
return 400;
|
||||||
|
|
||||||
$content = $request->getContent();
|
$content = $request->getContent();
|
||||||
$messages = explode(',', (string)$content->getParam('messages'));
|
|
||||||
|
|
||||||
if(empty($messages))
|
$messages = (string)$content->getParam('messages');
|
||||||
|
if($messages === '')
|
||||||
return [
|
return [
|
||||||
'error' => [
|
'error' => [
|
||||||
'name' => 'msgs:empty',
|
'name' => 'msgs:empty',
|
||||||
|
@ -566,6 +570,8 @@ class MessagesRoutes extends RouteHandler {
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$messages = explode(',', $messages);
|
||||||
|
|
||||||
$this->msgsCtx->getDatabase()->deleteMessages(
|
$this->msgsCtx->getDatabase()->deleteMessages(
|
||||||
$this->authInfo->getUserInfo(),
|
$this->authInfo->getUserInfo(),
|
||||||
$messages
|
$messages
|
||||||
|
@ -574,16 +580,16 @@ class MessagesRoutes extends RouteHandler {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/restore')]
|
#[HttpPost('/messages/restore')]
|
||||||
#[URLInfo('messages-restore', '/messages/restore')]
|
#[URLInfo('messages-restore', '/messages/restore')]
|
||||||
public function postRestore($response, $request) {
|
public function postRestore($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
return 400;
|
return 400;
|
||||||
|
|
||||||
$content = $request->getContent();
|
$content = $request->getContent();
|
||||||
$messages = explode(',', (string)$content->getParam('messages'));
|
|
||||||
|
|
||||||
if(empty($messages))
|
$messages = (string)$content->getParam('messages');
|
||||||
|
if($messages === '')
|
||||||
return [
|
return [
|
||||||
'error' => [
|
'error' => [
|
||||||
'name' => 'msgs:empty',
|
'name' => 'msgs:empty',
|
||||||
|
@ -591,6 +597,8 @@ class MessagesRoutes extends RouteHandler {
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$messages = explode(',', $messages);
|
||||||
|
|
||||||
$this->msgsCtx->getDatabase()->restoreMessages(
|
$this->msgsCtx->getDatabase()->restoreMessages(
|
||||||
$this->authInfo->getUserInfo(),
|
$this->authInfo->getUserInfo(),
|
||||||
$messages
|
$messages
|
||||||
|
@ -599,16 +607,16 @@ class MessagesRoutes extends RouteHandler {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/messages/nuke')]
|
#[HttpPost('/messages/nuke')]
|
||||||
#[URLInfo('messages-nuke', '/messages/nuke')]
|
#[URLInfo('messages-nuke', '/messages/nuke')]
|
||||||
public function postNuke($response, $request) {
|
public function postNuke($response, $request) {
|
||||||
if(!$request->isFormContent())
|
if(!$request->isFormContent())
|
||||||
return 400;
|
return 400;
|
||||||
|
|
||||||
$content = $request->getContent();
|
$content = $request->getContent();
|
||||||
$messages = explode(',', (string)$content->getParam('messages'));
|
|
||||||
|
|
||||||
if(empty($messages))
|
$messages = (string)$content->getParam('messages');
|
||||||
|
if($messages === '')
|
||||||
return [
|
return [
|
||||||
'error' => [
|
'error' => [
|
||||||
'name' => 'msgs:empty',
|
'name' => 'msgs:empty',
|
||||||
|
@ -616,6 +624,8 @@ class MessagesRoutes extends RouteHandler {
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$messages = explode(',', $messages);
|
||||||
|
|
||||||
$this->msgsCtx->getDatabase()->nukeMessages(
|
$this->msgsCtx->getDatabase()->nukeMessages(
|
||||||
$this->authInfo->getUserInfo(),
|
$this->authInfo->getUserInfo(),
|
||||||
$messages
|
$messages
|
||||||
|
|
|
@ -212,7 +212,6 @@ class MisuzuContext {
|
||||||
$routingCtx = new RoutingContext();
|
$routingCtx = new RoutingContext();
|
||||||
|
|
||||||
$this->urls = $routingCtx->getURLs();
|
$this->urls = $routingCtx->getURLs();
|
||||||
$routingCtx->registerDefaultErrorPages();
|
|
||||||
|
|
||||||
$routingCtx->register(new \Misuzu\Home\HomeRoutes(
|
$routingCtx->register(new \Misuzu\Home\HomeRoutes(
|
||||||
$this->config,
|
$this->config,
|
||||||
|
@ -263,6 +262,7 @@ class MisuzuContext {
|
||||||
|
|
||||||
$routingCtx->register(new \Misuzu\SharpChat\SharpChatRoutes(
|
$routingCtx->register(new \Misuzu\SharpChat\SharpChatRoutes(
|
||||||
$this->config->scopeTo('sockChat'),
|
$this->config->scopeTo('sockChat'),
|
||||||
|
$this->config->scopeTo('impersonate'),
|
||||||
$this->urls,
|
$this->urls,
|
||||||
$this->usersCtx,
|
$this->usersCtx,
|
||||||
$this->authCtx,
|
$this->authCtx,
|
||||||
|
|
|
@ -41,7 +41,7 @@ class News {
|
||||||
public function getCategories(
|
public function getCategories(
|
||||||
?bool $hidden = null,
|
?bool $hidden = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
$hasHidden = $hidden !== null;
|
$hasHidden = $hidden !== null;
|
||||||
$hasPagination = $pagination !== null;
|
$hasPagination = $pagination !== null;
|
||||||
|
|
||||||
|
@ -61,13 +61,7 @@ class News {
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(NewsCategoryInfo::fromResult(...));
|
||||||
$categories = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$categories[] = new NewsCategoryInfo($result);
|
|
||||||
|
|
||||||
return $categories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategory(
|
public function getCategory(
|
||||||
|
@ -107,7 +101,7 @@ class News {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('News category not found.');
|
throw new RuntimeException('News category not found.');
|
||||||
|
|
||||||
return new NewsCategoryInfo($result);
|
return NewsCategoryInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createCategory(
|
public function createCategory(
|
||||||
|
@ -224,7 +218,7 @@ class News {
|
||||||
bool $includeScheduled = false,
|
bool $includeScheduled = false,
|
||||||
bool $includeDeleted = false,
|
bool $includeDeleted = false,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($categoryInfo instanceof NewsCategoryInfo)
|
if($categoryInfo instanceof NewsCategoryInfo)
|
||||||
$categoryInfo = $categoryInfo->getId();
|
$categoryInfo = $categoryInfo->getId();
|
||||||
|
|
||||||
|
@ -271,13 +265,7 @@ class News {
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(NewsPostInfo::fromResult(...));
|
||||||
$posts = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$posts[] = new NewsPostInfo($result);
|
|
||||||
|
|
||||||
return $posts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPost(string $postId): NewsPostInfo {
|
public function getPost(string $postId): NewsPostInfo {
|
||||||
|
@ -289,7 +277,7 @@ class News {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No news post with that ID exists.');
|
throw new RuntimeException('No news post with that ID exists.');
|
||||||
|
|
||||||
return new NewsPostInfo($result);
|
return NewsPostInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPost(
|
public function createPost(
|
||||||
|
|
|
@ -5,20 +5,24 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class NewsCategoryInfo {
|
class NewsCategoryInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $name;
|
private string $id,
|
||||||
private string $description;
|
private string $name,
|
||||||
private bool $hidden;
|
private string $description,
|
||||||
private int $created;
|
private bool $hidden,
|
||||||
private int $posts;
|
private int $created,
|
||||||
|
private int $posts,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): NewsCategoryInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new NewsCategoryInfo(
|
||||||
$this->name = $result->getString(1);
|
id: $result->getString(0),
|
||||||
$this->description = $result->getString(2);
|
name: $result->getString(1),
|
||||||
$this->hidden = $result->getInteger(3) !== 0;
|
description: $result->getString(2),
|
||||||
$this->created = $result->getInteger(4);
|
hidden: $result->getBoolean(3),
|
||||||
$this->posts = $result->getInteger(5);
|
created: $result->getInteger(4),
|
||||||
|
posts: $result->getInteger(5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -5,30 +5,34 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class NewsPostInfo {
|
class NewsPostInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $categoryId;
|
private string $id,
|
||||||
private ?string $userId;
|
private string $categoryId,
|
||||||
private ?string $commentsSectionId;
|
private ?string $userId,
|
||||||
private bool $featured;
|
private ?string $commentsSectionId,
|
||||||
private string $title;
|
private bool $featured,
|
||||||
private string $body;
|
private string $title,
|
||||||
private int $scheduled;
|
private string $body,
|
||||||
private int $created;
|
private int $scheduled,
|
||||||
private int $updated;
|
private int $created,
|
||||||
private ?int $deleted;
|
private int $updated,
|
||||||
|
private ?int $deleted,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): NewsPostInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new NewsPostInfo(
|
||||||
$this->categoryId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->userId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
categoryId: $result->getString(1),
|
||||||
$this->commentsSectionId = $result->isNull(3) ? null : (string)$result->getInteger(3);
|
userId: $result->getStringOrNull(2),
|
||||||
$this->featured = $result->getInteger(4) !== 0;
|
commentsSectionId: $result->getStringOrNull(3),
|
||||||
$this->title = $result->getString(5);
|
featured: $result->getBoolean(4),
|
||||||
$this->body = $result->getString(6);
|
title: $result->getString(5),
|
||||||
$this->scheduled = $result->getInteger(7);
|
body: $result->getString(6),
|
||||||
$this->created = $result->getInteger(8);
|
scheduled: $result->getInteger(7),
|
||||||
$this->updated = $result->getInteger(9);
|
created: $result->getInteger(8),
|
||||||
$this->deleted = $result->isNull(10) ? null : $result->getInteger(10);
|
updated: $result->getInteger(9),
|
||||||
|
deleted: $result->getIntegerOrNull(10),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -3,24 +3,14 @@ namespace Misuzu\News;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use Index\DateTime;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\{DbTools,IDbConnection};
|
||||||
use Index\Data\IDbConnection;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\Route;
|
use Misuzu\{Pagination,SiteInfo,Template};
|
||||||
use Index\Routing\RouteHandler;
|
|
||||||
use Misuzu\Pagination;
|
|
||||||
use Misuzu\SiteInfo;
|
|
||||||
use Misuzu\Template;
|
|
||||||
use Misuzu\Auth\AuthInfo;
|
use Misuzu\Auth\AuthInfo;
|
||||||
use Misuzu\Comments\Comments;
|
use Misuzu\Comments\{Comments,CommentsCategory,CommentsEx};
|
||||||
use Misuzu\Comments\CommentsCategory;
|
use Misuzu\Feeds\{Feed,FeedItem,AtomFeedSerializer,RssFeedSerializer};
|
||||||
use Misuzu\Comments\CommentsEx;
|
|
||||||
use Misuzu\Feeds\Feed;
|
|
||||||
use Misuzu\Feeds\FeedItem;
|
|
||||||
use Misuzu\Feeds\AtomFeedSerializer;
|
|
||||||
use Misuzu\Feeds\RssFeedSerializer;
|
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
use Misuzu\URLs\URLInfo;
|
use Misuzu\URLs\{URLInfo,URLRegistry};
|
||||||
use Misuzu\URLs\URLRegistry;
|
|
||||||
use Misuzu\Users\UsersContext;
|
use Misuzu\Users\UsersContext;
|
||||||
|
|
||||||
class NewsRoutes extends RouteHandler {
|
class NewsRoutes extends RouteHandler {
|
||||||
|
@ -91,7 +81,7 @@ class NewsRoutes extends RouteHandler {
|
||||||
return $posts;
|
return $posts;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news')]
|
#[HttpGet('/news')]
|
||||||
#[URLInfo('news-index', '/news', ['p' => '<page>'])]
|
#[URLInfo('news-index', '/news', ['p' => '<page>'])]
|
||||||
public function getIndex() {
|
public function getIndex() {
|
||||||
$categories = $this->news->getCategories(hidden: false);
|
$categories = $this->news->getCategories(hidden: false);
|
||||||
|
@ -109,24 +99,21 @@ class NewsRoutes extends RouteHandler {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news.rss')]
|
#[HttpGet('/news.rss')]
|
||||||
#[URLInfo('news-feed-rss', '/news.rss')]
|
#[URLInfo('news-feed-rss', '/news.rss')]
|
||||||
public function getFeedRss($response) {
|
public function getFeedRss($response) {
|
||||||
return $this->getFeed($response, 'rss');
|
return $this->getFeed($response, 'rss');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news.atom')]
|
#[HttpGet('/news.atom')]
|
||||||
#[URLInfo('news-feed-atom', '/news.atom')]
|
#[URLInfo('news-feed-atom', '/news.atom')]
|
||||||
public function getFeedAtom($response) {
|
public function getFeedAtom($response) {
|
||||||
return $this->getFeed($response, 'atom');
|
return $this->getFeed($response, 'atom');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/:category')]
|
#[HttpGet('/news/([0-9]+)(?:\.(rss|atom))?')]
|
||||||
#[URLInfo('news-category', '/news/<category>', ['p' => '<page>'])]
|
#[URLInfo('news-category', '/news/<category>', ['p' => '<page>'])]
|
||||||
public function getCategory($response, $request, string $fileName) {
|
public function getCategory($response, $request, string $categoryId, string $type = '') {
|
||||||
$categoryId = pathinfo($fileName, PATHINFO_FILENAME);
|
|
||||||
$type = pathinfo($fileName, PATHINFO_EXTENSION);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$categoryInfo = $this->news->getCategory(categoryId: $categoryId);
|
$categoryInfo = $this->news->getCategory(categoryId: $categoryId);
|
||||||
} catch(RuntimeException $ex) {
|
} catch(RuntimeException $ex) {
|
||||||
|
@ -163,7 +150,7 @@ class NewsRoutes extends RouteHandler {
|
||||||
return $this->getFeed($response, 'atom', $categoryInfo);
|
return $this->getFeed($response, 'atom', $categoryInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/news/post/:id')]
|
#[HttpGet('/news/post/([0-9]+)')]
|
||||||
#[URLInfo('news-post', '/news/post/<post>')]
|
#[URLInfo('news-post', '/news/post/<post>')]
|
||||||
#[URLInfo('news-post-comments', '/news/post/<post>', fragment: 'comments')]
|
#[URLInfo('news-post-comments', '/news/post/<post>', fragment: 'comments')]
|
||||||
public function getPost($response, $request, string $postId) {
|
public function getPost($response, $request, string $postId) {
|
||||||
|
|
|
@ -6,24 +6,30 @@ use Index\Data\IDbResult;
|
||||||
class PermissionInfo implements IPermissionResult {
|
class PermissionInfo implements IPermissionResult {
|
||||||
use PermissionResultShared;
|
use PermissionResultShared;
|
||||||
|
|
||||||
private ?string $userId;
|
|
||||||
private ?string $roleId;
|
|
||||||
private ?string $forumCategoryId;
|
|
||||||
private string $category;
|
|
||||||
private int $allow;
|
|
||||||
private int $deny;
|
|
||||||
private int $calculated;
|
private int $calculated;
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public function __construct(
|
||||||
$this->userId = $result->isNull(0) ? null : $result->getString(0);
|
private ?string $userId,
|
||||||
$this->roleId = $result->isNull(1) ? null : $result->getString(1);
|
private ?string $roleId,
|
||||||
$this->forumCategoryId = $result->isNull(2) ? null : $result->getString(2);
|
private ?string $forumCategoryId,
|
||||||
$this->category = $result->getString(3);
|
private string $category,
|
||||||
$this->allow = $result->getInteger(4);
|
private int $allow,
|
||||||
$this->deny = $result->getInteger(5);
|
private int $deny,
|
||||||
|
) {
|
||||||
$this->calculated = $this->allow & ~$this->deny;
|
$this->calculated = $this->allow & ~$this->deny;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromResult(IDbResult $result): PermissionInfo {
|
||||||
|
return new PermissionInfo(
|
||||||
|
userId: $result->getStringOrNull(0),
|
||||||
|
roleId: $result->getStringOrNull(1),
|
||||||
|
forumCategoryId: $result->getStringOrNull(2),
|
||||||
|
category: $result->getString(3),
|
||||||
|
allow: $result->getInteger(4),
|
||||||
|
deny: $result->getInteger(5),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function hasUserId(): bool {
|
public function hasUserId(): bool {
|
||||||
return $this->userId !== null;
|
return $this->userId !== null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,11 +76,11 @@ class Permissions {
|
||||||
$result = $stmt->getResult();
|
$result = $stmt->getResult();
|
||||||
|
|
||||||
if(is_string($categoryNames))
|
if(is_string($categoryNames))
|
||||||
return $result->next() ? new PermissionInfo($result) : null;
|
return $result->next() ? PermissionInfo::fromResult($result) : null;
|
||||||
|
|
||||||
$perms = [];
|
$perms = [];
|
||||||
while($result->next())
|
while($result->next())
|
||||||
$perms[$result->getString(3)] = new PermissionInfo($result);
|
$perms[$result->getString(3)] = PermissionInfo::fromResult($result);
|
||||||
|
|
||||||
return $perms;
|
return $perms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,22 @@ namespace Misuzu\Profile;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ProfileFieldFormatInfo {
|
class ProfileFieldFormatInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $fieldId;
|
private string $id,
|
||||||
private ?string $regex;
|
private string $fieldId,
|
||||||
private ?string $linkFormat;
|
private ?string $regex,
|
||||||
private string $displayFormat;
|
private ?string $linkFormat,
|
||||||
|
private string $displayFormat,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ProfileFieldFormatInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ProfileFieldFormatInfo(
|
||||||
$this->fieldId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->regex = $result->isNull(2) ? null : $result->getString(2);
|
fieldId: $result->getString(1),
|
||||||
$this->linkFormat = $result->isNull(3) ? null : $result->getString(3);
|
regex: $result->getStringOrNull(2),
|
||||||
$this->displayFormat = $result->getString(4);
|
linkFormat: $result->getStringOrNull(3),
|
||||||
|
displayFormat: $result->getString(4),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -4,18 +4,22 @@ namespace Misuzu\Profile;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ProfileFieldInfo {
|
class ProfileFieldInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private int $order;
|
private string $id,
|
||||||
private string $name;
|
private int $order,
|
||||||
private string $title;
|
private string $name,
|
||||||
private string $regex;
|
private string $title,
|
||||||
|
private string $regex,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ProfileFieldInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new ProfileFieldInfo(
|
||||||
$this->order = $result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->name = $result->getString(2);
|
order: $result->getInteger(1),
|
||||||
$this->title = $result->getString(3);
|
name: $result->getString(2),
|
||||||
$this->regex = $result->getString(4);
|
title: $result->getString(3),
|
||||||
|
regex: $result->getString(4),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -4,16 +4,20 @@ namespace Misuzu\Profile;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ProfileFieldValueInfo {
|
class ProfileFieldValueInfo {
|
||||||
private string $fieldId;
|
public function __construct(
|
||||||
private string $userId;
|
private string $fieldId,
|
||||||
private string $formatId;
|
private string $userId,
|
||||||
private string $value;
|
private string $formatId,
|
||||||
|
private string $value,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ProfileFieldValueInfo {
|
||||||
$this->fieldId = (string)$result->getInteger(0);
|
return new ProfileFieldValueInfo(
|
||||||
$this->userId = (string)$result->getInteger(1);
|
fieldId: $result->getString(0),
|
||||||
$this->formatId = (string)$result->getInteger(2);
|
userId: $result->getString(1),
|
||||||
$this->value = $result->getString(3);
|
formatId: $result->getString(2),
|
||||||
|
value: $result->getString(3)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldId(): string {
|
public function getFieldId(): string {
|
||||||
|
|
|
@ -16,10 +16,15 @@ class ProfileFields {
|
||||||
$this->cache = new DbStatementCache($dbConn);
|
$this->cache = new DbStatementCache($dbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFields(?array $fieldValueInfos = null): array {
|
public function getFields(?iterable $fieldValueInfos = null): iterable {
|
||||||
$hasFieldValueInfos = $fieldValueInfos !== null;
|
$hasFieldValueInfos = $fieldValueInfos !== null;
|
||||||
if($hasFieldValueInfos && empty($fieldValueInfos))
|
if($hasFieldValueInfos) {
|
||||||
|
if(!is_array($fieldValueInfos))
|
||||||
|
$fieldValueInfos = iterator_to_array($fieldValueInfos);
|
||||||
|
|
||||||
|
if(empty($fieldValueInfos))
|
||||||
return [];
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$query = 'SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields';
|
$query = 'SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields';
|
||||||
if($hasFieldValueInfos)
|
if($hasFieldValueInfos)
|
||||||
|
@ -37,13 +42,8 @@ class ProfileFields {
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->getResult();
|
|
||||||
$fields = [];
|
|
||||||
|
|
||||||
while($result->next())
|
return $stmt->getResult()->getIterator(ProfileFieldInfo::fromResult(...));
|
||||||
$fields[] = new ProfileFieldInfo($result);
|
|
||||||
|
|
||||||
return $fields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getField(string $fieldId): ProfileFieldInfo {
|
public function getField(string $fieldId): ProfileFieldInfo {
|
||||||
|
@ -55,20 +55,30 @@ class ProfileFields {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No field found with the provided field id.');
|
throw new RuntimeException('No field found with the provided field id.');
|
||||||
|
|
||||||
return new ProfileFieldInfo($result);
|
return ProfileFieldInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldFormats(
|
public function getFieldFormats(
|
||||||
?array $fieldInfos = null,
|
?iterable $fieldInfos = null,
|
||||||
?array $fieldValueInfos = null
|
?iterable $fieldValueInfos = null
|
||||||
): array {
|
): iterable {
|
||||||
$hasFieldInfos = $fieldInfos !== null;
|
$hasFieldInfos = $fieldInfos !== null;
|
||||||
$hasFieldValueInfos = $fieldValueInfos !== null;
|
$hasFieldValueInfos = $fieldValueInfos !== null;
|
||||||
|
|
||||||
if($hasFieldInfos && empty($fieldInfos))
|
if($hasFieldInfos) {
|
||||||
|
if(!is_array($fieldInfos))
|
||||||
|
$fieldInfos = iterator_to_array($fieldInfos);
|
||||||
|
|
||||||
|
if(empty($fieldInfos))
|
||||||
return [];
|
return [];
|
||||||
if($hasFieldValueInfos && empty($fieldValueInfos))
|
}
|
||||||
|
if($hasFieldValueInfos) {
|
||||||
|
if(!is_array($fieldValueInfos))
|
||||||
|
$fieldValueInfos = iterator_to_array($fieldValueInfos);
|
||||||
|
|
||||||
|
if(empty($fieldValueInfos))
|
||||||
return [];
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$args = 0;
|
$args = 0;
|
||||||
$query = 'SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats';
|
$query = 'SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats';
|
||||||
|
@ -101,13 +111,8 @@ class ProfileFields {
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->getResult();
|
|
||||||
$formats = [];
|
|
||||||
|
|
||||||
while($result->next())
|
return $stmt->getResult()->getIterator(ProfileFieldFormatInfo::fromResult(...));
|
||||||
$formats[] = new ProfileFieldFormatInfo($result);
|
|
||||||
|
|
||||||
return $formats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldFormat(string $formatId): ProfileFieldFormatInfo {
|
public function getFieldFormat(string $formatId): ProfileFieldFormatInfo {
|
||||||
|
@ -119,7 +124,7 @@ class ProfileFields {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No format found with the provided format id.');
|
throw new RuntimeException('No format found with the provided format id.');
|
||||||
|
|
||||||
return new ProfileFieldFormatInfo($result);
|
return ProfileFieldFormatInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selectFieldFormat(
|
public function selectFieldFormat(
|
||||||
|
@ -138,10 +143,10 @@ class ProfileFields {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Could not determine an appropriate format for this field (missing default formatting)');
|
throw new RuntimeException('Could not determine an appropriate format for this field (missing default formatting)');
|
||||||
|
|
||||||
return new ProfileFieldFormatInfo($result);
|
return ProfileFieldFormatInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldValues(UserInfo|string $userInfo): array {
|
public function getFieldValues(UserInfo|string $userInfo): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -151,13 +156,7 @@ class ProfileFields {
|
||||||
$stmt->addParameter(1, $userInfo);
|
$stmt->addParameter(1, $userInfo);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ProfileFieldValueInfo::fromResult(...));
|
||||||
$values = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$values[] = new ProfileFieldValueInfo($result);
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldValue(
|
public function getFieldValue(
|
||||||
|
@ -179,7 +178,7 @@ class ProfileFields {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No value for this field and user combination found.');
|
throw new RuntimeException('No value for this field and user combination found.');
|
||||||
|
|
||||||
return new ProfileFieldValueInfo($result);
|
return ProfileFieldValueInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFieldValues(
|
public function setFieldValues(
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\Http\HttpFx;
|
use Index\Http\Routing\{HttpRouter,IRouter,IRouteHandler};
|
||||||
use Index\Http\HttpRequest;
|
use Misuzu\URLs\{IURLSource,URLInfo,URLRegistry};
|
||||||
use Index\Routing\IRouter;
|
|
||||||
use Index\Routing\IRouteHandler;
|
|
||||||
use Misuzu\URLs\IURLSource;
|
|
||||||
use Misuzu\URLs\URLInfo;
|
|
||||||
use Misuzu\URLs\URLRegistry;
|
|
||||||
|
|
||||||
class RoutingContext {
|
class RoutingContext {
|
||||||
private URLRegistry $urls;
|
private URLRegistry $urls;
|
||||||
private HttpFx $router;
|
private HttpRouter $router;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->urls = new URLRegistry;
|
$this->urls = new URLRegistry;
|
||||||
$this->router = new HttpFx;
|
$this->router = new HttpRouter(errorHandler: new RoutingErrorHandler);
|
||||||
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
|
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,25 +22,6 @@ class RoutingContext {
|
||||||
return $this->router;
|
return $this->router;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerDefaultErrorPages(): void {
|
|
||||||
$this->router->addErrorHandler(400, fn($resp) => $resp->setContent(Template::renderRaw('errors.400')));
|
|
||||||
$this->router->addErrorHandler(403, fn($resp) => $resp->setContent(Template::renderRaw('errors.403')));
|
|
||||||
$this->router->addErrorHandler(404, fn($resp) => $resp->setContent(Template::renderRaw('errors.404')));
|
|
||||||
$this->router->addErrorHandler(500, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/500.html')));
|
|
||||||
$this->router->addErrorHandler(503, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/503.html')));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function registerSimpleErrorPages(IRouter $router, string $path): void {
|
|
||||||
if($router instanceof HttpFx)
|
|
||||||
$router->use($path, function() use($router) {
|
|
||||||
$router->addErrorHandler(400, fn($resp) => $resp->setContent('HTTP 400'));
|
|
||||||
$router->addErrorHandler(403, fn($resp) => $resp->setContent('HTTP 403'));
|
|
||||||
$router->addErrorHandler(404, fn($resp) => $resp->setContent('HTTP 404'));
|
|
||||||
$router->addErrorHandler(500, fn($resp) => $resp->setContent('HTTP 500'));
|
|
||||||
$router->addErrorHandler(503, fn($resp) => $resp->setContent('HTTP 503'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function register(IRouteHandler|IURLSource $handler): void {
|
public function register(IRouteHandler|IURLSource $handler): void {
|
||||||
if($handler instanceof IRouteHandler)
|
if($handler instanceof IRouteHandler)
|
||||||
$this->router->register($handler);
|
$this->router->register($handler);
|
||||||
|
@ -54,7 +30,7 @@ class RoutingContext {
|
||||||
URLInfo::handleAttributes($this->urls, $handler);
|
URLInfo::handleAttributes($this->urls, $handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(?HttpRequest $request = null): void {
|
public function dispatch(...$args): void {
|
||||||
$this->router->dispatch($request);
|
$this->router->dispatch(...$args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
src/RoutingErrorHandler.php
Normal file
29
src/RoutingErrorHandler.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use Index\Http\{HttpResponseBuilder,HttpRequest};
|
||||||
|
use Index\Http\ErrorHandling\HtmlErrorHandler;
|
||||||
|
|
||||||
|
class RoutingErrorHandler extends HtmlErrorHandler {
|
||||||
|
public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void {
|
||||||
|
if(str_starts_with($request->getPath(), '/_')) {
|
||||||
|
$response->setTypePlain();
|
||||||
|
$response->setContent(sprintf('HTTP %03d', $code));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($code === 500 || $code === 503) {
|
||||||
|
$response->setTypeHTML();
|
||||||
|
$response->setContent(file_get_contents(sprintf('%s/%03d.html', MSZ_TEMPLATES, $code)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($code === 401 || $code === 403 || $code === 404) {
|
||||||
|
$response->setTypeHTML();
|
||||||
|
$response->setContent(Template::renderRaw(sprintf('errors.%03d', $code)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::handle($response, $request, $code, $message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,7 @@ namespace Misuzu\Satori;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Routing\IRouter;
|
use Index\Http\Routing\{HttpGet,HttpMiddleware,RouteHandler};
|
||||||
use Index\Routing\IRouteHandler;
|
|
||||||
use Index\Routing\Route;
|
|
||||||
use Syokuhou\IConfig;
|
use Syokuhou\IConfig;
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\RoutingContext;
|
use Misuzu\RoutingContext;
|
||||||
|
@ -13,7 +11,7 @@ use Misuzu\Forum\ForumContext;
|
||||||
use Misuzu\Profile\ProfileFields;
|
use Misuzu\Profile\ProfileFields;
|
||||||
use Misuzu\Users\UsersContext;
|
use Misuzu\Users\UsersContext;
|
||||||
|
|
||||||
final class SatoriRoutes implements IRouteHandler {
|
final class SatoriRoutes extends RouteHandler {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private IConfig $config,
|
private IConfig $config,
|
||||||
private UsersContext $usersCtx,
|
private UsersContext $usersCtx,
|
||||||
|
@ -21,12 +19,7 @@ final class SatoriRoutes implements IRouteHandler {
|
||||||
private ProfileFields $profileFields
|
private ProfileFields $profileFields
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function registerRoutes(IRouter $router): void {
|
#[HttpMiddleware('/_satori')]
|
||||||
RoutingContext::registerSimpleErrorPages($router, '/_satori');
|
|
||||||
Route::handleAttributes($router, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/_satori')]
|
|
||||||
public function verifyRequest($response, $request) {
|
public function verifyRequest($response, $request) {
|
||||||
$secretKey = $this->config->getString('secret');
|
$secretKey = $this->config->getString('secret');
|
||||||
|
|
||||||
|
@ -46,7 +39,7 @@ final class SatoriRoutes implements IRouteHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_satori/get-profile-field')]
|
#[HttpGet('/_satori/get-profile-field')]
|
||||||
public function getProfileField($response, $request): array {
|
public function getProfileField($response, $request): array {
|
||||||
$userId = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
|
$userId = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$fieldId = (string)$request->getParam('field', FILTER_SANITIZE_NUMBER_INT);
|
$fieldId = (string)$request->getParam('field', FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
@ -62,7 +55,7 @@ final class SatoriRoutes implements IRouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_satori/get-recent-forum-posts')]
|
#[HttpGet('/_satori/get-recent-forum-posts')]
|
||||||
public function getRecentForumPosts($response, $request): array {
|
public function getRecentForumPosts($response, $request): array {
|
||||||
$categoryIds = $this->config->getArray('forum.categories');
|
$categoryIds = $this->config->getArray('forum.categories');
|
||||||
if(empty($categoryIds))
|
if(empty($categoryIds))
|
||||||
|
@ -104,7 +97,7 @@ final class SatoriRoutes implements IRouteHandler {
|
||||||
return $posts;
|
return $posts;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_satori/get-recent-registrations')]
|
#[HttpGet('/_satori/get-recent-registrations')]
|
||||||
public function getRecentRegistrations($response, $request) {
|
public function getRecentRegistrations($response, $request) {
|
||||||
$batchSize = $this->config->getInteger('users.batch', 10);
|
$batchSize = $this->config->getInteger('users.batch', 10);
|
||||||
$backlogDays = $this->config->getInteger('users.backlog', 7);
|
$backlogDays = $this->config->getInteger('users.backlog', 7);
|
||||||
|
|
|
@ -3,25 +3,21 @@ namespace Misuzu\SharpChat;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Routing\IRouter;
|
use Index\Http\Routing\{HandlerAttribute,HttpDelete,HttpGet,HttpOptions,HttpPost,RouteHandler};
|
||||||
use Index\Routing\IRouteHandler;
|
|
||||||
use Index\Routing\Route;
|
|
||||||
use Syokuhou\IConfig;
|
use Syokuhou\IConfig;
|
||||||
use Misuzu\RoutingContext;
|
use Misuzu\RoutingContext;
|
||||||
use Misuzu\Auth\AuthContext;
|
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
||||||
use Misuzu\Auth\AuthInfo;
|
|
||||||
use Misuzu\Auth\Sessions;
|
|
||||||
use Misuzu\Emoticons\Emotes;
|
use Misuzu\Emoticons\Emotes;
|
||||||
use Misuzu\Perms\Permissions;
|
use Misuzu\Perms\Permissions;
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\URLs\URLRegistry;
|
||||||
use Misuzu\Users\Bans;
|
use Misuzu\Users\{Bans,UsersContext,UserInfo};
|
||||||
use Misuzu\Users\UsersContext;
|
|
||||||
|
|
||||||
final class SharpChatRoutes implements IRouteHandler {
|
final class SharpChatRoutes extends RouteHandler {
|
||||||
private string $hashKey;
|
private string $hashKey;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private IConfig $config,
|
private IConfig $config,
|
||||||
|
private IConfig $impersonateConfig, // this sucks lol
|
||||||
private URLRegistry $urls,
|
private URLRegistry $urls,
|
||||||
private UsersContext $usersCtx,
|
private UsersContext $usersCtx,
|
||||||
private AuthContext $authCtx,
|
private AuthContext $authCtx,
|
||||||
|
@ -32,13 +28,8 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
$this->hashKey = $this->config->getString('hashKey', 'woomy');
|
$this->hashKey = $this->config->getString('hashKey', 'woomy');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerRoutes(IRouter $router): void {
|
#[HttpOptions('/_sockchat/emotes')]
|
||||||
RoutingContext::registerSimpleErrorPages($router, '/_sockchat');
|
#[HttpGet('/_sockchat/emotes')]
|
||||||
Route::handleAttributes($router, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('OPTIONS', '/_sockchat/emotes')]
|
|
||||||
#[Route('GET', '/_sockchat/emotes')]
|
|
||||||
public function getEmotes($response, $request): array|int {
|
public function getEmotes($response, $request): array|int {
|
||||||
$response->setHeader('Access-Control-Allow-Origin', '*');
|
$response->setHeader('Access-Control-Allow-Origin', '*');
|
||||||
$response->setHeader('Access-Control-Allow-Methods', 'GET');
|
$response->setHeader('Access-Control-Allow-Methods', 'GET');
|
||||||
|
@ -66,7 +57,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_sockchat/login')]
|
#[HttpGet('/_sockchat/login')]
|
||||||
public function getLogin($response, $request) {
|
public function getLogin($response, $request) {
|
||||||
if(!$this->authInfo->isLoggedIn()) {
|
if(!$this->authInfo->isLoggedIn()) {
|
||||||
$response->redirect($this->urls->format('auth-login'));
|
$response->redirect($this->urls->format('auth-login'));
|
||||||
|
@ -79,8 +70,16 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('OPTIONS', '/_sockchat/token')]
|
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||||
#[Route('GET', '/_sockchat/token')]
|
if($impersonator->isSuperUser())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
$whitelist = $this->impersonateConfig->getArray(sprintf('allow.u%s', $impersonator->getId()));
|
||||||
|
return in_array($targetId, $whitelist, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[HttpOptions('/_sockchat/token')]
|
||||||
|
#[HttpGet('/_sockchat/token')]
|
||||||
public function getToken($response, $request) {
|
public function getToken($response, $request) {
|
||||||
$host = $request->hasHeader('Host') ? $request->getHeaderFirstLine('Host') : '';
|
$host = $request->hasHeader('Host') ? $request->getHeaderFirstLine('Host') : '';
|
||||||
$origin = $request->hasHeader('Origin') ? $request->getHeaderFirstLine('Origin') : '';
|
$origin = $request->hasHeader('Origin') ? $request->getHeaderFirstLine('Origin') : '';
|
||||||
|
@ -121,7 +120,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
return ['ok' => false, 'err' => 'user'];
|
return ['ok' => false, 'err' => 'user'];
|
||||||
|
|
||||||
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
|
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
|
||||||
$userId = $tokenInfo->hasImpersonatedUserId() && $userInfo->isSuperUser()
|
$userId = $tokenInfo->hasImpersonatedUserId() && $this->canImpersonateUserId($userInfo, $tokenInfo->getImpersonatedUserId())
|
||||||
? $tokenInfo->getImpersonatedUserId()
|
? $tokenInfo->getImpersonatedUserId()
|
||||||
: $userInfo->getId();
|
: $userInfo->getId();
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/_sockchat/bump')]
|
#[HttpPost('/_sockchat/bump')]
|
||||||
public function postBump($response, $request) {
|
public function postBump($response, $request) {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature'))
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
||||||
return 400;
|
return 400;
|
||||||
|
@ -164,7 +163,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
$this->usersCtx->getUsers()->recordUserActivity($userId, remoteAddr: $ipAddr);
|
$this->usersCtx->getUsers()->recordUserActivity($userId, remoteAddr: $ipAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/_sockchat/verify')]
|
#[HttpPost('/_sockchat/verify')]
|
||||||
public function postVerify($response, $request) {
|
public function postVerify($response, $request) {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature'))
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
||||||
return 400;
|
return 400;
|
||||||
|
@ -215,7 +214,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
$this->authCtx->getSessions()->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $ipAddress);
|
$this->authCtx->getSessions()->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $ipAddress);
|
||||||
|
|
||||||
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
|
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
|
||||||
if($tokenInfo->hasImpersonatedUserId() && $userInfo->isSuperUser()) {
|
if($tokenInfo->hasImpersonatedUserId() && $this->canImpersonateUserId($userInfo, $tokenInfo->getImpersonatedUserId())) {
|
||||||
$userInfoReal = $userInfo;
|
$userInfoReal = $userInfo;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -245,7 +244,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_sockchat/bans/list')]
|
#[HttpGet('/_sockchat/bans/list')]
|
||||||
public function getBanList($response, $request) {
|
public function getBanList($response, $request) {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature'))
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
||||||
return 400;
|
return 400;
|
||||||
|
@ -280,7 +279,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
return $list;
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/_sockchat/bans/check')]
|
#[HttpGet('/_sockchat/bans/check')]
|
||||||
public function getBanCheck($response, $request) {
|
public function getBanCheck($response, $request) {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature'))
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
||||||
return 400;
|
return 400;
|
||||||
|
@ -318,7 +317,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('POST', '/_sockchat/bans/create')]
|
#[HttpPost('/_sockchat/bans/create')]
|
||||||
public function postBanCreate($response, $request): int {
|
public function postBanCreate($response, $request): int {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature') || !$request->isFormContent())
|
if(!$request->hasHeader('X-SharpChat-Signature') || !$request->isFormContent())
|
||||||
return 400;
|
return 400;
|
||||||
|
@ -392,7 +391,7 @@ final class SharpChatRoutes implements IRouteHandler {
|
||||||
return 201;
|
return 201;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('DELETE', '/_sockchat/bans/revoke')]
|
#[HttpDelete('/_sockchat/bans/revoke')]
|
||||||
public function deleteBanRevoke($response, $request): int {
|
public function deleteBanRevoke($response, $request): int {
|
||||||
if(!$request->hasHeader('X-SharpChat-Signature'))
|
if(!$request->hasHeader('X-SharpChat-Signature'))
|
||||||
return 400;
|
return 400;
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\Routing\IRouter;
|
|
||||||
use Index\Http\HttpFx;
|
|
||||||
|
|
||||||
final class Tools {
|
final class Tools {
|
||||||
public static function isLocalURL(
|
public static function isLocalURL(
|
||||||
string $url,
|
string $url,
|
||||||
|
|
|
@ -3,14 +3,11 @@ namespace Misuzu\Users\Assets;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\Routing\Route;
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Index\Routing\RouteHandler;
|
|
||||||
use Misuzu\Perm;
|
use Misuzu\Perm;
|
||||||
use Misuzu\Auth\AuthInfo;
|
use Misuzu\Auth\AuthInfo;
|
||||||
use Misuzu\URLs\URLInfo;
|
use Misuzu\URLs\{URLInfo,URLRegistry};
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\Users\{UsersContext,UserInfo};
|
||||||
use Misuzu\Users\UsersContext;
|
|
||||||
use Misuzu\Users\UserInfo;
|
|
||||||
|
|
||||||
class AssetsRoutes extends RouteHandler {
|
class AssetsRoutes extends RouteHandler {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -29,11 +26,10 @@ class AssetsRoutes extends RouteHandler {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/assets/avatar')]
|
#[HttpGet('/assets/avatar')]
|
||||||
#[Route('GET', '/assets/avatar/:filename')]
|
#[HttpGet('/assets/avatar/([0-9]+)(?:\.[a-z]+)?')]
|
||||||
#[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])]
|
#[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])]
|
||||||
public function getAvatar($response, $request, string $fileName = '') {
|
public function getAvatar($response, $request, string $userId = '') {
|
||||||
$userId = pathinfo($fileName, PATHINFO_FILENAME);
|
|
||||||
$assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC);
|
$assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -52,12 +48,10 @@ class AssetsRoutes extends RouteHandler {
|
||||||
$this->serveAsset($response, $request, $assetInfo);
|
$this->serveAsset($response, $request, $assetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/assets/profile-background')]
|
#[HttpGet('/assets/profile-background')]
|
||||||
#[Route('GET', '/assets/profile-background/:filename')]
|
#[HttpGet('/assets/profile-background/([0-9]+)(?:\.[a-z]+)?')]
|
||||||
#[URLInfo('user-background', '/assets/profile-background/<user>')]
|
#[URLInfo('user-background', '/assets/profile-background/<user>')]
|
||||||
public function getProfileBackground($response, $request, string $fileName = '') {
|
public function getProfileBackground($response, $request, string $userId = '') {
|
||||||
$userId = pathinfo($fileName, PATHINFO_FILENAME);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$userInfo = $this->usersCtx->getUserInfo($userId);
|
$userInfo = $this->usersCtx->getUserInfo($userId);
|
||||||
} catch(RuntimeException $ex) {
|
} catch(RuntimeException $ex) {
|
||||||
|
@ -78,7 +72,7 @@ class AssetsRoutes extends RouteHandler {
|
||||||
$this->serveAsset($response, $request, $assetInfo);
|
$this->serveAsset($response, $request, $assetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('GET', '/user-assets.php')]
|
#[HttpGet('/user-assets.php')]
|
||||||
public function getUserAssets($response, $request) {
|
public function getUserAssets($response, $request) {
|
||||||
$userId = (string)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT);
|
$userId = (string)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$mode = (string)$request->getParam('m');
|
$mode = (string)$request->getParam('m');
|
||||||
|
|
|
@ -5,24 +5,28 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class BanInfo {
|
class BanInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $userId;
|
private string $id,
|
||||||
private ?string $modId;
|
private string $userId,
|
||||||
private int $severity;
|
private ?string $modId,
|
||||||
private string $publicReason;
|
private int $severity,
|
||||||
private string $privateReason;
|
private string $publicReason,
|
||||||
private int $created;
|
private string $privateReason,
|
||||||
private ?int $expires;
|
private int $created,
|
||||||
|
private ?int $expires,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): BanInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new BanInfo(
|
||||||
$this->userId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->modId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
userId: $result->getString(1),
|
||||||
$this->severity = $result->getInteger(3);
|
modId: $result->getStringOrNull(2),
|
||||||
$this->publicReason = $result->getString(4);
|
severity: $result->getInteger(3),
|
||||||
$this->privateReason = $result->getString(5);
|
publicReason: $result->getString(4),
|
||||||
$this->created = $result->getInteger(6);
|
privateReason: $result->getString(5),
|
||||||
$this->expires = $result->isNull(7) ? null : $result->getInteger(7);
|
created: $result->getInteger(6),
|
||||||
|
expires: $result->getIntegerOrNull(7),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Bans {
|
||||||
?bool $activeOnly = null,
|
?bool $activeOnly = null,
|
||||||
?bool $activeFirst = null,
|
?bool $activeFirst = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -101,13 +101,7 @@ class Bans {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(BanInfo::fromResult(...));
|
||||||
$bans = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$bans[] = new BanInfo($result);
|
|
||||||
|
|
||||||
return $bans;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBan(string $banId): BanInfo {
|
public function getBan(string $banId): BanInfo {
|
||||||
|
@ -119,7 +113,7 @@ class Bans {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No ban with ID $banId found.');
|
throw new RuntimeException('No ban with ID $banId found.');
|
||||||
|
|
||||||
return new BanInfo($result);
|
return BanInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function countActiveBans(
|
public function countActiveBans(
|
||||||
|
@ -153,7 +147,7 @@ class Bans {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
$result = $stmt->getResult();
|
||||||
return $result->next() ? new BanInfo($result) : null;
|
return $result->next() ? BanInfo::fromResult($result) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createBan(
|
public function createBan(
|
||||||
|
|
|
@ -5,20 +5,24 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ModNoteInfo {
|
class ModNoteInfo {
|
||||||
private string $noteId;
|
public function __construct(
|
||||||
private string $userId;
|
private string $noteId,
|
||||||
private ?string $authorId;
|
private string $userId,
|
||||||
private int $created;
|
private ?string $authorId,
|
||||||
private string $title;
|
private int $created,
|
||||||
private string $body;
|
private string $title,
|
||||||
|
private string $body,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): ModNoteInfo {
|
||||||
$this->noteId = (string)$result->getInteger(0);
|
return new ModNoteInfo(
|
||||||
$this->userId = (string)$result->getInteger(1);
|
noteId: $result->getString(0),
|
||||||
$this->authorId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
userId: $result->getString(1),
|
||||||
$this->created = $result->getInteger(3);
|
authorId: $result->getStringOrNull(2),
|
||||||
$this->title = $result->getString(4);
|
created: $result->getInteger(3),
|
||||||
$this->body = $result->getString(5);
|
title: $result->getString(4),
|
||||||
|
body: $result->getString(5)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -59,7 +59,7 @@ class ModNotes {
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
UserInfo|string|null $authorInfo = null,
|
UserInfo|string|null $authorInfo = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($authorInfo instanceof UserInfo)
|
if($authorInfo instanceof UserInfo)
|
||||||
|
@ -93,13 +93,7 @@ class ModNotes {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(ModNoteInfo::fromResult(...));
|
||||||
$notes = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$notes[] = new ModNoteInfo($result);
|
|
||||||
|
|
||||||
return $notes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNote(string $noteId): ModNoteInfo {
|
public function getNote(string $noteId): ModNoteInfo {
|
||||||
|
@ -111,7 +105,7 @@ class ModNotes {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('No note with ID $noteId found.');
|
throw new RuntimeException('No note with ID $noteId found.');
|
||||||
|
|
||||||
return new ModNoteInfo($result);
|
return ModNoteInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createNote(
|
public function createNote(
|
||||||
|
|
|
@ -7,26 +7,30 @@ use Index\Colour\Colour;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class RoleInfo implements Stringable {
|
class RoleInfo implements Stringable {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private int $rank;
|
private string $id,
|
||||||
private string $name;
|
private int $rank,
|
||||||
private ?string $title;
|
private string $name,
|
||||||
private ?string $description;
|
private ?string $title,
|
||||||
private bool $hidden;
|
private ?string $description,
|
||||||
private bool $leavable;
|
private bool $hidden,
|
||||||
private ?int $colour;
|
private bool $leavable,
|
||||||
private int $created;
|
private ?int $colour,
|
||||||
|
private int $created,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): RoleInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new RoleInfo(
|
||||||
$this->rank = $result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->name = $result->getString(2);
|
rank: $result->getInteger(1),
|
||||||
$this->title = $result->isNull(3) ? null : $result->getString(3);
|
name: $result->getString(2),
|
||||||
$this->description = $result->isNull(4) ? null : $result->getString(4);
|
title: $result->getStringOrNull(3),
|
||||||
$this->hidden = $result->getInteger(5) !== 0;
|
description: $result->getStringOrNull(4),
|
||||||
$this->leavable = $result->getInteger(6) !== 0;
|
hidden: $result->getBoolean(5),
|
||||||
$this->colour = $result->isNull(7) ? null : $result->getInteger(7);
|
leavable: $result->getBoolean(6),
|
||||||
$this->created = $result->getInteger(8);
|
colour: $result->getIntegerOrNull(7),
|
||||||
|
created: $result->getInteger(8),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Roles {
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?bool $hidden = null,
|
?bool $hidden = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -87,13 +87,7 @@ class Roles {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$roles = [];
|
return $stmt->getResult()->getIterator(RoleInfo::fromResult(...));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$roles[] = new RoleInfo($result);
|
|
||||||
|
|
||||||
return $roles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRole(string $roleId): RoleInfo {
|
public function getRole(string $roleId): RoleInfo {
|
||||||
|
@ -105,7 +99,7 @@ class Roles {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Could not find role with ID $roleId.');
|
throw new RuntimeException('Could not find role with ID $roleId.');
|
||||||
|
|
||||||
return new RoleInfo($result);
|
return RoleInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createRole(
|
public function createRole(
|
||||||
|
|
|
@ -9,50 +9,54 @@ use Index\Net\IPAddress;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
|
||||||
class UserInfo {
|
class UserInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $name;
|
private string $id,
|
||||||
private ?string $passwordHash;
|
private string $name,
|
||||||
private string $emailAddr;
|
private ?string $passwordHash,
|
||||||
private string $registerRemoteAddr;
|
private string $emailAddr,
|
||||||
private string $lastRemoteAddr;
|
private string $registerRemoteAddr,
|
||||||
private bool $super;
|
private string $lastRemoteAddr,
|
||||||
private string $countryCode;
|
private bool $super,
|
||||||
private ?int $colour;
|
private string $countryCode,
|
||||||
private int $created;
|
private ?int $colour,
|
||||||
private ?int $lastActive;
|
private int $created,
|
||||||
private ?int $deleted;
|
private ?int $lastActive,
|
||||||
private ?string $displayRoleId;
|
private ?int $deleted,
|
||||||
private ?string $totpKey;
|
private ?string $displayRoleId,
|
||||||
private ?string $aboutContent;
|
private ?string $totpKey,
|
||||||
private int $aboutParser;
|
private ?string $aboutContent,
|
||||||
private ?string $signatureContent;
|
private int $aboutParser,
|
||||||
private int $signatureParser;
|
private ?string $signatureContent,
|
||||||
private ?string $birthdate;
|
private int $signatureParser,
|
||||||
private ?int $backgroundSettings;
|
private ?string $birthdate,
|
||||||
private ?string $title;
|
private ?int $backgroundSettings,
|
||||||
|
private ?string $title,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): self {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new UserInfo(
|
||||||
$this->name = $result->getString(1);
|
id: $result->getString(0),
|
||||||
$this->passwordHash = $result->isNull(2) ? null : $result->getString(2);
|
name: $result->getString(1),
|
||||||
$this->emailAddr = $result->getString(3);
|
passwordHash: $result->getStringOrNull(2),
|
||||||
$this->registerRemoteAddr = $result->getString(4);
|
emailAddr: $result->getString(3),
|
||||||
$this->lastRemoteAddr = $result->isNull(5) ? null : $result->getString(5);
|
registerRemoteAddr: $result->getString(4),
|
||||||
$this->super = $result->getInteger(6) !== 0;
|
lastRemoteAddr: $result->getStringOrNull(5),
|
||||||
$this->countryCode = $result->getString(7);
|
super: $result->getBoolean(6),
|
||||||
$this->colour = $result->isNull(8) ? null : $result->getInteger(8);
|
countryCode: $result->getString(7),
|
||||||
$this->created = $result->getInteger(9);
|
colour: $result->getIntegerOrNull(8),
|
||||||
$this->lastActive = $result->isNull(10) ? null : $result->getInteger(10);
|
created: $result->getInteger(9),
|
||||||
$this->deleted = $result->isNull(11) ? null : $result->getInteger(11);
|
lastActive: $result->getIntegerOrNull(10),
|
||||||
$this->displayRoleId = $result->isNull(12) ? null : (string)$result->getInteger(12);
|
deleted: $result->getIntegerOrNull(11),
|
||||||
$this->totpKey = $result->isNull(13) ? null : $result->getString(13);
|
displayRoleId: $result->getStringOrNull(12),
|
||||||
$this->aboutContent = $result->isNull(14) ? null : $result->getString(14);
|
totpKey: $result->getStringOrNull(13),
|
||||||
$this->aboutParser = $result->getInteger(15);
|
aboutContent: $result->getStringOrNull(14),
|
||||||
$this->signatureContent = $result->isNull(16) ? null : $result->getString(16);
|
aboutParser: $result->getInteger(15),
|
||||||
$this->signatureParser = $result->getInteger(17);
|
signatureContent: $result->getStringOrNull(16),
|
||||||
$this->birthdate = $result->isNull(18) ? null : $result->getString(18);
|
signatureParser: $result->getInteger(17),
|
||||||
$this->backgroundSettings = $result->isNull(19) ? null : $result->getInteger(19);
|
birthdate: $result->getStringOrNull(18),
|
||||||
$this->title = $result->getString(20);
|
backgroundSettings: $result->getIntegerOrNull(19),
|
||||||
|
title: $result->getString(20),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -112,7 +112,7 @@ class Users {
|
||||||
?bool $reverseOrder = null,
|
?bool $reverseOrder = null,
|
||||||
?array $searchQuery = null,
|
?array $searchQuery = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
// remove this hack when search server
|
// remove this hack when search server
|
||||||
$hasSearchQuery = $searchQuery !== null;
|
$hasSearchQuery = $searchQuery !== null;
|
||||||
$searchLimitResults = false;
|
$searchLimitResults = false;
|
||||||
|
@ -211,13 +211,7 @@ class Users {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$users = [];
|
return $stmt->getResult()->getIterator(UserInfo::fromResult(...));
|
||||||
$result = $stmt->getResult();
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$users[] = new UserInfo($result);
|
|
||||||
|
|
||||||
return $users;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public const GET_USER_ID = 0x01;
|
public const GET_USER_ID = 0x01;
|
||||||
|
@ -283,7 +277,7 @@ class Users {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('User not found.');
|
throw new RuntimeException('User not found.');
|
||||||
|
|
||||||
return new UserInfo($result);
|
return UserInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createUser(
|
public function createUser(
|
||||||
|
|
|
@ -5,18 +5,22 @@ use Index\DateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class WarningInfo {
|
class WarningInfo {
|
||||||
private string $id;
|
public function __construct(
|
||||||
private string $userId;
|
private string $id,
|
||||||
private ?string $modId;
|
private string $userId,
|
||||||
private string $body;
|
private ?string $modId,
|
||||||
private int $created;
|
private string $body,
|
||||||
|
private int $created,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function __construct(IDbResult $result) {
|
public static function fromResult(IDbResult $result): WarningInfo {
|
||||||
$this->id = (string)$result->getInteger(0);
|
return new WarningInfo(
|
||||||
$this->userId = (string)$result->getInteger(1);
|
id: $result->getString(0),
|
||||||
$this->modId = $result->isNull(2) ? null : (string)$result->getInteger(2);
|
userId: $result->getString(1),
|
||||||
$this->body = $result->getString(3);
|
modId: $result->getStringOrNull(2),
|
||||||
$this->created = $result->getInteger(4);
|
body: $result->getString(3),
|
||||||
|
created: $result->getInteger(4)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): string {
|
public function getId(): string {
|
||||||
|
|
|
@ -53,18 +53,14 @@ class Warnings {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
$result = $stmt->getResult();
|
||||||
$count = 0;
|
|
||||||
|
|
||||||
if($result->next())
|
return $result->next() ? $result->getInteger(0) : 0;
|
||||||
$count = $result->getInteger(0);
|
|
||||||
|
|
||||||
return $count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWarningsWithDefaultBacklog(
|
public function getWarningsWithDefaultBacklog(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
return $this->getWarnings(
|
return $this->getWarnings(
|
||||||
$userInfo,
|
$userInfo,
|
||||||
self::VISIBLE_BACKLOG,
|
self::VISIBLE_BACKLOG,
|
||||||
|
@ -76,7 +72,7 @@ class Warnings {
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?int $backlog = null,
|
?int $backlog = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): array {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
|
|
||||||
|
@ -111,13 +107,7 @@ class Warnings {
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
$result = $stmt->getResult();
|
return $stmt->getResult()->getIterator(WarningInfo::fromResult(...));
|
||||||
$warns = [];
|
|
||||||
|
|
||||||
while($result->next())
|
|
||||||
$warns[] = new WarningInfo($result);
|
|
||||||
|
|
||||||
return $warns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWarning(string $warnId): WarningInfo {
|
public function getWarning(string $warnId): WarningInfo {
|
||||||
|
@ -130,7 +120,7 @@ class Warnings {
|
||||||
if(!$result->next())
|
if(!$result->next())
|
||||||
throw new RuntimeException('Could not find warning info for ID $warnId.');
|
throw new RuntimeException('Could not find warning info for ID $warnId.');
|
||||||
|
|
||||||
return new WarningInfo($result);
|
return WarningInfo::fromResult($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createWarning(
|
public function createWarning(
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
{% set show_profile_fields = not profile_is_guest and (profile_is_editing ? perms.edit_profile : profile_fields_display_values|default([]) is not empty) %}
|
{% set show_profile_fields = not profile_is_guest and (profile_is_editing ? perms.edit_profile : profile_fields_display_values|default([]) is not empty) %}
|
||||||
{% set show_background_settings = profile_is_editing and perms.edit_background %}
|
{% set show_background_settings = profile_is_editing and perms.edit_background %}
|
||||||
{% set show_birthdate = profile_is_editing and perms.edit_birthdate %}
|
{% set show_birthdate = profile_is_editing and perms.edit_birthdate %}
|
||||||
{% set show_active_forum_info = not profile_is_guest and not profile_is_deleted and not profile_is_editing or (profile_active_category_info is defined and profile_active_category_info is not empty or profile_active_topic_info.topic_id|default(0) > 0) %}
|
{% set show_active_forum_info = not profile_is_guest and not profile_is_deleted and not profile_is_editing and profile_active_topic_info.id|default(0) > 0 %}
|
||||||
{% set show_warnings = profile_warnings is defined and profile_warnings|length > 0 %}
|
{% set show_warnings = profile_warnings is defined and profile_warnings|length > 0 %}
|
||||||
{% set show_sidebar = (not profile_is_banned or profile_can_edit) and (profile_is_guest or show_profile_fields or show_background_settings or show_birthdate or show_active_forum_info or show_warnings) %}
|
{% set show_sidebar = (not profile_is_banned or profile_can_edit) and (profile_is_guest or show_profile_fields or show_background_settings or show_birthdate or show_active_forum_info or show_warnings) %}
|
||||||
|
|
||||||
|
|
91
tools/cron
91
tools/cron
|
@ -132,6 +132,15 @@ msz_sched_task_func('Resync statistics counters.', true, function() use ($msz) {
|
||||||
'users:warnings:visible' => 'SELECT COUNT(*) FROM msz_users_warnings WHERE warn_created > NOW() - INTERVAL 90 DAY',
|
'users:warnings:visible' => 'SELECT COUNT(*) FROM msz_users_warnings WHERE warn_created > NOW() - INTERVAL 90 DAY',
|
||||||
'users:bans:total' => 'SELECT COUNT(*) FROM msz_users_bans',
|
'users:bans:total' => 'SELECT COUNT(*) FROM msz_users_bans',
|
||||||
'users:bans:active' => 'SELECT COUNT(*) FROM msz_users_bans WHERE ban_expires IS NULL OR ban_expires > NOW()',
|
'users:bans:active' => 'SELECT COUNT(*) FROM msz_users_bans WHERE ban_expires IS NULL OR ban_expires > NOW()',
|
||||||
|
'pms:msgs:total' => 'SELECT COUNT(*) FROM msz_messages',
|
||||||
|
'pms:msgs:messages' => 'SELECT COUNT(DISTINCT msg_id) FROM msz_messages',
|
||||||
|
'pms:msgs:replies' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_reply_to IS NULL',
|
||||||
|
'pms:msgs:drafts' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_sent IS NULL',
|
||||||
|
'pms:msgs:unread' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_read IS NULL',
|
||||||
|
'pms:msgs:deleted' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_deleted IS NOT NULL',
|
||||||
|
'pms:msgs:plain' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 0',
|
||||||
|
'pms:msgs:bbcode' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 1',
|
||||||
|
'pms:msgs:markdown' => 'SELECT COUNT(*) FROM msz_messages WHERE msg_parser = 2',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach($stats as $name => $query) {
|
foreach($stats as $name => $query) {
|
||||||
|
@ -149,6 +158,88 @@ msz_sched_task_func('Recalculate permissions (maybe)...', false, function() use
|
||||||
$msz->getPerms()->precalculatePermissions($msz->getForumContext()->getCategories());
|
$msz->getPerms()->precalculatePermissions($msz->getForumContext()->getCategories());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
msz_sched_task_func('Omega disliking comments...', true, function() use ($msz) {
|
||||||
|
$commentIds = $msz->getConfig()->getArray('comments.omegadislike');
|
||||||
|
if(!is_array($commentIds))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$dbConn = $msz->getDbConn();
|
||||||
|
$stmt = $dbConn->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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
msz_sched_task_func('Announcing random topics...', true, function() use ($msz) {
|
||||||
|
$categoryIds = $msz->getConfig()->getArray('forum.rngannounce');
|
||||||
|
if(!is_array($categoryIds))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$dbConn = $msz->getDbConn();
|
||||||
|
$stmtRevert = $dbConn->prepare('UPDATE msz_forum_topics SET topic_type = 0 WHERE forum_id = ? AND topic_type = 2');
|
||||||
|
$stmtRandom = $dbConn->prepare('SELECT topic_id FROM msz_forum_topics WHERE forum_id = ? AND topic_deleted IS NULL ORDER BY RAND() LIMIT 1');
|
||||||
|
$stmtAnnounce = $dbConn->prepare('UPDATE msz_forum_topics SET topic_type = 2 WHERE topic_id = ?');
|
||||||
|
foreach($categoryIds as $categoryId) {
|
||||||
|
$stmtRevert->addParameter(1, $categoryId);
|
||||||
|
$stmtRevert->execute();
|
||||||
|
|
||||||
|
$stmtRandom->addParameter(1, $categoryId);
|
||||||
|
$stmtRandom->execute();
|
||||||
|
|
||||||
|
$resultRandom = $stmtRandom->getResult();
|
||||||
|
if($resultRandom->next()) {
|
||||||
|
$stmtAnnounce->addParameter(1, $resultRandom->getInteger(0));
|
||||||
|
$stmtAnnounce->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
msz_sched_task_func('Changing category icons...', false, function() use ($msz) {
|
||||||
|
$config = $msz->getConfig();
|
||||||
|
$categoryIds = $config->getArray('forum.rngicon');
|
||||||
|
if(!is_array($categoryIds))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$dbConn = $msz->getDbConn();
|
||||||
|
|
||||||
|
$stmtIcon = $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 = $dbConn->prepare('UPDATE msz_forum_topics SET topic_locked = IF(?, NULL, COALESCE(topic_locked, NOW())) WHERE topic_id = ?');
|
||||||
|
|
||||||
|
foreach($categoryIds as $categoryId) {
|
||||||
|
$scoped = $config->scopeTo(sprintf('forum.rngicon.fc%d', $categoryId));
|
||||||
|
|
||||||
|
$icons = $scoped->getArray('icons');
|
||||||
|
$icon = $icons[array_rand($icons)];
|
||||||
|
|
||||||
|
$name = null;
|
||||||
|
$names = $scoped->getArray('names');
|
||||||
|
for($i = 0; $i < count($names); $i += 2)
|
||||||
|
if($names[$i] === $icon) {
|
||||||
|
$name = $names[$i + 1] ?? null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$name ??= $scoped->getString('name');
|
||||||
|
|
||||||
|
$stmtIcon->addParameter(1, $icon);
|
||||||
|
$stmtIcon->addParameter(2, empty($name) ? null : $name);
|
||||||
|
$stmtIcon->addParameter(3, $categoryId);
|
||||||
|
$stmtIcon->execute();
|
||||||
|
|
||||||
|
$unlockModes = $scoped->getArray('unlock');
|
||||||
|
foreach($unlockModes as $unlockMode) {
|
||||||
|
$unlockScoped = $scoped->scopeTo(sprintf('unlock.%s', $unlockMode));
|
||||||
|
$topicId = $unlockScoped->getInteger('topic');
|
||||||
|
$match = $unlockScoped->getArray('match');
|
||||||
|
$matches = in_array($icon, $match);
|
||||||
|
|
||||||
|
$stmtUnlock->addParameter(1, $matches ? 1 : 0);
|
||||||
|
$stmtUnlock->addParameter(2, $topicId);
|
||||||
|
$stmtUnlock->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
echo 'Running ' . count($schedTasks) . ' tasks...' . PHP_EOL;
|
echo 'Running ' . count($schedTasks) . ' tasks...' . PHP_EOL;
|
||||||
|
|
||||||
$dbConn = $msz->getDbConn();
|
$dbConn = $msz->getDbConn();
|
||||||
|
|
Loading…
Reference in a new issue