Rewrote forum permission backend (removed all WITH RECURSIVE statements).

This commit is contained in:
flash 2019-04-30 22:55:12 +02:00
parent 7a9462d660
commit 3b84f4c9e0
16 changed files with 281 additions and 227 deletions

View file

@ -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/)

View file

@ -0,0 +1,42 @@
<?php
namespace Misuzu\DatabaseMigrations\RemoveWithRecursive;
use PDO;
function migrate_up(PDO $conn): void
{
$conn->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`
");
}

View file

@ -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 <i>at least</i> PHP <b>' . MSZ_PHP_MIN_VER . '</b> to run.');
}
error_reporting(MSZ_DEBUG ? -1 : 0);
ini_set('display_errors', MSZ_DEBUG ? 'On' : 'Off');

View file

@ -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);
}
}

View file

@ -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)
);
}
}

View file

@ -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;
}

View file

@ -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))

View file

@ -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'));

View file

@ -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'])) {

View file

@ -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
$getBreadcrumb = db_prepare('
SELECT `forum_id`, `forum_name`, `forum_type`, `forum_parent`
FROM `msz_forum_categories`
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
');
$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
SELECT `forum_id`, `forum_parent`, `forum_colour`
FROM `msz_forum_categories`
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
');
$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);
}
return $memoized[$memoId];
}
@ -330,8 +334,11 @@ function forum_latest_post(int $forumId, int $userId): array
return $memoized[$memoId];
}
$getLastPost = db_prepare(sprintf(
'
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`,
@ -349,15 +356,9 @@ function forum_latest_post(int $forumId, int $userId): array
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
));
');
$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);

View file

@ -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 = [];
foreach (MSZ_FORUM_PERM_MODES as $mode) {
foreach (MSZ_PERM_SETS as $set) {
$perms[] = perms_get_key($mode, $set);
}
}
$perms = perms_get_blank(MSZ_FORUM_PERM_MODES);
if ($user < 1 || $forum < 0) {
return $perms;
}
function forum_perms_create(): array
{
$perms = [];
static $memo = [];
$memoId = "{$forum}-{$user}";
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_role(?int $forum, int $role): array
{
$perms = perms_get_blank(MSZ_FORUM_PERM_MODES);
if ($role < 1 || $forum < 0) {
return $perms;
}
static $memo = [];
$memoId = "{$forum}-{$role}";
if (array_key_exists($memoId, $memo)) {
return $memo[$memoId];
}
if ($forum > 0) {
$perms = forum_perms_get_role(
forum_get_parent_id($forum),
$role
);
}
function forum_perms_get_user(string $prefix, int $forum, int $user): int
{
if (!in_array($prefix, MSZ_FORUM_PERM_MODES) || $user < 0) {
return 0;
}
$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;
}
function forum_perms_get_role(string $prefix, int $forum, int $role): int
{
if (!in_array($prefix, MSZ_FORUM_PERM_MODES) || $role < 1) {
return 0;
}
$getPerms = db_prepare("
SELECT BIT_OR(`{$prefix}_perms`)
FROM `msz_forum_permissions_view`
$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()) . '`
$getPerms = db_prepare(sprintf(
'
SELECT `%s`
FROM `msz_forum_permissions`
WHERE `forum_id` %s
AND `user_id` = :user_id
AND `role_id` IS NULL
', $forum === null ? 'IS NULL' : '= :forum_id'));
',
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);
}

View file

@ -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']);

View file

@ -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']);

View file

@ -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)
function array_bit_or(array $array1, array $array2): array
{
if (count($array)) {
reset($array);
return key($array);
foreach ($array1 as $key => $value) {
$array1[$key] |= $array2[$key] ?? 0;
}
return null;
}
return $array1;
}

View file

@ -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

View file

@ -30,7 +30,7 @@
{{ container_title('<i class="fas fa-comment-slash fa-fw"></i> Forums') }}
<div class="container__content">
<p>There are no forums yet, check back later!</p>
<p>There are currently no visible forums.</p>
</div>
</div>
{% endif %}