Checkpoint! Perms work on the index.

This commit is contained in:
flash 2018-08-23 20:13:37 +02:00
parent 0752577888
commit 1ae61e6a23
7 changed files with 326 additions and 150 deletions

View file

@ -15,7 +15,8 @@
"swiftmailer/swiftmailer": "~6.0",
"erusev/parsedown": "~1.6",
"geoip2/geoip2": "~2.0",
"twig/extensions": "^1.5"
"twig/extensions": "^1.5",
"filp/whoops": "^2.2"
},
"require-dev": {
"phpunit/phpunit": "~6.0"

110
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b859e162d3882d5c8dbbfbb02b1eb0b7",
"content-hash": "1e2dfc77fb54aea063a4063f00da713e",
"packages": [
{
"name": "composer/ca-bundle",
@ -219,6 +219,67 @@
],
"time": "2018-03-08T01:11:30+00:00"
},
{
"name": "filp/whoops",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/181c4502d8f34db7aed7bfe88d4f87875b8e947a",
"reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a",
"shasum": ""
},
"require": {
"php": "^5.5.9 || ^7.0",
"psr/log": "^1.0.1"
},
"require-dev": {
"mockery/mockery": "^0.9 || ^1.0",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"symfony/var-dumper": "^2.6 || ^3.0 || ^4.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool kids",
"homepage": "https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"time": "2018-03-03T17:56:25+00:00"
},
{
"name": "geoip2/geoip2",
"version": "v2.9.0",
@ -428,6 +489,53 @@
],
"time": "2018-07-05T06:59:26+00:00"
},
{
"name": "psr/log",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2016-10-10T12:19:37+00:00"
},
{
"name": "swiftmailer/swiftmailer",
"version": "v6.1.2",

View file

@ -34,9 +34,40 @@ function migrate_up(PDO $conn): void
ON DELETE CASCADE
)
");
$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`
');
}
function migrate_down(PDO $conn): void
{
$conn->exec('DROP VIEW `msz_forum_permissions_view`');
$conn->exec('DROP TABLE `msz_forum_permissions`');
}

View file

@ -3,7 +3,20 @@ namespace Misuzu;
date_default_timezone_set('UTC');
define('MSZ_DEBUG', file_exists(__DIR__ . '/vendor/phpunit/phpunit/composer.json'));
require_once __DIR__ . '/vendor/autoload.php';
if (MSZ_DEBUG) {
$errorHandler = new \Whoops\Run;
$errorHandler->pushHandler(
PHP_SAPI === 'cli'
? new \Whoops\Handler\PlainTextHandler
: new \Whoops\Handler\PrettyPageHandler
);
$errorHandler->register();
}
require_once __DIR__ . '/src/audit_log.php';
require_once __DIR__ . '/src/changelog.php';
require_once __DIR__ . '/src/colour.php';
@ -29,7 +42,7 @@ require_once __DIR__ . '/src/Users/validation.php';
$app = new Application(
__DIR__ . '/config/config.ini',
IO\Directory::exists(__DIR__ . '/vendor/phpunit/phpunit')
MSZ_DEBUG
);
$app->startDatabase();

View file

@ -78,11 +78,14 @@ class Application extends ApplicationBase
$this->debugMode = $debug;
$this->configInstance = new ConfigManager($configFile);
ExceptionHandler::register(
$debug,
$this->configInstance->get('Exceptions', 'report_url', 'string', null),
$this->configInstance->get('Exceptions', 'hash_key', 'string', null)
);
// only use this error handler in prod mode, dev uses Whoops now
if (!$debug) {
ExceptionHandler::register(
false,
$this->configInstance->get('Exceptions', 'report_url', 'string', null),
$this->configInstance->get('Exceptions', 'hash_key', 'string', null)
);
}
}
public function getTimeSinceStart(): float
@ -105,14 +108,6 @@ class Application extends ApplicationBase
return $this->configInstance;
}
/**
* Shuts the application down.
*/
public function __destruct()
{
ExceptionHandler::unregister();
}
/**
* Gets whether we're in debug mode or not.
* @return bool

View file

@ -1,6 +1,8 @@
<?php
use Misuzu\Database;
require_once __DIR__ . '/perms.php';
define('MSZ_PERM_FORUM_MANAGE_FORUMS', 1);
define('MSZ_FORUM_PERM_LIST_FORUM', 1); // can see stats, but will get error when trying to view
@ -86,6 +88,7 @@ function forum_get_root_categories(int $userId): array
forum_perms_get_user_sql('forum', 'f.`forum_id`'),
MSZ_FORUM_PERM_CAN_LIST_FORUM
);
$getCategories = Database::prepare("
SELECT
f.`forum_id`, f.`forum_name`, f.`forum_type`,
@ -101,8 +104,8 @@ function forum_get_root_categories(int $userId): array
AND {$categoryPermSql} > 0
ORDER BY f.`forum_order`
");
$getCategories->bindValue('perm_user_id_1', $userId);
$getCategories->bindValue('perm_user_id_2', $userId);
$getCategories->bindValue('perm_user_id_user', $userId);
$getCategories->bindValue('perm_user_id_role', $userId);
$categories = $getCategories->execute() ? $getCategories->fetchAll(PDO::FETCH_ASSOC) : [];
$categories = array_merge([MSZ_FORUM_ROOT_DATA], $categories);
@ -118,8 +121,8 @@ function forum_get_root_categories(int $userId): array
AND `forum_type` != 1
AND {$forumPermSql} > 0
", MSZ_FORUM_ROOT));
$getRootForumCount->bindValue('perm_user_id_1', $userId);
$getRootForumCount->bindValue('perm_user_id_2', $userId);
$getRootForumCount->bindValue('perm_user_id_user', $userId);
$getRootForumCount->bindValue('perm_user_id_role', $userId);
$getRootForumCount->execute();
$categories[0]['forum_children'] = (int)$getRootForumCount->fetchColumn();
@ -133,22 +136,28 @@ function forum_get_breadcrumbs(
array $indexLink = ['Forums' => '/forum/']
): array {
$breadcrumbs = [];
$getBreadcrumb = Database::prepare('
SELECT `forum_id`, `forum_name`, `forum_parent`
FROM `msz_forum_categories`
WHERE `forum_id` = :forum_id
$getBreadcrumbs = Database::prepare('
WITH RECURSIVE breadcrumbs(forum_id, forum_name, forum_parent) as (
SELECT c.`forum_id`, c.`forum_name`, c.`forum_parent`
FROM `msz_forum_categories` as c
WHERE `forum_id` = :forum_id
UNION ALL
SELECT p.`forum_id`, p.`forum_name`, p.`forum_parent`
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 = $getBreadcrumbs->execute() ? $getBreadcrumbs->fetchAll(PDO::FETCH_ASSOC) : [];
while ($forumId > MSZ_FORUM_ROOT) {
$getBreadcrumb->bindValue('forum_id', $forumId);
$breadcrumb = $getBreadcrumb->execute() ? $getBreadcrumb->fetch() : [];
if (!$breadcrumb) {
break;
}
if (!$breadcrumbsDb) {
return [$indexLink];
}
foreach ($breadcrumbsDb as $breadcrumb) {
$breadcrumbs[$breadcrumb['forum_name']] = sprintf($linkFormat, $breadcrumb['forum_id']);
$forumId = $breadcrumb['forum_parent'];
}
return array_reverse($breadcrumbs + $indexLink);
@ -156,132 +165,146 @@ function forum_get_breadcrumbs(
function forum_increment_clicks(int $forumId): void
{
$incrementLinkClicks = Database::prepare('
$incrementLinkClicks = Database::prepare(sprintf('
UPDATE `msz_forum_categories`
SET `forum_link_clicks` = `forum_link_clicks` + 1
WHERE `forum_id` = :forum_id
AND `forum_type` = ' . MSZ_FORUM_TYPE_LINK . '
AND `forum_type` = %d
AND `forum_link_clicks` IS NOT NULL
');
', MSZ_FORUM_TYPE_LINK));
$incrementLinkClicks->bindValue('forum_id', $forumId);
$incrementLinkClicks->execute();
}
define('MSZ_FORUM_GET_CHILDREN_QUERY_SMALL', '
SELECT
:user_id as `target_user_id`,
f.`forum_id`, f.`forum_name`,
(
function forum_read_status_sql(
string $topic_id_param,
string $topic_bumped_param,
string $forum_id_param = 'f.`forum_id`',
string $user_param = '`target_user_id`'
): string {
return sprintf(
'
SELECT
`target_user_id` > 0
%1$s > 0
AND
t.`topic_id` IS NOT NULL
%2$s IS NOT NULL
AND
t.`topic_bumped` >= NOW() - INTERVAL 1 MONTH
%3$s >= NOW() - INTERVAL 1 MONTH
AND (
SELECT COUNT(ti.`topic_id`) < (
SELECT COUNT(`topic_id`)
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
WHERE `forum_id` = %4$s
AND `topic_bumped` >= NOW() - INTERVAL 1 MONTH
AND `topic_deleted` IS NULL
)
FROM `msz_forum_topics_track` as tt
RIGHT JOIN `msz_forum_topics` as ti
ON ti.`topic_id` = tt.`topic_id`
WHERE ti.`forum_id` = f.`forum_id`
AND tt.`user_id` = `target_user_id`
WHERE ti.`forum_id` = %4$s
AND tt.`user_id` = %1$s
AND `track_last_read` >= `topic_bumped`
)
) as `forum_unread`
FROM `msz_forum_categories` as f
LEFT JOIN `msz_forum_topics` as t
ON t.`topic_id` = (
SELECT `topic_id`
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
AND `topic_deleted` IS NULL
ORDER BY `topic_bumped` DESC
LIMIT 1
)
WHERE `forum_parent` = :parent_id
AND `forum_hidden` = false
ORDER BY f.`forum_order`
');
define('MSZ_FORUM_GET_CHILDREN_QUERY_STANDARD', '
SELECT
: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`,
t.`topic_id` as `recent_topic_id`, p.`post_id` as `recent_post_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`,
(
SELECT COUNT(`topic_id`)
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
) as `forum_topic_count`,
(
SELECT COUNT(`post_id`)
FROM `msz_forum_posts`
WHERE `forum_id` = f.`forum_id`
) as `forum_post_count`,
(
',
$user_param,
$topic_id_param,
$topic_bumped_param,
$forum_id_param
);
}
define(
'MSZ_FORUM_GET_CHILDREN_QUERY_SMALL',
sprintf(
'
SELECT
`target_user_id` > 0
AND
`recent_topic_id` IS NOT NULL
AND
`recent_topic_bumped` >= NOW() - INTERVAL 1 MONTH
AND (
SELECT COUNT(ti.`topic_id`) < (
:user_id as `target_user_id`,
f.`forum_id`, f.`forum_name`,
(%s) as `forum_unread`
FROM `msz_forum_categories` as f
LEFT JOIN `msz_forum_topics` as t
ON t.`topic_id` = (
SELECT `topic_id`
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
AND `topic_deleted` IS NULL
ORDER BY `topic_bumped` DESC
LIMIT 1
)
WHERE `forum_parent` = :parent_id
AND `forum_hidden` = false
AND (%s & %d) > 0
ORDER BY f.`forum_order`
',
forum_read_status_sql('t.`topic_id`', 't.`topic_bumped`'),
forum_perms_get_user_sql('forum', 'f.`forum_id`'),
MSZ_FORUM_PERM_CAN_LIST_FORUM
)
);
define(
'MSZ_FORUM_GET_CHILDREN_QUERY_STANDARD',
sprintf(
'
SELECT
: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`,
t.`topic_id` as `recent_topic_id`, p.`post_id` as `recent_post_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`,
(
SELECT COUNT(`topic_id`)
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
AND `topic_bumped` >= NOW() - INTERVAL 1 MONTH
AND `topic_deleted` IS NULL
)
FROM `msz_forum_topics_track` as tt
RIGHT JOIN `msz_forum_topics` as ti
ON ti.`topic_id` = tt.`topic_id`
WHERE ti.`forum_id` = f.`forum_id`
AND tt.`user_id` = `target_user_id`
AND `track_last_read` >= `topic_bumped`
) as `forum_topic_count`,
(
SELECT COUNT(`post_id`)
FROM `msz_forum_posts`
WHERE `forum_id` = f.`forum_id`
) as `forum_post_count`,
(%s) as `forum_unread`
FROM `msz_forum_categories` as f
LEFT JOIN `msz_forum_topics` as t
ON t.`topic_id` = (
SELECT `topic_id`
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
AND `topic_deleted` IS NULL
ORDER BY `topic_bumped` DESC
LIMIT 1
)
) as `forum_unread`
FROM `msz_forum_categories` as f
LEFT JOIN `msz_forum_topics` as t
ON t.`topic_id` = (
SELECT `topic_id`
FROM `msz_forum_topics`
WHERE `forum_id` = f.`forum_id`
AND `topic_deleted` IS NULL
ORDER BY `topic_bumped` DESC
LIMIT 1
LEFT JOIN `msz_forum_posts` as p
ON p.`post_id` = (
SELECT `post_id`
FROM `msz_forum_posts`
WHERE `topic_id` = t.`topic_id`
ORDER BY `post_id` DESC
LIMIT 1
)
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 f.`forum_parent` = :parent_id
AND f.`forum_hidden` = false
AND (%4$s & %5$d) > 0
AND (
(f.`forum_parent` = %2$d AND f.`forum_type` != %3$d)
OR f.`forum_parent` != %2$d
)
ORDER BY f.`forum_order`
',
forum_read_status_sql('`recent_topic_id`', '`recent_topic_bumped`'),
MSZ_FORUM_ROOT,
MSZ_FORUM_TYPE_CATEGORY,
forum_perms_get_user_sql('forum', 'f.`forum_id`'),
MSZ_FORUM_PERM_CAN_LIST_FORUM
)
LEFT JOIN `msz_forum_posts` as p
ON p.`post_id` = (
SELECT `post_id`
FROM `msz_forum_posts`
WHERE `topic_id` = t.`topic_id`
ORDER BY `post_id` DESC
LIMIT 1
)
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 f.`forum_parent` = :parent_id
AND f.`forum_hidden` = false
AND (
(f.`forum_parent` = ' . MSZ_FORUM_ROOT . ' AND f.`forum_type` != ' . MSZ_FORUM_TYPE_CATEGORY . ')
OR f.`forum_parent` != ' . MSZ_FORUM_ROOT . '
)
ORDER BY f.`forum_order`
');
);
function forum_get_children(int $parentId, int $userId, bool $small = false): array
{
@ -291,6 +314,8 @@ function forum_get_children(int $parentId, int $userId, bool $small = false): ar
: MSZ_FORUM_GET_CHILDREN_QUERY_STANDARD
);
$getListing->bindValue('user_id', $userId);
$getListing->bindValue('perm_user_id_user', $userId);
$getListing->bindValue('perm_user_id_role', $userId);
$getListing->bindValue('parent_id', $parentId);
return $getListing->execute() ? $getListing->fetchAll() : [];

View file

@ -33,30 +33,33 @@ function forum_perms_create(): int
function forum_perms_get_user_sql(
string $prefix,
string $forum = ':perm_forum_id',
string $user_for_user = ':perm_user_id_1',
string $user_for_role = ':perm_user_id_2'
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 "
SELECT BIT_OR(`{$prefix}_perms_allow`) &~ BIT_OR(`{$prefix}_perms_deny`)
FROM `msz_forum_permissions`
WHERE (
`forum_id` = {$forum}
OR `forum_id` IS NULL
)
AND (
(`user_id` IS NULL AND `role_id` IS NULL)
OR (`user_id` = {$user_for_user} AND `role_id` IS NULL)
OR (
`user_id` IS NULL
AND `role_id` IN (
SELECT `role_id`
FROM `msz_user_roles`
WHERE `user_id` = {$user_for_role}
return sprintf(
'
SELECT BIT_OR(`%1$s_perms`)
FROM `msz_forum_permissions_view`
WHERE `forum_id` = %2$s
AND (
(`user_id` IS NULL AND `role_id` IS NULL)
OR (`user_id` = %3$s 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
)
)
)
)
";
',
$prefix,
$forum_id_param,
$user_id_user_param,
$user_id_role_param
);
}
function forum_perms_get_user(string $prefix, int $forum, int $user): int