543 lines
16 KiB
PHP
543 lines
16 KiB
PHP
<?php
|
|
define('MSZ_FORUM_TYPE_DISCUSSION', 0);
|
|
define('MSZ_FORUM_TYPE_CATEGORY', 1);
|
|
define('MSZ_FORUM_TYPE_LINK', 2);
|
|
define('MSZ_FORUM_TYPES', [
|
|
MSZ_FORUM_TYPE_DISCUSSION,
|
|
MSZ_FORUM_TYPE_CATEGORY,
|
|
MSZ_FORUM_TYPE_LINK,
|
|
]);
|
|
|
|
define('MSZ_FORUM_MAY_HAVE_CHILDREN', [
|
|
MSZ_FORUM_TYPE_DISCUSSION,
|
|
MSZ_FORUM_TYPE_CATEGORY,
|
|
]);
|
|
|
|
define('MSZ_FORUM_MAY_HAVE_TOPICS', [
|
|
MSZ_FORUM_TYPE_DISCUSSION,
|
|
]);
|
|
|
|
define('MSZ_FORUM_ROOT', 0);
|
|
define('MSZ_FORUM_ROOT_DATA', [ // should be compatible with the data fetched in forum_get_root_categories
|
|
'forum_id' => MSZ_FORUM_ROOT,
|
|
'forum_name' => 'Forums',
|
|
'forum_children' => 0,
|
|
'forum_type' => MSZ_FORUM_TYPE_CATEGORY,
|
|
'forum_colour' => null,
|
|
'forum_permissions' => MSZ_FORUM_PERM_SET_READ,
|
|
]);
|
|
|
|
function forum_is_valid_type(int $type): bool {
|
|
return in_array($type, MSZ_FORUM_TYPES, true);
|
|
}
|
|
|
|
function forum_may_have_children(int $forumType): bool {
|
|
return in_array($forumType, MSZ_FORUM_MAY_HAVE_CHILDREN);
|
|
}
|
|
|
|
function forum_may_have_topics(int $forumType): bool {
|
|
return in_array($forumType, MSZ_FORUM_MAY_HAVE_TOPICS);
|
|
}
|
|
|
|
function forum_get(int $forumId, bool $showDeleted = false): array {
|
|
$getForum = \Misuzu\DB::prepare(sprintf(
|
|
'
|
|
SELECT
|
|
`forum_id`, `forum_name`, `forum_type`, `forum_link`, `forum_archived`,
|
|
`forum_link_clicks`, `forum_parent`, `forum_colour`, `forum_icon`,
|
|
(
|
|
SELECT COUNT(`topic_id`)
|
|
FROM `msz_forum_topics`
|
|
WHERE `forum_id` = f.`forum_id`
|
|
%1$s
|
|
) as `forum_topic_count`
|
|
FROM `msz_forum_categories` as f
|
|
WHERE `forum_id` = :forum_id
|
|
',
|
|
$showDeleted ? '' : 'AND `topic_deleted` IS NULL'
|
|
));
|
|
$getForum->bind('forum_id', $forumId);
|
|
return $getForum->fetch();
|
|
}
|
|
|
|
function forum_get_root_categories(int $userId): array {
|
|
$getCategories = \Misuzu\DB::prepare(sprintf(
|
|
'
|
|
SELECT
|
|
f.`forum_id`, f.`forum_name`, f.`forum_type`, f.`forum_colour`, f.`forum_icon`,
|
|
(
|
|
SELECT COUNT(`forum_id`)
|
|
FROM `msz_forum_categories` AS sf
|
|
WHERE sf.`forum_parent` = f.`forum_id`
|
|
) AS `forum_children`
|
|
FROM `msz_forum_categories` AS f
|
|
WHERE f.`forum_parent` = 0
|
|
AND f.`forum_type` = %1$d
|
|
AND f.`forum_hidden` = 0
|
|
GROUP BY f.`forum_id`
|
|
ORDER BY f.`forum_order`
|
|
',
|
|
MSZ_FORUM_TYPE_CATEGORY
|
|
));
|
|
$categories = array_merge([MSZ_FORUM_ROOT_DATA], $getCategories->fetchAll());
|
|
|
|
$getRootForumCount = \Misuzu\DB::prepare(sprintf(
|
|
"
|
|
SELECT COUNT(`forum_id`)
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_parent` = %d
|
|
AND `forum_type` != %d
|
|
",
|
|
MSZ_FORUM_ROOT,
|
|
MSZ_FORUM_TYPE_CATEGORY
|
|
));
|
|
$categories[0]['forum_children'] = (int)$getRootForumCount->fetchColumn();
|
|
|
|
foreach($categories as $key => $category) {
|
|
$categories[$key]['forum_permissions'] = $perms = forum_perms_get_user($category['forum_id'], $userId)[MSZ_FORUM_PERMS_GENERAL];
|
|
|
|
if(!perms_check($perms, MSZ_FORUM_PERM_SET_READ)) {
|
|
unset($categories[$key]);
|
|
continue;
|
|
}
|
|
|
|
$categories[$key] = array_merge(
|
|
$category,
|
|
['forum_unread' => forum_topics_unread($category['forum_id'], $userId)],
|
|
forum_latest_post($category['forum_id'], $userId)
|
|
);
|
|
}
|
|
|
|
return $categories;
|
|
}
|
|
|
|
function forum_get_breadcrumbs(
|
|
int $forumId,
|
|
string $linkFormat = '/forum/forum.php?f=%d',
|
|
string $rootFormat = '/forum/#f%d',
|
|
array $indexLink = ['Forums' => '/forum/']
|
|
): array {
|
|
$breadcrumbs = [];
|
|
$getBreadcrumb = \Misuzu\DB::prepare('
|
|
SELECT `forum_id`, `forum_name`, `forum_type`, `forum_parent`
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_id` = :forum_id
|
|
');
|
|
|
|
while($forumId > 0) {
|
|
$getBreadcrumb->bind('forum_id', $forumId);
|
|
$breadcrumb = $getBreadcrumb->fetch();
|
|
|
|
if(empty($breadcrumb)) {
|
|
break;
|
|
}
|
|
|
|
$breadcrumbs[$breadcrumb['forum_name']] = sprintf(
|
|
$breadcrumb['forum_parent'] === MSZ_FORUM_ROOT
|
|
&& $breadcrumb['forum_type'] === MSZ_FORUM_TYPE_CATEGORY
|
|
? $rootFormat
|
|
: $linkFormat,
|
|
$breadcrumb['forum_id']
|
|
);
|
|
$forumId = $breadcrumb['forum_parent'];
|
|
}
|
|
|
|
return array_reverse($breadcrumbs + $indexLink);
|
|
}
|
|
|
|
function forum_get_colour(int $forumId): int {
|
|
$getColours = \Misuzu\DB::prepare('
|
|
SELECT `forum_id`, `forum_parent`, `forum_colour`
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_id` = :forum_id
|
|
');
|
|
|
|
while($forumId > 0) {
|
|
$getColours->bind('forum_id', $forumId);
|
|
$colourInfo = $getColours->fetch();
|
|
|
|
if(empty($colourInfo)) {
|
|
break;
|
|
}
|
|
|
|
if(!empty($colourInfo['forum_colour'])) {
|
|
return $colourInfo['forum_colour'];
|
|
}
|
|
|
|
$forumId = $colourInfo['forum_parent'];
|
|
}
|
|
|
|
return 0x40000000;
|
|
}
|
|
|
|
function forum_increment_clicks(int $forumId): void {
|
|
$incrementLinkClicks = \Misuzu\DB::prepare(sprintf('
|
|
UPDATE `msz_forum_categories`
|
|
SET `forum_link_clicks` = `forum_link_clicks` + 1
|
|
WHERE `forum_id` = :forum_id
|
|
AND `forum_type` = %d
|
|
AND `forum_link_clicks` IS NOT NULL
|
|
', MSZ_FORUM_TYPE_LINK));
|
|
$incrementLinkClicks->bind('forum_id', $forumId);
|
|
$incrementLinkClicks->execute();
|
|
}
|
|
|
|
function forum_get_parent_id(int $forumId): int {
|
|
if($forumId < 1) {
|
|
return 0;
|
|
}
|
|
|
|
static $memoized = [];
|
|
|
|
if(array_key_exists($forumId, $memoized)) {
|
|
return $memoized[$forumId];
|
|
}
|
|
|
|
$getParent = \Misuzu\DB::prepare('
|
|
SELECT `forum_parent`
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_id` = :forum_id
|
|
');
|
|
$getParent->bind('forum_id', $forumId);
|
|
|
|
return (int)$getParent->fetchColumn();
|
|
}
|
|
|
|
function forum_get_child_ids(int $forumId): array {
|
|
if($forumId < 1) {
|
|
return [];
|
|
}
|
|
|
|
static $memoized = [];
|
|
|
|
if(array_key_exists($forumId, $memoized)) {
|
|
return $memoized[$forumId];
|
|
}
|
|
|
|
$getChildren = \Misuzu\DB::prepare('
|
|
SELECT `forum_id`
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_parent` = :forum_id
|
|
');
|
|
$getChildren->bind('forum_id', $forumId);
|
|
$children = $getChildren->fetchAll();
|
|
|
|
return $memoized[$forumId] = array_column($children, 'forum_id');
|
|
}
|
|
|
|
function forum_topics_unread(int $forumId, int $userId): int {
|
|
if($userId < 1 || $forumId < 1)
|
|
return 0;
|
|
|
|
static $memoized = [];
|
|
$memoId = "{$forumId}-{$userId}";
|
|
|
|
if(array_key_exists($memoId, $memoized)) {
|
|
return $memoized[$memoId];
|
|
}
|
|
|
|
$memoized[$memoId] = 0;
|
|
$children = forum_get_child_ids($forumId);
|
|
|
|
foreach($children as $child) {
|
|
$memoized[$memoId] += forum_topics_unread($child, $userId);
|
|
}
|
|
|
|
if(forum_perms_check_user(MSZ_FORUM_PERMS_GENERAL, $forumId, $userId, MSZ_FORUM_PERM_SET_READ)) {
|
|
$countUnread = \Misuzu\DB::prepare('
|
|
SELECT COUNT(ti.`topic_id`)
|
|
FROM `msz_forum_topics` AS ti
|
|
LEFT JOIN `msz_forum_topics_track` AS tt
|
|
ON tt.`topic_id` = ti.`topic_id` AND tt.`user_id` = :user_id
|
|
WHERE ti.`forum_id` = :forum_id
|
|
AND ti.`topic_deleted` IS NULL
|
|
AND ti.`topic_bumped` >= NOW() - INTERVAL 1 MONTH
|
|
AND (
|
|
tt.`track_last_read` IS NULL
|
|
OR tt.`track_last_read` < ti.`topic_bumped`
|
|
)
|
|
');
|
|
$countUnread->bind('forum_id', $forumId);
|
|
$countUnread->bind('user_id', $userId);
|
|
$memoized[$memoId] += (int)$countUnread->fetchColumn();
|
|
}
|
|
|
|
return $memoized[$memoId];
|
|
}
|
|
|
|
function forum_latest_post(int $forumId, int $userId): array {
|
|
if($forumId < 1) {
|
|
return [];
|
|
}
|
|
|
|
static $memoized = [];
|
|
$memoId = "{$forumId}-{$userId}";
|
|
|
|
if(array_key_exists($memoId, $memoized)) {
|
|
return $memoized[$memoId];
|
|
}
|
|
|
|
if(!forum_perms_check_user(MSZ_FORUM_PERMS_GENERAL, $forumId, $userId, MSZ_FORUM_PERM_SET_READ)) {
|
|
return $memoized[$memoId] = [];
|
|
}
|
|
|
|
$getLastPost = \Misuzu\DB::prepare('
|
|
SELECT
|
|
p.`post_id` AS `recent_post_id`, t.`topic_id` AS `recent_topic_id`,
|
|
t.`topic_title` AS `recent_topic_title`, t.`topic_bumped` AS `recent_topic_bumped`,
|
|
p.`post_created` AS `recent_post_created`,
|
|
u.`user_id` AS `recent_post_user_id`,
|
|
u.`username` AS `recent_post_username`,
|
|
COALESCE(u.`user_colour`, r.`role_colour`) AS `recent_post_user_colour`,
|
|
UNIX_TIMESTAMP(p.`post_created`) AS `post_created_unix`
|
|
FROM `msz_forum_posts` AS p
|
|
LEFT JOIN `msz_forum_topics` AS t
|
|
ON t.`topic_id` = p.`topic_id`
|
|
LEFT JOIN `msz_users` AS u
|
|
ON u.`user_id` = p.`user_id`
|
|
LEFT JOIN `msz_roles` AS r
|
|
ON r.`role_id` = u.`display_role`
|
|
WHERE p.`forum_id` = :forum_id
|
|
AND p.`post_deleted` IS NULL
|
|
ORDER BY p.`post_id` DESC
|
|
');
|
|
$getLastPost->bind('forum_id', $forumId);
|
|
$currentLast = $getLastPost->fetch();
|
|
|
|
$children = forum_get_child_ids($forumId);
|
|
|
|
foreach($children as $child) {
|
|
$lastPost = forum_latest_post($child, $userId);
|
|
|
|
if(($currentLast['post_created_unix'] ?? 0) < ($lastPost['post_created_unix'] ?? 0)) {
|
|
$currentLast = $lastPost;
|
|
}
|
|
}
|
|
|
|
return $memoized[$memoId] = $currentLast;
|
|
}
|
|
|
|
function forum_get_children(int $parentId, int $userId): array {
|
|
$getListing = \Misuzu\DB::prepare(sprintf(
|
|
'
|
|
SELECT
|
|
:user_id AS `target_user_id`,
|
|
f.`forum_id`, f.`forum_name`, f.`forum_description`, f.`forum_type`, f.`forum_icon`,
|
|
f.`forum_link`, f.`forum_link_clicks`, f.`forum_archived`, f.`forum_colour`,
|
|
f.`forum_count_topics`, f.`forum_count_posts`
|
|
FROM `msz_forum_categories` AS f
|
|
WHERE f.`forum_parent` = :parent_id
|
|
AND f.`forum_hidden` = 0
|
|
AND (
|
|
(f.`forum_parent` = %1$d AND f.`forum_type` != %2$d)
|
|
OR f.`forum_parent` != %1$d
|
|
)
|
|
GROUP BY f.`forum_id`
|
|
ORDER BY f.`forum_order`
|
|
',
|
|
MSZ_FORUM_ROOT,
|
|
MSZ_FORUM_TYPE_CATEGORY
|
|
));
|
|
|
|
$getListing->bind('user_id', $userId);
|
|
$getListing->bind('parent_id', $parentId);
|
|
|
|
$listing = $getListing->fetchAll();
|
|
|
|
foreach($listing as $key => $forum) {
|
|
$listing[$key]['forum_permissions'] = $perms = forum_perms_get_user($forum['forum_id'], $userId)[MSZ_FORUM_PERMS_GENERAL];
|
|
|
|
if(!perms_check($perms, MSZ_FORUM_PERM_SET_READ)) {
|
|
unset($listing[$key]);
|
|
continue;
|
|
}
|
|
|
|
$listing[$key] = array_merge(
|
|
$forum,
|
|
['forum_unread' => forum_topics_unread($forum['forum_id'], $userId)],
|
|
forum_latest_post($forum['forum_id'], $userId)
|
|
);
|
|
}
|
|
|
|
return $listing;
|
|
}
|
|
|
|
function forum_timeout(int $forumId, int $userId): int {
|
|
$checkTimeout = \Misuzu\DB::prepare('
|
|
SELECT TIMESTAMPDIFF(SECOND, COALESCE(MAX(`post_created`), NOW() - INTERVAL 1 YEAR), NOW())
|
|
FROM `msz_forum_posts`
|
|
WHERE `forum_id` = :forum_id
|
|
AND `user_id` = :user_id
|
|
');
|
|
$checkTimeout->bind('forum_id', $forumId);
|
|
$checkTimeout->bind('user_id', $userId);
|
|
|
|
return (int)$checkTimeout->fetchColumn();
|
|
}
|
|
|
|
// $forumId == null marks all forums as read
|
|
function forum_mark_read(?int $forumId, int $userId): void {
|
|
// shitty fix for dumb-ass function signature
|
|
if($forumId === 0)
|
|
$forumId = null;
|
|
|
|
if(($forumId !== null && $forumId < 1) || $userId < 1) {
|
|
return;
|
|
}
|
|
|
|
$entireForum = $forumId === null;
|
|
|
|
if(!$entireForum) {
|
|
$children = forum_get_child_ids($forumId);
|
|
|
|
foreach($children as $child) {
|
|
forum_mark_read($child, $userId);
|
|
}
|
|
}
|
|
|
|
$doMark = \Misuzu\DB::prepare(sprintf(
|
|
'
|
|
INSERT INTO `msz_forum_topics_track`
|
|
(`user_id`, `topic_id`, `forum_id`, `track_last_read`)
|
|
SELECT u.`user_id`, t.`topic_id`, t.`forum_id`, NOW()
|
|
FROM `msz_forum_topics` AS t
|
|
LEFT JOIN `msz_users` AS u
|
|
ON u.`user_id` = :user
|
|
WHERE t.`topic_deleted` IS NULL
|
|
AND t.`topic_bumped` >= NOW() - INTERVAL 1 MONTH
|
|
%1$s
|
|
GROUP BY t.`topic_id`
|
|
ON DUPLICATE KEY UPDATE
|
|
`track_last_read` = NOW()
|
|
',
|
|
$entireForum ? '' : 'AND t.`forum_id` = :forum'
|
|
));
|
|
$doMark->bind('user', $userId);
|
|
|
|
if(!$entireForum) {
|
|
$doMark->bind('forum', $forumId);
|
|
}
|
|
|
|
$doMark->execute();
|
|
}
|
|
|
|
function forum_posting_info(int $userId): array {
|
|
$getPostingInfo = \Misuzu\DB::prepare('
|
|
SELECT
|
|
u.`user_country`, u.`user_created`,
|
|
(
|
|
SELECT COUNT(`post_id`)
|
|
FROM `msz_forum_posts`
|
|
WHERE `user_id` = u.`user_id`
|
|
AND `post_deleted` IS NULL
|
|
) AS `user_forum_posts`,
|
|
(
|
|
SELECT `post_parse`
|
|
FROM `msz_forum_posts`
|
|
WHERE `user_id` = u.`user_id`
|
|
AND `post_deleted` IS NULL
|
|
ORDER BY `post_id` DESC
|
|
LIMIT 1
|
|
) AS `user_post_parse`
|
|
FROM `msz_users` as u
|
|
WHERE `user_id` = :user_id
|
|
');
|
|
$getPostingInfo->bind('user_id', $userId);
|
|
return $getPostingInfo->fetch();
|
|
}
|
|
|
|
function forum_count_increase(int $forumId, bool $topic = false): void {
|
|
$increaseCount = \Misuzu\DB::prepare(sprintf(
|
|
'
|
|
UPDATE `msz_forum_categories`
|
|
SET `forum_count_posts` = `forum_count_posts` + 1
|
|
%s
|
|
WHERE `forum_id` = :forum
|
|
',
|
|
$topic ? ',`forum_count_topics` = `forum_count_topics` + 1' : ''
|
|
));
|
|
$increaseCount->bind('forum', $forumId);
|
|
$increaseCount->execute();
|
|
}
|
|
|
|
function forum_count_synchronise(int $forumId = MSZ_FORUM_ROOT, bool $save = true): array {
|
|
static $getChildren = null;
|
|
static $getCounts = null;
|
|
static $setCounts = null;
|
|
|
|
if(is_null($getChildren)) {
|
|
$getChildren = \Misuzu\DB::prepare('
|
|
SELECT `forum_id`, `forum_parent`
|
|
FROM `msz_forum_categories`
|
|
WHERE `forum_parent` = :parent
|
|
');
|
|
}
|
|
|
|
if(is_null($getCounts)) {
|
|
$getCounts = \Misuzu\DB::prepare('
|
|
SELECT :forum as `target_forum_id`,
|
|
(
|
|
SELECT COUNT(`topic_id`)
|
|
FROM `msz_forum_topics`
|
|
WHERE `forum_id` = `target_forum_id`
|
|
AND `topic_deleted` IS NULL
|
|
) AS `count_topics`,
|
|
(
|
|
SELECT COUNT(`post_id`)
|
|
FROM `msz_forum_posts`
|
|
WHERE `forum_id` = `target_forum_id`
|
|
AND `post_deleted` IS NULL
|
|
) AS `count_posts`
|
|
');
|
|
}
|
|
|
|
if($save && is_null($setCounts)) {
|
|
$setCounts = \Misuzu\DB::prepare('
|
|
UPDATE `msz_forum_categories`
|
|
SET `forum_count_topics` = :topics,
|
|
`forum_count_posts` = :posts
|
|
WHERE `forum_id` = :forum_id
|
|
');
|
|
}
|
|
|
|
$getChildren->bind('parent', $forumId);
|
|
$children = $getChildren->fetchAll();
|
|
|
|
$topics = 0;
|
|
$posts = 0;
|
|
|
|
foreach($children as $child) {
|
|
$childCount = forum_count_synchronise($child['forum_id'], $save);
|
|
$topics += $childCount['topics'];
|
|
$posts += $childCount['posts'];
|
|
}
|
|
|
|
$getCounts->bind('forum', $forumId);
|
|
$counts = $getCounts->fetch();
|
|
$topics += $counts['count_topics'];
|
|
$posts += $counts['count_posts'];
|
|
|
|
if($forumId > 0 && $save) {
|
|
$setCounts->bind('forum_id', $forumId);
|
|
$setCounts->bind('topics', $topics);
|
|
$setCounts->bind('posts', $posts);
|
|
$setCounts->execute();
|
|
}
|
|
|
|
return compact('topics', 'posts');
|
|
}
|
|
|
|
function forum_get_user_most_active_category_info(int $userId): ?object {
|
|
if($userId < 1)
|
|
return null;
|
|
|
|
global $cfg;
|
|
|
|
$getActiveForum = \Misuzu\DB::prepare(sprintf(
|
|
'SELECT forum_id, COUNT(*) AS post_count FROM msz_forum_posts WHERE user_id = :user AND post_deleted IS NULL AND forum_id NOT IN (%s) GROUP BY forum_id ORDER BY post_count DESC LIMIT 1',
|
|
implode(',', $cfg->getValue('forum_leader.unranked.forum', \Misuzu\Config\IConfig::T_ARR))
|
|
));
|
|
$getActiveForum->bind('user', $userId);
|
|
|
|
return $getActiveForum->fetchObject();
|
|
}
|