diff options
-rw-r--r-- | Zotlabs/Access/AccessList.php | 56 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 2 | ||||
-rw-r--r-- | Zotlabs/Module/Chat.php | 2 | ||||
-rw-r--r-- | Zotlabs/Module/Sse_bs.php | 24 | ||||
-rw-r--r-- | Zotlabs/Widget/Messages.php | 6 | ||||
-rw-r--r-- | boot.php | 2 | ||||
-rw-r--r-- | tests/unit/Access/AccessListTest.php | 36 | ||||
-rw-r--r-- | view/js/main.js | 29 |
8 files changed, 108 insertions, 49 deletions
diff --git a/Zotlabs/Access/AccessList.php b/Zotlabs/Access/AccessList.php index 790ef4745..3f5271e87 100644 --- a/Zotlabs/Access/AccessList.php +++ b/Zotlabs/Access/AccessList.php @@ -2,6 +2,7 @@ namespace Zotlabs\Access; + /** * @brief AccessList class which represents individual content ACLs. * @@ -17,29 +18,48 @@ class AccessList { * @brief Allow contacts * @var string */ - private $allow_cid; + private ?string $allow_cid; /** * @brief Allow groups * @var string */ - private $allow_gid; + private ?string $allow_gid; /** * @brief Deny contacts * @var string */ - private $deny_cid; + private ?string $deny_cid; /** * @brief Deny groups * @var string */ - private $deny_gid; + private ?string $deny_gid; /** * @brief Indicates if we are using the default constructor values or * values that have been set explicitly. * @var boolean */ - private $explicit; + private bool $explicit; + + /** + * @brief Keys required by the constructor if the channel array is given. + */ + private const REQUIRED_KEYS_CONSTRUCTOR = [ + 'channel_allow_cid', + 'channel_allow_gid', + 'channel_deny_cid', + 'channel_deny_gid' + ]; + /** + * @brief Keys required by the set method. + */ + private const REQUIRED_KEYS_SET = [ + 'allow_cid', + 'allow_gid', + 'deny_cid', + 'deny_gid' + ]; /** * @brief Constructor for AccessList class. @@ -53,8 +73,9 @@ class AccessList { * * \e string \b channel_deny_cid => string of denied cids * * \e string \b channel_deny_gid => string of denied gids */ - function __construct($channel) { + function __construct(array $channel) { if ($channel) { + $this->validate_input_array($channel, self::REQUIRED_KEYS_CONSTRUCTOR); $this->allow_cid = $channel['channel_allow_cid']; $this->allow_gid = $channel['channel_allow_gid']; $this->deny_cid = $channel['channel_deny_cid']; @@ -70,13 +91,24 @@ class AccessList { $this->explicit = false; } + private function validate_input_array(array $arr, array $required_keys) : void { + $missing_keys = array_diff($required_keys, array_keys($arr)); + + if (!empty($missing_keys)) { + throw new \Exception( + 'Invalid AccessList object: Expected array with keys: ' + . implode(', ', $missing_keys) + ); + } + } + /** * @brief Get if we are using the default constructor values * or values that have been set explicitly. * * @return boolean */ - function get_explicit() { + function get_explicit() : bool { return $this->explicit; } @@ -94,7 +126,9 @@ class AccessList { * * \e string \b deny_gid => string of denied gids * @param boolean $explicit (optional) default true */ - function set($arr, $explicit = true) { + function set(array $arr, bool $explicit = true) : void { + $this->validate_input_array($arr, self::REQUIRED_KEYS_SET); + $this->allow_cid = $arr['allow_cid']; $this->allow_gid = $arr['allow_gid']; $this->deny_cid = $arr['deny_cid']; @@ -112,7 +146,7 @@ class AccessList { * * \e string \b deny_cid => string of denied cids * * \e string \b deny_gid => string of denied gids */ - function get() { + function get() : array { return [ 'allow_cid' => $this->allow_cid, 'allow_gid' => $this->allow_gid, @@ -138,7 +172,7 @@ class AccessList { * * \e array|string \b group_deny => array with gids or comma-seperated string * @param boolean $explicit (optional) default true */ - function set_from_array($arr, $explicit = true) { + function set_from_array(array $arr, bool $explicit = true) : void { $arr['contact_allow'] = $arr['contact_allow'] ?? []; $arr['group_allow'] = $arr['group_allow'] ?? []; $arr['contact_deny'] = $arr['contact_deny'] ?? []; @@ -161,7 +195,7 @@ class AccessList { * * @return boolean Return true if any of allow_* deny_* values is set. */ - function is_private() { + function is_private() : bool { return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false); } diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 7fa621470..7d2bcde56 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -101,7 +101,7 @@ class ThreadItem { $conv = $this->get_conversation(); $observer = $conv->get_observer(); - $acl = new AccessList(false); + $acl = new AccessList([]); $acl->set($item); $lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private())) diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php index fc74016ab..2d36e022a 100644 --- a/Zotlabs/Module/Chat.php +++ b/Zotlabs/Module/Chat.php @@ -181,7 +181,7 @@ class Chat extends Controller { ); if($x) { - $acl = new AccessList(false); + $acl = new AccessList([]); $acl->set($x[0]); $private = $acl->is_private(); diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php index 970c482a9..a3a3afd23 100644 --- a/Zotlabs/Module/Sse_bs.php +++ b/Zotlabs/Module/Sse_bs.php @@ -169,12 +169,12 @@ class Sse_bs extends Controller { $sql_extra2 = ''; if(self::$xchans) - $sql_extra2 = " AND CASE WHEN verb = '" . ACTIVITY_SHARE . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") "; + $sql_extra2 = " AND CASE WHEN verb = '" . dbesc(ACTIVITY_SHARE) . "' THEN owner_xchan ELSE author_xchan END IN (" . self::$xchans . ") "; $item_normal = item_normal(); - // FEP-5624 filter approvals for comments - $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + // Filter FEP-5624 approvals for comments and internal follow activities + $item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') "; if ($notifications) { $items = q("SELECT * FROM item @@ -184,7 +184,6 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal - $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", @@ -258,8 +257,8 @@ class Sse_bs extends Controller { $item_normal = item_normal(); - // FEP-5624 filter approvals for comments - $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + // Filter FEP-5624 approvals for comments and internal follow activities + $item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') "; if ($notifications) { $items = q("SELECT * FROM item @@ -269,7 +268,6 @@ class Sse_bs extends Controller { AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') AND author_xchan != '%s' $item_normal - $approvals $sql_extra $sql_extra2 ORDER BY created DESC LIMIT $limit OFFSET $offset", @@ -343,8 +341,8 @@ class Sse_bs extends Controller { $item_normal = item_normal(); - // FEP-5624 filter approvals for comments - $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + // Filter FEP-5624 approvals for comments and internal follow activities + $item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') "; if ($notifications) { $items = q("SELECT * FROM item @@ -445,8 +443,8 @@ class Sse_bs extends Controller { $item_normal = item_normal(); - // FEP-5624 filter approvals for comments - $approvals = " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject') "; + // Filter FEP-5624 approvals for comments and internal follow activities + $item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') "; if ($notifications) { $items = q("SELECT * FROM item @@ -641,6 +639,10 @@ class Sse_bs extends Controller { $item_normal = item_normal(); + // Filter FEP-5624 approvals for comments and internal follow activities + $item_normal .= " AND verb NOT IN ('" . dbesc(ACTIVITY_ATTEND) . "', 'Accept', '" . dbesc(ACTIVITY_ATTENDNO) . "', 'Reject', '" . dbesc(ACTIVITY_FOLLOW) . "') "; + + $r = q("SELECT * FROM item WHERE verb = '%s' AND obj_type IN ('Document', 'Video', 'Audio', 'Image') diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php index 0a8900c4f..cdd889121 100644 --- a/Zotlabs/Widget/Messages.php +++ b/Zotlabs/Widget/Messages.php @@ -60,8 +60,10 @@ class Messages { } $channel = App::get_channel(); - $item_normal_i = str_replace('item.', 'i.', item_normal()); - $item_normal_c = str_replace('item.', 'c.', item_normal()); + $item_normal = item_normal(); + $item_normal .= " and item.verb != '" . ACTIVITY_FOLLOW . "'"; + $item_normal_i = str_replace('item.', 'i.', $item_normal); + $item_normal_c = str_replace('item.', 'c.', $item_normal); $entries = []; $limit = 30; $dummy_order_sql = ''; @@ -60,7 +60,7 @@ require_once('include/bbcode.php'); require_once('include/items.php'); define('PLATFORM_NAME', 'hubzilla'); -define('STD_VERSION', '8.7'); +define('STD_VERSION', '8.7.1'); define('ZOT_REVISION', '6.0'); define('DB_UPDATE_VERSION', 1258); diff --git a/tests/unit/Access/AccessListTest.php b/tests/unit/Access/AccessListTest.php index 2f185db17..635f09930 100644 --- a/tests/unit/Access/AccessListTest.php +++ b/tests/unit/Access/AccessListTest.php @@ -60,14 +60,24 @@ class AccessListTest extends UnitTestCase { } /** - * @expectedException PHPUnit\Framework\Error\Error + * AccessList constructor should throw an exception if input is not + * an array. */ -/* - public function testPHPErrorOnInvalidConstructor() { + public function testConstructorThrowsOnInvalidInputType() { + $this->expectException("TypeError"); $accessList = new AccessList('invalid'); - // Causes: "Illegal string offset 'channel_allow_cid'" } -*/ + + /** + * AccessList constructor should throw an exception on + * invalid input. + */ + public function testConstructorThrowsOnMissingKeysInArray() { + $this->expectException("Exception"); + $this->expectExceptionMessage("Invalid AccessList object"); + $accessList = new AccessList(['something_else' => 'should_this_fail?']); + } + /** * Test that the defaults are as expected when constructed with * an empty array. @@ -111,16 +121,22 @@ class AccessListTest extends UnitTestCase { } /** - * @expectedException PHPUnit\Framework\Error\Error + * The set method should throw an exception if input is not an array. */ -/* - public function testPHPErrorOnInvalidSet() { + public function testSetThrowsOnInvalidInputType() { + $this->expectException('TypeError'); $accessList = new AccessList([]); $accessList->set('invalid'); - // Causes: "Illegal string offset 'allow_cid'" } -*/ + + public function testSetThrowsOnMissingKeysInArray() { + $this->expectException('Exception'); + $this->expectExceptionMessage('Invalid AccessList object'); + + $accessList = new AccessList([]); + $accessList->set(['something_else' => 'should_this_fail?']); + } /** * The set_from_array() function calls some other functions, too which are diff --git a/view/js/main.js b/view/js/main.js index 9c2480795..c463b1f59 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -646,7 +646,8 @@ function updatePageItems(mode, data) { function updateConvItems(mode,data) { - var scroll_position = $(window).scrollTop(); + let scroll_position = $(window).scrollTop(); + let b64mids = []; if(mode !== 'update') $(document).trigger('hz:updateConvItems'); @@ -660,12 +661,12 @@ function updateConvItems(mode,data) { $('.thread-wrapper', data).each(function() { if(this.classList.contains('toplevel_item')) { - var ident = this.id; - var convId = ident.replace('thread-wrapper-',''); - var commentWrap = $('#'+ident+' .collapsed-comments').attr('id'); + let ident = this.id; + let convId = ident.replace('thread-wrapper-',''); + let commentWrap = $('#'+ident+' .collapsed-comments').attr('id'); - var itmId = 0; - var isVisible = false; + let itmId = 0; + let isVisible = false; // figure out the comment state if(typeof commentWrap !== 'undefined') @@ -695,7 +696,7 @@ function updateConvItems(mode,data) { if(isVisible) showHideComments(itmId); - var commentBody = localStorage.getItem("comment_body-" + convId); + let commentBody = localStorage.getItem("comment_body-" + convId); if(commentBody) { var commentElm = $('#comment-edit-text-' + convId); @@ -723,7 +724,7 @@ function updateConvItems(mode,data) { if(mode === 'replace') { if (window.location.search.indexOf("mid=") != -1 || window.location.pathname.indexOf("display") != -1) { - var title = $(".wall-item-title").text(); + let title = $(".wall-item-title").text(); title.replace(/^\s+/, ''); title.replace(/\s+$/, ''); if (title) { @@ -734,10 +735,14 @@ function updateConvItems(mode,data) { } } - $(document).trigger('hz:sse_setNotificationsStatus', [$(this).data('b64mids')]); + $(this).data('b64mids').forEach((b64mid) => { + b64mids.push(b64mid); + }); }); + $(document).trigger('hz:sse_setNotificationsStatus', [b64mids]); + $(window).scrollTop(scroll_position); if(followUpPageLoad) { @@ -802,7 +807,7 @@ function updateConvItems(mode,data) { } // reset rotators and cursors we may have set before reaching this place - $('.like-rotator').hide(); + $("#page-spinner").hide(); $("#profile-jot-text-loading").hide(); @@ -837,8 +842,7 @@ function scrollToItem() { } function collapseHeight() { - - $(".wall-item-content, .directory-collapse").each(function() { + $(".wall-item-content:not('.divmore_checked'), .directory-collapse:not('.divmore_checked')").each(function(i) { var orgHeight = $(this).outerHeight(true); var id = $(this).attr('id') var open = ((expanded_items.indexOf($(this).attr('id')) === -1) ? false : true); @@ -866,6 +870,7 @@ function collapseHeight() { $(this).addClass('divmore'); } } + $(this).addClass('divmore_checked'); }); } |