X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=mod%2Fitem.php;h=a96d28819365c1c02426d3febd65097fe078b194;hb=67a0e97f7cb2636a798d8e14e72d65335e0e1020;hp=5e6f88bac7ea33224c78b741d68633c76fd43491;hpb=895b3abf320a28ecf0f797f4f4900e6baf429308;p=friendica.git diff --git a/mod/item.php b/mod/item.php index 5e6f88bac7..a96d288193 100644 --- a/mod/item.php +++ b/mod/item.php @@ -16,31 +16,40 @@ */ use Friendica\App; +use Friendica\BaseObject; use Friendica\Content\Pager; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; -use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\Protocol; +use Friendica\Core\Session; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; +use Friendica\Model\Attach; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\FileTag; use Friendica\Model\Item; use Friendica\Model\Photo; +use Friendica\Model\Term; +use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; use Friendica\Util\Security; use Friendica\Util\Strings; +use Friendica\Worker\Delivery; + +require_once __DIR__ . '/../include/items.php'; function item_post(App $a) { - if (!local_user() && !remote_user()) { + if (!Session::isAuthenticated()) { return 0; } @@ -54,16 +63,16 @@ function item_post(App $a) { exit(); } - Addon::callHooks('post_local_start', $_REQUEST); + Hook::callAll('post_local_start', $_REQUEST); Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA); - $api_source = defaults($_REQUEST, 'api_source', false); + $api_source = $_REQUEST['api_source'] ?? false; $message_id = ((!empty($_REQUEST['message_id']) && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); - $return_path = defaults($_REQUEST, 'return', ''); - $preview = intval(defaults($_REQUEST, 'preview', 0)); + $return_path = $_REQUEST['return'] ?? ''; + $preview = intval($_REQUEST['preview'] ?? 0); /* * Check for doubly-submitted posts, and reject duplicates @@ -80,40 +89,41 @@ function item_post(App $a) { } // Is this a reply to something? - $thr_parent = intval(defaults($_REQUEST, 'parent', 0)); - $thr_parent_uri = trim(defaults($_REQUEST, 'parent_uri', '')); + $toplevel_item_id = intval($_REQUEST['parent'] ?? 0); + $thr_parent_uri = trim($_REQUEST['parent_uri'] ?? ''); - $thr_parent_contact = null; + $thread_parent_id = 0; + $thread_parent_contact = null; - $parent = 0; - $parent_item = null; + $toplevel_item = null; $parent_user = null; $parent_contact = null; $objecttype = null; - $profile_uid = defaults($_REQUEST, 'profile_uid', local_user()); - $posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE); + $profile_uid = ($_REQUEST['profile_uid'] ?? 0) ?: local_user(); + $posttype = ($_REQUEST['post_type'] ?? '') ?: Item::PT_ARTICLE; - if ($thr_parent || $thr_parent_uri) { - if ($thr_parent) { - $parent_item = Item::selectFirst([], ['id' => $thr_parent]); + if ($toplevel_item_id || $thr_parent_uri) { + if ($toplevel_item_id) { + $toplevel_item = Item::selectFirst([], ['id' => $toplevel_item_id]); } elseif ($thr_parent_uri) { - $parent_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]); + $toplevel_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]); } - // if this isn't the real parent of the conversation, find it - if (DBA::isResult($parent_item)) { + // if this isn't the top-level parent of the conversation, find it + if (DBA::isResult($toplevel_item)) { // The URI and the contact is taken from the direct parent which needn't to be the top parent - $thr_parent_uri = $parent_item['uri']; - $thr_parent_contact = Contact::getDetailsByURL($parent_item["author-link"]); + $thread_parent_id = $toplevel_item['id']; + $thr_parent_uri = $toplevel_item['uri']; + $thread_parent_contact = Contact::getDetailsByURL($toplevel_item["author-link"]); - if ($parent_item['id'] != $parent_item['parent']) { - $parent_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $parent_item['parent']]); + if ($toplevel_item['id'] != $toplevel_item['parent']) { + $toplevel_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $toplevel_item['parent']]); } } - if (!DBA::isResult($parent_item)) { + if (!DBA::isResult($toplevel_item)) { notice(L10n::t('Unable to locate original post.') . EOL); if (!empty($_REQUEST['return'])) { $a->internalRedirect($return_path); @@ -121,22 +131,20 @@ function item_post(App $a) { exit(); } - $parent = $parent_item['id']; - $parent_user = $parent_item['uid']; - - $parent_contact = Contact::getDetailsByURL($parent_item["author-link"]); + $toplevel_item_id = $toplevel_item['id']; + $parent_user = $toplevel_item['uid']; - $objecttype = ACTIVITY_OBJ_COMMENT; + $objecttype = Activity\ObjectType::COMMENT; } - if ($parent) { - Logger::log('mod_item: item_post parent=' . $parent); + if ($toplevel_item_id) { + Logger::info('mod_item: item_post parent=' . $toplevel_item_id); } - $post_id = intval(defaults($_REQUEST, 'post_id', 0)); - $app = strip_tags(defaults($_REQUEST, 'source', '')); - $extid = strip_tags(defaults($_REQUEST, 'extid', '')); - $object = defaults($_REQUEST, 'object', ''); + $post_id = intval($_REQUEST['post_id'] ?? 0); + $app = strip_tags($_REQUEST['source'] ?? ''); + $extid = strip_tags($_REQUEST['extid'] ?? ''); + $object = $_REQUEST['object'] ?? ''; // Don't use "defaults" here. It would turn 0 to 1 if (!isset($_REQUEST['wall'])) { @@ -159,7 +167,7 @@ function item_post(App $a) { } // Allow commenting if it is an answer to a public post - $allow_comment = local_user() && ($profile_uid == 0) && $parent && in_array($parent_item['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]); + $allow_comment = local_user() && ($profile_uid == 0) && $toplevel_item_id && in_array($toplevel_item['network'], Protocol::FEDERATED); // Now check that valid personal details have been provided if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) { @@ -182,13 +190,50 @@ function item_post(App $a) { $user = DBA::selectFirst('user', [], ['uid' => $profile_uid]); - if (!DBA::isResult($user) && !$parent) { + if (!DBA::isResult($user) && !$toplevel_item_id) { return 0; } $categories = ''; $postopts = ''; $emailcc = ''; + $body = $_REQUEST['body'] ?? ''; + $has_attachment = $_REQUEST['has_attachment'] ?? 0; + + // If we have a speparate attachment, we need to add it to the body. + if (!empty($has_attachment)) { + $attachment_type = $_REQUEST['attachment_type'] ?? ''; + $attachment_title = $_REQUEST['attachment_title'] ?? ''; + $attachment_text = $_REQUEST['attachment_text'] ?? ''; + + $attachment_url = hex2bin($_REQUEST['attachment_url'] ?? ''); + $attachment_img_src = hex2bin($_REQUEST['attachment_img_src'] ?? ''); + + $attachment_img_width = $_REQUEST['attachment_img_width'] ?? 0; + $attachment_img_height = $_REQUEST['attachment_img_height'] ?? 0; + $attachment = [ + 'type' => $attachment_type, + 'title' => $attachment_title, + 'text' => $attachment_text, + 'url' => $attachment_url, + ]; + + if (!empty($attachment_img_src)) { + $attachment['images'] = [ + 0 => [ + 'src' => $attachment_img_src, + 'width' => $attachment_img_width, + 'height' => $attachment_img_height + ] + ]; + } + + $att_bbcode = add_page_info_data($attachment); + $body .= $att_bbcode; + } + + // Convert links with empty descriptions to links without an explicit description + $body = preg_replace('#\[url=([^\]]*?)\]\[/url\]#ism', '[url]$1[/url]', $body); if (!empty($orig_post)) { $str_group_allow = $orig_post['allow_gid']; @@ -202,7 +247,7 @@ function item_post(App $a) { $app = $orig_post['app']; $categories = $orig_post['file']; $title = Strings::escapeTags(trim($_REQUEST['title'])); - $body = Strings::escapeHtml(trim($_REQUEST['body'])); + $body = Strings::escapeHtml(trim($body)); $private = $orig_post['private']; $pubmail_enabled = $orig_post['pubmail']; $network = $orig_post['network']; @@ -227,49 +272,49 @@ function item_post(App $a) { $str_contact_deny = $user['deny_cid']; } else { // use the posted permissions - $str_group_allow = perms2str(defaults($_REQUEST, 'group_allow', '')); - $str_contact_allow = perms2str(defaults($_REQUEST, 'contact_allow', '')); - $str_group_deny = perms2str(defaults($_REQUEST, 'group_deny', '')); - $str_contact_deny = perms2str(defaults($_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(defaults($_REQUEST, 'title' , ''))); - $location = Strings::escapeTags(trim(defaults($_REQUEST, 'location', ''))); - $coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , ''))); - $verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , ''))); - $emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , ''))); - $body = Strings::escapeHtml(trim(defaults($_REQUEST, 'body' , ''))); - $network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN))); + $title = Strings::escapeTags(trim($_REQUEST['title'] ?? '')); + $location = Strings::escapeTags(trim($_REQUEST['location'] ?? '')); + $coord = Strings::escapeTags(trim($_REQUEST['coord'] ?? '')); + $verb = Strings::escapeTags(trim($_REQUEST['verb'] ?? '')); + $emailcc = Strings::escapeTags(trim($_REQUEST['emailcc'] ?? '')); + $body = Strings::escapeHtml(trim($body)); + $network = Strings::escapeTags(trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN)); $guid = System::createUUID(); - $postopts = defaults($_REQUEST, 'postopts', ''); + $postopts = $_REQUEST['postopts'] ?? ''; $private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0); - if ($user['hidewall']) { - $private = 2; - } - // If this is a comment, set the permissions from the parent. - if ($parent_item) { + if ($toplevel_item) { // for non native networks use the network of the original post as network of the item - if (($parent_item['network'] != Protocol::DIASPORA) - && ($parent_item['network'] != Protocol::OSTATUS) + if (($toplevel_item['network'] != Protocol::DIASPORA) + && ($toplevel_item['network'] != Protocol::OSTATUS) && ($network == "")) { - $network = $parent_item['network']; + $network = $toplevel_item['network']; } - $str_contact_allow = $parent_item['allow_cid']; - $str_group_allow = $parent_item['allow_gid']; - $str_contact_deny = $parent_item['deny_cid']; - $str_group_deny = $parent_item['deny_gid']; - $private = $parent_item['private']; + $str_contact_allow = $toplevel_item['allow_cid']; + $str_group_allow = $toplevel_item['allow_gid']; + $str_contact_deny = $toplevel_item['deny_cid']; + $str_group_deny = $toplevel_item['deny_gid']; + $private = $toplevel_item['private']; - $wall = $parent_item['wall']; + $wall = $toplevel_item['wall']; } - $pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private; + $pubmail_enabled = ($_REQUEST['pubmail_enable'] ?? false) && !$private; // if using the API, we won't see pubmail_enable - figure out if it should be set if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) { @@ -290,21 +335,19 @@ function item_post(App $a) { } } - if (!empty($categories)) - { + if (!empty($categories)) { // get the "fileas" tags for this post - $filedas = FileTag::fileToList($categories, 'file'); + $filedas = FileTag::fileToArray($categories); } // save old and new categories, so we can determine what needs to be deleted from pconfig $categories_old = $categories; - $categories = FileTag::listToFile(trim(defaults($_REQUEST, 'category', '')), 'category'); + $categories = FileTag::listToFile(trim($_REQUEST['category'] ?? ''), 'category'); $categories_new = $categories; - if (!empty($filedas)) - { + if (!empty($filedas) && is_array($filedas)) { // append the fileas stuff to the new categories list - $categories .= FileTag::listToFile($filedas, 'file'); + $categories .= FileTag::arrayToFile($filedas); } // get contact info for poster @@ -316,18 +359,8 @@ function item_post(App $a) { if (local_user() && ((local_user() == $profile_uid) || $allow_comment)) { $self = true; $author = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]); - } elseif (remote_user()) { - if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) { - foreach ($_SESSION['remote'] as $v) { - if ($v['uid'] == $profile_uid) { - $contact_id = $v['cid']; - break; - } - } - } - if ($contact_id) { - $author = DBA::selectFirst('contact', [], ['id' => $contact_id]); - } + } elseif (!empty(Session::getRemoteContactID($profile_uid))) { + $author = DBA::selectFirst('contact', [], ['id' => Session::getRemoteContactID($profile_uid)]); } if (DBA::isResult($author)) { @@ -347,12 +380,8 @@ function item_post(App $a) { $tags = BBCode::getTags($body); - // Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them) - if ($parent && in_array($thr_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) { - $contact = '@[url=' . $thr_parent_contact['url'] . ']' . $thr_parent_contact['nick'] . '[/url]'; - if (!stripos(implode($tags), '[url=' . $thr_parent_contact['url'] . ']')) { - $tags[] = $contact; - } + if ($thread_parent_id && !\Friendica\Content\Feature::isEnabled($uid, 'explicit_mentions')) { + $tags = item_add_implicit_mentions($tags, $thread_parent_contact, $thread_parent_id); } $tagged = []; @@ -365,7 +394,7 @@ function item_post(App $a) { foreach ($tags as $tag) { $tag_type = substr($tag, 0, 1); - if ($tag_type == '#') { + if ($tag_type == Term::TAG_CHARACTER[Term::HASHTAG]) { continue; } @@ -385,14 +414,14 @@ function item_post(App $a) { continue; } - $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network); + $success = handle_tag($body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network); if ($success['replaced']) { $tagged[] = $tag; } // When the forum is private or the forum is addressed with a "!" make the post private - if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == '!'))) { + if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]))) { $private_forum = $success['contact']['prv']; - $only_to_forum = ($tag_type == '!'); + $only_to_forum = ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]); $private_id = $success['contact']['id']; $forum_contact = $success['contact']; } elseif (is_array($success['contact']) && !empty($success['contact']['forum']) && @@ -407,7 +436,7 @@ function item_post(App $a) { $original_contact_id = $contact_id; - if (!$parent && count($forum_contact) && ($private_forum || $only_to_forum)) { + if (!$toplevel_item_id && count($forum_contact) && ($private_forum || $only_to_forum)) { // we tagged a forum in a top level post. Now we change the post $private = $private_forum; @@ -437,43 +466,10 @@ function item_post(App $a) { $match = null; - /// @todo these lines should be moved to Model/Photo - if (!$preview && preg_match_all("/\[img([\=0-9x]*?)\](.*?)\[\/img\]/",$body,$match)) { - $images = $match[2]; - if (count($images)) { - - $objecttype = ACTIVITY_OBJ_IMAGE; - - foreach ($images as $image) { - if (!stristr($image, System::baseUrl() . '/photo/')) { - continue; - } - $image_uri = substr($image,strrpos($image,'/') + 1); - $image_uri = substr($image_uri,0, strpos($image_uri,'-')); - if (!strlen($image_uri)) { - continue; - } - - // Ensure to only modify photos that you own - $srch = '<' . intval($original_contact_id) . '>'; - - $condition = [ - 'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', - 'resource-id' => $image_uri, 'uid' => $profile_uid - ]; - if (!Photo::exists($condition)) { - continue; - } - - $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, - 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny]; - $condition = ['resource-id' => $image_uri, 'uid' => $profile_uid]; - Photo::update($fields, $condition); - } - } + if (!$preview && Photo::setPermissionFromBody($body, $profile_uid, $original_contact_id, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny)) { + $objecttype = Activity\ObjectType::IMAGE; } - /* * Next link in any attachment references we find in the post. */ @@ -489,14 +485,14 @@ function item_post(App $a) { $condition = ['allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', 'id' => $attach]; - if (!DBA::exists('attach', $condition)) { + if (!Attach::exists($condition)) { continue; } $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny]; $condition = ['id' => $attach]; - DBA::update('attach', $fields, $condition); + Attach::update($fields, $condition); } } } @@ -507,11 +503,12 @@ function item_post(App $a) { if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $body, $match, PREG_SET_ORDER) || isset($data["type"])) && ($posttype != Item::PT_PERSONAL_NOTE)) { $posttype = Item::PT_PAGE; - $objecttype = ACTIVITY_OBJ_BOOKMARK; + $objecttype = Activity\ObjectType::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); @@ -520,15 +517,15 @@ function item_post(App $a) { // Setting the object type if not defined before if (!$objecttype) { - $objecttype = ACTIVITY_OBJ_NOTE; // Default value + $objecttype = Activity\ObjectType::NOTE; // Default value $objectdata = BBCode::getAttachedData($body); if ($objectdata["type"] == "link") { - $objecttype = ACTIVITY_OBJ_BOOKMARK; + $objecttype = Activity\ObjectType::BOOKMARK; } elseif ($objectdata["type"] == "video") { - $objecttype = ACTIVITY_OBJ_VIDEO; + $objecttype = Activity\ObjectType::VIDEO; } elseif ($objectdata["type"] == "photo") { - $objecttype = ACTIVITY_OBJ_IMAGE; + $objecttype = Activity\ObjectType::IMAGE; } } @@ -539,8 +536,8 @@ function item_post(App $a) { if (preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$body,$match)) { foreach ($match[2] as $mtch) { $fields = ['id', 'filename', 'filesize', 'filetype']; - $attachment = DBA::selectFirst('attach', $fields, ['id' => $mtch]); - if (DBA::isResult($attachment)) { + $attachment = Attach::selectFirst($fields, ['id' => $mtch]); + if ($attachment !== false) { if (strlen($attachments)) { $attachments .= ','; } @@ -553,14 +550,14 @@ function item_post(App $a) { } if (!strlen($verb)) { - $verb = ACTIVITY_POST; + $verb = Activity::POST; } if ($network == "") { $network = Protocol::DFRN; } - $gravity = ($parent ? GRAVITY_COMMENT : GRAVITY_PARENT); + $gravity = ($toplevel_item_id ? GRAVITY_COMMENT : GRAVITY_PARENT); // even if the post arrived via API we are considering that it // originated on this site by default for determining relayability. @@ -572,12 +569,10 @@ function item_post(App $a) { $origin = $_REQUEST['origin']; } - $notify_type = ($parent ? 'comment-new' : 'wall-new'); - $uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid)); // Fallback so that we alway have a parent uri - if (!$thr_parent_uri || !$parent) { + if (!$thr_parent_uri || !$toplevel_item_id) { $thr_parent_uri = $uri; } @@ -635,7 +630,7 @@ function item_post(App $a) { * 'self' if true indicates the owner is posting on their own wall * If parent is 0 it is a top-level post. */ - $datarray['parent'] = $parent; + $datarray['parent'] = $toplevel_item_id; $datarray['self'] = $self; // This triggers posts via API and the mirror functions @@ -679,7 +674,7 @@ function item_post(App $a) { exit(); } - Addon::callHooks('post_local',$datarray); + Hook::callAll('post_local',$datarray); if (!empty($datarray['cancel'])) { Logger::log('mod_item: post cancelled by addon.'); @@ -722,8 +717,6 @@ function item_post(App $a) { $a->internalRedirect($return_path); } exit(); - } else { - $post_id = 0; } unset($datarray['edit']); @@ -755,7 +748,7 @@ function item_post(App $a) { FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category'); // These notifications are sent if someone else is commenting other your wall - if ($parent) { + if ($toplevel_item_id) { if ($contact_record != $author) { notification([ 'type' => NOTIFY_COMMENT, @@ -769,10 +762,10 @@ function item_post(App $a) { 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], - 'verb' => ACTIVITY_POST, + 'verb' => Activity::POST, 'otype' => 'item', - 'parent' => $parent, - 'parent_uri' => $parent_item['uri'] + 'parent' => $toplevel_item_id, + 'parent_uri' => $toplevel_item['uri'] ]); } } else { @@ -789,13 +782,13 @@ function item_post(App $a) { 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], - 'verb' => ACTIVITY_POST, + 'verb' => Activity::POST, 'otype' => 'item' ]); } } - Addon::callHooks('post_local_end', $datarray); + Hook::callAll('post_local_end', $datarray); if (strlen($emailcc) && $profile_uid == local_user()) { $erecips = explode(',', $emailcc); @@ -840,7 +833,7 @@ function item_post(App $a) { // When we are doing some forum posting via ! we have to start the notifier manually. // These kind of posts don't initiate the notifier call in the item class. if ($only_to_forum) { - Worker::add(PRIORITY_HIGH, "Notifier", $notify_type, $post_id); + Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => false], "Notifier", Delivery::POST, $post_id); } Logger::log('post_complete'); @@ -879,7 +872,7 @@ function item_post_return($baseurl, $api_source, $return_path) function item_content(App $a) { - if (!local_user() && !remote_user()) { + if (!Session::isAuthenticated()) { return; } @@ -909,26 +902,27 @@ function item_content(App $a) /** * This function removes the tag $tag from the text $body and replaces it with - * the appropiate link. + * the appropriate link. * - * @param App $a Application instance @TODO is unused in this function's scope (excluding included files) - * @param string $body the text to replace the tag in - * @param string $inform a comma-seperated string containing everybody to inform - * @param string $str_tags string to add the tag to + * @param App $a + * @param string $body the text to replace the tag in + * @param string $inform a comma-seperated string containing everybody to inform + * @param string $str_tags string to add the tag to * @param integer $profile_uid - * @param string $tag the tag to replace - * @param string $network The network of the post + * @param string $tag the tag to replace + * @param string $network The network of the post * - * @return boolean true if replaced, false if not replaced + * @return array|bool ['replaced' => $replaced, 'contact' => $contact]; + * @throws ImagickException + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ -function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") +function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") { $replaced = false; $r = null; - $tag_type = '@'; //is it a person tag? - if ((strpos($tag, '@') === 0) || (strpos($tag, '!') === 0)) { + if (Term::isType($tag, Term::MENTION, Term::IMPLICIT_MENTION, Term::EXCLUSIVE_MENTION)) { $tag_type = substr($tag, 0, 1); //is it already replaced? if (strpos($tag, '[url=')) { @@ -961,7 +955,6 @@ function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $n return $replaced; } - $stat = false; //get the person's name $name = substr($tag, 1); @@ -1030,7 +1023,7 @@ function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $n $profile = $contact["url"]; $alias = $contact["alias"]; - $newname = defaults($contact, "name", $contact["nick"]); + $newname = ($contact["name"] ?? '') ?: $contact["nick"]; } //if there is an url for this persons profile @@ -1052,7 +1045,7 @@ function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $n * Status.Net seems to require the numeric ID URL in a mention if the person isn't * subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both. */ - if (strlen($alias)) { + if (!empty($alias)) { $newtag = '@[url=' . $alias . ']' . $newname . '[/url]'; if (!stripos($str_tags, '[url=' . $alias . ']')) { if (strlen($str_tags)) { @@ -1066,3 +1059,34 @@ function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $n return ['replaced' => $replaced, 'contact' => $contact]; } + +function item_add_implicit_mentions(array $tags, array $thread_parent_contact, $thread_parent_id) +{ + if (Config::get('system', 'disable_implicit_mentions')) { + // Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them) + if (in_array($thread_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) { + $contact = Term::TAG_CHARACTER[Term::MENTION] . '[url=' . $thread_parent_contact['url'] . ']' . $thread_parent_contact['nick'] . '[/url]'; + if (!stripos(implode($tags), '[url=' . $thread_parent_contact['url'] . ']')) { + $tags[] = $contact; + } + } + } else { + $implicit_mentions = [ + $thread_parent_contact['url'] => $thread_parent_contact['nick'] + ]; + + $parent_terms = Term::tagArrayFromItemId($thread_parent_id, [Term::MENTION, Term::IMPLICIT_MENTION]); + + foreach ($parent_terms as $parent_term) { + $implicit_mentions[$parent_term['url']] = $parent_term['term']; + } + + foreach ($implicit_mentions as $url => $label) { + if ($url != \Friendica\Model\Profile::getMyURL() && !stripos(implode($tags), '[url=' . $url . ']')) { + $tags[] = Term::TAG_CHARACTER[Term::IMPLICIT_MENTION] . '[url=' . $url . ']' . $label . '[/url]'; + } + } + } + + return $tags; +}