From 3b84f4c9e0521975d828a4f727162bb54a860fbe Mon Sep 17 00:00:00 2001 From: flashwave Date: Tue, 30 Apr 2019 22:55:12 +0200 Subject: [PATCH] Rewrote forum permission backend (removed all WITH RECURSIVE statements). --- README.md | 4 +- ...019_04_30_190530_remove_with_recursive.php | 42 ++++ misuzu.php | 5 + public/forum/forum.php | 6 +- public/forum/index.php | 6 +- public/forum/post.php | 15 +- public/forum/posting.php | 2 +- public/forum/topic.php | 10 +- public/manage/forum.php | 2 +- src/Forum/forum.php | 205 +++++++++--------- src/Forum/perms.php | 146 +++++++------ src/Forum/post.php | 22 +- src/Forum/topic.php | 2 +- src/array.php | 16 +- src/perms.php | 23 +- templates/forum/index.twig | 2 +- 16 files changed, 281 insertions(+), 227 deletions(-) create mode 100644 database/2019_04_30_190530_remove_with_recursive.php diff --git a/README.md b/README.md index 188eba8a..540f43bf 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ [![License](https://img.shields.io/github/license/flashwave/misuzu.svg)](https://github.com/flashwave/misuzu/blob/master/LICENSE) ## Requirements - - PHP 7.2 - - MySQL 8.0 + - PHP 7.3 + - MariaDB 10.3 - [Composer](https://getcomposer.org/) - [node.js](https://nodejs.org/) (for the typescript and less compilers) - [Yarn](https://yarnpkg.com/) diff --git a/database/2019_04_30_190530_remove_with_recursive.php b/database/2019_04_30_190530_remove_with_recursive.php new file mode 100644 index 00000000..25c8c65d --- /dev/null +++ b/database/2019_04_30_190530_remove_with_recursive.php @@ -0,0 +1,42 @@ +exec('DROP VIEW `msz_forum_permissions_view`'); +} + +function migrate_down(PDO $conn): void +{ + $conn->exec(" + CREATE VIEW `msz_forum_permissions_view` AS + WITH RECURSIVE permissions(user_id, role_id, forum_id, forum_perms_allow, forum_perms_deny) as ( + SELECT + pp.`user_id`, pp.`role_id`, + pc.`forum_id`, + IFNULL(pp.`forum_perms_allow`, 0), IFNULL(pp.`forum_perms_deny`, 0) + FROM `msz_forum_categories` as pc + LEFT JOIN `msz_forum_permissions` as pp + ON pp.`forum_id` = pc.`forum_id` + GROUP BY `user_id`, `role_id`, `forum_id` + UNION ALL + SELECT + permissions.`user_id`, permissions.`role_id`, + cc.`forum_id`, + IFNULL(cp.`forum_perms_allow`, 0) | permissions.`forum_perms_allow`, + IFNULL(cp.`forum_perms_deny`, 0) | permissions.`forum_perms_deny` + FROM `msz_forum_categories` as cc + LEFT JOIN `msz_forum_permissions` as cp + ON cp.`forum_id` = cc.`forum_id` + INNER JOIN permissions + ON cc.`forum_parent` = permissions.`forum_id` + ) + SELECT + `user_id`, `role_id`, `forum_id`, + (BIT_OR(`forum_perms_allow`) &~ BIT_OR(`forum_perms_deny`)) as `forum_perms` + FROM permissions + GROUP BY `user_id`, `role_id`, `forum_id` + "); +} diff --git a/misuzu.php b/misuzu.php index fff8b486..788ca2c4 100644 --- a/misuzu.php +++ b/misuzu.php @@ -4,6 +4,11 @@ namespace Misuzu; define('MSZ_STARTUP', microtime(true)); define('MSZ_ROOT', __DIR__); define('MSZ_DEBUG', is_file(MSZ_ROOT . '/.debug')); +define('MSZ_PHP_MIN_VER', '7.3.0'); + +if (version_compare(PHP_VERSION, MSZ_PHP_MIN_VER, '<')) { + die('Misuzu requires at least PHP ' . MSZ_PHP_MIN_VER . ' to run.'); +} error_reporting(MSZ_DEBUG ? -1 : 0); ini_set('display_errors', MSZ_DEBUG ? 'On' : 'Off'); diff --git a/public/forum/forum.php b/public/forum/forum.php index cfd84613..57a35436 100644 --- a/public/forum/forum.php +++ b/public/forum/forum.php @@ -17,7 +17,7 @@ if (empty($forum) || ($forum['forum_type'] == MSZ_FORUM_TYPE_LINK && empty($foru return; } -$perms = forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $forum['forum_id'], $forumUserId); +$perms = forum_perms_get_user($forum['forum_id'], $forumUserId)[MSZ_FORUM_PERMS_GENERAL]; if (!perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM)) { echo render_error(403); @@ -58,11 +58,11 @@ $topics = $forumMayHaveTopics $forumMayHaveChildren = forum_may_have_children($forum['forum_type']); if ($forumMayHaveChildren) { - $forum['forum_subforums'] = forum_get_children($forum['forum_id'], $forumUserId, MSZ_FORUM_POSTS_PER_PAGE); + $forum['forum_subforums'] = forum_get_children($forum['forum_id'], $forumUserId); foreach ($forum['forum_subforums'] as $skey => $subforum) { $forum['forum_subforums'][$skey]['forum_subforums'] - = forum_get_children($subforum['forum_id'], $forumUserId, MSZ_FORUM_POSTS_PER_PAGE, true); + = forum_get_children($subforum['forum_id'], $forumUserId); } } diff --git a/public/forum/index.php b/public/forum/index.php index 21698aef..9286ac5a 100644 --- a/public/forum/index.php +++ b/public/forum/index.php @@ -22,8 +22,7 @@ switch ($indexMode) { foreach ($categories as $key => $category) { $categories[$key]['forum_subforums'] = forum_get_children( $category['forum_id'], - user_session_current('user_id', 0), - perms_check($category['forum_permissions'], MSZ_FORUM_PERM_DELETE_ANY_POST) + user_session_current('user_id', 0) ); foreach ($categories[$key]['forum_subforums'] as $skey => $sub) { @@ -34,8 +33,7 @@ switch ($indexMode) { $categories[$key]['forum_subforums'][$skey]['forum_subforums'] = forum_get_children( $sub['forum_id'], - user_session_current('user_id', 0), - perms_check($sub['forum_permissions'], MSZ_FORUM_PERM_DELETE_ANY_POST) + user_session_current('user_id', 0) ); } } diff --git a/public/forum/post.php b/public/forum/post.php index 1d8ed7f9..ea42fe3c 100644 --- a/public/forum/post.php +++ b/public/forum/post.php @@ -55,7 +55,9 @@ if ($isXHR) { } $postInfo = forum_post_get($postId, true); -$perms = empty($postInfo) ? 0 : forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $postInfo['forum_id'], $currentUserId); +$perms = empty($postInfo) + ? 0 + : forum_perms_get_user($postInfo['forum_id'], $currentUserId)[MSZ_FORUM_PERMS_GENERAL]; switch ($postMode) { case 'delete': @@ -244,7 +246,9 @@ switch ($postMode) { break; default: // function as an alt for topic.php?p= by default - if (!empty($postInfo['post_deleted']) && !perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST)) { + $canDeleteAny = perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST); + + if (!empty($postInfo['post_deleted']) && !$canDeleteAny) { echo render_error(404); break; } @@ -256,8 +260,13 @@ switch ($postMode) { break; } + if ($canDeleteAny) { + $postInfo['preceeding_post_count'] += $postInfo['preceeding_post_deleted_count']; + } + + unset($postInfo['preceeding_post_deleted_count']); + if ($isXHR) { - unset($postFind['can_view_deleted']); echo json_encode($postFind); break; } diff --git a/public/forum/posting.php b/public/forum/posting.php index ce3d2a9e..91b2bcb6 100644 --- a/public/forum/posting.php +++ b/public/forum/posting.php @@ -78,7 +78,7 @@ if (empty($forum)) { return; } -$perms = forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $forum['forum_id'], user_session_current('user_id')); +$perms = forum_perms_get_user($forum['forum_id'], user_session_current('user_id'))[MSZ_FORUM_PERMS_GENERAL]; if ($forum['forum_archived'] || (!empty($topic['topic_locked']) && !perms_check($perms, MSZ_FORUM_PERM_LOCK_TOPIC)) diff --git a/public/forum/topic.php b/public/forum/topic.php index 05a4a5a3..5aceada3 100644 --- a/public/forum/topic.php +++ b/public/forum/topic.php @@ -18,7 +18,7 @@ if ($topicId < 1 && $postId > 0) { $topic = forum_topic_get($topicId, true); $perms = $topic - ? forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $topic['forum_id'], $topicUserId) + ? forum_perms_get_user($topic['forum_id'], $topicUserId)[MSZ_FORUM_PERMS_GENERAL] : 0; if (user_warning_check_restriction($topicUserId)) { @@ -329,7 +329,13 @@ if ($canDeleteAny) { $topicPagination = pagination_create($topicPosts, MSZ_FORUM_POSTS_PER_PAGE); if (isset($postInfo['preceeding_post_count'])) { - $postsPage = floor($postInfo['preceeding_post_count'] / $topicPagination['range']) + 1; + $preceedingPosts = $postInfo['preceeding_post_count']; + + if ($canDeleteAny) { + $preceedingPosts += $postInfo['preceeding_post_deleted_count']; + } + + $postsPage = floor($preceedingPosts / $topicPagination['range']) + 1; } $postsOffset = pagination_offset($topicPagination, $postsPage ?? pagination_param('page')); diff --git a/public/manage/forum.php b/public/manage/forum.php index e2bb8065..17e1c3f0 100644 --- a/public/manage/forum.php +++ b/public/manage/forum.php @@ -4,7 +4,7 @@ require_once '../../misuzu.php'; switch ($_GET['v'] ?? null) { case 'listing': $forums = db_query('SELECT * FROM `msz_forum_categories`'); - $rawPerms = forum_perms_create(); + $rawPerms = perms_create(MSZ_FORUM_PERM_MODES); $perms = manage_forum_perms_list($rawPerms); if (!empty($_POST['perms']) && is_array($_POST['perms'])) { diff --git a/src/Forum/forum.php b/src/Forum/forum.php index 3ff157d7..98efa726 100644 --- a/src/Forum/forum.php +++ b/src/Forum/forum.php @@ -119,22 +119,16 @@ function forum_get_root_categories(int $userId): array SELECT COUNT(`forum_id`) FROM `msz_forum_categories` AS sf WHERE sf.`forum_parent` = f.`forum_id` - ) AS `forum_children`, - (%2$s) AS `forum_permissions` + ) 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` - HAVING (`forum_permissions` & %3$d) > 0 ORDER BY f.`forum_order` ', - MSZ_FORUM_TYPE_CATEGORY, - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 'f.`forum_id`'), - MSZ_FORUM_PERM_SET_READ + MSZ_FORUM_TYPE_CATEGORY )); - $getCategories->bindValue('perm_user_id_user', $userId); - $getCategories->bindValue('perm_user_id_role', $userId); $categories = array_merge([MSZ_FORUM_ROOT_DATA], db_fetch_all($getCategories)); $getRootForumCount = db_prepare(sprintf( @@ -143,18 +137,20 @@ function forum_get_root_categories(int $userId): array FROM `msz_forum_categories` WHERE `forum_parent` = %d AND `forum_type` != %d - AND (%s & %d) > 0 ", MSZ_FORUM_ROOT, - MSZ_FORUM_TYPE_CATEGORY, - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, '`forum_id`'), - MSZ_FORUM_PERM_SET_READ + MSZ_FORUM_TYPE_CATEGORY )); - $getRootForumCount->bindValue('perm_user_id_user', $userId); - $getRootForumCount->bindValue('perm_user_id_role', $userId); $categories[0]['forum_children'] = (int)($getRootForumCount->execute() ? $getRootForumCount->fetchColumn() : 0); 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)], @@ -172,27 +168,20 @@ function forum_get_breadcrumbs( array $indexLink = ['Forums' => '/forum/'] ): array { $breadcrumbs = []; - $getBreadcrumbs = db_prepare(' - WITH RECURSIVE breadcrumbs(forum_id, forum_name, forum_parent, forum_type) as ( - SELECT c.`forum_id`, c.`forum_name`, c.`forum_parent`, c.`forum_type` - FROM `msz_forum_categories` as c - WHERE `forum_id` = :forum_id - UNION ALL - SELECT p.`forum_id`, p.`forum_name`, p.`forum_parent`, p.`forum_type` - FROM `msz_forum_categories` as p - INNER JOIN breadcrumbs - ON p.`forum_id` = breadcrumbs.forum_parent - ) - SELECT * FROM breadcrumbs + $getBreadcrumb = db_prepare(' + SELECT `forum_id`, `forum_name`, `forum_type`, `forum_parent` + FROM `msz_forum_categories` + WHERE `forum_id` = :forum_id '); - $getBreadcrumbs->bindValue('forum_id', $forumId); - $breadcrumbsDb = db_fetch_all($getBreadcrumbs); - if (!$breadcrumbsDb) { - return [$indexLink]; - } + while($forumId > 0) { + $getBreadcrumb->bindValue('forum_id', $forumId); + $breadcrumb = db_fetch($getBreadcrumb); + + if(empty($breadcrumb)) { + break; + } - foreach ($breadcrumbsDb as $breadcrumb) { $breadcrumbs[$breadcrumb['forum_name']] = sprintf( $breadcrumb['forum_parent'] === MSZ_FORUM_ROOT && $breadcrumb['forum_type'] === MSZ_FORUM_TYPE_CATEGORY @@ -200,6 +189,7 @@ function forum_get_breadcrumbs( : $linkFormat, $breadcrumb['forum_id'] ); + $forumId = $breadcrumb['forum_parent']; } return array_reverse($breadcrumbs + $indexLink); @@ -208,27 +198,24 @@ function forum_get_breadcrumbs( function forum_get_colour(int $forumId): int { $getColours = db_prepare(' - WITH RECURSIVE breadcrumbs(forum_id, forum_parent, forum_colour) as ( - SELECT c.`forum_id`, c.`forum_parent`, c.`forum_colour` - FROM `msz_forum_categories` as c - WHERE `forum_id` = :forum_id - UNION ALL - SELECT p.`forum_id`, p.`forum_parent`, p.`forum_colour` - FROM `msz_forum_categories` as p - INNER JOIN breadcrumbs - ON p.`forum_id` = breadcrumbs.forum_parent - ) - SELECT * FROM breadcrumbs + SELECT `forum_id`, `forum_parent`, `forum_colour` + FROM `msz_forum_categories` + WHERE `forum_id` = :forum_id '); - $getColours->bindValue('forum_id', $forumId); - $colours = db_fetch_all($getColours); - if ($colours) { - foreach ($colours as $colour) { - if ($colour['forum_colour'] !== null) { - return $colour['forum_colour']; - } + while($forumId > 0) { + $getColours->bindValue('forum_id', $forumId); + $colourInfo = db_fetch($getColours); + + if(empty($colourInfo)) { + break; } + + if(!empty($colourInfo['forum_colour'])) { + return $colourInfo['forum_colour']; + } + + $forumId = $colourInfo['forum_parent']; } return colour_none(); @@ -247,6 +234,28 @@ function forum_increment_clicks(int $forumId): void $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 = db_prepare(' + SELECT `forum_parent` + FROM `msz_forum_categories` + WHERE `forum_id` = :forum_id + '); + $getParent->bindValue('forum_id', $forumId); + + return (int)($getParent->execute() ? $getParent->fetchColumn() : 0); +} + function forum_get_child_ids(int $forumId): array { if ($forumId < 1) { @@ -290,29 +299,24 @@ function forum_topics_unread(int $forumId, int $userId): int $memoized[$memoId] += forum_topics_unread($child, $userId); } - $countUnread = db_prepare(sprintf( - ' + if (forum_perms_check_user(MSZ_FORUM_PERMS_GENERAL, $forumId, $userId, MSZ_FORUM_PERM_SET_READ)) { + $countUnread = 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 ((%s) & %d) > 0 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` ) - ', - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 'ti.`forum_id`'), - MSZ_FORUM_PERM_SET_READ - )); - $countUnread->bindValue('forum_id', $forumId); - $countUnread->bindValue('user_id', $userId); - $countUnread->bindValue('perm_user_id_user', $userId); - $countUnread->bindValue('perm_user_id_role', $userId); - $memoized[$memoId] += (int)($countUnread->execute() ? $countUnread->fetchColumn() : 0); + '); + $countUnread->bindValue('forum_id', $forumId); + $countUnread->bindValue('user_id', $userId); + $memoized[$memoId] += (int)($countUnread->execute() ? $countUnread->fetchColumn() : 0); + } return $memoized[$memoId]; } @@ -330,34 +334,31 @@ function forum_latest_post(int $forumId, int $userId): array return $memoized[$memoId]; } - $getLastPost = db_prepare(sprintf( - ' - 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 - AND ((%s) & %d) > 0 - ORDER BY p.`post_id` DESC - ', - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 'p.`forum_id`'), - MSZ_FORUM_PERM_SET_READ - )); + if (!forum_perms_check_user(MSZ_FORUM_PERMS_GENERAL, $forumId, $userId, MSZ_FORUM_PERM_SET_READ)) { + return $memoized[$memoId] = []; + } + + $getLastPost = 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->bindValue('forum_id', $forumId); - $getLastPost->bindValue('perm_user_id_user', $userId); - $getLastPost->bindValue('perm_user_id_role', $userId); $currentLast = db_fetch($getLastPost); $children = forum_get_child_ids($forumId); @@ -373,7 +374,7 @@ function forum_latest_post(int $forumId, int $userId): array return $memoized[$memoId] = $currentLast; } -function forum_get_children(int $parentId, int $userId, bool $showDeleted = false): array +function forum_get_children(int $parentId, int $userId): array { $getListing = db_prepare(sprintf( ' @@ -381,8 +382,7 @@ function forum_get_children(int $parentId, int $userId, bool $showDeleted = fals :user_id AS `target_user_id`, f.`forum_id`, f.`forum_name`, f.`forum_description`, f.`forum_type`, f.`forum_link`, f.`forum_link_clicks`, f.`forum_archived`, f.`forum_colour`, - f.`forum_count_topics`, f.`forum_count_posts`, - (%3$s) AS `forum_permissions` + 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 @@ -391,25 +391,25 @@ function forum_get_children(int $parentId, int $userId, bool $showDeleted = fals OR f.`forum_parent` != %1$d ) GROUP BY f.`forum_id` - HAVING (`forum_permissions` & %4$d) > 0 ORDER BY f.`forum_order` ', MSZ_FORUM_ROOT, - MSZ_FORUM_TYPE_CATEGORY, - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 'f.`forum_id`'), - MSZ_FORUM_PERM_SET_READ, - $showDeleted ? '' : 'AND `topic_deleted` IS NULL', - $showDeleted ? '' : 'AND `post_deleted` IS NULL' + MSZ_FORUM_TYPE_CATEGORY )); $getListing->bindValue('user_id', $userId); - $getListing->bindValue('perm_user_id_user', $userId); - $getListing->bindValue('perm_user_id_role', $userId); $getListing->bindValue('parent_id', $parentId); $listing = db_fetch_all($getListing); 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)], @@ -454,13 +454,10 @@ function forum_mark_read(?int $forumId, int $userId): void AND t.`topic_bumped` >= NOW() - INTERVAL 1 MONTH %1$s GROUP BY t.`topic_id` - HAVING ((%2$s) & %3$d) > 0 ON DUPLICATE KEY UPDATE `track_last_read` = NOW() ', - $entireForum ? '' : 'AND t.`forum_id` = :forum', - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 't.`forum_id`', 'u.`user_id`', 'u.`user_id`'), - MSZ_FORUM_PERM_SET_READ + $entireForum ? '' : 'AND t.`forum_id` = :forum' )); $doMark->bindValue('user', $userId); diff --git a/src/Forum/perms.php b/src/Forum/perms.php index 29709c81..5264976a 100644 --- a/src/Forum/perms.php +++ b/src/Forum/perms.php @@ -5,106 +5,109 @@ define('MSZ_FORUM_PERM_MODES', [ MSZ_FORUM_PERMS_GENERAL, ]); -function forum_perms_get_keys(): array +function forum_perms_get_user(?int $forum, int $user): array { - $perms = []; + $perms = perms_get_blank(MSZ_FORUM_PERM_MODES); - foreach (MSZ_FORUM_PERM_MODES as $mode) { - foreach (MSZ_PERM_SETS as $set) { - $perms[] = perms_get_key($mode, $set); - } + if ($user < 1 || $forum < 0) { + return $perms; } - return $perms; -} + static $memo = []; + $memoId = "{$forum}-{$user}"; -function forum_perms_create(): array -{ - $perms = []; - - foreach (forum_perms_get_keys() as $key) { - $perms[$key] = 0; + if (array_key_exists($memoId, $memo)) { + return $memo[$memoId]; } - return $perms; -} + if ($forum > 0) { + $perms = forum_perms_get_user( + forum_get_parent_id($forum), + $user + ); + } -function forum_perms_get_user_sql( - string $prefix, - string $forum_id_param = ':perm_forum_id', - string $user_id_user_param = ':perm_user_id_user', - string $user_id_role_param = ':perm_user_id_role' -): string { - return sprintf( + $getPerms = db_prepare(sprintf( ' - SELECT BIT_OR(`%1$s_perms`) - FROM `msz_forum_permissions_view` - WHERE (`forum_id` = %2$s OR `forum_id` IS NULL) + SELECT %s + FROM `msz_forum_permissions` + WHERE (`forum_id` = :forum_id OR `forum_id` IS NULL) AND ( - (`user_id` IS NULL AND `role_id` IS NULL) - OR (`user_id` = %3$s AND `role_id` IS NULL) + (`user_id` = :user_id_1 AND `role_id` IS NULL) OR ( `user_id` IS NULL AND `role_id` IN ( SELECT `role_id` FROM `msz_user_roles` - WHERE `user_id` = %4$s + WHERE `user_id` = :user_id_2 ) ) ) ', - $prefix, - $forum_id_param, - $user_id_user_param, - $user_id_role_param - ); + perms_get_select(MSZ_FORUM_PERM_MODES) + )); + $getPerms->bindValue('forum_id', $forum); + $getPerms->bindValue('user_id_1', $user); + $getPerms->bindValue('user_id_2', $user); + + return $memo[$memoId] = array_bit_or($perms, db_fetch($getPerms)); } -function forum_perms_get_user(string $prefix, int $forum, int $user): int +function forum_perms_get_role(?int $forum, int $role): array { - if (!in_array($prefix, MSZ_FORUM_PERM_MODES) || $user < 0) { - return 0; + $perms = perms_get_blank(MSZ_FORUM_PERM_MODES); + + if ($role < 1 || $forum < 0) { + return $perms; } - $getPerms = db_prepare(forum_perms_get_user_sql($prefix)); - $getPerms->bindValue('perm_forum_id', $forum); - $getPerms->bindValue('perm_user_id_user', $user); - $getPerms->bindValue('perm_user_id_role', $user); - return $getPerms->execute() ? (int)$getPerms->fetchColumn() : 0; -} + static $memo = []; + $memoId = "{$forum}-{$role}"; -function forum_perms_get_role(string $prefix, int $forum, int $role): int -{ - if (!in_array($prefix, MSZ_FORUM_PERM_MODES) || $role < 1) { - return 0; + if (array_key_exists($memoId, $memo)) { + return $memo[$memoId]; } - $getPerms = db_prepare(" - SELECT BIT_OR(`{$prefix}_perms`) - FROM `msz_forum_permissions_view` - WHERE (`forum_id` = :forum_id OR `forum_id` IS NULL) - AND `role_id` = :role_id - AND `user_id` IS NULL - "); + if ($forum > 0) { + $perms = forum_perms_get_role( + forum_get_parent_id($forum), + $role + ); + } + + $getPerms = db_prepare(sprintf( + ' + SELECT %s + FROM `msz_forum_permissions` + WHERE (`forum_id` = :forum_id OR `forum_id` IS NULL) + AND `role_id` = :role_id + AND `user_id` IS NULL + ', + perms_get_select(MSZ_FORUM_PERM_MODES) + )); $getPerms->bindValue('forum_id', $forum); $getPerms->bindValue('role_id', $role); - return $getPerms->execute() ? (int)$getPerms->fetchColumn() : 0; + + return $memo[$memoId] = array_bit_or($perms, db_fetch($getPerms)); } function forum_perms_get_user_raw(?int $forum, int $user): array { if ($user < 1) { - return forum_perms_create(); + return perms_create(MSZ_FORUM_PERM_MODES); } - $getPerms = db_prepare(sprintf(' - SELECT - `' . implode('`, `', forum_perms_get_keys()) . '` - FROM `msz_forum_permissions` - WHERE `forum_id` %s - AND `user_id` = :user_id - AND `role_id` IS NULL - ', $forum === null ? 'IS NULL' : '= :forum_id')); + $getPerms = db_prepare(sprintf( + ' + SELECT `%s` + FROM `msz_forum_permissions` + WHERE `forum_id` %s + AND `user_id` = :user_id + AND `role_id` IS NULL + ', + implode('`, `', perms_get_keys(MSZ_FORUM_PERM_MODES)), + $forum === null ? 'IS NULL' : '= :forum_id' + )); if ($forum !== null) { $getPerms->bindValue('forum_id', $forum); @@ -114,7 +117,7 @@ function forum_perms_get_user_raw(?int $forum, int $user): array $perms = db_fetch($getPerms); if (empty($perms)) { - return forum_perms_create(); + return perms_create(MSZ_FORUM_PERM_MODES); } return $perms; @@ -123,18 +126,18 @@ function forum_perms_get_user_raw(?int $forum, int $user): array function forum_perms_get_role_raw(?int $forum, ?int $role): array { if ($role < 1 && $role !== null) { - return forum_perms_create(); + return perms_create(MSZ_FORUM_PERM_MODES); } $getPerms = db_prepare(sprintf( ' - SELECT - `' . implode('`, `', forum_perms_get_keys()) . '` + SELECT `%s` FROM `msz_forum_permissions` WHERE `forum_id` %s AND `user_id` IS NULL AND `role_id` %s ', + implode('`, `', perms_get_keys(MSZ_FORUM_PERM_MODES)), $forum === null ? 'IS NULL' : '= :forum_id', $role === null ? 'IS NULL' : '= :role_id' )); @@ -150,8 +153,13 @@ function forum_perms_get_role_raw(?int $forum, ?int $role): array $perms = db_fetch($getPerms); if (empty($perms)) { - return forum_perms_create(); + return perms_create(MSZ_FORUM_PERM_MODES); } return $perms; } + +function forum_perms_check_user(string $prefix, ?int $forumId, ?int $userId, int $perm): bool +{ + return $userId > 0 && perms_check(forum_perms_get_user($forumId, $userId)[$prefix] ?? 0, $perm); +} diff --git a/src/Forum/post.php b/src/Forum/post.php index 32ef4858..dd2b1f69 100644 --- a/src/Forum/post.php +++ b/src/Forum/post.php @@ -64,24 +64,26 @@ function forum_post_find(int $postId, int $userId): array ' SELECT p.`post_id`, p.`topic_id`, - ((%s) & %d) as `can_view_deleted`, ( SELECT COUNT(`post_id`) FROM `msz_forum_posts` WHERE `topic_id` = p.`topic_id` AND `post_id` < p.`post_id` - AND (`can_view_deleted` OR `post_deleted` IS NULL) + AND `post_deleted` IS NULL ORDER BY `post_id` - ) as `preceeding_post_count` + ) as `preceeding_post_count`, + ( + SELECT COUNT(`post_id`) + FROM `msz_forum_posts` + WHERE `topic_id` = p.`topic_id` + AND `post_id` < p.`post_id` + AND `post_deleted` IS NOT NULL + ORDER BY `post_id` + ) as `preceeding_post_deleted_count` FROM `msz_forum_posts` AS p WHERE p.`post_id` = :post_id - ', - forum_perms_get_user_sql(MSZ_FORUM_PERMS_GENERAL, 'p.`forum_id`'), - MSZ_FORUM_PERM_DELETE_ANY_POST - )); + ')); $getPostInfo->bindValue('post_id', $postId); - $getPostInfo->bindValue('perm_user_id_user', $userId); - $getPostInfo->bindValue('perm_user_id_role', $userId); return db_fetch($getPostInfo); } @@ -232,7 +234,7 @@ function forum_post_can_delete($postId, ?int $userId = null): int } $isSystemReq = $userId === null; - $perms = $isSystemReq ? 0 : forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $post['forum_id'], $userId); + $perms = $isSystemReq ? 0 : forum_perms_get_user($post['forum_id'], $userId)[MSZ_FORUM_PERMS_GENERAL]; $canDeleteAny = $isSystemReq ? true : perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST); $canViewPost = $isSystemReq ? true : perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM); $postIsDeleted = !empty($post['post_deleted']); diff --git a/src/Forum/topic.php b/src/Forum/topic.php index 68686582..05554f66 100644 --- a/src/Forum/topic.php +++ b/src/Forum/topic.php @@ -451,7 +451,7 @@ function forum_topic_can_delete($topicId, ?int $userId = null): int } $isSystemReq = $userId === null; - $perms = $isSystemReq ? 0 : forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $topic['forum_id'], $userId); + $perms = $isSystemReq ? 0 : forum_perms_get_user($topic['forum_id'], $userId)[MSZ_FORUM_PERMS_GENERAL]; $canDeleteAny = $isSystemReq ? true : perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST); $canViewPost = $isSystemReq ? true : perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM); $postIsDeleted = !empty($topic['topic_deleted']); diff --git a/src/array.php b/src/array.php index fb5adf48..7344357f 100644 --- a/src/array.php +++ b/src/array.php @@ -19,15 +19,11 @@ function array_apply(array $array, callable $func): array return $array; } -if (!function_exists('array_key_first')) { - // https://secure.php.net/manual/en/function.array-key-first.php#123301 - function array_key_first(array $array) - { - if (count($array)) { - reset($array); - return key($array); - } - - return null; +function array_bit_or(array $array1, array $array2): array +{ + foreach ($array1 as $key => $value) { + $array1[$key] |= $array2[$key] ?? 0; } + + return $array1; } diff --git a/src/perms.php b/src/perms.php index 16e17fb9..e27591d0 100644 --- a/src/perms.php +++ b/src/perms.php @@ -14,32 +14,23 @@ define('MSZ_PERM_MODES', [ define('MSZ_PERMS_ALLOW', 'allow'); define('MSZ_PERMS_DENY', 'deny'); -define('MSZ_PERM_SETS', [ - MSZ_PERMS_ALLOW, MSZ_PERMS_DENY, -]); - -function perms_get_keys(): array +function perms_get_keys(array $modes = MSZ_PERM_MODES): array { $perms = []; foreach (MSZ_PERM_MODES as $mode) { - foreach (MSZ_PERM_SETS as $set) { - $perms[] = perms_get_key($mode, $set); - } + $perms[] = [ + perms_get_key($mode, MSZ_PERMS_ALLOW), + perms_get_key($mode, MSZ_PERMS_DENY), + ]; } return $perms; } -function perms_create(): array +function perms_create(array $modes = MSZ_PERM_MODES): array { - $perms = []; - - foreach (perms_get_keys() as $key) { - $perms[$key] = 0; - } - - return $perms; + return array_fill_keys(perms_get_keys($modes), 0); } function perms_get_key(string $prefix, string $suffix): string diff --git a/templates/forum/index.twig b/templates/forum/index.twig index 2b69e6e2..dac33494 100644 --- a/templates/forum/index.twig +++ b/templates/forum/index.twig @@ -30,7 +30,7 @@ {{ container_title(' Forums') }}
-

There are no forums yet, check back later!

+

There are currently no visible forums.

{% endif %}