From b0cb6536dd5a6e0b2c92e182c427eb3b2e5d28e1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 May 2020 05:08:05 +0000 Subject: [PATCH 1/3] The old tag handling is removed --- include/api.php | 3 +- include/enotify.php | 2 +- include/items.php | 22 ---- mod/item.php | 47 +------- mod/tagger.php | 43 ------- mod/tagrm.php | 20 +--- src/Model/Item.php | 114 +----------------- src/Model/Tag.php | 2 - src/Model/Term.php | 244 +------------------------------------- src/Model/UserItem.php | 14 ++- src/Protocol/DFRN.php | 33 +----- src/Protocol/Diaspora.php | 5 +- src/Protocol/Feed.php | 19 +-- src/Protocol/OStatus.php | 15 +-- 14 files changed, 40 insertions(+), 543 deletions(-) diff --git a/include/api.php b/include/api.php index c04174313e..fdebdd48bc 100644 --- a/include/api.php +++ b/include/api.php @@ -2033,7 +2033,7 @@ function api_statuses_repeat($type) Logger::log('API: api_statuses_repeat: '.$id); - $fields = ['uri-id', 'body', 'title', 'attach', 'tag', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $fields = ['uri-id', 'body', 'title', 'attach', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; $item = Item::selectFirst($fields, ['id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED]]); if (DBA::isResult($item) && $item['body'] != "") { @@ -2051,7 +2051,6 @@ function api_statuses_repeat($type) $post .= "[/share]"; } $_REQUEST['body'] = $post; - $_REQUEST['tag'] = $item['tag']; $_REQUEST['attach'] = $item['attach']; $_REQUEST['profile_uid'] = api_user(); $_REQUEST['api_source'] = true; diff --git a/include/enotify.php b/include/enotify.php index 2ae7a99157..78a390e657 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -574,7 +574,7 @@ function check_user_notification($itemid) { * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ function check_item_notification($itemid, $uid, $notification_type) { - $fields = ['id', 'mention', 'tag', 'parent', 'title', 'body', + $fields = ['id', 'mention', 'parent', 'title', 'body', 'author-link', 'author-name', 'author-avatar', 'author-id', 'guid', 'parent-uri', 'uri', 'contact-id', 'network']; $condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false]; diff --git a/include/items.php b/include/items.php index 582fbb0933..38f4a58fba 100644 --- a/include/items.php +++ b/include/items.php @@ -141,28 +141,6 @@ function query_page_info($url, $photo = "", $keywords = false, $keyword_blacklis return $data; } -function add_page_keywords($url, $photo = "", $keywords = false, $keyword_blacklist = "") -{ - $data = query_page_info($url, $photo, $keywords, $keyword_blacklist); - if (empty($data["keywords"]) || !is_array($data["keywords"])) { - return ''; - } - - $tags = ""; - foreach ($data["keywords"] as $keyword) { - $hashtag = str_replace([" ", "+", "/", ".", "#", "'"], - ["", "", "", "", "", ""], $keyword); - - if ($tags != "") { - $tags .= ", "; - } - - $tags .= "#[url=" . DI::baseUrl() . "/search?tag=" . $hashtag . "]" . $hashtag . "[/url]"; - } - - return $tags; -} - function get_page_keywords($url, $photo = "", $keywords = false, $keyword_blacklist = "") { $data = query_page_info($url, $photo, $keywords, $keyword_blacklist); diff --git a/mod/item.php b/mod/item.php index 30b5f5aefa..10ad3ff05b 100644 --- a/mod/item.php +++ b/mod/item.php @@ -375,7 +375,6 @@ function item_post(App $a) { } // Look for any tags and linkify them - $str_tags = ''; $inform = ''; $tags = BBCode::getTags($body); @@ -414,7 +413,7 @@ function item_post(App $a) { continue; } - $success = handle_tag($body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network); + $success = handle_tag($body, $inform, local_user() ? local_user() : $profile_uid, $tag, $network); if ($success['replaced']) { $tagged[] = $tag; } @@ -598,7 +597,6 @@ function item_post(App $a) { $datarray['app'] = $app; $datarray['location'] = $location; $datarray['coord'] = $coord; - $datarray['tag'] = $str_tags; $datarray['file'] = $categories; $datarray['inform'] = $inform; $datarray['verb'] = $verb; @@ -695,7 +693,6 @@ function item_post(App $a) { $fields = [ 'title' => $datarray['title'], 'body' => $datarray['body'], - 'tag' => $datarray['tag'], 'attach' => $datarray['attach'], 'file' => $datarray['file'], 'rendered-html' => $datarray['rendered-html'], @@ -890,7 +887,6 @@ function item_content(App $a) * @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 @@ -899,24 +895,15 @@ function item_content(App $a) * @throws ImagickException * @throws HTTPException\InternalServerErrorException */ -function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") +function handle_tag(&$body, &$inform, $profile_uid, $tag, $network = "") { $replaced = false; - $r = null; //is it a person tag? if (Tag::isType($tag, Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION)) { $tag_type = substr($tag, 0, 1); //is it already replaced? if (strpos($tag, '[url=')) { - //append tag to str_tags - if (!stristr($str_tags, $tag)) { - if (strlen($str_tags)) { - $str_tags .= ','; - } - $str_tags .= $tag; - } - // Checking for the alias that is used for OStatus $pattern = "/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism"; if (preg_match($pattern, $tag, $matches)) { @@ -924,14 +911,6 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = if ($data["alias"] != "") { $newtag = '@[url=' . $data["alias"] . ']' . $data["nick"] . '[/url]'; - - if (!stripos($str_tags, '[url=' . $data["alias"] . ']')) { - if (strlen($str_tags)) { - $str_tags .= ','; - } - - $str_tags .= $newtag; - } } } @@ -1005,7 +984,6 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = } $profile = $contact["url"]; - $alias = $contact["alias"]; $newname = ($contact["name"] ?? '') ?: $contact["nick"]; } @@ -1016,27 +994,6 @@ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = $profile = str_replace(',', '%2c', $profile); $newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]'; $body = str_replace($tag_type . $name, $newtag, $body); - // append tag to str_tags - if (!stristr($str_tags, $newtag)) { - if (strlen($str_tags)) { - $str_tags .= ','; - } - $str_tags .= $newtag; - } - - /* - * 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 (!empty($alias)) { - $newtag = '@[url=' . $alias . ']' . $newname . '[/url]'; - if (!stripos($str_tags, '[url=' . $alias . ']')) { - if (strlen($str_tags)) { - $str_tags .= ','; - } - $str_tags .= $newtag; - } - } } } diff --git a/mod/tagger.php b/mod/tagger.php index f39c37103a..86a6ff69f3 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -29,7 +29,6 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Item; use Friendica\Model\Tag; -use Friendica\Model\Term; use Friendica\Protocol\Activity; use Friendica\Util\Strings; use Friendica\Util\XML; @@ -170,50 +169,8 @@ EOT; Item::update(['visible' => true], ['id' => $item['id']]); } - $term_objtype = ($item['resource-id'] ? Term::OBJECT_TYPE_PHOTO : Term::OBJECT_TYPE_POST); - Tag::store($item['uri-id'], Tag::HASHTAG, $term); - $t = q("SELECT count(tid) as tcount FROM term WHERE oid=%d AND term='%s'", - intval($item['id']), - DBA::escape($term) - ); - - if (!$blocktags && $t[0]['tcount'] == 0) { - q("INSERT INTO term (oid, otype, type, term, url, uid) VALUE (%d, %d, %d, '%s', '%s', %d)", - intval($item['id']), - $term_objtype, - Tag::HASHTAG, - DBA::escape($term), - '', - intval($owner_uid) - ); - } - - // if the original post is on this site, update it. - $original_item = Item::selectFirst(['tag', 'id', 'uid'], ['origin' => true, 'uri' => $item['uri']]); - if (DBA::isResult($original_item)) { - $x = q("SELECT `blocktags` FROM `user` WHERE `uid`=%d LIMIT 1", - intval($original_item['uid']) - ); - $t = q("SELECT COUNT(`tid`) AS `tcount` FROM `term` WHERE `oid`=%d AND `term`='%s'", - intval($original_item['id']), - DBA::escape($term) - ); - - if (DBA::isResult($x) && !$x[0]['blocktags'] && $t[0]['tcount'] == 0){ - q("INSERT INTO term (`oid`, `otype`, `type`, `term`, `url`, `uid`) VALUE (%d, %d, %d, '%s', '%s', %d)", - intval($original_item['id']), - $term_objtype, - Tag::HASHTAG, - DBA::escape($term), - '', - intval($owner_uid) - ); - } - } - - $arr['id'] = $post_id; Hook::callAll('post_local_end', $arr); diff --git a/mod/tagrm.php b/mod/tagrm.php index 51000c9854..7e8ae8524b 100644 --- a/mod/tagrm.php +++ b/mod/tagrm.php @@ -25,7 +25,6 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Item; use Friendica\Model\Tag; -use Friendica\Model\Term; use Friendica\Util\Strings; function tagrm_post(App $a) @@ -58,35 +57,24 @@ function tagrm_post(App $a) * @param $tags array * @throws Exception */ -function update_tags($item_id, $tags){ - if (empty($item_id) || empty($tags)){ +function update_tags($item_id, $tags) +{ + if (empty($item_id) || empty($tags)) { return; } - $item = Item::selectFirst(['tag', 'uri-id'], ['id' => $item_id, 'uid' => local_user()]); + $item = Item::selectFirst(['uri-id'], ['id' => $item_id, 'uid' => local_user()]); if (!DBA::isResult($item)) { return; } - $old_tags = explode(',', $item['tag']); - foreach ($tags as $new_tag) { if (preg_match_all('/([#@!])\[url\=([^\[\]]*)\]([^\[\]]*)\[\/url\]/ism', $new_tag, $results, PREG_SET_ORDER)) { foreach ($results as $tag) { Tag::removeByHash($item['uri-id'], $tag[1], $tag[3], $tag[2]); } } - - foreach ($old_tags as $index => $old_tag) { - if (strcmp($old_tag, $new_tag) == 0) { - unset($old_tags[$index]); - break; - } - } } - - $tag_str = implode(',', $old_tags); - Term::insertFromTagFieldByItemId($item_id, $tag_str); } function tagrm_content(App $a) diff --git a/src/Model/Item.php b/src/Model/Item.php index 1096c22131..1ef4810578 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -80,7 +80,7 @@ class Item const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', 'parent-guid', 'created', 'edited', 'verb', 'object-type', 'object', 'target', 'private', 'title', 'body', 'location', 'coord', 'app', - 'attach', 'tag', 'deleted', 'extid', 'post-type', + 'attach', 'deleted', 'extid', 'post-type', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'author-id', 'author-link', 'owner-link', 'contact-uid', 'signed_text', 'signature', 'signer', 'network']; @@ -98,7 +98,7 @@ class Item 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'iaid', 'psid', 'created', 'edited', 'commented', 'received', 'changed', 'verb', - 'postopts', 'plink', 'resource-id', 'event-id', 'tag', 'attach', 'inform', + 'postopts', 'plink', 'resource-id', 'event-id', 'attach', 'inform', 'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'network', @@ -317,11 +317,6 @@ class Item } if (!array_key_exists('verb', $row) || in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) { - // Build the tag string out of the term entries - if (array_key_exists('tag', $row) && empty($row['tag'])) { - $row['tag'] = Term::tagTextFromItemId($row['internal-iid']); - } - // Build the file string out of the term entries if (array_key_exists('file', $row) && empty($row['file'])) { $row['file'] = Term::fileTextFromItemId($row['internal-iid']); @@ -673,7 +668,7 @@ class Item 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'contact-id', 'owner-id', 'author-id', 'type', 'wall', 'gravity', 'extid', 'created', 'edited', 'commented', 'received', 'changed', 'psid', - 'resource-id', 'event-id', 'tag', 'attach', 'post-type', 'file', + 'resource-id', 'event-id', 'attach', 'post-type', 'file', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', 'id' => 'item_id', 'network', 'icid', 'iaid', 'id' => 'internal-iid', @@ -922,7 +917,7 @@ class Item // We cannot simply expand the condition to check for origin entries // The condition needn't to be a simple array but could be a complex condition. // And we have to execute this query before the update to ensure to fetch the same data. - $items = DBA::select('item', ['id', 'origin', 'uri', 'uri-id', 'iaid', 'icid', 'tag', 'file'], $condition); + $items = DBA::select('item', ['id', 'origin', 'uri', 'uri-id', 'iaid', 'icid', 'file'], $condition); $content_fields = []; foreach (array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST) as $field) { @@ -945,13 +940,6 @@ class Item } } - if (array_key_exists('tag', $fields)) { - $tags = $fields['tag']; - $fields['tag'] = null; - } else { - $tags = null; - } - if (array_key_exists('file', $fields)) { $files = $fields['file']; $fields['file'] = null; @@ -1024,13 +1012,6 @@ class Item } } - if (!is_null($tags)) { - Term::insertFromTagFieldByItemId($item['id'], $tags); - if (!empty($item['tag'])) { - DBA::update('item', ['tag' => ''], ['id' => $item['id']]); - } - } - if (!is_null($files)) { Term::insertFromFileFieldByItemId($item['id'], $files); if (!empty($item['file'])) { @@ -1184,9 +1165,6 @@ class Item } } - // Delete tags that had been attached to other items - self::deleteTagsFromItem($item); - // Delete notifications DBA::delete('notify', ['iid' => $item['id'], 'uid' => $item['uid']]); @@ -1194,7 +1172,6 @@ class Item $item_fields = ['deleted' => true, 'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()]; DBA::update('item', $item_fields, ['id' => $item['id']]); - Term::insertFromTagFieldByItemId($item['id'], ''); Term::insertFromFileFieldByItemId($item['id'], ''); self::deleteThread($item['id'], $item['parent-uri']); @@ -1243,43 +1220,6 @@ class Item return true; } - private static function deleteTagsFromItem($item) - { - if (($item["verb"] != Activity::TAG) || ($item["object-type"] != Activity\ObjectType::TAGTERM)) { - return; - } - - $xo = XML::parseString($item["object"]); - $xt = XML::parseString($item["target"]); - - if ($xt->type != Activity\ObjectType::NOTE) { - return; - } - - $i = self::selectFirst(['id', 'contact-id', 'tag'], ['uri' => $xt->id, 'uid' => $item['uid']]); - if (!DBA::isResult($i)) { - return; - } - - // For tags, the owner cannot remove the tag on the author's copy of the post. - $owner_remove = ($item["contact-id"] == $i["contact-id"]); - $author_copy = $item["origin"]; - - if (($owner_remove && $author_copy) || !$owner_remove) { - return; - } - - $tags = explode(',', $i["tag"]); - $newtags = []; - if (count($tags)) { - foreach ($tags as $tag) { - if (trim($tag) !== trim($xo->body)) { - $newtags[] = trim($tag); - } - } - } - self::update(['tag' => implode(',', $newtags)], ['id' => $i["id"]]); - } private static function guid($item, $notify) { @@ -1547,7 +1487,6 @@ class Item $item['deny_gid'] = trim($item['deny_gid'] ?? ''); $item['private'] = intval($item['private'] ?? self::PUBLIC); $item['body'] = trim($item['body'] ?? ''); - $item['tag'] = trim($item['tag'] ?? ''); $item['attach'] = trim($item['attach'] ?? ''); $item['app'] = trim($item['app'] ?? ''); $item['origin'] = intval($item['origin'] ?? 0); @@ -1870,13 +1809,6 @@ class Item Logger::log('' . print_r($item,true), Logger::DATA); - if (array_key_exists('tag', $item)) { - $tags = $item['tag']; - unset($item['tag']); - } else { - $tags = ''; - } - if (array_key_exists('file', $item)) { $files = $item['file']; unset($item['file']); @@ -2016,10 +1948,6 @@ class Item * Due to deadlock issues with the "term" table we are doing these steps after the commit. * This is not perfect - but a workable solution until we found the reason for the problem. */ - if (!empty($tags)) { - Term::insertFromTagFieldByItemId($current_post, $tags); - } - if (!empty($files)) { Term::insertFromFileFieldByItemId($current_post, $files); } @@ -2634,9 +2562,6 @@ class Item if (DI::config()->get('system', 'local_tags')) { $item["body"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", "#[url=".DI::baseUrl()."/search?tag=$2]$2[/url]", $item["body"]); - - $item["tag"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - "#[url=".DI::baseUrl()."/search?tag=$2]$2[/url]", $item["tag"]); } // mask hashtags inside of url, bookmarks and attachments to avoid urls in urls @@ -2668,13 +2593,6 @@ class Item $newtag = '#[url=' . DI::baseUrl() . '/search?tag=' . $basetag . ']' . $basetag . '[/url]'; $item["body"] = str_replace($tag, $newtag, $item["body"]); - - if (!stristr($item["tag"], "/search?tag=" . $basetag . "]" . $basetag . "[/url]")) { - if (strlen($item["tag"])) { - $item["tag"] = ',' . $item["tag"]; - } - $item["tag"] = $newtag . $item["tag"]; - } } // Convert back the masked hashtags @@ -3032,30 +2950,6 @@ class Item return $recipients; } - public static function getFeedTags($item) - { - $ret = []; - $matches = false; - $cnt = preg_match_all('|\#\[url\=(.*?)\](.*?)\[\/url\]|', $item['tag'], $matches); - if ($cnt) { - for ($x = 0; $x < $cnt; $x ++) { - if ($matches[1][$x]) { - $ret[$matches[2][$x]] = ['#', $matches[1][$x], $matches[2][$x]]; - } - } - } - $matches = false; - $cnt = preg_match_all('|\@\[url\=(.*?)\](.*?)\[\/url\]|', $item['tag'], $matches); - if ($cnt) { - for ($x = 0; $x < $cnt; $x ++) { - if ($matches[1][$x]) { - $ret[] = ['@', $matches[1][$x], $matches[2][$x]]; - } - } - } - return $ret; - } - public static function expire($uid, $days, $network = "", $force = false) { if (!$uid || ($days < 1)) { diff --git a/src/Model/Tag.php b/src/Model/Tag.php index 04107f804c..0a06dcc250 100644 --- a/src/Model/Tag.php +++ b/src/Model/Tag.php @@ -40,8 +40,6 @@ class Tag const UNKNOWN = 0; const HASHTAG = 1; const MENTION = 2; - const CATEGORY = 3; - const FILE = 5; /** * An implicit mention is a mention in a comment body that is redundant with the threading information. */ diff --git a/src/Model/Term.php b/src/Model/Term.php index 5f54024871..ea9ddc1919 100644 --- a/src/Model/Term.php +++ b/src/Model/Term.php @@ -21,10 +21,7 @@ namespace Friendica\Model; -use Friendica\Core\Logger; use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Util\Strings; /** * Class Term @@ -36,66 +33,10 @@ use Friendica\Util\Strings; class Term { const UNKNOWN = 0; - const HASHTAG = 1; - const MENTION = 2; const CATEGORY = 3; const FILE = 5; - /** - * An implicit mention is a mention in a comment body that is redundant with the threading information. - */ - const IMPLICIT_MENTION = 8; - /** - * An exclusive mention transfers the ownership of the post to the target account, usually a forum. - */ - const EXCLUSIVE_MENTION = 9; - - const TAG_CHARACTER = [ - self::HASHTAG => '#', - self::MENTION => '@', - self::IMPLICIT_MENTION => '%', - self::EXCLUSIVE_MENTION => '!', - ]; const OBJECT_TYPE_POST = 1; - const OBJECT_TYPE_PHOTO = 2; - - /** - * Generates the legacy item.tag field comma-separated BBCode string from an item ID. - * Includes only hashtags, implicit and explicit mentions. - * - * @param int $item_id - * @return string - * @throws \Exception - */ - public static function tagTextFromItemId($item_id) - { - $tag_list = []; - $tags = self::getByItemId($item_id, [self::HASHTAG, self::MENTION, self::IMPLICIT_MENTION]); - foreach ($tags as $tag) { - $tag_list[] = self::TAG_CHARACTER[$tag['type']] . '[url=' . $tag['url'] . ']' . $tag['term'] . '[/url]'; - } - - return implode(',', $tag_list); - } - - /** - * Retrieves the terms from the provided type(s) associated with the provided item ID. - * - * @param int $item_id - * @param int|array $type - * @return array - * @throws \Exception - */ - private static function getByItemId($item_id, $type = [self::HASHTAG, self::MENTION]) - { - $condition = ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => $type]; - $tags = DBA::select('term', ['type', 'term', 'url'], $condition); - if (!DBA::isResult($tags)) { - return []; - } - - return DBA::toArray($tags); - } /** * Generates the legacy item.file field string from an item ID. @@ -108,7 +49,9 @@ class Term public static function fileTextFromItemId($item_id) { $file_text = ''; - $tags = self::getByItemId($item_id, [self::FILE, self::CATEGORY]); + + $condition = ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => [self::FILE, self::CATEGORY]]; + $tags = DBA::selectToArray('term', ['type', 'term', 'url'], $condition); foreach ($tags as $tag) { if ($tag['type'] == self::CATEGORY) { $file_text .= '<' . $tag['term'] . '>'; @@ -120,170 +63,6 @@ class Term return $file_text; } - /** - * Inserts new terms for the provided item ID based on the legacy item.tag field BBCode content. - * Deletes all previous tag terms for the same item ID. - * Sets both the item.mention and thread.mentions field flags if a mention concerning the item UID is found. - * - * @param int $item_id - * @param string $tag_str - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ - public static function insertFromTagFieldByItemId($item_id, $tag_str) - { - $profile_base = DI::baseUrl(); - $profile_data = parse_url($profile_base); - $profile_path = $profile_data['path'] ?? ''; - $profile_base_friendica = $profile_data['host'] . $profile_path . '/profile/'; - $profile_base_diaspora = $profile_data['host'] . $profile_path . '/u/'; - - $fields = ['guid', 'uid', 'id', 'edited', 'deleted', 'created', 'received', 'title', 'body', 'parent']; - $item = Item::selectFirst($fields, ['id' => $item_id]); - if (!DBA::isResult($item)) { - return; - } - - $item['tag'] = $tag_str; - - // Clean up all tags - self::deleteByItemId($item_id); - - if ($item['deleted']) { - return; - } - - $taglist = explode(',', $item['tag']); - - $tags_string = ''; - foreach ($taglist as $tag) { - if (Strings::startsWith($tag, self::TAG_CHARACTER)) { - $tags_string .= ' ' . trim($tag); - } else { - $tags_string .= ' #' . trim($tag); - } - } - - $data = ' ' . $item['title'] . ' ' . $item['body'] . ' ' . $tags_string . ' '; - - // ignore anything in a code block - $data = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $data); - - $tags = []; - - $pattern = '/\W\#([^\[].*?)[\s\'".,:;\?!\[\]\/]/ism'; - if (preg_match_all($pattern, $data, $matches)) { - foreach ($matches[1] as $match) { - $tags['#' . $match] = ''; - } - } - - $pattern = '/\W([\#@!%])\[url\=(.*?)\](.*?)\[\/url\]/ism'; - if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER)) { - foreach ($matches as $match) { - - if (in_array($match[1], [ - self::TAG_CHARACTER[self::MENTION], - self::TAG_CHARACTER[self::IMPLICIT_MENTION], - self::TAG_CHARACTER[self::EXCLUSIVE_MENTION] - ])) { - $contact = Contact::getDetailsByURL($match[2], 0); - if (!empty($contact['addr'])) { - $match[3] = $contact['addr']; - } - - if (!empty($contact['url'])) { - $match[2] = $contact['url']; - } - } - - $tags[$match[2]] = $match[1] . trim($match[3], ',.:;[]/\"?!'); - } - } - - foreach ($tags as $link => $tag) { - if (Tag::isType($tag, self::HASHTAG)) { - // try to ignore #039 or #1 or anything like that - if (ctype_digit(substr(trim($tag), 1))) { - continue; - } - - // try to ignore html hex escapes, e.g. #x2317 - if ((substr(trim($tag), 1, 1) == 'x' || substr(trim($tag), 1, 1) == 'X') && ctype_digit(substr(trim($tag), 2))) { - continue; - } - - $type = self::HASHTAG; - $term = substr($tag, 1); - $link = ''; - } elseif (Tag::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION)) { - if (Tag::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION)) { - $type = self::MENTION; - } else { - $type = self::IMPLICIT_MENTION; - } - - $contact = Contact::getDetailsByURL($link, 0); - if (!empty($contact['name'])) { - $term = $contact['name']; - } else { - $term = substr($tag, 1); - } - } else { // This shouldn't happen - $type = self::HASHTAG; - $term = $tag; - $link = ''; - - Logger::notice('Unknown term type', ['tag' => $tag]); - } - - if (DBA::exists('term', ['uid' => $item['uid'], 'otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'term' => $term, 'type' => $type])) { - continue; - } - - if (empty($term)) { - continue; - } - - if ($item['uid'] == 0) { - $global = true; - DBA::update('term', ['global' => true], ['otype' => self::OBJECT_TYPE_POST, 'guid' => $item['guid']]); - } else { - $global = DBA::exists('term', ['uid' => 0, 'otype' => self::OBJECT_TYPE_POST, 'guid' => $item['guid']]); - } - - DBA::insert('term', [ - 'uid' => $item['uid'], - 'oid' => $item_id, - 'otype' => self::OBJECT_TYPE_POST, - 'type' => $type, - 'term' => substr($term, 0, 255), - 'url' => $link, - 'guid' => $item['guid'], - 'created' => $item['created'], - 'received' => $item['received'], - 'global' => $global - ]); - - // Search for mentions - if (Tag::isType($tag, self::MENTION, self::EXCLUSIVE_MENTION) - && ( - strpos($link, $profile_base_friendica) !== false - || strpos($link, $profile_base_diaspora) !== false - ) - ) { - $users_stmt = DBA::p("SELECT `uid` FROM `contact` WHERE self AND (`url` = ? OR `nurl` = ?)", $link, $link); - $users = DBA::toArray($users_stmt); - foreach ($users AS $user) { - if ($user['uid'] == $item['uid']) { - /// @todo This function is called from Item::update - so we mustn't call that function here - DBA::update('item', ['mention' => true], ['id' => $item_id]); - DBA::update('thread', ['mention' => true], ['iid' => $item['parent']]); - } - } - } - } - } - /** * Inserts new terms for the provided item ID based on the legacy item.file field BBCode content. * Deletes all previous file terms for the same item ID. @@ -333,21 +112,4 @@ class Term } } } - - /** - * Delete tags of the specific type(s) from an item - * - * @param int $item_id - * @param int|array $type - * @throws \Exception - */ - public static function deleteByItemId($item_id, $type = [self::HASHTAG, self::MENTION, self::IMPLICIT_MENTION]) - { - if (empty($item_id)) { - return; - } - - // Clean up all tags - DBA::delete('term', ['otype' => self::OBJECT_TYPE_POST, 'oid' => $item_id, 'type' => $type]); - } } diff --git a/src/Model/UserItem.php b/src/Model/UserItem.php index 50e23e1580..89dbafed82 100644 --- a/src/Model/UserItem.php +++ b/src/Model/UserItem.php @@ -227,9 +227,10 @@ class UserItem */ private static function checkImplicitMention(array $item, array $profiles) { - foreach ($profiles AS $profile) { - if (strpos($item['tag'], '=' . $profile.']') || strpos($item['body'], '=' . $profile . ']')) { - if (strpos($item['body'], $profile) === false) { + $mentions = Tag::getByURIId($item['uri-id'], [Tag::IMPLICIT_MENTION]); + foreach ($mentions as $mention) { + foreach ($profiles as $profile) { + if (Strings::compareLink($profile, $mention['url'])) { return true; } } @@ -246,9 +247,10 @@ class UserItem */ private static function checkExplicitMention(array $item, array $profiles) { - foreach ($profiles AS $profile) { - if (strpos($item['tag'], '=' . $profile.']') || strpos($item['body'], '=' . $profile . ']')) { - if (!(strpos($item['body'], $profile) === false)) { + $mentions = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]); + foreach ($mentions as $mention) { + foreach ($profiles as $profile) { + if (Strings::compareLink($profile, $mention['url'])) { return true; } } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 4e5aac37d9..5060a7d563 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1080,21 +1080,15 @@ class DFRN $entry->appendChild($actarg); } - $tags = Item::getFeedTags($item); + $tags = Tag::getByURIId($item['uri-id']); - /// @TODO Combine this with similar below if() block? if (count($tags)) { - foreach ($tags as $t) { - if (($type != 'html') || ($t[0] != "@")) { - XML::addElement($doc, $entry, "category", "", ["scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2]]); + foreach ($tags as $tag) { + if (($type != 'html') || ($tag['type'] == Tag::HASHTAG)) { + XML::addElement($doc, $entry, "category", "", ["scheme" => "X-DFRN:" . Tag::TAG_CHARACTER[$tag['type']] . ":" . $tag['url'], "term" => $tag['name']]); } - } - } - - if (count($tags)) { - foreach ($tags as $t) { - if ($t[0] == "@") { - $mentioned[$t[1]] = $t[1]; + if ($tag['type'] != Tag::HASHTAG) { + $mentioned[$tag['url']] = $tag['url']; } } } @@ -2238,11 +2232,6 @@ class DFRN // extract tag, if not duplicate, add to parent item if ($xo->content) { Tag::store($item_tag['uri-id'], Tag::HASHTAG, $xo->content); - - if (!stristr($item_tag["tag"], trim($xo->content))) { - $tag = $item_tag["tag"] . (strlen($item_tag["tag"]) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'; - Item::update(['tag' => $tag], ['id' => $item_tag["id"]]); - } } } } @@ -2440,17 +2429,7 @@ class DFRN if (($term != "") && ($scheme != "")) { $parts = explode(":", $scheme); if ((count($parts) >= 4) && (array_shift($parts) == "X-DFRN")) { - $termhash = array_shift($parts); $termurl = implode(":", $parts); - - if (!empty($item["tag"])) { - $item["tag"] .= ","; - } else { - $item["tag"] = ""; - } - - $item["tag"] .= $termhash . "[url=" . $termurl . "]" . $term . "[/url]"; - Tag::store($item['uri-id'], Tag::IMPLICIT_MENTION, $term, $termurl); } } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index a91c5cdf80..c8d218ac21 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -2582,7 +2582,7 @@ class Diaspora } // Do we already have this item? - $fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', + $fields = ['body', 'title', 'attach', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); @@ -2626,7 +2626,7 @@ class Diaspora } if ($stored) { - $fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', + $fields = ['body', 'title', 'attach', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]]; $item = Item::selectFirst($fields, $condition); @@ -2772,7 +2772,6 @@ class Diaspora Tag::storeFromBody($datarray['uri-id'], $datarray["body"]); - $datarray["tag"] = $original_item["tag"]; $datarray["attach"] = $original_item["attach"]; $datarray["app"] = $original_item["app"]; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 14a3c28ab9..fd6dc10df5 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -385,18 +385,10 @@ class Feed { $item["attach"] .= '[attach]href="' . $href . '" length="' . $length . '" type="' . $type . '"[/attach]'; } - $tags = ''; $taglist = []; $categories = $xpath->query("category", $entry); foreach ($categories AS $category) { - $hashtag = $category->nodeValue; - if ($tags != '') { - $tags .= ', '; - } - - $taglink = "#[url=" . DI::baseUrl() . "/search?tag=" . $hashtag . "]" . $hashtag . "[/url]"; - $tags .= $taglink; - $taglist[] = $hashtag; + $taglist[] = $category->nodeValue; } $body = trim(XML::getFirstNodeValue($xpath, 'atom:content/text()', $entry)); @@ -477,7 +469,6 @@ class Feed { // We always strip the title since it will be added in the page information $item["title"] = ""; $item["body"] = $item["body"] . add_page_info($item["plink"], false, $preview, ($contact["fetch_further_information"] == 2), $contact["ffi_keyword_blacklist"]); - $item["tag"] = add_page_keywords($item["plink"], $preview, ($contact["fetch_further_information"] == 2), $contact["ffi_keyword_blacklist"]); $taglist = get_page_keywords($item["plink"], $preview, ($contact["fetch_further_information"] == 2), $contact["ffi_keyword_blacklist"]); $item["object-type"] = Activity\ObjectType::BOOKMARK; unset($item["attach"]); @@ -487,14 +478,10 @@ class Feed { } if (!empty($contact["fetch_further_information"]) && ($contact["fetch_further_information"] == 3)) { - if (!empty($tags)) { - $item["tag"] = $tags; - } else { - // @todo $preview is never set in this case, is it intended? - @MrPetovan 2018-02-13 - $item["tag"] = add_page_keywords($item["plink"], $preview, true, $contact["ffi_keyword_blacklist"]); + if (empty($taglist)) { $taglist = get_page_keywords($item["plink"], $preview, true, $contact["ffi_keyword_blacklist"]); } - $item["body"] .= "\n" . $item['tag']; + /// @todo $item["body"] .= "\n" . $tags; } else { $taglist = []; } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index ccec6d9348..8ab14c0781 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -2081,13 +2081,10 @@ class OStatus XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); } - $tags = item::getFeedTags($item); - + $tags = Tag::getByURIId($item['uri-id']); if (count($tags)) { - foreach ($tags as $t) { - if ($t[0] == "@") { - $mentioned[$t[1]] = $t[1]; - } + foreach ($tags as $tag) { + $mentioned[$tag['url']] = $tag['url']; } } @@ -2138,9 +2135,9 @@ class OStatus } if (count($tags)) { - foreach ($tags as $t) { - if ($t[0] != "@") { - XML::addElement($doc, $entry, "category", "", ["term" => $t[2]]); + foreach ($tags as $tag) { + if ($tag['type'] == Tag::HASHTAG) { + XML::addElement($doc, $entry, "category", "", ["term" => $tag['name']]); } } } From 11406fd3b66fadece61c33defdf16f61be0421ca Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 May 2020 05:14:30 +0000 Subject: [PATCH 2/3] Fix for "Undefined index: uri-id"" --- src/Protocol/ActivityPub/Processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 43343f1e6b..479d8d55c7 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -387,7 +387,7 @@ class Processor if (empty($activity['directmessage']) && ($item['thr-parent'] != $item['uri']) && ($item['gravity'] == GRAVITY_COMMENT)) { $item_private = !in_array(0, $activity['item_receiver']); - $parent = Item::selectFirst(['id', 'private', 'author-link', 'alias'], ['uri' => $item['thr-parent']]); + $parent = Item::selectFirst(['id', 'uri-id', 'private', 'author-link', 'alias'], ['uri' => $item['thr-parent']]); if (!DBA::isResult($parent)) { Logger::warning('Unknown parent item.', ['uri' => $item['thr-parent']]); return false; From 233d6eea2b908aaf408337e16bf802f3f9982fcb Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 May 2020 05:43:00 +0000 Subject: [PATCH 3/3] Tags are now added to the body again --- src/Protocol/Feed.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index fd6dc10df5..baf439dc02 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -481,7 +481,7 @@ class Feed { if (empty($taglist)) { $taglist = get_page_keywords($item["plink"], $preview, true, $contact["ffi_keyword_blacklist"]); } - /// @todo $item["body"] .= "\n" . $tags; + $item["body"] .= "\n" . self::tagToString($taglist); } else { $taglist = []; } @@ -527,6 +527,27 @@ class Feed { return ["header" => $author, "items" => $items]; } + /** + * Convert a tag array to a tag string + * + * @param array $tags + * @return string tag string + */ + private static function tagToString(array $tags) + { + $tagstr = ''; + + foreach ($tags as $tag) { + if ($tagstr != "") { + $tagstr .= ", "; + } + + $tagstr .= "#[url=" . DI::baseUrl() . "/search?tag=" . urlencode($tag) . "]" . $tag . "[/url]"; + } + + return $tagstr; + } + private static function titleIsBody($title, $body) { $title = strip_tags($title);