diff --git a/mod/item.php b/mod/item.php index 13ffe7568..77cfc4795 100644 --- a/mod/item.php +++ b/mod/item.php @@ -41,10 +41,8 @@ use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Model\ItemURI; -use Friendica\Model\Photo; use Friendica\Model\Post; use Friendica\Network\HTTPException; -use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; function item_post(App $a) { @@ -108,6 +106,7 @@ function item_edit(int $uid, array $request, bool $preview, string $return_path) $post['edit'] = $post; $post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']); + Post\Media::deleteByURIId($post['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]); $post = item_process($post, $request, $preview, $return_path); $fields = [ diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 6730309e6..949f9d9cf 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -437,7 +437,7 @@ class BBCode * @param boolean $no_link_desc No link description * @return string with replaced body */ - public static function removeAttachment(string $body, bool $no_link_desc = false): string + public static function replaceAttachment(string $body, bool $no_link_desc = false): string { return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", function ($match) use ($body, $no_link_desc) { @@ -454,6 +454,17 @@ class BBCode }, $body); } + /** + * Remove [attachment] BBCode + * + * @param string $body + * @return string with removed attachment + */ + public static function removeAttachment(string $body): string + { + return trim(preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body)); + } + /** * Converts a BBCode text into plaintext * @@ -469,7 +480,7 @@ class BBCode $text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text); // Remove attachment - $text = self::removeAttachment($text); + $text = self::replaceAttachment($text); $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls); @@ -1583,9 +1594,9 @@ class BBCode /// @todo Have a closer look at the different html modes // Handle attached links or videos if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) { - $text = self::removeAttachment($text); + $text = self::replaceAttachment($text); } elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) { - $text = self::removeAttachment($text, true); + $text = self::replaceAttachment($text, true); } else { $text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid); } diff --git a/src/Model/Item.php b/src/Model/Item.php index a62d3c2e6..78275c835 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -210,8 +210,6 @@ class Item } } - Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']); - $content_fields = ['raw-body' => trim($fields['raw-body'] ?? $fields['body'])]; // Remove all media attachments from the body and store them in the post-media table @@ -220,6 +218,10 @@ class Item $content_fields['raw-body'] = self::setHashtags($content_fields['raw-body']); Post\Media::insertFromRelevantUrl($item['uri-id'], $content_fields['raw-body'], $fields['body'], $item['author-network']); + + Post\Media::insertFromAttachmentData($item['uri-id'], $fields['body']); + $content_fields['raw-body'] = BBCode::removeAttachment($content_fields['raw-body']); + Post\Content::update($item['uri-id'], $content_fields); } @@ -1143,8 +1145,6 @@ class Item $item['body'] = BBCode::removeSharedData($item['body']); } - Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']); - // Remove all media attachments from the body and store them in the post-media table $item['raw-body'] = Post\Media::insertFromBody($item['uri-id'], $item['raw-body']); $item['raw-body'] = self::setHashtags($item['raw-body']); @@ -1152,6 +1152,10 @@ class Item $author = Contact::getById($item['author-id'], ['network']); Post\Media::insertFromRelevantUrl($item['uri-id'], $item['raw-body'], $item['body'], $author['network'] ?? ''); + Post\Media::insertFromAttachmentData($item['uri-id'], $item['body']); + $item['body'] = BBCode::removeAttachment($item['body']); + $item['raw-body'] = BBCode::removeAttachment($item['raw-body']); + // Check for hashtags in the body and repair or add hashtag links $item['body'] = self::setHashtags($item['body']); @@ -3003,8 +3007,9 @@ class Item $fields = ['uri-id', 'uri', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink', 'network', 'has-media', 'quote-uri-id', 'post-type']; - $shared_uri_id = 0; - $shared_links = []; + $shared_uri_id = 0; + $shared_links = []; + $quote_shared_links = []; $shared = DI::contentItem()->getSharedPost($item, $fields); if (!empty($shared['post'])) { @@ -3023,7 +3028,14 @@ class Item $shared_links[] = strtolower($media[0]['url']); } - $quote_uri_id = $shared_item['uri-id'] ?? 0; + if (!empty($shared_item['uri-id'])) { + $data = BBCode::getAttachmentData($shared_item['body']); + if (!empty($data['url'])) { + $quote_shared_links[] = $data['url']; + } + + $quote_uri_id = $shared_item['uri-id']; + } } } @@ -3098,7 +3110,7 @@ class Item if (!empty($shared_attachments)) { $s = self::addVisualAttachments($shared_attachments, $shared_item, $s, true); - $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, []); + $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, $quote_shared_links); $s = self::addNonVisualAttachments($shared_attachments, $item, $s, true); $body = BBCode::removeSharedData($body); } @@ -3418,7 +3430,7 @@ class Item DI::profiler()->stopRecording(); if (isset($data['url']) && !in_array(strtolower($data['url']), $ignore_links)) { - if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview'])) { + if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview']) || (!empty($data['title']) && !Strings::compareLink($data['title'], $data['url']))) { $parts = parse_url($data['url']); if (!empty($parts['scheme']) && !empty($parts['host'])) { if (empty($data['provider_name'])) { diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 8216d7383..653bdba98 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -68,18 +68,18 @@ class Media * * @param array $media * @param bool $force - * @return void + * @return bool */ - public static function insert(array $media, bool $force = false) + public static function insert(array $media, bool $force = false): bool { if (empty($media['url']) || empty($media['uri-id']) || !isset($media['type'])) { Logger::warning('Incomplete media data', ['media' => $media]); - return; + return false; } if (DBA::exists('post-media', ['uri-id' => $media['uri-id'], 'preview' => $media['url']])) { Logger::info('Media already exists as preview', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]); - return; + return false; } // "document" has got the lowest priority. So when the same file is both attached as document @@ -87,12 +87,12 @@ class Media $found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]); if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) { Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]); - return; + return false; } if (!ItemURI::exists($media['uri-id'])) { Logger::info('Media referenced URI ID not found', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'callstack' => System::callstack()]); - return; + return false; } $media = self::unsetEmptyFields($media); @@ -114,6 +114,7 @@ class Media } else { Logger::info('Nothing to update', ['media' => $media]); } + return $result; } /** @@ -573,9 +574,14 @@ class Media if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches)) { foreach ($matches[1] as $url) { Logger::info('Got page url (link without description)', ['uri-id' => $uriid, 'url' => $url]); - self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network); - if ($network == Protocol::DFRN) { + $result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network); + if ($result && ($network == Protocol::DFRN)) { self::revertHTMLType($uriid, $url, $fullbody); + Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]); + } elseif ($result) { + Logger::debug('Media had been added', ['uri-id' => $uriid, 'url' => $url]); + } else { + Logger::debug('Media had not been added', ['uri-id' => $uriid, 'url' => $url]); } } } @@ -584,9 +590,14 @@ class Media if (preg_match_all("/\[url\=(https?:.*?)\].*?\[\/url\]/ism", $body, $matches)) { foreach ($matches[1] as $url) { Logger::info('Got page url (link with description)', ['uri-id' => $uriid, 'url' => $url]); - self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network); - if ($network == Protocol::DFRN) { + $result = self::insert(['uri-id' => $uriid, 'type' => self::UNKNOWN, 'url' => $url], false, $network); + if ($result && ($network == Protocol::DFRN)) { self::revertHTMLType($uriid, $url, $fullbody); + Logger::debug('Revert HTML type', ['uri-id' => $uriid, 'url' => $url]); + } elseif ($result) { + Logger::debug('Media has been added', ['uri-id' => $uriid, 'url' => $url]); + } else { + Logger::debug('Media has not been added', ['uri-id' => $uriid, 'url' => $url]); } } } @@ -705,6 +716,25 @@ class Media return DBA::exists('post-media', $condition); } + /** + * Delete media by uri-id and media type + * + * @param int $uri_id URI id + * @param array $types Media types + * @return bool Whether media attachment exists + * @throws \Exception + */ + public static function deleteByURIId(int $uri_id, array $types = []): bool + { + $condition = ['uri-id' => $uri_id]; + + if (!empty($types)) { + $condition = DBA::mergeConditions($condition, ['type' => $types]); + } + + return DBA::delete('post-media', $condition); + } + /** * Split the attachment media in the three segments "visual", "link" and "additional" * @@ -830,7 +860,7 @@ class Media } $original_body = $body; - $body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body); + $body = BBCode::removeAttachment($body); foreach (self::getByURIId($uriid, $types) as $media) { if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) { diff --git a/src/Module/Post/Edit.php b/src/Module/Post/Edit.php index 55c86988a..2ca980381 100644 --- a/src/Module/Post/Edit.php +++ b/src/Module/Post/Edit.php @@ -115,6 +115,8 @@ class Edit extends BaseModule $lockstate = 'unlock'; } + $item['body'] = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); + $jotplugins = ''; Hook::callAll('jot_tool', $jotplugins); diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 02dc7ff54..9123ae533 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -1675,7 +1675,7 @@ class Transmitter if ($type == 'Page') { // When we transmit "Page" posts we have to remove the attachment. // The attachment contains the link that we already transmit in the "url" field. - $body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body); + $body = BBCode::removeAttachment($body); } $body = BBCode::setMentionsToNicknames($body); @@ -1707,7 +1707,7 @@ class Transmitter $richbody = DI::contentItem()->addSharedPost($item, $richbody); } } - $richbody = BBCode::removeAttachment($richbody); + $richbody = BBCode::replaceAttachment($richbody); $data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL); }