diff --git a/composer.json b/composer.json index 9ed9017d8..83b51a174 100644 --- a/composer.json +++ b/composer.json @@ -83,7 +83,6 @@ "include/dba.php", "include/enotify.php", "include/items.php", - "include/text.php", "boot.php" ] }, diff --git a/doc/Addons.md b/doc/Addons.md index 0382cee49..69b591a82 100644 --- a/doc/Addons.md +++ b/doc/Addons.md @@ -503,16 +503,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('item_photo_menu', $args); Hook::callAll('jot_tool', $jotplugins); -### include/text.php - - Hook::callAll('contact_block_end', $arr); - Hook::callAll('poke_verbs', $arr); - Hook::callAll('put_item_in_cache', $hook_data); - Hook::callAll('prepare_body_init', $item); - Hook::callAll('prepare_body_content_filter', $hook_data); - Hook::callAll('prepare_body', $hook_data); - Hook::callAll('prepare_body_final', $hook_data); - ### include/items.php Hook::callAll('page_info_data', $data); @@ -649,6 +639,11 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('post_remote_end', $posted_item); Hook::callAll('tagged', $arr); Hook::callAll('post_local_end', $new_item); + Hook::callAll('put_item_in_cache', $hook_data); + Hook::callAll('prepare_body_init', $item); + Hook::callAll('prepare_body_content_filter', $hook_data); + Hook::callAll('prepare_body', $hook_data); + Hook::callAll('prepare_body_final', $hook_data); ### src/Model/Contact.php @@ -673,6 +668,10 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('register_account', $uid); Hook::callAll('remove_user', $user); +### src/Content/ContactBlock.php + + Hook::callAll('contact_block_end', $arr); + ### src/Content/Text/BBCode.php Hook::callAll('bbcode', $text); @@ -746,6 +745,10 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- self::callSingle(self::getApp(), 'hook_fork', $fork_hook, $hookdata); +### src/Core/L10n/L10n.php + + Hook::callAll('poke_verbs', $arr); + ### src/Core/Worker.php Hook::callAll("proc_run", $arr); diff --git a/doc/de/Addons.md b/doc/de/Addons.md index 3cbbb4b0b..755db95d0 100644 --- a/doc/de/Addons.md +++ b/doc/de/Addons.md @@ -226,16 +226,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('item_photo_menu', $args); Hook::callAll('jot_tool', $jotplugins); -### include/text.php - - Hook::callAll('contact_block_end', $arr); - Hook::callAll('poke_verbs', $arr); - Hook::callAll('put_item_in_cache', $hook_data); - Hook::callAll('prepare_body_init', $item); - Hook::callAll('prepare_body_content_filter', $hook_data); - Hook::callAll('prepare_body', $hook_data); - Hook::callAll('prepare_body_final', $hook_data); - ### include/items.php Hook::callAll('page_info_data', $data); @@ -365,6 +355,11 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('post_remote_end', $posted_item); Hook::callAll('tagged', $arr); Hook::callAll('post_local_end', $new_item); + Hook::callAll('put_item_in_cache', $hook_data); + Hook::callAll('prepare_body_init', $item); + Hook::callAll('prepare_body_content_filter', $hook_data); + Hook::callAll('prepare_body', $hook_data); + Hook::callAll('prepare_body_final', $hook_data); ### src/Model/Contact.php @@ -387,6 +382,10 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('register_account', $uid); Hook::callAll('remove_user', $user); + +### src/Content/ContactBlock.php + + Hook::callAll('contact_block_end', $arr); ### src/Content/Text/BBCode.php @@ -457,6 +456,18 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll($a->module.'_post_'.$selname, $o); Hook::callAll('jot_networks', $jotnets); +### src/Core/Authentication.php + + Hook::callAll('logged_in', $a->user); + +### src/Core/Hook.php + + self::callSingle(self::getApp(), 'hook_fork', $fork_hook, $hookdata); + +### src/Core/L10n/L10n.php + + Hook::callAll('poke_verbs', $arr); + ### src/Core/Worker.php Hook::callAll("proc_run", $arr); diff --git a/include/conversation.php b/include/conversation.php index b6faa4d2c..8bcd1b338 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -4,8 +4,10 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\ContactSelector; use Friendica\Content\Feature; +use Friendica\Content\Item as ContentItem; use Friendica\Content\Pager; use Friendica\Content\Text\BBCode; use Friendica\Core\Config; @@ -24,6 +26,7 @@ use Friendica\Model\Profile; use Friendica\Model\Term; use Friendica\Object\Post; use Friendica\Object\Thread; +use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; use Friendica\Util\Temporal; @@ -138,12 +141,15 @@ function localize_item(&$item) During the further steps of the database restructuring I would like to address this issue. */ + /** @var Activity $activity */ + $activity = BaseObject::getClass(Activity::class); + $xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">"; - if (activity_match($item['verb'], ACTIVITY_LIKE) - || activity_match($item['verb'], ACTIVITY_DISLIKE) - || activity_match($item['verb'], ACTIVITY_ATTEND) - || activity_match($item['verb'], ACTIVITY_ATTENDNO) - || activity_match($item['verb'], ACTIVITY_ATTENDMAYBE)) { + if ($activity->match($item['verb'], ACTIVITY_LIKE) + || $activity->match($item['verb'], ACTIVITY_DISLIKE) + || $activity->match($item['verb'], ACTIVITY_ATTEND) + || $activity->match($item['verb'], ACTIVITY_ATTENDNO) + || $activity->match($item['verb'], ACTIVITY_ATTENDMAYBE)) { $fields = ['author-link', 'author-name', 'verb', 'object-type', 'resource-id', 'body', 'plink']; $obj = Item::selectFirst($fields, ['uri' => $item['parent-uri']]); @@ -178,22 +184,22 @@ function localize_item(&$item) $plink = '[url=' . $obj['plink'] . ']' . $post_type . '[/url]'; $bodyverb = ''; - if (activity_match($item['verb'], ACTIVITY_LIKE)) { + if ($activity->match($item['verb'], ACTIVITY_LIKE)) { $bodyverb = L10n::t('%1$s likes %2$s\'s %3$s'); - } elseif (activity_match($item['verb'], ACTIVITY_DISLIKE)) { + } elseif ($activity->match($item['verb'], ACTIVITY_DISLIKE)) { $bodyverb = L10n::t('%1$s doesn\'t like %2$s\'s %3$s'); - } elseif (activity_match($item['verb'], ACTIVITY_ATTEND)) { + } elseif ($activity->match($item['verb'], ACTIVITY_ATTEND)) { $bodyverb = L10n::t('%1$s attends %2$s\'s %3$s'); - } elseif (activity_match($item['verb'], ACTIVITY_ATTENDNO)) { + } elseif ($activity->match($item['verb'], ACTIVITY_ATTENDNO)) { $bodyverb = L10n::t('%1$s doesn\'t attend %2$s\'s %3$s'); - } elseif (activity_match($item['verb'], ACTIVITY_ATTENDMAYBE)) { + } elseif ($activity->match($item['verb'], ACTIVITY_ATTENDMAYBE)) { $bodyverb = L10n::t('%1$s attends maybe %2$s\'s %3$s'); } $item['body'] = sprintf($bodyverb, $author, $objauthor, $plink); } - if (activity_match($item['verb'], ACTIVITY_FRIEND)) { + if ($activity->match($item['verb'], ACTIVITY_FRIEND)) { if ($item['object-type']=="" || $item['object-type']!== ACTIVITY_OBJ_PERSON) return; @@ -275,7 +281,7 @@ function localize_item(&$item) } - if (activity_match($item['verb'], ACTIVITY_TAG)) { + if ($activity->match($item['verb'], ACTIVITY_TAG)) { $fields = ['author-id', 'author-link', 'author-name', 'author-network', 'verb', 'object-type', 'resource-id', 'body', 'plink']; $obj = Item::selectFirst($fields, ['uri' => $item['parent-uri']]); @@ -320,7 +326,7 @@ function localize_item(&$item) $item['body'] = L10n::t('%1$s tagged %2$s\'s %3$s with %4$s', $author, $objauthor, $plink, $tag); } - if (activity_match($item['verb'], ACTIVITY_FAVORITE)) { + if ($activity->match($item['verb'], ACTIVITY_FAVORITE)) { if ($item['object-type'] == "") { return; } @@ -393,19 +399,22 @@ function count_descendants($item) { function visible_activity($item) { + /** @var Activity $activity */ + $activity = BaseObject::getClass(Activity::class); + /* * likes (etc.) can apply to other things besides posts. Check if they are post children, * in which case we handle them specially */ $hidden_activities = [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE, ACTIVITY_FOLLOW, ACTIVITY2_ANNOUNCE]; foreach ($hidden_activities as $act) { - if (activity_match($item['verb'], $act)) { + if ($activity->match($item['verb'], $act)) { return false; } } // @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere; - if (activity_match($item['verb'], ACTIVITY_FOLLOW) && $item['object-type'] === ACTIVITY_OBJ_NOTE && empty($item['self']) && $item['uid'] == local_user()) { + if ($activity->match($item['verb'], ACTIVITY_FOLLOW) && $item['object-type'] === ACTIVITY_OBJ_NOTE && empty($item['self']) && $item['uid'] == local_user()) { return false; } @@ -663,7 +672,10 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ $body = Item::prepareBody($item, true, $preview); - list($categories, $folders) = get_cats_and_terms($item); + /** @var ContentItem $contItem */ + $contItem = BaseObject::getClass(ContentItem::class); + + list($categories, $folders) = $contItem->determineCategoriesTerms($item); if (!empty($item['content-warning']) && PConfig::get(local_user(), 'system', 'disable_cw', false)) { $title = ucfirst($item['content-warning']); @@ -1017,7 +1029,10 @@ function builtin_activity_puller($item, &$conv_responses) { return; } - if (activity_match($item['verb'], $verb) && ($item['id'] != $item['parent'])) { + /** @var Activity $activity */ + $activity = BaseObject::getClass(Activity::class); + + if ($activity->match($item['verb'], $verb) && ($item['id'] != $item['parent'])) { $author = ['uid' => 0, 'id' => $item['author-id'], 'network' => $item['author-network'], 'url' => $item['author-link']]; $url = Contact::magicLinkByContact($author); diff --git a/include/text.php b/include/text.php deleted file mode 100644 index 2050e5702..000000000 --- a/include/text.php +++ /dev/null @@ -1,275 +0,0 @@ -<2><3>" => array(1,2,3); - preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $s, $matches, PREG_PATTERN_ORDER); - - return $matches[1]; -} - - -/** - * Wrap ACL elements in angle brackets for storage - * @param string $item - */ -function sanitise_acl(&$item) { - if (intval($item)) { - $item = '<' . intval(Strings::escapeTags(trim($item))) . '>'; - } elseif (in_array($item, [Group::FOLLOWERS, Group::MUTUALS])) { - $item = '<' . $item . '>'; - } else { - unset($item); - } -} - - -/** - * Convert an ACL array to a storable string - * - * Normally ACL permissions will be an array. - * We'll also allow a comma-separated string. - * - * @param string|array $p - * @return string - */ -function perms2str($p) { - $ret = ''; - if (is_array($p)) { - $tmp = $p; - } else { - $tmp = explode(',', $p); - } - - if (is_array($tmp)) { - array_walk($tmp, 'sanitise_acl'); - $ret = implode('', $tmp); - } - return $ret; -} - -/** - * for html,xml parsing - let's say you've got - * an attribute foobar="class1 class2 class3" - * and you want to find out if it contains 'class3'. - * you can't use a normal sub string search because you - * might match 'notclass3' and a regex to do the job is - * possible but a bit complicated. - * pass the attribute string as $attr and the attribute you - * are looking for as $s - returns true if found, otherwise false - * - * @param string $attr attribute value - * @param string $s string to search - * @return boolean True if found, False otherwise - */ -function attribute_contains($attr, $s) { - $a = explode(' ', $attr); - return (count($a) && in_array($s,$a)); -} - -/** - * Compare activity uri. Knows about activity namespace. - * - * @param string $haystack - * @param string $needle - * @return boolean - */ -function activity_match($haystack,$needle) { - return (($haystack === $needle) || ((basename($needle) === $haystack) && strstr($needle, NAMESPACE_ACTIVITY_SCHEMA))); -} - -/** - * quick and dirty quoted_printable encoding - * - * @param string $s - * @return string - */ -function qp($s) { - return str_replace("%", "=", rawurlencode($s)); -} - -/** - * @brief Find any non-embedded images in private items and add redir links to them - * - * @param App $a - * @param array &$item The field array of an item row - */ -function redir_private_images($a, &$item) -{ - $matches = []; - $cnt = preg_match_all('|\[img\](http[^\[]*?/photo/[a-fA-F0-9]+?(-[0-9]\.[\w]+?)?)\[\/img\]|', $item['body'], $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - if (strpos($mtch[1], '/redir') !== false) { - continue; - } - - if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $a->contact['id']) && ($item['network'] == Protocol::DFRN)) { - $img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]); - $item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']); - } - } - } -} - -/** - * @brief Given a text string, convert from bbcode to html and add smilie icons. - * - * @param string $text String with bbcode. - * @return string Formatted HTML - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ -function prepare_text($text) -{ - $s = BBCode::convert($text); - return trim($s); -} - -/** - * return array with details for categories and folders for an item - * - * @param array $item - * @return array - * - * [ - * [ // categories array - * { - * 'name': 'category name', - * 'removeurl': 'url to remove this category', - * 'first': 'is the first in this array? true/false', - * 'last': 'is the last in this array? true/false', - * } , - * .... - * ], - * [ //folders array - * { - * 'name': 'folder name', - * 'removeurl': 'url to remove this folder', - * 'first': 'is the first in this array? true/false', - * 'last': 'is the last in this array? true/false', - * } , - * .... - * ] - * ] - */ -function get_cats_and_terms($item) -{ - $categories = []; - $folders = []; - $first = true; - - foreach (FileTag::fileToArray($item['file'] ?? '', 'category') as $savedFolderName) { - $categories[] = [ - 'name' => $savedFolderName, - 'url' => "#", - 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&cat=' . rawurlencode($savedFolderName) : ""), - 'first' => $first, - 'last' => false - ]; - $first = false; - } - - if (count($categories)) { - $categories[count($categories) - 1]['last'] = true; - } - - if (local_user() == $item['uid']) { - foreach (FileTag::fileToArray($item['file'] ?? '') as $savedFolderName) { - $folders[] = [ - 'name' => $savedFolderName, - 'url' => "#", - 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . rawurlencode($savedFolderName) : ""), - 'first' => $first, - 'last' => false - ]; - $first = false; - } - } - - if (count($folders)) { - $folders[count($folders) - 1]['last'] = true; - } - - return [$categories, $folders]; -} - -/** - * return number of bytes in size (K, M, G) - * @param string $size_str - * @return int - */ -function return_bytes($size_str) { - switch (substr ($size_str, -1)) { - case 'M': case 'm': return (int)$size_str * 1048576; - case 'K': case 'k': return (int)$size_str * 1024; - case 'G': case 'g': return (int)$size_str * 1073741824; - default: return $size_str; - } -} - -function bb_translate_video($s) { - - $matches = null; - $r = preg_match_all("/\[video\](.*?)\[\/video\]/ism",$s,$matches,PREG_SET_ORDER); - if ($r) { - foreach ($matches as $mtch) { - if ((stristr($mtch[1], 'youtube')) || (stristr($mtch[1], 'youtu.be'))) { - $s = str_replace($mtch[0], '[youtube]' . $mtch[1] . '[/youtube]', $s); - } elseif (stristr($mtch[1], 'vimeo')) { - $s = str_replace($mtch[0], '[vimeo]' . $mtch[1] . '[/vimeo]', $s); - } - } - } - return $s; -} - -function undo_post_tagging($s) { - $matches = null; - $cnt = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - if (in_array($mtch[1], ['!', '@'])) { - $contact = Contact::getDetailsByURL($mtch[2]); - $mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr']; - } - $s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s); - } - } - return $s; -} - -/// @TODO Rewrite this -function is_a_date_arg($s) { - $i = intval($s); - - if ($i > 1900) { - $y = date('Y'); - - if ($i <= $y + 1 && strpos($s, '-') == 4) { - $m = intval(substr($s, 5)); - - if ($m > 0 && $m <= 12) { - return true; - } - } - } - - return false; -} diff --git a/mod/editpost.php b/mod/editpost.php index e14baffa2..690cb2ac0 100644 --- a/mod/editpost.php +++ b/mod/editpost.php @@ -8,9 +8,10 @@ use Friendica\Content\Feature; use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\Model\Contact; use Friendica\Model\FileTag; use Friendica\Model\Item; -use Friendica\Database\DBA; use Friendica\Util\Crypto; function editpost_content(App $a) @@ -118,3 +119,18 @@ function editpost_content(App $a) return $o; } + +function undo_post_tagging($s) { + $matches = null; + $cnt = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + if (in_array($mtch[1], ['!', '@'])) { + $contact = Contact::getDetailsByURL($mtch[2]); + $mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr']; + } + $s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s); + } + } + return $s; +} diff --git a/mod/events.php b/mod/events.php index 649a25ab1..11bb25f51 100644 --- a/mod/events.php +++ b/mod/events.php @@ -5,6 +5,7 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\Nav; use Friendica\Content\Widget\CalendarExport; use Friendica\Core\ACL; @@ -18,6 +19,7 @@ use Friendica\Model\Event; use Friendica\Model\Item; use Friendica\Model\Profile; use Friendica\Module\Login; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; use Friendica\Util\Strings; use Friendica\Util\Temporal; @@ -146,10 +148,14 @@ function events_post(App $a) if ($share) { - $str_group_allow = perms2str($_POST['group_allow'] ?? ''); - $str_contact_allow = perms2str($_POST['contact_allow'] ?? ''); - $str_group_deny = perms2str($_POST['group_deny'] ?? ''); - $str_contact_deny = perms2str($_POST['contact_deny'] ?? ''); + + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $str_group_allow = $aclFormatter->toString($_POST['group_allow'] ?? ''); + $str_contact_allow = $aclFormatter->toString($_POST['contact_allow'] ?? ''); + $str_group_deny = $aclFormatter->toString($_POST['group_deny'] ?? ''); + $str_contact_deny = $aclFormatter->toString($_POST['contact_deny'] ?? ''); // Undo the pseudo-contact of self, since there are real contacts now if (strpos($str_contact_allow, '<' . $self . '>') !== false) { diff --git a/mod/item.php b/mod/item.php index 7c8ebee4a..a5875d258 100644 --- a/mod/item.php +++ b/mod/item.php @@ -16,6 +16,7 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\Pager; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; @@ -24,8 +25,8 @@ use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\Protocol; -use Friendica\Core\System; use Friendica\Core\Session; +use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Attach; @@ -37,6 +38,7 @@ use Friendica\Model\Photo; use Friendica\Model\Term; use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; use Friendica\Util\Security; @@ -269,10 +271,14 @@ function item_post(App $a) { $str_contact_deny = $user['deny_cid']; } else { // use the posted permissions - $str_group_allow = perms2str($_REQUEST['group_allow'] ?? ''); - $str_contact_allow = perms2str($_REQUEST['contact_allow'] ?? ''); - $str_group_deny = perms2str($_REQUEST['group_deny'] ?? ''); - $str_contact_deny = perms2str($_REQUEST['contact_deny'] ?? ''); + + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $str_group_allow = $aclFormatter->toString($_REQUEST['group_allow'] ?? ''); + $str_contact_allow = $aclFormatter->toString($_REQUEST['contact_allow'] ?? ''); + $str_group_deny = $aclFormatter->toString($_REQUEST['group_deny'] ?? ''); + $str_contact_deny = $aclFormatter->toString($_REQUEST['contact_deny'] ?? ''); } $title = Strings::escapeTags(trim($_REQUEST['title'] ?? '')); @@ -499,8 +505,9 @@ function item_post(App $a) { $objecttype = ACTIVITY_OBJ_BOOKMARK; } - $body = bb_translate_video($body); - + /** @var BBCode\Video $bbCodeVideo */ + $bbCodeVideo = BaseObject::getClass(BBCode\Video::class); + $body = $bbCodeVideo->transform($body); // Fold multi-line [code] sequences $body = preg_replace('/\[\/code\]\s*\[code\]/ism', "\n", $body); diff --git a/mod/lockview.php b/mod/lockview.php index eede1b6a0..9f9dcfea4 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -3,11 +3,13 @@ * @file mod/lockview.php */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Database\DBA; use Friendica\Model\Group; use Friendica\Model\Item; +use Friendica\Util\ACLFormatter; function lockview_content(App $a) { @@ -59,10 +61,13 @@ function lockview_content(App $a) exit(); } - $allowed_users = expand_acl($item['allow_cid']); - $allowed_groups = expand_acl($item['allow_gid']); - $deny_users = expand_acl($item['deny_cid']); - $deny_groups = expand_acl($item['deny_gid']); + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $allowed_users = $aclFormatter->expand($item['allow_cid']); + $allowed_groups = $aclFormatter->expand($item['allow_gid']); + $deny_users = $aclFormatter->expand($item['deny_cid']); + $deny_groups = $aclFormatter->expand($item['deny_gid']); $o = L10n::t('Visible to:') . '
'; $l = []; diff --git a/mod/network.php b/mod/network.php index 0438be705..64f5cf505 100644 --- a/mod/network.php +++ b/mod/network.php @@ -5,6 +5,7 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\Feature; use Friendica\Content\ForumManager; use Friendica\Content\Nav; @@ -51,9 +52,12 @@ function network_init(App $a) $group_id = 0; } + /** @var DateTimeFormat $dtFormat */ + $dtFormat = BaseObject::getClass(DateTimeFormat::class); + if ($a->argc > 1) { for ($x = 1; $x < $a->argc; $x ++) { - if (is_a_date_arg($a->argv[$x])) { + if ($dtFormat->isYearMonth($a->argv[$x])) { $is_a_date_query = true; break; } @@ -461,9 +465,12 @@ function networkThreadedView(App $a, $update, $parent) $default_permissions = []; + /** @var DateTimeFormat $dtFormat */ + $dtFormat = BaseObject::getClass(DateTimeFormat::class); + if ($a->argc > 1) { for ($x = 1; $x < $a->argc; $x ++) { - if (is_a_date_arg($a->argv[$x])) { + if ($dtFormat->isYearMonth($a->argv[$x])) { if ($datequery) { $datequery2 = Strings::escapeHtml($a->argv[$x]); } else { diff --git a/mod/photos.php b/mod/photos.php index 1789c0710..d89cd04b0 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -4,6 +4,7 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Pager; @@ -14,18 +15,17 @@ use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\Renderer; -use Friendica\Core\System; use Friendica\Core\Session; +use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Contact; -use Friendica\Model\Group; use Friendica\Model\Item; use Friendica\Model\Photo; use Friendica\Model\Profile; use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Object\Image; -use Friendica\Protocol\DFRN; +use Friendica\Util\ACLFormatter; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; @@ -296,10 +296,13 @@ function photos_post(App $a) $albname = !empty($_POST['albname']) ? Strings::escapeTags(trim($_POST['albname'])) : ''; $origaname = !empty($_POST['origaname']) ? Strings::escapeTags(trim($_POST['origaname'])) : ''; - $str_group_allow = !empty($_POST['group_allow']) ? perms2str($_POST['group_allow']) : ''; - $str_contact_allow = !empty($_POST['contact_allow']) ? perms2str($_POST['contact_allow']) : ''; - $str_group_deny = !empty($_POST['group_deny']) ? perms2str($_POST['group_deny']) : ''; - $str_contact_deny = !empty($_POST['contact_deny']) ? perms2str($_POST['contact_deny']) : ''; + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $str_group_allow = !empty($_POST['group_allow']) ? $aclFormatter->toString($_POST['group_allow']) : ''; + $str_contact_allow = !empty($_POST['contact_allow']) ? $aclFormatter->toString($_POST['contact_allow']) : ''; + $str_group_deny = !empty($_POST['group_deny']) ? $aclFormatter->toString($_POST['group_deny']) : ''; + $str_contact_deny = !empty($_POST['contact_deny']) ? $aclFormatter->toString($_POST['contact_deny']) : ''; $resource_id = $a->argv[3]; @@ -635,10 +638,13 @@ function photos_post(App $a) $group_deny = $_REQUEST['group_deny'] ?? []; $contact_deny = $_REQUEST['contact_deny'] ?? []; - $str_group_allow = perms2str(is_array($group_allow) ? $group_allow : explode(',', $group_allow)); - $str_contact_allow = perms2str(is_array($contact_allow) ? $contact_allow : explode(',', $contact_allow)); - $str_group_deny = perms2str(is_array($group_deny) ? $group_deny : explode(',', $group_deny)); - $str_contact_deny = perms2str(is_array($contact_deny) ? $contact_deny : explode(',', $contact_deny)); + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $str_group_allow = $aclFormatter->toString(is_array($group_allow) ? $group_allow : explode(',', $group_allow)); + $str_contact_allow = $aclFormatter->toString(is_array($contact_allow) ? $contact_allow : explode(',', $contact_allow)); + $str_group_deny = $aclFormatter->toString(is_array($group_deny) ? $group_deny : explode(',', $group_deny)); + $str_contact_deny = $aclFormatter->toString(is_array($contact_deny) ? $contact_deny : explode(',', $contact_deny)); $ret = ['src' => '', 'filename' => '', 'filesize' => 0, 'type' => '']; @@ -1438,7 +1444,12 @@ function photos_content(App $a) $template = $tpl; $sparkle = ''; - if ((activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) && ($item['id'] != $item['parent'])) { + /** @var \Friendica\Protocol\Activity $activity */ + $activity = BaseObject::getClass(\Friendica\Protocol\Activity::class); + + if (($activity->match($item['verb'], ACTIVITY_LIKE) || + $activity->match($item['verb'], ACTIVITY_DISLIKE)) && + ($item['id'] != $item['parent'])) { continue; } diff --git a/mod/settings.php b/mod/settings.php index b5011881c..8c3ce6684 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -5,6 +5,7 @@ use Friendica\App; use Friendica\BaseModule; +use Friendica\BaseObject; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Core\ACL; @@ -25,6 +26,7 @@ use Friendica\Model\Group; use Friendica\Model\User; use Friendica\Module\Login; use Friendica\Protocol\Email; +use Friendica\Util\ACLFormatter; use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Util\Temporal; @@ -533,10 +535,13 @@ function settings_post(App $a) date_default_timezone_set($timezone); } - $str_group_allow = !empty($_POST['group_allow']) ? perms2str($_POST['group_allow']) : ''; - $str_contact_allow = !empty($_POST['contact_allow']) ? perms2str($_POST['contact_allow']) : ''; - $str_group_deny = !empty($_POST['group_deny']) ? perms2str($_POST['group_deny']) : ''; - $str_contact_deny = !empty($_POST['contact_deny']) ? perms2str($_POST['contact_deny']) : ''; + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $str_group_allow = !empty($_POST['group_allow']) ? $aclFormatter->toString($_POST['group_allow']) : ''; + $str_contact_allow = !empty($_POST['contact_allow']) ? $aclFormatter->toString($_POST['contact_allow']) : ''; + $str_group_deny = !empty($_POST['group_deny']) ? $aclFormatter->toString($_POST['group_deny']) : ''; + $str_contact_deny = !empty($_POST['contact_deny']) ? $aclFormatter->toString($_POST['contact_deny']) : ''; $openidserver = $a->user['openidserver']; //$openid = Strings::normaliseOpenID($openid); diff --git a/src/BaseObject.php b/src/BaseObject.php index 996824f4a..204818845 100644 --- a/src/BaseObject.php +++ b/src/BaseObject.php @@ -54,7 +54,7 @@ class BaseObject * * @throws InternalServerErrorException */ - protected static function getClass(string $name) + public static function getClass(string $name) { if (empty(self::$dice)) { throw new InternalServerErrorException('DICE isn\'t initialized.'); diff --git a/src/Content/Item.php b/src/Content/Item.php new file mode 100644 index 000000000..ed6ec9c87 --- /dev/null +++ b/src/Content/Item.php @@ -0,0 +1,79 @@ + $savedFolderName, + 'url' => "#", + 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&cat=' . rawurlencode($savedFolderName) : ""), + 'first' => $first, + 'last' => false + ]; + $first = false; + } + + if (count($categories)) { + $categories[count($categories) - 1]['last'] = true; + } + + if (local_user() == $item['uid']) { + foreach (FileTag::fileToArray($item['file'] ?? '') as $savedFolderName) { + $folders[] = [ + 'name' => $savedFolderName, + 'url' => "#", + 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . rawurlencode($savedFolderName) : ""), + 'first' => $first, + 'last' => false + ]; + $first = false; + } + } + + if (count($folders)) { + $folders[count($folders) - 1]['last'] = true; + } + + return [$categories, $folders]; + } +} diff --git a/src/Content/Text/BBCode/Video.php b/src/Content/Text/BBCode/Video.php new file mode 100644 index 000000000..b73ddce0b --- /dev/null +++ b/src/Content/Text/BBCode/Video.php @@ -0,0 +1,32 @@ + $item['event-id'], - '$title' => prepare_text($item['event-summary']), + '$title' => BBCode::convert($item['event-summary']), '$dtstart_label' => L10n::t('Starts:'), '$dtstart_title' => $dtstart_title, '$dtstart_dt' => $dtstart_dt, @@ -929,7 +929,7 @@ class Event extends BaseObject '$author_name' => $item['author-name'], '$author_link' => $profile_link, '$author_avatar' => $item['author-avatar'], - '$description' => prepare_text($item['event-desc']), + '$description' => BBCode::convert($item['event-desc']), '$location_label' => L10n::t('Location:'), '$show_map_label' => L10n::t('Show map'), '$hide_map_label' => L10n::t('Hide map'), @@ -979,7 +979,7 @@ class Event extends BaseObject } } - $location['name'] = prepare_text($location['name']); + $location['name'] = BBCode::convert($location['name']); // Construct the map HTML. if (isset($location['address'])) { diff --git a/src/Model/Item.php b/src/Model/Item.php index ff0f46676..2c544a263 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -17,13 +17,15 @@ use Friendica\Core\Logger; use Friendica\Core\PConfig; use Friendica\Core\Protocol; use Friendica\Core\Renderer; -use Friendica\Core\System; use Friendica\Core\Session; +use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; +use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; use Friendica\Util\Network; @@ -1357,13 +1359,16 @@ class Item extends BaseObject $item['parent-uri'] = $item['thr-parent']; } + /** @var Activity $activity */ + $activity = self::getClass(Activity::class); + if (isset($item['gravity'])) { $item['gravity'] = intval($item['gravity']); } elseif ($item['parent-uri'] === $item['uri']) { $item['gravity'] = GRAVITY_PARENT; - } elseif (activity_match($item['verb'], ACTIVITY_POST)) { + } elseif ($activity->match($item['verb'], ACTIVITY_POST)) { $item['gravity'] = GRAVITY_COMMENT; - } elseif (activity_match($item['verb'], ACTIVITY_FOLLOW)) { + } elseif ($activity->match($item['verb'], ACTIVITY_FOLLOW)) { $item['gravity'] = GRAVITY_ACTIVITY; } else { $item['gravity'] = GRAVITY_UNKNOWN; // Should not happen @@ -2892,10 +2897,13 @@ class Item extends BaseObject */ public static function enumeratePermissions(array $obj, bool $check_dead = false) { - $allow_people = expand_acl($obj['allow_cid']); - $allow_groups = Group::expand($obj['uid'], expand_acl($obj['allow_gid']), $check_dead); - $deny_people = expand_acl($obj['deny_cid']); - $deny_groups = Group::expand($obj['uid'], expand_acl($obj['deny_gid']), $check_dead); + /** @var ACLFormatter $aclFormater */ + $aclFormater = self::getClass(ACLFormatter::class); + + $allow_people = $aclFormater->expand($obj['allow_cid']); + $allow_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['allow_gid']), $check_dead); + $deny_people = $aclFormater->expand($obj['deny_cid']); + $deny_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['deny_gid']), $check_dead); $recipients = array_unique(array_merge($allow_people, $allow_groups)); $deny = array_unique(array_merge($deny_people, $deny_groups)); $recipients = array_diff($recipients, $deny); @@ -3342,10 +3350,9 @@ class Item extends BaseObject || $rendered_hash != hash("md5", $item["body"]) || Config::get("system", "ignore_cache") ) { - $a = self::getApp(); - redir_private_images($a, $item); + self::addRedirToImageTags($item); - $item["rendered-html"] = prepare_text($item["body"]); + $item["rendered-html"] = BBCode::convert($item["body"]); $item["rendered-hash"] = hash("md5", $item["body"]); $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; @@ -3378,6 +3385,31 @@ class Item extends BaseObject $item["body"] = $body; } + /** + * @brief Find any non-embedded images in private items and add redir links to them + * + * @param array &$item The field array of an item row + */ + private static function addRedirToImageTags(array &$item) + { + $app = self::getApp(); + + $matches = []; + $cnt = preg_match_all('|\[img\](http[^\[]*?/photo/[a-fA-F0-9]+?(-[0-9]\.[\w]+?)?)\[\/img\]|', $item['body'], $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + if (strpos($mtch[1], '/redir') !== false) { + continue; + } + + if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $app->contact['id']) && ($item['network'] == Protocol::DFRN)) { + $img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]); + $item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']); + } + } + } + } + /** * @brief Given an item array, convert the body element from bbcode to html and add smilie icons. * If attach is true, also add icons for item attachments. diff --git a/src/Model/Profile.php b/src/Model/Profile.php index b69860edf..de3290389 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -823,51 +823,51 @@ class Profile $profile['religion'] = [L10n::t('Religion:'), $a->profile['religion']]; } - if ($txt = prepare_text($a->profile['about'])) { + if ($txt = BBCode::convert($a->profile['about'])) { $profile['about'] = [L10n::t('About:'), $txt]; } - if ($txt = prepare_text($a->profile['interest'])) { + if ($txt = BBCode::convert($a->profile['interest'])) { $profile['interest'] = [L10n::t('Hobbies/Interests:'), $txt]; } - if ($txt = prepare_text($a->profile['likes'])) { + if ($txt = BBCode::convert($a->profile['likes'])) { $profile['likes'] = [L10n::t('Likes:'), $txt]; } - if ($txt = prepare_text($a->profile['dislikes'])) { + if ($txt = BBCode::convert($a->profile['dislikes'])) { $profile['dislikes'] = [L10n::t('Dislikes:'), $txt]; } - if ($txt = prepare_text($a->profile['contact'])) { + if ($txt = BBCode::convert($a->profile['contact'])) { $profile['contact'] = [L10n::t('Contact information and Social Networks:'), $txt]; } - if ($txt = prepare_text($a->profile['music'])) { + if ($txt = BBCode::convert($a->profile['music'])) { $profile['music'] = [L10n::t('Musical interests:'), $txt]; } - if ($txt = prepare_text($a->profile['book'])) { + if ($txt = BBCode::convert($a->profile['book'])) { $profile['book'] = [L10n::t('Books, literature:'), $txt]; } - if ($txt = prepare_text($a->profile['tv'])) { + if ($txt = BBCode::convert($a->profile['tv'])) { $profile['tv'] = [L10n::t('Television:'), $txt]; } - if ($txt = prepare_text($a->profile['film'])) { + if ($txt = BBCode::convert($a->profile['film'])) { $profile['film'] = [L10n::t('Film/dance/culture/entertainment:'), $txt]; } - if ($txt = prepare_text($a->profile['romance'])) { + if ($txt = BBCode::convert($a->profile['romance'])) { $profile['romance'] = [L10n::t('Love/Romance:'), $txt]; } - if ($txt = prepare_text($a->profile['work'])) { + if ($txt = BBCode::convert($a->profile['work'])) { $profile['work'] = [L10n::t('Work/employment:'), $txt]; } - if ($txt = prepare_text($a->profile['education'])) { + if ($txt = BBCode::convert($a->profile['education'])) { $profile['education'] = [L10n::t('School/education:'), $txt]; } diff --git a/src/Module/Item/Compose.php b/src/Module/Item/Compose.php index 11b886a2e..c44e4c61a 100644 --- a/src/Module/Item/Compose.php +++ b/src/Module/Item/Compose.php @@ -16,6 +16,7 @@ use Friendica\Model\Item; use Friendica\Model\User; use Friendica\Module\Login; use Friendica\Network\HTTPException\NotImplementedException; +use Friendica\Util\ACLFormatter; use Friendica\Util\Crypto; class Compose extends BaseModule @@ -58,6 +59,9 @@ class Compose extends BaseModule $user = User::getById(local_user(), ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'hidewall', 'default-location']); + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = self::getClass(ACLFormatter::class); + switch ($posttype) { case Item::PT_PERSONAL_NOTE: $compose_title = L10n::t('Compose new personal note'); @@ -70,8 +74,8 @@ class Compose extends BaseModule $compose_title = L10n::t('Compose new post'); $type = 'post'; $doesFederate = true; - $contact_allow = implode(',', expand_acl($user['allow_cid'])); - $group_allow = implode(',', expand_acl($user['allow_gid'])) ?: Group::FOLLOWERS; + $contact_allow = implode(',', $aclFormatter->expand($user['allow_cid'])); + $group_allow = implode(',', $aclFormatter->expand($user['allow_gid'])) ?: Group::FOLLOWERS; break; } @@ -82,8 +86,8 @@ class Compose extends BaseModule $wall = $_REQUEST['wall'] ?? $type == 'post'; $contact_allow = $_REQUEST['contact_allow'] ?? $contact_allow; $group_allow = $_REQUEST['group_allow'] ?? $group_allow; - $contact_deny = $_REQUEST['contact_deny'] ?? implode(',', expand_acl($user['deny_cid'])); - $group_deny = $_REQUEST['group_deny'] ?? implode(',', expand_acl($user['deny_gid'])); + $contact_deny = $_REQUEST['contact_deny'] ?? implode(',', $aclFormatter->expand($user['deny_cid'])); + $group_deny = $_REQUEST['group_deny'] ?? implode(',', $aclFormatter->expand($user['deny_gid'])); $visibility = ($contact_allow . $user['allow_gid'] . $user['deny_cid'] . $user['deny_gid']) ? 'custom' : 'public'; $acl_contacts = Contact::selectToArray(['id', 'name', 'addr', 'micro'], ['uid' => local_user(), 'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]); diff --git a/src/Module/Profile.php b/src/Module/Profile.php index ed3754075..f38c77f2c 100644 --- a/src/Module/Profile.php +++ b/src/Module/Profile.php @@ -131,9 +131,12 @@ class Profile extends BaseModule $category = $datequery = $datequery2 = ''; + /** @var DateTimeFormat $dtFormat */ + $dtFormat = self::getClass(DateTimeFormat::class); + if ($a->argc > 2) { for ($x = 2; $x < $a->argc; $x ++) { - if (is_a_date_arg($a->argv[$x])) { + if ($dtFormat->isYearMonth($a->argv[$x])) { if ($datequery) { $datequery2 = Strings::escapeHtml($a->argv[$x]); } else { diff --git a/src/Object/Post.php b/src/Object/Post.php index 04775bbd0..7dd530801 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -7,6 +7,7 @@ namespace Friendica\Object; use Friendica\BaseObject; use Friendica\Content\ContactSelector; use Friendica\Content\Feature; +use Friendica\Content\Item as ContentItem; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Hook; @@ -21,6 +22,7 @@ use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Model\Term; use Friendica\Model\User; +use Friendica\Protocol\Activity; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; @@ -323,7 +325,10 @@ class Post extends BaseObject $body = Item::prepareBody($item, true); - list($categories, $folders) = get_cats_and_terms($item); + /** @var ContentItem $contItem */ + $contItem = self::getClass(ContentItem::class); + + list($categories, $folders) = $contItem->determineCategoriesTerms($item); $body_e = $body; $text_e = strip_tags($body); @@ -517,12 +522,17 @@ class Post extends BaseObject Logger::log('[WARN] Post::addChild : Item already exists (' . $item->getId() . ').', Logger::DEBUG); return false; } + + /** @var Activity $activity */ + $activity = self::getClass(Activity::class); + /* * Only add what will be displayed */ if ($item->getDataValue('network') === Protocol::MAIL && local_user() != $item->getDataValue('uid')) { return false; - } elseif (activity_match($item->getDataValue('verb'), ACTIVITY_LIKE) || activity_match($item->getDataValue('verb'), ACTIVITY_DISLIKE)) { + } elseif ($activity->match($item->getDataValue('verb'), ACTIVITY_LIKE) || + $activity->match($item->getDataValue('verb'), ACTIVITY_DISLIKE)) { return false; } diff --git a/src/Protocol/Activity.php b/src/Protocol/Activity.php new file mode 100644 index 000000000..64253b065 --- /dev/null +++ b/src/Protocol/Activity.php @@ -0,0 +1,23 @@ + $importer['id']]); + /** @var Activity $activity */ + $activity = BaseObject::getClass(Activity::class); + // Big question: Do we need these functions? They were part of the "consume_feed" function. // This function once was responsible for DFRN and OStatus. - if (activity_match($item["verb"], ACTIVITY_FOLLOW)) { + if ($activity->match($item["verb"], ACTIVITY_FOLLOW)) { Logger::log("New follower"); Contact::addRelationship($importer, $contact, $item); return false; } - if (activity_match($item["verb"], ACTIVITY_UNFOLLOW)) { + if ($activity->match($item["verb"], ACTIVITY_UNFOLLOW)) { Logger::log("Lost follower"); Contact::removeFollower($importer, $contact, $item); return false; } - if (activity_match($item["verb"], ACTIVITY_REQ_FRIEND)) { + if ($activity->match($item["verb"], ACTIVITY_REQ_FRIEND)) { Logger::log("New friend request"); Contact::addRelationship($importer, $contact, $item, true); return false; } - if (activity_match($item["verb"], ACTIVITY_UNFRIEND)) { + if ($activity->match($item["verb"], ACTIVITY_UNFRIEND)) { Logger::log("Lost sharer"); Contact::removeSharer($importer, $contact, $item); return false; diff --git a/src/Util/ACLFormatter.php b/src/Util/ACLFormatter.php new file mode 100644 index 000000000..1fb778761 --- /dev/null +++ b/src/Util/ACLFormatter.php @@ -0,0 +1,67 @@ +<2><3>" => array(1,2,3); + preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $ids, $matches, PREG_PATTERN_ORDER); + + return $matches[1]; + } + + /** + * Wrap ACL elements in angle brackets for storage + * + * @param string $item The item to sanitise + */ + private function sanitize(string &$item) { + if (intval($item)) { + $item = '<' . intval(Strings::escapeTags(trim($item))) . '>'; + } elseif (in_array($item, [Group::FOLLOWERS, Group::MUTUALS])) { + $item = '<' . $item . '>'; + } else { + $item = ''; + } + } + + /** + * Convert an ACL array to a storable string + * + * Normally ACL permissions will be an array. + * We'll also allow a comma-separated string. + * + * @param string|array $permissions + * + * @return string + */ + function toString($permissions) { + $return = ''; + if (is_array($permissions)) { + $item = $permissions; + } else { + $item = explode(',', $permissions); + } + + if (is_array($item)) { + array_walk($item, [$this, 'sanitize']); + $return = implode('', $item); + } + return $return; + } +} diff --git a/src/Util/DateTimeFormat.php b/src/Util/DateTimeFormat.php index 0b47a16f1..e29420e9e 100644 --- a/src/Util/DateTimeFormat.php +++ b/src/Util/DateTimeFormat.php @@ -148,4 +148,37 @@ class DateTimeFormat return $d->format($format); } + + /** + * Checks, if the given string is a date with the pattern YYYY-MM + * + * @param string $dateString The given date + * + * @return boolean True, if the date is a valid pattern + */ + public function isYearMonth(string $dateString) + { + // Check format (2019-01, 2019-1, 2019-10) + if (!preg_match('/^([12]\d{3}-(1[0-2]|0[1-9]|\d))$/', $dateString)) { + return false; + } + + $date = DateTime::createFromFormat('Y-m', $dateString); + + if (!$date) { + return false; + } + + try { + $now = new DateTime(); + } catch (\Throwable $t) { + return false; + } + + if ($date > $now) { + return false; + } + + return true; + } } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 4bf97aca5..ebc70ffb5 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -24,6 +24,7 @@ use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Protocol\Salmon; +use Friendica\Util\ACLFormatter; require_once 'include/items.php'; @@ -272,10 +273,13 @@ class Notifier $public_message = false; // private recipients, not public } - $allow_people = expand_acl($parent['allow_cid']); - $allow_groups = Group::expand($uid, expand_acl($parent['allow_gid']),true); - $deny_people = expand_acl($parent['deny_cid']); - $deny_groups = Group::expand($uid, expand_acl($parent['deny_gid'])); + /** @var ACLFormatter $aclFormatter */ + $aclFormatter = BaseObject::getClass(ACLFormatter::class); + + $allow_people = $aclFormatter->expand($parent['allow_cid']); + $allow_groups = Group::expand($uid, $aclFormatter->expand($parent['allow_gid']),true); + $deny_people = $aclFormatter->expand($parent['deny_cid']); + $deny_groups = Group::expand($uid, $aclFormatter->expand($parent['deny_gid'])); // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing // a delivery fork. private groups (forum_mode == 2) do not uplink diff --git a/tests/src/Content/ItemTest.php b/tests/src/Content/ItemTest.php new file mode 100644 index 000000000..5cdfa978b --- /dev/null +++ b/tests/src/Content/ItemTest.php @@ -0,0 +1,13 @@ +markTestIncomplete('Test data needed.'); + } +} diff --git a/tests/src/Content/Text/BBCode/VideoTest.php b/tests/src/Content/Text/BBCode/VideoTest.php new file mode 100644 index 000000000..4a176871a --- /dev/null +++ b/tests/src/Content/Text/BBCode/VideoTest.php @@ -0,0 +1,43 @@ + [ + 'input' => '[video]https://youtube.link/4523[/video]', + 'assert' => '[youtube]https://youtube.link/4523[/youtube]', + ], + 'youtu.be' => [ + 'input' => '[video]https://youtu.be.link/4523[/video]', + 'assert' => '[youtube]https://youtu.be.link/4523[/youtube]', + ], + 'vimeo' => [ + 'input' => '[video]https://vimeo.link/2343[/video]', + 'assert' => '[vimeo]https://vimeo.link/2343[/vimeo]', + ], + 'mixed' => [ + 'input' => '[video]https://vimeo.link/2343[/video] With other [b]string[/b] [video]https://youtu.be/blaa[/video]', + 'assert' => '[vimeo]https://vimeo.link/2343[/vimeo] With other [b]string[/b] [youtube]https://youtu.be/blaa[/youtube]', + ] + ]; + } + + /** + * Test if the BBCode is successfully transformed for video links + * + * @dataProvider dataVideo + */ + public function testTransform(string $input, string $assert) + { + $bbCodeVideo = new Video(); + + $this->assertEquals($assert, $bbCodeVideo->transform($input)); + } +} diff --git a/tests/src/Core/InstallerTest.php b/tests/src/Core/InstallerTest.php index a898dd295..735a52cd0 100644 --- a/tests/src/Core/InstallerTest.php +++ b/tests/src/Core/InstallerTest.php @@ -339,9 +339,6 @@ class InstallerTest extends MockedTest // Mocking that we can use CURL $this->setFunctions(['curl_init' => true]); - // needed because of "normalise_link" - require_once __DIR__ . '/../../../include/text.php'; - $install = new Installer(); $this->assertTrue($install->checkHtAccess('https://test')); diff --git a/tests/src/Protocol/ActivityTest.php b/tests/src/Protocol/ActivityTest.php new file mode 100644 index 000000000..b6fcbf395 --- /dev/null +++ b/tests/src/Protocol/ActivityTest.php @@ -0,0 +1,57 @@ + [ + 'haystack' => '', + 'needle' => '', + 'assert' => true, + ], + 'simple' => [ + 'haystack' => ACTIVITY_OBJ_TAGTERM, + 'needle' => ACTIVITY_OBJ_TAGTERM, + 'assert' => true, + ], + 'withNamespace' => [ + 'haystack' => 'tagterm', + 'needle' => NAMESPACE_ACTIVITY_SCHEMA . ACTIVITY_OBJ_TAGTERM, + 'assert' => true, + ], + 'invalidSimple' => [ + 'haystack' => 'tagterm', + 'needle' => '', + 'assert' => false, + ], + 'invalidWithOutNamespace' => [ + 'haystack' => 'tagterm', + 'needle' => ACTIVITY_OBJ_TAGTERM, + 'assert' => false, + ], + 'withSubPath' => [ + 'haystack' => 'tagterm', + 'needle' => NAMESPACE_ACTIVITY_SCHEMA . '/bla/' . ACTIVITY_OBJ_TAGTERM, + 'assert' => true, + ], + ]; + } + + /** + * Test the different, possible matchings + * + * @dataProvider dataMatch + */ + public function testMatch(string $haystack, string $needle, bool $assert) + { + $activity = new Activity(); + + $this->assertEquals($assert, $activity->match($haystack, $needle)); + } +} diff --git a/tests/include/TextTest.php b/tests/src/Util/ACLFormaterTest.php similarity index 53% rename from tests/include/TextTest.php rename to tests/src/Util/ACLFormaterTest.php index 5676da8f6..76a566baa 100644 --- a/tests/include/TextTest.php +++ b/tests/src/Util/ACLFormaterTest.php @@ -1,63 +1,25 @@ assertTrue(attribute_contains($testAttr, "class3")); - $this->assertFalse(attribute_contains($testAttr, "class2")); - } - - /** - * test attribute contains - */ - public function testAttributeContains2() - { - $testAttr="class1 not-class2 class3"; - $this->assertTrue(attribute_contains($testAttr, "class3")); - $this->assertFalse(attribute_contains($testAttr, "class2")); - } - - /** - * test with empty input - */ - public function testAttributeContainsEmpty() - { - $testAttr=""; - $this->assertFalse(attribute_contains($testAttr, "class2")); - } - - /** - * test input with special chars - */ - public function testAttributeContainsSpecialChars() - { - $testAttr="--... %\$ä() /(=?}"; - $this->assertFalse(attribute_contains($testAttr, "class2")); - } - /** * test expand_acl, perfect input */ public function testExpandAclNormal() { + $aclFormatter = new ACLFormatter(); + $text='<1><2><3><' . Group::FOLLOWERS . '><' . Group::MUTUALS . '>'; - $this->assertEquals(array('1', '2', '3', Group::FOLLOWERS, Group::MUTUALS), expand_acl($text)); + $this->assertEquals(array('1', '2', '3', Group::FOLLOWERS, Group::MUTUALS), $aclFormatter->expand($text)); } /** @@ -65,8 +27,10 @@ class TextTest extends TestCase */ public function testExpandAclBigNumber() { + $aclFormatter = new ACLFormatter(); + $text='<1><' . PHP_INT_MAX . '><15>'; - $this->assertEquals(array('1', (string)PHP_INT_MAX, '15'), expand_acl($text)); + $this->assertEquals(array('1', (string)PHP_INT_MAX, '15'), $aclFormatter->expand($text)); } /** @@ -76,8 +40,10 @@ class TextTest extends TestCase */ public function testExpandAclString() { + $aclFormatter = new ACLFormatter(); + $text="<1><279012>"; - $this->assertEquals(array('1', '279012'), expand_acl($text)); + $this->assertEquals(array('1', '279012'), $aclFormatter->expand($text)); } /** @@ -87,8 +53,10 @@ class TextTest extends TestCase */ public function testExpandAclSpace() { + $aclFormatter = new ACLFormatter(); + $text="<1><279 012><32>"; - $this->assertEquals(array('1', '32'), expand_acl($text)); + $this->assertEquals(array('1', '32'), $aclFormatter->expand($text)); } /** @@ -96,8 +64,10 @@ class TextTest extends TestCase */ public function testExpandAclEmpty() { + $aclFormatter = new ACLFormatter(); + $text=""; - $this->assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -107,8 +77,10 @@ class TextTest extends TestCase */ public function testExpandAclNoBrackets() { + $aclFormatter = new ACLFormatter(); + $text="According to documentation, that's invalid. "; //should be invalid - $this->assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -118,8 +90,10 @@ class TextTest extends TestCase */ public function testExpandAclJustOneBracket1() { + $aclFormatter = new ACLFormatter(); + $text="assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -129,8 +103,10 @@ class TextTest extends TestCase */ public function testExpandAclJustOneBracket2() { + $aclFormatter = new ACLFormatter(); + $text="Another invalid> string"; //should be invalid - $this->assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -140,8 +116,10 @@ class TextTest extends TestCase */ public function testExpandAclCloseOnly() { + $aclFormatter = new ACLFormatter(); + $text="Another> invalid> string>"; //should be invalid - $this->assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -151,8 +129,10 @@ class TextTest extends TestCase */ public function testExpandAclOpenOnly() { + $aclFormatter = new ACLFormatter(); + $text="assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -162,8 +142,10 @@ class TextTest extends TestCase */ public function testExpandAclNoMatching1() { + $aclFormatter = new ACLFormatter(); + $text=" invalid "; //should be invalid - $this->assertEquals(array(), expand_acl($text)); + $this->assertEquals(array(), $aclFormatter->expand($text)); } /** @@ -174,18 +156,45 @@ class TextTest extends TestCase */ public function testExpandAclEmptyMatch() { + $aclFormatter = new ACLFormatter(); + $text="<1><><3>"; - $this->assertEquals(array('1', '3'), expand_acl($text)); + $this->assertEquals(array('1', '3'), $aclFormatter->expand($text)); + } + + public function dataAclToString() + { + return [ + 'empty' => [ + 'input' => '', + 'assert' => '', + ], + 'string' => [ + 'input' => '1,2,3,4', + 'assert' => '<1><2><3><4>', + ], + 'array' => [ + 'input' => [1, 2, 3, 4], + 'assert' => '<1><2><3><4>', + ], + 'invalid' => [ + 'input' => [1, 'a', 3, 4], + 'assert' => '<1><3><4>', + ], + 'invalidString' => [ + 'input' => 'a,bsd23,4', + 'assert' => '<4>', + ], + ]; } /** - * test hex2bin and reverse + * @dataProvider dataAclToString */ - public function testHex2Bin() + public function testAclToString($input, string $assert) { - $this->assertEquals(-3, hex2bin(bin2hex(-3))); - $this->assertEquals(0, hex2bin(bin2hex(0))); - $this->assertEquals(12, hex2bin(bin2hex(12))); - $this->assertEquals(PHP_INT_MAX, hex2bin(bin2hex(PHP_INT_MAX))); + $aclFormatter = new ACLFormatter(); + + $this->assertEquals($assert, $aclFormatter->toString($input)); } } diff --git a/tests/src/Util/DateTimeFormatTest.php b/tests/src/Util/DateTimeFormatTest.php new file mode 100644 index 000000000..bdc902eab --- /dev/null +++ b/tests/src/Util/DateTimeFormatTest.php @@ -0,0 +1,61 @@ + [ + 'input' => '1990-10', + 'assert' => true, + ], + 'validOneCharMonth' => [ + 'input' => '1990-1', + 'assert' => true, + ], + 'validTwoCharMonth' => [ + 'input' => '1990-01', + 'assert' => true, + ], + 'invalidFormat' => [ + 'input' => '199-11', + 'assert' => false, + ], + 'invalidFormat2' => [ + 'input' => '1990-15', + 'assert' => false, + ], + 'invalidFormat3' => [ + 'input' => '99-101', + 'assert' => false, + ], + 'invalidFormat4' => [ + 'input' => '11-1990', + 'assert' => false, + ], + 'invalidFuture' => [ + 'input' => '3030-12', + 'assert' => false, + ], + 'invalidYear' => [ + 'input' => '-100-10', + 'assert' => false, + ], + ]; + } + + /** + * @dataProvider dataYearMonth + */ + public function testIsYearMonth(string $input, bool $assert) + { + $dtFormat = new DateTimeFormat(); + + $this->assertEquals($assert, $dtFormat->isYearMonth($input)); + } +}