From 7ccc978bc5c51b784af8b94ffb1e4da08849cc29 Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Tue, 28 Feb 2023 15:35:37 -0500 Subject: [PATCH 01/16] Add title/spoiler text handling and capturing invalid update to Mastodon edit --- src/Module/Api/Mastodon/Statuses.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index 01856b2d8b..bf5c9aa6a2 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -21,6 +21,7 @@ namespace Friendica\Module\Api\Mastodon; +use Friendica\Content\Text\BBCode; use Friendica\Content\Text\Markdown; use Friendica\Core\Protocol; use Friendica\Core\System; @@ -50,9 +51,9 @@ class Statuses extends BaseApi $request = $this->getRequest([ 'status' => '', // Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided. - 'in_reply_to_id' => 0, // ID of the status being replied to, if status is a reply 'spoiler_text' => '', // Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field. 'language' => '', // ISO 639 language code for this status. + 'friendica' => [], ], $request); $owner = User::getOwnerDataById($uid); @@ -65,7 +66,7 @@ class Statuses extends BaseApi 'origin' => true, ]; - $post = Post::selectFirst(['uri-id', 'id'], $condition); + $post = Post::selectFirst(['uri-id', 'id', 'gravity'], $condition); if (empty($post['id'])) { throw new HTTPException\NotFoundException('Item with URI ID ' . $this->parameters['id'] . ' not found for user ' . $uid . '.'); } @@ -77,14 +78,25 @@ class Statuses extends BaseApi $item['language'] = json_encode([$request['language'] => 1]); } - if (!empty($request['spoiler_text'])) { - if (($request['in_reply_to_id'] == $post['uri-id']) && DI::pConfig()->get($uid, 'system', 'api_spoiler_title', true)) { - $item['title'] = $request['spoiler_text']; + if ($post['gravity'] == 0) { + $item['title'] = $request['friendica']['title'] ?? ''; + } + + $spoiler_text = $request['spoiler_text']; + + if (!empty($spoiler_text)) { + if (!isset($request['friendica']['title']) && $post['gravity'] == 0 && DI::pConfig()->get($uid, 'system', 'api_spoiler_title', true)) { + $item['title'] = $spoiler_text; } else { - $item['body'] = '[abstract=' . Protocol::ACTIVITYPUB . ']' . $request['spoiler_text'] . "[/abstract]\n" . $item['body']; + $item['body'] = '[abstract=' . Protocol::ACTIVITYPUB . ']' . $spoiler_text . "[/abstract]\n" . $item['body']; + $item['content-warning'] = BBCode::toPlaintext($spoiler_text); } } + if (!Item::isValid($item)) { + throw new \Exception('Missing parameters in definitien'); + } + Item::update($item, ['id' => $post['id']]); Item::updateDisplayCache($post['uri-id']); From b761760d6537a64b74d41bbe3a9e75a58254e947 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 4 Mar 2023 19:04:37 +0000 Subject: [PATCH 02/16] Fix missing attached links in posts --- src/Factory/Api/Mastodon/Status.php | 2 + src/Factory/Api/Twitter/Status.php | 1 + src/Model/Post/Media.php | 68 ++++++++++++++++++++++++ src/Module/Post/Edit.php | 1 + src/Protocol/ActivityPub/Transmitter.php | 2 + src/Protocol/DFRN.php | 1 + src/Protocol/Diaspora.php | 2 + src/Protocol/Feed.php | 1 + src/Protocol/OStatus.php | 1 + src/Worker/Notifier.php | 1 + 10 files changed, 80 insertions(+) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index d794247cb1..a1f7060ac0 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -260,9 +260,11 @@ class Status extends BaseFactory } $item['body'] = $this->contentItem->addSharedPost($item); + $item['body'] = Post\Media::addHTMLAttachmentToBody($uriId, $item['body']); if (!is_null($item['raw-body'])) { $item['raw-body'] = $this->contentItem->addSharedPost($item, $item['raw-body']); + $item['raw-body'] = Post\Media::addHTMLLinkToBody($uriId, $item['raw-body']); } } diff --git a/src/Factory/Api/Twitter/Status.php b/src/Factory/Api/Twitter/Status.php index de01ffd076..810b421cab 100644 --- a/src/Factory/Api/Twitter/Status.php +++ b/src/Factory/Api/Twitter/Status.php @@ -124,6 +124,7 @@ class Status extends BaseFactory */ private function createFromArray(array $item, int $uid, bool $include_entities): \Friendica\Object\Api\Twitter\Status { + $item = Post\Media::addHTMLAttachmentToItem($item); $author = $this->twitterUser->createFromContactId($item['author-id'], $uid, true); if (!empty($item['causer-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT)) { diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 653bdba98a..c6185cf1a8 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -21,6 +21,7 @@ namespace Friendica\Model\Post; +use Friendica\Content\PageInfo; use Friendica\Content\Text\BBCode; use Friendica\Core\Logger; use Friendica\Core\Protocol; @@ -895,6 +896,73 @@ class Media return $body; } + public static function addHTMLAttachmentToBody(int $uriid, string $body): string + { + if (preg_match("/.*(\[attachment.*?\].*?\[\/attachment\]).*/ism", $body, $match)) { + return $body; + } + + $links = self::getByURIId($uriid, [self::HTML]); + if (empty($links)) { + return $body; + } + + $data = [ + 'type' => 'link', + 'url' => $links[0]['url'], + 'title' => $links[0]['name'], + 'text' => $links[0]['description'], + 'alternative_title' => '', + 'publisher_name' => $links[0]['publisher-name'], + 'publisher_url' => $links[0]['publisher-url'], + 'publisher_img' => $links[0]['publisher-image'], + 'author_name' => $links[0]['author-name'], + 'author_url' => $links[0]['author-url'], + 'author_img' => $links[0]['author-image'], + 'images' => [[ + 'src' => $links[0]['preview'], + 'height' => $links[0]['preview-height'], + 'width' => $links[0]['preview-width'], + ]] + ]; + $body .= "\n" . PageInfo::getFooterFromData($data); + + return $body; + } + + public static function addHTMLLinkToBody(int $uriid, string $body): string + { + $links = self::getByURIId($uriid, [self::HTML]); + if (empty($links)) { + return $body; + } + + if (strpos($body, $links[0]['url'])) { + return $body; + } + + if (!empty($links[0]['name']) && ($links[0]['name'] != $links[0]['url'])) { + return $body . "\n[url=" . $links[0]['url'] . ']' . $links[0]['name'] . "[/url]"; + } else { + return $body . "\n[url]" . $links[0]['url'] . "[/url]"; + } + } + + public static function addHTMLAttachmentToItem(array $item): array + { + if (($item['gravity'] == Item::GRAVITY_ACTIVITY) || empty($item['uri-id'])) { + return $item; + } + + $item['body'] = self::addHTMLAttachmentToBody($item['uri-id'], $item['body']); + + if (!empty($item['raw-body'])) { + $item['raw-body'] = self::addHTMLLinkToBody($item['uri-id'], $item['raw-body']); + } + + return $item; + } + /** * Get preview link for given media id * diff --git a/src/Module/Post/Edit.php b/src/Module/Post/Edit.php index 2ca9803818..5fb339e179 100644 --- a/src/Module/Post/Edit.php +++ b/src/Module/Post/Edit.php @@ -116,6 +116,7 @@ class Edit extends BaseModule } $item['body'] = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); + $item = Post\Media::addHTMLAttachmentToItem($item); $jotplugins = ''; diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 9123ae533f..7da110f671 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -1639,6 +1639,8 @@ class Transmitter $real_quote = false; + $item = Post\Media::addHTMLAttachmentToItem($item); + $body = $item['body']; if ($type == 'Note') { diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 26d5376e4e..1bb7bf3ff1 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -774,6 +774,7 @@ class DFRN } $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); + $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); if ($item['private'] == Item::PRIVATE) { $body = Item::fixPrivatePhotos($body, $owner['uid'], $item, $cid); diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 271b71b893..91eb1cc2c4 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -3326,6 +3326,7 @@ class Diaspora $title = $item['title']; $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item), $attach_media); + $body = Post\Media::addHTMLLinkToBody($item['uri-id'], $body); // Fetch the title from an attached link - if there is one if (empty($item['title']) && DI::pConfig()->get($owner['uid'], 'system', 'attach_link_title')) { @@ -3585,6 +3586,7 @@ class Diaspora } $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); + $body = Post\Media::addHTMLLinkToBody($item['uri-id'], $body); // The replied to autor mention is prepended for clarity if: // - Item replied isn't yours diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 7d778ee582..cbffd810c1 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -1124,6 +1124,7 @@ class Feed XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); + $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB); diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index a93a0584dd..220424a31c 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1515,6 +1515,7 @@ class OStatus XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); + $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); if (!empty($item['title'])) { $body = '[b]' . $item['title'] . "[/b]\n\n" . $body; diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 93c6c180ab..2e42c225fc 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -114,6 +114,7 @@ class Notifier // find ancestors $condition = ['id' => $target_id, 'visible' => true]; $target_item = Post::selectFirst(Item::DELIVER_FIELDLIST, $condition); + $target_item = Post\Media::addHTMLAttachmentToItem($target_item); if (!DBA::isResult($target_item) || !intval($target_item['parent'])) { Logger::info('No target item', ['cmd' => $cmd, 'target' => $target_id]); From 60ddef172039458c7798cc0455c51ec04a79b5c7 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 4 Mar 2023 19:28:31 +0000 Subject: [PATCH 03/16] Unneeded field removed --- src/Model/Post/Media.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index c6185cf1a8..5dfb227d64 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -912,12 +912,11 @@ class Media 'url' => $links[0]['url'], 'title' => $links[0]['name'], 'text' => $links[0]['description'], - 'alternative_title' => '', - 'publisher_name' => $links[0]['publisher-name'], - 'publisher_url' => $links[0]['publisher-url'], - 'publisher_img' => $links[0]['publisher-image'], - 'author_name' => $links[0]['author-name'], - 'author_url' => $links[0]['author-url'], + 'publisher_name' => $links[0]['publisher-name'], + 'publisher_url' => $links[0]['publisher-url'], + 'publisher_img' => $links[0]['publisher-image'], + 'author_name' => $links[0]['author-name'], + 'author_url' => $links[0]['author-url'], 'author_img' => $links[0]['author-image'], 'images' => [[ 'src' => $links[0]['preview'], @@ -926,7 +925,7 @@ class Media ]] ]; $body .= "\n" . PageInfo::getFooterFromData($data); - + return $body; } From d41ec728e4fb0b92c84200ae020295c8d0c504f4 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 4 Mar 2023 21:36:19 +0000 Subject: [PATCH 04/16] We only need a link here --- src/Factory/Api/Mastodon/Status.php | 6 +++--- src/Protocol/Feed.php | 2 +- src/Protocol/OStatus.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index a1f7060ac0..190f1e0e21 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -259,12 +259,12 @@ class Status extends BaseFactory } } - $item['body'] = $this->contentItem->addSharedPost($item); - $item['body'] = Post\Media::addHTMLAttachmentToBody($uriId, $item['body']); - if (!is_null($item['raw-body'])) { $item['raw-body'] = $this->contentItem->addSharedPost($item, $item['raw-body']); $item['raw-body'] = Post\Media::addHTMLLinkToBody($uriId, $item['raw-body']); + } else { + $item['body'] = $this->contentItem->addSharedPost($item); + $item['body'] = Post\Media::addHTMLLinkToBody($uriId, $item['body']); } } diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index cbffd810c1..625305161f 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -1124,7 +1124,7 @@ class Feed XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); - $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); + $body = Post\Media::addHTMLLinkToBody($item['uri-id'], $body); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB); diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 220424a31c..abaa298ebc 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1515,7 +1515,7 @@ class OStatus XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); - $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); + $body = Post\Media::addHTMLLinkToBody($item['uri-id'], $body); if (!empty($item['title'])) { $body = '[b]' . $item['title'] . "[/b]\n\n" . $body; From eafe54f2ddf58a38a1a8a73761d7c394cbfdea1f Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 5 Mar 2023 21:22:22 +0000 Subject: [PATCH 05/16] The function "getAttachedData" has been removed --- src/Content/Item.php | 12 +- src/Content/Text/BBCode.php | 250 +----------------------------- src/Content/Text/Plaintext.php | 2 +- src/Factory/Api/Mastodon/Card.php | 59 ++++--- src/Model/Post/Media.php | 20 +++ src/Protocol/Diaspora.php | 6 +- src/Protocol/Feed.php | 6 +- 7 files changed, 56 insertions(+), 299 deletions(-) diff --git a/src/Content/Item.php b/src/Content/Item.php index 2e86fb82d6..e74ca846da 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -925,7 +925,7 @@ class Item // embedded bookmark or attachment in post? set bookmark flag $data = BBCode::getAttachmentData($post['body']); - if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || isset($data['type'])) + if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || !empty($data['type'])) && ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE)) { $post['post-type'] = ItemModel::PT_PAGE; $post['object-type'] = Activity\ObjectType::BOOKMARK; @@ -934,16 +934,6 @@ class Item // Setting the object type if not defined before if (empty($post['object-type'])) { $post['object-type'] = ($post['gravity'] == ItemModel::GRAVITY_PARENT) ? Activity\ObjectType::NOTE : Activity\ObjectType::COMMENT; - - $objectdata = BBCode::getAttachedData($post['body']); - - if ($objectdata['type'] == 'link') { - $post['object-type'] = Activity\ObjectType::BOOKMARK; - } elseif ($objectdata['type'] == 'video') { - $post['object-type'] = Activity\ObjectType::VIDEO; - } elseif ($objectdata['type'] == 'photo') { - $post['object-type'] = Activity\ObjectType::IMAGE; - } } return $post; } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 949f9d9cf0..9651e91cfc 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -74,77 +74,6 @@ class BBCode const PREVIEW_LARGE = 2; const PREVIEW_SMALL = 3; - /** - * Fetches attachment data that were generated the old way - * - * @param string $body Message body - * @return array - * 'type' -> Message type ('link', 'video', 'photo') - * 'text' -> Text before the shared message - * 'after' -> Text after the shared message - * 'image' -> Preview image of the message - * 'url' -> Url to the attached message - * 'title' -> Title of the attachment - * 'description' -> Description of the attachment - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ - private static function getOldAttachmentData(string $body): array - { - $post = []; - - // Simplify image codes - $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); - - if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) { - foreach ($attached as $data) { - if (!in_array($data[1], ['type-link', 'type-video', 'type-photo'])) { - continue; - } - - $post['type'] = substr($data[1], 5); - - $pos = strpos($body, $data[0]); - if ($pos > 0) { - $post['text'] = trim(substr($body, 0, $pos)); - $post['after'] = trim(substr($body, $pos + strlen($data[0]))); - } else { - $post['text'] = trim(str_replace($data[0], '', $body)); - $post['after'] = ''; - } - - $attacheddata = $data[2]; - - if (preg_match("/\[img\](.*?)\[\/img\]/ism", $attacheddata, $matches)) { - - $picturedata = Images::getInfoFromURLCached($matches[1]); - - if ($picturedata) { - if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { - $post['image'] = $matches[1]; - } else { - $post['preview'] = $matches[1]; - } - } - } - - if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { - $post['url'] = $matches[1]; - $post['title'] = $matches[2]; - } - if (!empty($post['url']) && (in_array($post['type'], ['link', 'video'])) - && preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { - $post['url'] = $matches[1]; - } - - // Search for description - if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) { - $post['description'] = $matches[1]; - } - } - } - return $post; - } - /** * Fetches attachment data that were generated with the "attachment" element * @@ -178,7 +107,7 @@ class BBCode if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match)) { DI::profiler()->stopRecording(); - return self::getOldAttachmentData($body); + return []; } $attributes = $match[2]; @@ -253,183 +182,6 @@ class BBCode return $data; } - public static function getAttachedData(string $body, array $item = []): array - { - /* - - text: - - type: link, video, photo - - title: - - url: - - image: - - description: - - (thumbnail) - */ - - DI::profiler()->startRecording('rendering'); - $has_title = !empty($item['title']); - $plink = $item['plink'] ?? ''; - $post = self::getAttachmentData($body); - - // Get all linked images with alternative image description - if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { - foreach ($pictures as $picture) { - if ($id = Photo::getIdForName($picture[1])) { - $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2], 'id' => $id]; - } else { - $post['remote_images'][] = ['url' => $picture[1], 'description' => $picture[2]]; - } - } - if (!empty($post['images']) && !empty($post['images'][0]['description'])) { - $post['image_description'] = $post['images'][0]['description']; - } - } - - if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { - foreach ($pictures as $picture) { - if ($id = Photo::getIdForName($picture[1])) { - $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '', 'id' => $id]; - } else { - $post['remote_images'][] = ['url' => $picture[1], 'description' => '']; - } - } - } - - if (!isset($post['type'])) { - $post['text'] = $body; - } - - // Simplify image codes - $post['text'] = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $post['text']); - $post['text'] = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $post['text']); - - // if nothing is found, it maybe having an image. - if (!isset($post['type'])) { - if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) { - if ((count($pictures) == 1) && !$has_title && !Photo::isLocal($pictures[0][2])) { - if (!empty($item['object-type']) && ($item['object-type'] == Activity\ObjectType::IMAGE)) { - // Replace the preview picture with the real picture - $url = str_replace('-1.', '-0.', $pictures[0][2]); - $data = ['url' => $url, 'type' => 'photo']; - } else { - // Checking, if the link goes to a picture - $data = ParseUrl::getSiteinfoCached($pictures[0][1]); - } - - // Workaround: - // Sometimes photo posts to the own album are not detected at the start. - // So we seem to cannot use the cache for these cases. That's strange. - if (($data['type'] != 'photo') && strstr($pictures[0][1], '/photos/')) { - $data = ParseUrl::getSiteinfo($pictures[0][1]); - } - - if ($data['type'] == 'photo') { - $post['type'] = 'photo'; - if (isset($data['images'][0])) { - $post['image'] = $data['images'][0]['src']; - $post['url'] = $data['url']; - } else { - $post['image'] = $data['url']; - } - - $post['preview'] = $pictures[0][2]; - $post['text'] = trim(str_replace($pictures[0][0], '', $post['text'])); - } else { - $imgdata = Images::getInfoFromURLCached($pictures[0][1]); - if (($imgdata) && substr($imgdata['mime'], 0, 6) == 'image/') { - $post['type'] = 'photo'; - $post['image'] = $pictures[0][1]; - $post['preview'] = $pictures[0][2]; - $post['text'] = trim(str_replace($pictures[0][0], '', $post['text'])); - } - } - } elseif (count($pictures) > 0) { - if (count($pictures) > 4) { - $post['type'] = 'link'; - $post['url'] = $plink; - } else { - $post['type'] = 'photo'; - } - - $post['image'] = $pictures[0][2]; - - foreach ($pictures as $picture) { - $post['text'] = trim(str_replace($picture[0], '', $post['text'])); - } - } - } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $post['text'], $pictures, PREG_SET_ORDER)) { - if ($has_title) { - $post['type'] = 'link'; - $post['url'] = $plink; - } else { - $post['type'] = 'photo'; - } - - $post['image'] = $pictures[0][1]; - foreach ($pictures as $picture) { - $post['text'] = trim(str_replace($picture[0], '', $post['text'])); - } - } - - // Test for the external links - preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER); - preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER); - - $links = array_merge($links1, $links2); - - // If there is only a single one, then use it. - // This should cover link posts via API. - if ((count($links) == 1) && !isset($post['preview']) && !$has_title) { - $post['type'] = 'link'; - $post['url'] = $links[0][1]; - } - - // Simplify "video" element - $post['text'] = preg_replace('(\[video.*?\ssrc\s?=\s?([^\s\]]+).*?\].*?\[/video\])ism', '[video]$1[/video]', $post['text']); - - // Now count the number of external media links - preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER); - preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER); - preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER); - preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER); - - // Add them to the other external links - $links = array_merge($links, $links1, $links2, $links3, $links4); - - // Are there more than one? - if (count($links) > 1) { - // The post will be the type "text", which means a blog post - unset($post['type']); - $post['url'] = $plink; - } - - if (!isset($post['type'])) { - $post['type'] = 'text'; - } - - if (($post['type'] == 'photo') && empty($post['images']) && !empty($post['remote_images'])) { - $post['images'] = $post['remote_images']; - $post['image'] = $post['images'][0]['url']; - if (!empty($post['images']) && !empty($post['images'][0]['description'])) { - $post['image_description'] = $post['images'][0]['description']; - } - } - unset($post['remote_images']); - } elseif (isset($post['url']) && ($post['type'] == 'video')) { - $data = ParseUrl::getSiteinfoCached($post['url']); - - if (isset($data['images'][0])) { - $post['image'] = $data['images'][0]['src']; - } - } elseif (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) { - foreach ($pictures as $picture) { - $post['text'] = trim(str_replace($picture[0], '', $post['text'])); - } - } - - DI::profiler()->stopRecording(); - return $post; - } - /** * Remove [attachment] BBCode and replaces it with a regular [url] * diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index 9a7435f5b6..0866e476cf 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -129,7 +129,7 @@ class Plaintext $body = BBCode::stripAbstract($body); // At first look at data that is attached via "type-..." stuff - $post = BBCode::getAttachedData($body, $item); + $post = BBCode::getAttachmentData($body, $item); if (($item['title'] != '') && ($post['text'] != '')) { $post['text'] = trim($item['title'] . "\n\n" . $post['text']); diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php index dc46a77804..f6f6e3b671 100644 --- a/src/Factory/Api/Mastodon/Card.php +++ b/src/Factory/Api/Mastodon/Card.php @@ -39,45 +39,40 @@ class Card extends BaseFactory */ public function createFromUriId(int $uriId, array $history = []): \Friendica\Object\Api\Mastodon\Card { - $item = Post::selectFirst(['body'], ['uri-id' => $uriId]); - if (!empty($item['body'])) { - $data = BBCode::getAttachmentData($item['body']); - } else { - $data = []; + $media = Post\Media::getByURIId($uriId, [Post\Media::HTML]); + if (empty($media) && empty($media[0]['description']) && !empty($media[0]['image']) && !empty($media[0]['preview'])) { + return new \Friendica\Object\Api\Mastodon\Card([], $history); } - foreach (Post\Media::getByURIId($uriId, [Post\Media::HTML]) as $attached) { - if ((empty($data['url']) || Strings::compareLink($data['url'], $attached['url'])) && - (!empty($attached['description']) || !empty($attached['image']) || !empty($attached['preview']))) { - $parts = parse_url($attached['url']); - if (!empty($parts['scheme']) && !empty($parts['host'])) { - if (empty($attached['publisher-name'])) { - $attached['publisher-name'] = $parts['host']; - } - if (empty($attached['publisher-url']) || empty(parse_url($attached['publisher-url'], PHP_URL_SCHEME))) { - $attached['publisher-url'] = $parts['scheme'] . '://' . $parts['host']; + $parts = parse_url($media[0]['url']); + if (!empty($parts['scheme']) && !empty($parts['host'])) { + if (empty($media[0]['publisher-name'])) { + $media[0]['publisher-name'] = $parts['host']; + } + if (empty($media[0]['publisher-url']) || empty(parse_url($media[0]['publisher-url'], PHP_URL_SCHEME))) { + $media[0]['publisher-url'] = $parts['scheme'] . '://' . $parts['host']; - if (!empty($parts['port'])) { - $attached['publisher-url'] .= ':' . $parts['port']; - } - } + if (!empty($parts['port'])) { + $media[0]['publisher-url'] .= ':' . $parts['port']; } - - $data['url'] = $attached['url']; - $data['title'] = $attached['name']; - $data['description'] = $attached['description']; - $data['type'] = 'link'; - $data['author_name'] = $attached['author-name']; - $data['author_url'] = $attached['author-url']; - $data['provider_name'] = $attached['publisher-name']; - $data['provider_url'] = $attached['publisher-url']; - $data['image'] = $attached['preview']; - $data['width'] = $attached['preview-width']; - $data['height'] = $attached['preview-height']; - $data['blurhash'] = $attached['blurhash']; } } + $data = []; + + $data['url'] = $media[0]['url']; + $data['title'] = $media[0]['name']; + $data['description'] = $media[0]['description']; + $data['type'] = 'link'; + $data['author_name'] = $media[0]['author-name']; + $data['author_url'] = $media[0]['author-url']; + $data['provider_name'] = $media[0]['publisher-name']; + $data['provider_url'] = $media[0]['publisher-url']; + $data['image'] = $media[0]['preview']; + $data['width'] = $media[0]['preview-width']; + $data['height'] = $media[0]['preview-height']; + $data['blurhash'] = $media[0]['blurhash']; + return new \Friendica\Object\Api\Mastodon\Card($data, $history); } } diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 5dfb227d64..ee74ee02b2 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -896,6 +896,13 @@ class Media return $body; } + /** + * Add an [attachment] element to the body for a given uri-id with a HTML media element + * + * @param integer $uriid + * @param string $body + * @return string + */ public static function addHTMLAttachmentToBody(int $uriid, string $body): string { if (preg_match("/.*(\[attachment.*?\].*?\[\/attachment\]).*/ism", $body, $match)) { @@ -929,6 +936,13 @@ class Media return $body; } + /** + * Add a link to the body for a given uri-id with a HTML media element + * + * @param integer $uriid + * @param string $body + * @return string + */ public static function addHTMLLinkToBody(int $uriid, string $body): string { $links = self::getByURIId($uriid, [self::HTML]); @@ -947,6 +961,12 @@ class Media } } + /** + * Add an [attachment] element to the body and a link to raw-body for a given uri-id with a HTML media element + * + * @param array $item + * @return array + */ public static function addHTMLAttachmentToItem(array $item): array { if (($item['gravity'] == Item::GRAVITY_ACTIVITY) || empty($item['uri-id'])) { diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 91eb1cc2c4..160667681f 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -3330,9 +3330,9 @@ class Diaspora // Fetch the title from an attached link - if there is one if (empty($item['title']) && DI::pConfig()->get($owner['uid'], 'system', 'attach_link_title')) { - $page_data = BBCode::getAttachmentData($item['body']); - if (!empty($page_data['type']) && !empty($page_data['title']) && ($page_data['type'] == 'link')) { - $title = $page_data['title']; + $media = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]); + if (!empty($media) && !empty($media[0]['name']) && ($media[0]['name'] != $media[0]['url'])) { + $title = $media[0]['name']; } } diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 625305161f..f9ea91c779 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -1211,9 +1211,9 @@ class Feed } // Fetch information about the post - $siteinfo = BBCode::getAttachedData($item['body']); - if (isset($siteinfo['title'])) { - return $siteinfo['title']; + $media = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]); + if (!empty($media) && !empty($media[0]['name']) && ($media[0]['name'] != $media[0]['url'])) { + return $media[0]['name']; } // If no bookmark is found then take the first line From aea3ed45483ab402666bf310ff88bba42405d661 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 5 Mar 2023 21:46:45 +0000 Subject: [PATCH 06/16] Code is reformatted --- src/Content/Item.php | 55 +++++--- src/Content/Text/BBCode.php | 229 +++++++++++++++++++++------------ src/Content/Text/Plaintext.php | 9 +- src/Model/Post/Media.php | 40 +++--- src/Protocol/Diaspora.php | 94 ++++++++------ src/Protocol/Feed.php | 41 ++++-- 6 files changed, 300 insertions(+), 168 deletions(-) diff --git a/src/Content/Item.php b/src/Content/Item.php index e74ca846da..58fe945d32 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -223,15 +223,19 @@ class Item // select someone by nick in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = ["`nick` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid]; + $condition = [ + "`nick` = ? AND `network` = ? AND `uid` = ?", + $name, $network, $profile_uid + ]; $contact = DBA::selectFirst('contact', $fields, $condition); } // select someone by attag in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = ["`attag` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid]; + $condition = [ + "`attag` = ? AND `network` = ? AND `uid` = ?", + $name, $network, $profile_uid + ]; $contact = DBA::selectFirst('contact', $fields, $condition); } @@ -271,7 +275,7 @@ class Item $replaced = true; // create profile link $profile = str_replace(',', '%2c', $profile); - $newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]'; + $newtag = $tag_type . '[url=' . $profile . ']' . $newname . '[/url]'; $body = str_replace($tag_type . $name, $newtag, $body); } } @@ -295,8 +299,10 @@ class Item $xmlhead = ''; if ($this->activity->match($item['verb'], Activity::TAG)) { - $fields = ['author-id', 'author-link', 'author-name', 'author-network', - 'verb', 'object-type', 'resource-id', 'body', 'plink']; + $fields = [ + 'author-id', 'author-link', 'author-name', 'author-network', + 'verb', 'object-type', 'resource-id', 'body', 'plink' + ]; $obj = Post::selectFirst($fields, ['uri' => $item['parent-uri']]); if (!DBA::isResult($obj)) { $this->profiler->stopRecording(); @@ -333,7 +339,8 @@ class Item default: if ($obj['resource-id']) { $post_type = $this->l10n->t('photo'); - $m=[]; preg_match("/\[url=([^]]*)\]/", $obj['body'], $m); + $m = []; + preg_match("/\[url=([^]]*)\]/", $obj['body'], $m); $rr['plink'] = $m[1]; } else { $post_type = $this->l10n->t('status'); @@ -433,7 +440,8 @@ class Item } if ((($cid == 0) || ($rel == Contact::FOLLOWER)) && - in_array($item['network'], Protocol::FEDERATED)) { + in_array($item['network'], Protocol::FEDERATED) + ) { $menu[$this->l10n->t('Connect/Follow')] = 'contact/follow?url=' . urlencode($item['author-link']) . '&auto=1'; } } else { @@ -891,7 +899,7 @@ class Item public function moveAttachmentsFromBodyToAttach(array $post): array { - if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$post['body'], $match)) { + if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/', $post['body'], $match)) { return $post; } @@ -903,11 +911,17 @@ class Item if ($post['attach']) { $post['attach'] .= ','; } - $post['attach'] .= Post\Media::getAttachElement($this->baseURL . '/attach/' . $attachment['id'], - $attachment['filesize'], $attachment['filetype'], $attachment['filename'] ?? ''); + $post['attach'] .= Post\Media::getAttachElement( + $this->baseURL . '/attach/' . $attachment['id'], + $attachment['filesize'], + $attachment['filetype'], + $attachment['filename'] ?? '' + ); - $fields = ['allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'], - 'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid']]; + $fields = [ + 'allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'], + 'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid'] + ]; $condition = ['id' => $attachment_id]; Attach::update($fields, $condition); } @@ -926,7 +940,8 @@ class Item // embedded bookmark or attachment in post? set bookmark flag $data = BBCode::getAttachmentData($post['body']); if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || !empty($data['type'])) - && ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE)) { + && ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE) + ) { $post['post-type'] = ItemModel::PT_PAGE; $post['object-type'] = Activity\ObjectType::BOOKMARK; } @@ -1029,8 +1044,14 @@ class Item continue; } - $this->emailer->send(new ItemCCEMail($this->app, $this->l10n, $this->baseURL, - $post, $address, $author['thumb'] ?? '')); + $this->emailer->send(new ItemCCEMail( + $this->app, + $this->l10n, + $this->baseURL, + $post, + $address, + $author['thumb'] ?? '' + )); } } } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 9651e91cfc..f072e59c9d 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -191,7 +191,8 @@ class BBCode */ public static function replaceAttachment(string $body, bool $no_link_desc = false): string { - return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", + return preg_replace_callback( + "/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", function ($match) use ($body, $no_link_desc) { $attach_data = self::getAttachmentData($match[0]); if (empty($attach_data['url'])) { @@ -203,7 +204,9 @@ class BBCode } else { return " \n[url=" . $attach_data['url'] . ']' . $attach_data['title'] . "[/url]\n"; } - }, $body); + }, + $body + ); } /** @@ -708,8 +711,11 @@ class BBCode // We're depending on the property of 'foreach' (specified on the PHP website) that // it loops over the array starting from the first element and going sequentially // to the last element - $newbody = str_replace('[$#saved_image' . $cnt . '#$]', - '' . DI::l10n()->t('Image/photo') . '', $newbody); + $newbody = str_replace( + '[$#saved_image' . $cnt . '#$]', + '' . DI::l10n()->t('Image/photo') . '', + $newbody + ); $cnt++; } @@ -865,7 +871,7 @@ class BBCode } $img_str = ' $value) { if (!empty($value)) { $img_str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT) . '"'; @@ -902,13 +908,13 @@ class BBCode switch ($simplehtml) { case self::MASTODON_API: case self::TWITTER_API: - $text = ($is_quote_share? '
' : '') . - '' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ":
\n" . - '
' . $content . '
'; + $text = ($is_quote_share ? '
' : '') . + '' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ":
\n" . + '
' . $content . '
'; break; case self::DIASPORA: if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) { - $text = ($is_quote_share? '
' : '') . '

' . $attributes['link'] . '

' . "\n"; + $text = ($is_quote_share ? '
' : '') . '

' . $attributes['link'] . '

' . "\n"; } else { $headline = '

' . $attributes['author'] . ':

' . "\n"; @@ -916,7 +922,7 @@ class BBCode $headline = '

' . $attributes['author'] . ' - ' . $attributes['posted'] . ' GMT

' . "\n"; } - $text = ($is_quote_share? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; + $text = ($is_quote_share ? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; if (empty($attributes['posted']) && !empty($attributes['link'])) { $text .= '

[Source]

' . "\n"; @@ -929,18 +935,18 @@ class BBCode $headline .= DI::l10n()->t('%2$s %3$s', $attributes['link'], $mention, $attributes['posted']); $headline .= ':

' . "\n"; - $text = ($is_quote_share? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; + $text = ($is_quote_share ? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; break; case self::OSTATUS: - $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; + $text = ($is_quote_share ? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; break; case self::ACTIVITYPUB: $author = '@' . $author_contact['addr'] . ':'; $text = '' . "\n"; break; default: - $text = ($is_quote_share? "\n" : ''); + $text = ($is_quote_share ? "\n" : ''); $contact = Contact::getByURL($attributes['profile'], false, ['network']); $network = $contact['network'] ?? Protocol::PHANTOM; @@ -1252,8 +1258,7 @@ class BBCode * $match[1] = $url * $match[2] = $title or absent */ - $try_oembed_callback = function (array $match) - { + $try_oembed_callback = function (array $match) { $url = $match[1]; $title = $match[2] ?? ''; @@ -1306,18 +1311,22 @@ class BBCode } // Remove linefeeds inside of the table elements. See issue #6799 - $search = ["\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ", + $search = [ + "\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ", "\n[td]", "[td]\n", " [td]", "\n[/td]", "[/td]\n", "[/td] ", "\n[tr]", "[tr]\n", " [tr]", "[tr] ", "\n[/tr]", "[/tr]\n", " [/tr]", "[/tr] ", "\n[hr]", "[hr]\n", " [hr]", "[hr] ", "\n[attachment ", " [attachment ", "\n[/attachment]", "[/attachment]\n", " [/attachment]", "[/attachment] ", - "[table]\n", "[table] ", " [table]", "\n[/table]", " [/table]", "[/table] "]; - $replace = ["[th]", "[th]", "[th]", "[/th]", "[/th]", "[/th]", + "[table]\n", "[table] ", " [table]", "\n[/table]", " [/table]", "[/table] " + ]; + $replace = [ + "[th]", "[th]", "[th]", "[/th]", "[/th]", "[/th]", "[td]", "[td]", "[td]", "[/td]", "[/td]", "[/td]", "[tr]", "[tr]", "[tr]", "[tr]", "[/tr]", "[/tr]", "[/tr]", "[/tr]", "[hr]", "[hr]", "[hr]", "[hr]", "[attachment ", "[attachment ", "[/attachment]", "[/attachment]", "[/attachment]", "[/attachment]", - "[table]", "[table]", "[table]", "[/table]", "[/table]", "[/table]"]; + "[table]", "[table]", "[table]", "[/table]", "[/table]", "[/table]" + ]; do { $oldtext = $text; $text = str_replace($search, $replace, $text); @@ -1333,10 +1342,14 @@ class BBCode // removing multiplicated newlines if (DI::config()->get('system', 'remove_multiplicated_lines')) { - $search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[*]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", - "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"]; - $replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[*]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", - "[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]"]; + $search = [ + "\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[*]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", + "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n" + ]; + $replace = [ + "\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[*]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", + "[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]" + ]; do { $oldtext = $text; $text = str_replace($search, $replace, $text); @@ -1454,9 +1467,9 @@ class BBCode $endlessloop = 0; while ((((strpos($text, "[/list]") !== false) && (strpos($text, "[list") !== false)) || - ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) || - ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) || - ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) { + ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) || + ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) || + ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) { $text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '
    $1
', $text); $text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '
    $1
', $text); $text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '
    $1
', $text); @@ -1502,10 +1515,12 @@ class BBCode // handle nested quotes $endlessloop = 0; - while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { - $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", + while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { + $text = preg_replace( + "/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", '
$1$2
', - $text); + $text + ); } // Declare the format for [quote] layout @@ -1524,10 +1539,12 @@ class BBCode // handle nested quotes $endlessloop = 0; - while ((strpos($text, "[/quote]")!== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) { - $text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", - "

" . $t_wrote . "

$2
", - $text); + while ((strpos($text, "[/quote]") !== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) { + $text = preg_replace( + "/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", + "

" . $t_wrote . "

$2
", + $text + ); } @@ -1548,13 +1565,15 @@ class BBCode $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '', $text); $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '', $text); - $text = preg_replace_callback("/\[img\=(.*?)\](.*?)\[\/img\]/ism", + $text = preg_replace_callback( + "/\[img\=(.*?)\](.*?)\[\/img\]/ism", function ($matches) use ($simple_html, $uriid) { $matches[1] = self::proxyUrl($matches[1], $simple_html, $uriid); $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT); return '' . $matches[2] . ''; }, - $text); + $text + ); // Images // [img]pathtoimage[/img] @@ -1576,8 +1595,8 @@ class BBCode $text = self::convertImages($text, $simple_html, $uriid); - $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); - $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); + $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); + $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); //$text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); // Simplify "video" element @@ -1585,20 +1604,32 @@ class BBCode if ($try_oembed) { // html5 video and audio - $text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", - '', $text); + $text = preg_replace( + "/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", + '', + $text + ); $text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", $try_oembed_callback, $text); $text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text); - $text = preg_replace("/\[video\](.*?)\[\/video\]/ism", - '$1', $text); + $text = preg_replace( + "/\[video\](.*?)\[\/video\]/ism", + '$1', + $text + ); $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", '', $text); } else { - $text = preg_replace("/\[video\](.*?)\[\/video\]/ism", - '$1', $text); - $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", - '$1', $text); + $text = preg_replace( + "/\[video\](.*?)\[\/video\]/ism", + '$1', + $text + ); + $text = preg_replace( + "/\[audio\](.*?)\[\/audio\]/ism", + '$1', + $text + ); } // Backward compatibility, [iframe] support has been removed in version 2020.12 @@ -1620,8 +1651,11 @@ class BBCode if ($try_oembed) { $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '', $text); } else { - $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", - 'https://www.youtube.com/watch?v=$1', $text); + $text = preg_replace( + "/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", + 'https://www.youtube.com/watch?v=$1', + $text + ); } if ($try_oembed) { @@ -1635,8 +1669,11 @@ class BBCode if ($try_oembed) { $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text); } else { - $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", - 'https://vimeo.com/$1', $text); + $text = preg_replace( + "/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", + 'https://vimeo.com/$1', + $text + ); } // oembed tag @@ -1672,27 +1709,39 @@ class BBCode // Handle mentions and hashtag links if ($simple_html == self::DIASPORA) { // The ! is converted to @ since Diaspora only understands the @ - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '@$3', - $text); + $text + ); } elseif (in_array($simple_html, [self::OSTATUS, self::ACTIVITYPUB])) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); - $text = preg_replace("/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text + ); + $text = preg_replace( + "/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', - $text); + $text + ); } elseif (in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::TWITTER_API])) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); + $text + ); } elseif ($simple_html == self::MASTODON_API) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); - $text = preg_replace("/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text + ); + $text = preg_replace( + "/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', - $text); + $text + ); } else { $text = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $text); } @@ -1710,8 +1759,11 @@ class BBCode // Bookmarks in red - will be converted to bookmarks in friendica $text = preg_replace("/#\^\[url\](.*?)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $text); $text = preg_replace("/#\^\[url\=(.*?)\](.*?)\[\/url\]/ism", '[bookmark=$1]$2[/bookmark]', $text); - $text = preg_replace("/#\[url\=.*?\]\^\[\/url\]\[url\=(.*?)\](.*?)\[\/url\]/i", - "[bookmark=$1]$2[/bookmark]", $text); + $text = preg_replace( + "/#\[url\=.*?\]\^\[\/url\]\[url\=(.*?)\](.*?)\[\/url\]/i", + "[bookmark=$1]$2[/bookmark]", + $text + ); if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) { $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", [self::class, 'expandLinksCallback'], $text); @@ -1731,20 +1783,22 @@ class BBCode "&\[url=/?posts/([^\[\]]*)\](.*)\[\/url\]&Usi", function ($match) { return "[url=" . DI::baseUrl() . "/display/" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text + }, + $text ); $text = preg_replace_callback( "&\[url=/people\?q\=(.*)\](.*)\[\/url\]&Usi", function ($match) { return "[url=" . DI::baseUrl() . "/search?search=%40" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text + }, + $text ); // Server independent link to posts and comments // See issue: https://github.com/diaspora/diaspora_federation/issues/75 $expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism"; - $text = preg_replace($expression, DI::baseUrl()."/display/$1", $text); + $text = preg_replace($expression, DI::baseUrl() . "/display/$1", $text); /* Tag conversion * Supports: @@ -1752,7 +1806,7 @@ class BBCode * - [url=]#[/url] */ self::performWithEscapedTags($text, ['url', 'share'], function ($text) use ($simple_html) { - $text = preg_replace_callback("/(?:#\[url\=[^\[\]]*\]|\[url\=[^\[\]]*\]#)(.*?)\[\/url\]/ism", function($matches) use ($simple_html) { + $text = preg_replace_callback("/(?:#\[url\=[^\[\]]*\]|\[url\=[^\[\]]*\]#)(.*?)\[\/url\]/ism", function ($matches) use ($simple_html) { if ($simple_html == self::ACTIVITYPUB) { return '#' @@ -1769,8 +1823,8 @@ class BBCode // We need no target="_blank" rel="noopener noreferrer" for local links // convert links start with DI::baseUrl() as local link without the target="_blank" rel="noopener noreferrer" attribute $escapedBaseUrl = preg_quote(DI::baseUrl(), '/'); - $text = preg_replace("/\[url\](".$escapedBaseUrl.".*?)\[\/url\]/ism", '$1', $text); - $text = preg_replace("/\[url\=(".$escapedBaseUrl.".*?)\](.*?)\[\/url\]/ism", '$2', $text); + $text = preg_replace("/\[url\](" . $escapedBaseUrl . ".*?)\[\/url\]/ism", '$1', $text); + $text = preg_replace("/\[url\=(" . $escapedBaseUrl . ".*?)\](.*?)\[\/url\]/ism", '$2', $text); $text = preg_replace("/\[url\](.*?)\[\/url\]/ism", '$1', $text); $text = preg_replace("/\[url\=(.*?)\](.*?)\[\/url\]/ism", '$2', $text); @@ -1801,10 +1855,15 @@ class BBCode // sanitizes src attributes (http and redir URLs for displaying in a web page, cid used for inline images in emails) $allowed_src_protocols = ['//', 'http://', 'https://', 'contact/redir/', 'cid:']; - array_walk($allowed_src_protocols, function(&$value) { $value = preg_quote($value, '#');}); + array_walk($allowed_src_protocols, function (&$value) { + $value = preg_quote($value, '#'); + }); - $text = preg_replace('#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism', - '<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">', $text); + $text = preg_replace( + '#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism', + '<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">', + $text + ); // sanitize href attributes (only allowlisted protocols URLs) // default value for backward compatibility @@ -1816,7 +1875,9 @@ class BBCode $allowed_link_protocols[] = 'https://'; $allowed_link_protocols[] = 'contact/redir/'; - array_walk($allowed_link_protocols, function(&$value) { $value = preg_quote($value, '#');}); + array_walk($allowed_link_protocols, function (&$value) { + $value = preg_quote($value, '#'); + }); $regex = '#<([^>]*?)(href)="(?!' . implode('|', $allowed_link_protocols) . ')(.*?)"(.*?)>#ism'; $text = preg_replace($regex, '<$1$2="javascript:void(0)"$4 data-original-href="$3" class="invalid-href" title="' . DI::l10n()->t('Invalid link protocol') . '">', $text); @@ -1826,7 +1887,8 @@ class BBCode $text, function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) { return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html); - }, $uriid + }, + $uriid ); $text = self::interpolateSavedImagesIntoItemBody($uriid, $text, $saved_image); @@ -1841,13 +1903,14 @@ class BBCode // Additionally, [pre] tags preserve spaces $text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", function ($match) { - return str_replace([' ', "\n"], [' ', "
"], htmlentities($match[1], ENT_NOQUOTES,'UTF-8')); + return str_replace([' ', "\n"], [' ', "
"], htmlentities($match[1], ENT_NOQUOTES, 'UTF-8')); }, $text); return $text; }); // Escaped code - $text = preg_replace_callback("#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism", + $text = preg_replace_callback( + "#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism", function ($matches) { if (strpos($matches[2], "\n") !== false) { $return = '
' . htmlentities(trim($matches[2], "\n\r"), ENT_NOQUOTES, 'UTF-8') . '
'; @@ -1863,8 +1926,8 @@ class BBCode // Default iframe allowed domains/path $allowedIframeDomains = [ DI::baseUrl()->getHost() - . (DI::baseUrl()->getPath() ? '/' . DI::baseUrl()->getPath() : '') - . '/oembed/', # The path part has to change with the source in Content\Oembed::iframe + . (DI::baseUrl()->getPath() ? '/' . DI::baseUrl()->getPath() : '') + . '/oembed/', # The path part has to change with the source in Content\Oembed::iframe 'www.youtube.com/embed/', 'player.vimeo.com/video/', ]; @@ -1977,7 +2040,8 @@ class BBCode * Transform #tags, strip off the [url] and replace spaces with underscore */ $url_search_string = "^\[\]"; - $text = preg_replace_callback("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i", + $text = preg_replace_callback( + "/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i", function ($matches) { return '#' . str_replace(' ', '_', $matches[2]); }, @@ -2112,7 +2176,8 @@ class BBCode */ public static function expandTags(string $body): string { - return preg_replace_callback("/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/", + return preg_replace_callback( + "/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/", function (array $match) { switch ($match[1]) { case '!': @@ -2129,7 +2194,9 @@ class BBCode default: return $match[1] . '[url=' . DI::baseUrl() . '/search?tag=' . $match[2] . ']' . $match[2] . '[/url]'; } - }, $body); + }, + $body + ); } /** diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index 0866e476cf..7e3263d127 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -122,8 +122,11 @@ class Plaintext $body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']); // Add an URL element if the text contains a raw link - $body = preg_replace('/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism', - '$1[url]$2[/url]', $body); + $body = preg_replace( + '/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism', + '$1[url]$2[/url]', + $body + ); // Remove the abstract $body = BBCode::stripAbstract($body); @@ -149,7 +152,7 @@ class Plaintext if (($limit == 0) && ($abstract == $default_abstract)) { $abstract = ''; } - } else {// Try to guess the correct target network + } else { // Try to guess the correct target network switch ($htmlmode) { case BBCode::TWITTER: $abstract = BBCode::getAbstract($item['body'], Protocol::TWITTER); diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index ee74ee02b2..ab17789724 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -162,8 +162,10 @@ class Media */ public static function getAttachElement(string $href, int $length, string $type, string $title = ''): string { - $media = self::fetchAdditionalData(['type' => self::DOCUMENT, 'url' => $href, - 'size' => $length, 'mimetype' => $type, 'description' => $title]); + $media = self::fetchAdditionalData([ + 'type' => self::DOCUMENT, 'url' => $href, + 'size' => $length, 'mimetype' => $type, 'description' => $title + ]); return '[attach]href="' . $media['url'] . '" length="' . $media['size'] . '" type="' . $media['mimetype'] . '" title="' . $media['description'] . '"[/attach]'; @@ -263,8 +265,10 @@ class Media return $media; } - if (!empty($item['plink']) && Strings::compareLink($item['plink'], $media['url']) && - parse_url($item['plink'], PHP_URL_HOST) != parse_url($item['uri'], PHP_URL_HOST)) { + if ( + !empty($item['plink']) && Strings::compareLink($item['plink'], $media['url']) && + parse_url($item['plink'], PHP_URL_HOST) != parse_url($item['uri'], PHP_URL_HOST) + ) { Logger::debug('Not a link to an activity', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'plink' => $item['plink'], 'uri' => $item['uri']]); return $media; } @@ -483,8 +487,10 @@ class Media } $body = str_replace($picture[0], '', $body); $image = str_replace('-1.', '-0.', $picture[2]); - $attachments[$image] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, - 'preview' => $picture[2], 'description' => $picture[3]]; + $attachments[$image] = [ + 'uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, + 'preview' => $picture[2], 'description' => $picture[3] + ]; } } @@ -502,8 +508,10 @@ class Media } $body = str_replace($picture[0], '', $body); $image = str_replace('-1.', '-0.', $picture[2]); - $attachments[$image] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, - 'preview' => $picture[2], 'description' => null]; + $attachments[$image] = [ + 'uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, + 'preview' => $picture[2], 'description' => null + ]; } } @@ -631,7 +639,7 @@ class Media public static function insertFromAttachmentData(int $uriid, string $body) { $data = BBCode::getAttachmentData($body); - if (empty($data)) { + if (empty($data)) { return; } @@ -803,8 +811,10 @@ class Media continue; } - if (in_array($medium['type'], [self::AUDIO, self::IMAGE]) || - in_array($filetype, ['audio', 'image'])) { + if ( + in_array($medium['type'], [self::AUDIO, self::IMAGE]) || + in_array($filetype, ['audio', 'image']) + ) { $attachments['visual'][] = $medium; } elseif (($medium['type'] == self::VIDEO) || ($filetype == 'video')) { if (!empty($medium['height'])) { @@ -871,15 +881,15 @@ class Media if ($media['type'] == self::IMAGE) { if (!empty($media['preview'])) { if (!empty($media['description'])) { - $body .= "\n[url=" . $media['url'] . "][img=" . $media['preview'] . ']' . $media['description'] .'[/img][/url]'; + $body .= "\n[url=" . $media['url'] . "][img=" . $media['preview'] . ']' . $media['description'] . '[/img][/url]'; } else { - $body .= "\n[url=" . $media['url'] . "][img]" . $media['preview'] .'[/img][/url]'; + $body .= "\n[url=" . $media['url'] . "][img]" . $media['preview'] . '[/img][/url]'; } } else { if (!empty($media['description'])) { - $body .= "\n[img=" . $media['url'] . ']' . $media['description'] .'[/img]'; + $body .= "\n[img=" . $media['url'] . ']' . $media['description'] . '[/img]'; } else { - $body .= "\n[img]" . $media['url'] .'[/img]'; + $body .= "\n[img]" . $media['url'] . '[/img]'; } } } elseif ($media['type'] == self::AUDIO) { diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 160667681f..5554af7d81 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -83,14 +83,21 @@ class Diaspora return $contacts; } - $items = Post::select(['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], - ['parent' => $item['parent'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]]); + $items = Post::select( + ['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], + ['parent' => $item['parent'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]] + ); while ($item = Post::fetch($items)) { - $contact = DBA::selectFirst('contact', ['id', 'url', 'name', 'protocol', 'batch', 'network'], - ['id' => $item['author-id']]); - if (!DBA::isResult($contact) || empty($contact['batch']) || + $contact = DBA::selectFirst( + 'contact', + ['id', 'url', 'name', 'protocol', 'batch', 'network'], + ['id' => $item['author-id']] + ); + if ( + !DBA::isResult($contact) || empty($contact['batch']) || ($contact['network'] != Protocol::DIASPORA) || - Strings::compareLink($item['parent-author-link'], $item['author-link'])) { + Strings::compareLink($item['parent-author-link'], $item['author-link']) + ) { continue; } @@ -270,7 +277,7 @@ class Diaspora $basedom = XML::parseString($xml, true); if (!is_object($basedom)) { - Logger::notice('Received data does not seem to be an XML. Discarding. '.$xml); + Logger::notice('Received data does not seem to be an XML. Discarding. ' . $xml); if ($no_exit) { return false; } else { @@ -438,7 +445,7 @@ class Diaspora $alg = $base->alg; - $signed_data = $data.'.'.Strings::base64UrlEncode($type).'.'.Strings::base64UrlEncode($encoding).'.'.Strings::base64UrlEncode($alg); + $signed_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); // decode the data @@ -719,7 +726,8 @@ class Diaspora $signed_data .= $entry; } - if (!in_array($fieldname, ['parent_author_signature', 'target_author_signature']) + if ( + !in_array($fieldname, ['parent_author_signature', 'target_author_signature']) || ($orig_type == 'relayable_retraction') ) { XML::copy($entry, $fields, $fieldname); @@ -795,7 +803,7 @@ class Diaspora Logger::info('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]); try { return DI::dsprContact()->getByAddr($uri)->pubKey; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { return ''; } } @@ -1185,9 +1193,11 @@ class Diaspora */ private static function parentItem(int $uid, string $guid, WebFingerUri $author, array $contact) { - $fields = ['id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin', + $fields = [ + 'id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin', 'author-name', 'author-link', 'author-avatar', 'gravity', - 'owner-name', 'owner-link', 'owner-avatar']; + 'owner-name', 'owner-link', 'owner-avatar' + ]; $condition = ['uid' => $uid, 'guid' => $guid]; $item = Post::selectFirst($fields, $condition); @@ -1435,7 +1445,7 @@ class Diaspora } elseif ($person_uri) { try { return DI::dsprContact()->selectOneByAddr($person_uri)->baseurl . '/objects/' . $guid; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { return ''; } } @@ -1472,7 +1482,6 @@ class Diaspora $contact = DI::dsprContact()->getByUrl(new Uri($match[3])); Tag::storeByHash($uriid, $match[1], $contact->name ?: $contact->nick, $contact->url); } catch (\Throwable $e) { - } } } @@ -1531,7 +1540,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -1783,7 +1792,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -1896,7 +1905,7 @@ class Diaspora try { $author = DI::dsprContact()->getByAddr($author_uri); - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author_uri->getAddr()]); return false; } @@ -1968,7 +1977,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -2013,8 +2022,10 @@ class Diaspora Logger::info('Participation stored', ['id' => $message_id, 'guid' => $guid, 'parent_guid' => $parent_guid, 'author' => $author]); // Send all existing comments and likes to the requesting server - $comments = Post::select(['id', 'uri-id', 'parent-author-network', 'author-network', 'verb', 'gravity'], - ['parent' => $toplevel_parent_item['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]]); + $comments = Post::select( + ['id', 'uri-id', 'parent-author-network', 'author-network', 'verb', 'gravity'], + ['parent' => $toplevel_parent_item['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]] + ); while ($comment = Post::fetch($comments)) { if (($comment['gravity'] == Item::GRAVITY_ACTIVITY) && !in_array($comment['verb'], [Activity::LIKE, Activity::DISLIKE])) { Logger::info('Unsupported activities are not relayed', ['item' => $comment['id'], 'verb' => $comment['verb']]); @@ -2089,7 +2100,7 @@ class Diaspora return false; } - $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? ' ' . XML::unescape($data->last_name) : ''); + $name = XML::unescape($data->first_name) . ((strlen($data->last_name)) ? ' ' . XML::unescape($data->last_name) : ''); $image_url = XML::unescape($data->image_url); $birthday = XML::unescape($data->birthday); $about = Markdown::toBBCode(XML::unescape($data->bio)); @@ -2136,10 +2147,12 @@ class Diaspora $birthday = $contact['bd']; } - $fields = ['name' => $name, 'location' => $location, + $fields = [ + 'name' => $name, 'location' => $location, 'name-date' => DateTimeFormat::utcNow(), 'about' => $about, 'addr' => $author->getAddr(), 'nick' => $author->getUser(), 'keywords' => $keywords, - 'unsearchable' => !$searchable, 'sensitive' => $nsfw]; + 'unsearchable' => !$searchable, 'sensitive' => $nsfw + ]; if (!empty($birthday)) { $fields['bd'] = $birthday; @@ -2249,7 +2262,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Cannot resolve diaspora handle for recipient', ['author' => $author->getAddr(), 'recipient' => $recipient]); return false; } @@ -2426,7 +2439,7 @@ class Diaspora try { $author = DI::dsprContact()->getByAddr($author_uri); - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find details for author', ['author' => $author_uri->getAddr()]); return false; } @@ -2561,7 +2574,7 @@ class Diaspora private static function storePhotoAsMedia(int $uriid, $photo) { // @TODO Need to find object type, roland@f.haeder.net - Logger::debug('photo='.get_class($photo)); + Logger::debug('photo=' . get_class($photo)); $data = []; $data['uri-id'] = $uriid; $data['type'] = Post\Media::IMAGE; @@ -2930,8 +2943,7 @@ class Diaspora try { $target = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr'])); $dest_url = $public_batch ? $target->batch : $target->notify; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { - + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { } if (empty($dest_url)) { @@ -3011,8 +3023,7 @@ class Diaspora if (!empty($contact['addr'])) { try { $pubkey = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr']))->pubKey; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { - + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { } } else { // The "addr" field should always be filled. @@ -3058,8 +3069,10 @@ class Diaspora // If the item belongs to a user, we take this user id. if ($item['uid'] == 0) { // @todo Possibly use an administrator account? - $condition = ['verified' => true, 'blocked' => false, - 'account_removed' => false, 'account_expired' => false, 'account-type' => User::ACCOUNT_TYPE_PERSON]; + $condition = [ + 'verified' => true, 'blocked' => false, + 'account_removed' => false, 'account_expired' => false, 'account-type' => User::ACCOUNT_TYPE_PERSON + ]; $first_user = DBA::selectFirst('user', ['uid'], $condition, ['order' => ['uid']]); $owner = User::getOwnerDataById($first_user['uid']); } else { @@ -3099,7 +3112,7 @@ class Diaspora $old_handle = DI::pConfig()->get($uid, 'system', 'previous_addr'); $profile = self::createProfileData($uid); - $signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; + $signed_text = 'AccountMigration:' . $old_handle . ':' . $profile['author']; $signature = base64_encode(Crypto::rsaSign($signed_text, $owner['uprvkey'], 'sha256')); $message = [ @@ -3388,9 +3401,11 @@ class Diaspora if (count($event)) { $message['event'] = $event; - if (!empty($event['location']['address']) && + if ( + !empty($event['location']['address']) && !empty($event['location']['lat']) && - !empty($event['location']['lng'])) { + !empty($event['location']['lng']) + ) { $message['location'] = $event['location']; } @@ -3453,7 +3468,8 @@ class Diaspora private static function prependParentAuthorMention(string $body, string $profile_url): string { $profile = Contact::getByURL($profile_url, false, ['addr', 'name']); - if (!empty($profile['addr']) + if ( + !empty($profile['addr']) && !strstr($body, $profile['addr']) && !strstr($body, $profile_url) ) { @@ -3908,9 +3924,9 @@ class Diaspora $kw = str_replace(' ', ' ', $kw); $arr = explode(' ', $kw); if (count($arr)) { - for ($x = 0; $x < 5; $x ++) { + for ($x = 0; $x < 5; $x++) { if (!empty($arr[$x])) { - $data['tag_string'] .= '#'. trim($arr[$x]) .' '; + $data['tag_string'] .= '#' . trim($arr[$x]) . ' '; } } } @@ -4095,7 +4111,7 @@ class Diaspora 'body' => '', 'quote-uri-id' => $UriId, 'allow_cid' => $owner['allow_cid'] ?? '', - 'allow_gid' => $owner['allow_gid']?? '', + 'allow_gid' => $owner['allow_gid'] ?? '', 'deny_cid' => $owner['deny_cid'] ?? '', 'deny_gid' => $owner['deny_gid'] ?? '', ]; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index f9ea91c779..a83819742e 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -384,8 +384,10 @@ class Feed } if (!$dryRun) { - $condition = ["`uid` = ? AND `uri` = ? AND `network` IN (?, ?)", - $importer['uid'], $item['uri'], Protocol::FEED, Protocol::DFRN]; + $condition = [ + "`uid` = ? AND `uri` = ? AND `network` IN (?, ?)", + $importer['uid'], $item['uri'], Protocol::FEED, Protocol::DFRN + ]; $previous = Post::selectFirst(['id', 'created'], $condition); if (DBA::isResult($previous)) { // Use the creation date when the post had been stored. It can happen this date changes in the feed. @@ -644,8 +646,10 @@ class Feed if (!$notify) { Post\Delayed::publish($item, $notify, $taglist, $attachments); } else { - $postings[] = ['item' => $item, 'notify' => $notify, - 'taglist' => $taglist, 'attachments' => $attachments]; + $postings[] = [ + 'item' => $item, 'notify' => $notify, + 'taglist' => $taglist, 'attachments' => $attachments + ]; } } else { Logger::info('Post already created or exists in the delayed posts queue', ['uid' => $item['uid'], 'uri' => $item['uri']]); @@ -852,7 +856,7 @@ class Feed $min_poll_interval = max(1, DI::config()->get('system', 'min_poll_interval')); - $poll_intervals = [$min_poll_interval, 15, 30, 60, 120, 180, 360, 720 ,1440, 10080, 43200]; + $poll_intervals = [$min_poll_interval, 15, 30, 60, 120, 180, 360, 720, 1440, 10080, 43200]; //$poll_intervals = [$min_poll_interval . ' minute', '15 minute', '30 minute', // '1 hour', '2 hour', '3 hour', '6 hour', '12 hour' ,'1 day', '1 week', '1 month']; @@ -942,7 +946,7 @@ class Feed $previous_created = $last_update; // Don't cache when the last item was posted less then 15 minutes ago (Cache duration) - if ((time() - strtotime($owner['last-item'])) < 15*60) { + if ((time() - strtotime($owner['last-item'])) < 15 * 60) { $result = DI::cache()->get($cachekey); if (!$nocache && !is_null($result)) { Logger::info('Cached feed duration', ['seconds' => number_format(microtime(true) - $stamp, 3), 'nick' => $owner['nickname'], 'filter' => $filter, 'created' => $previous_created]); @@ -953,11 +957,13 @@ class Feed $check_date = empty($last_update) ? '' : DateTimeFormat::utc($last_update); $authorid = Contact::getIdForURL($owner['url']); - $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) + $condition = [ + "`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?, ?, ?)", $owner['uid'], $check_date, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::PRIVATE, Protocol::ACTIVITYPUB, - Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA]; + Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA + ]; if ($filter === 'comments') { $condition[0] .= " AND `gravity` = ? "; @@ -1130,8 +1136,15 @@ class Feed XML::addElement($doc, $entry, 'content', $body, ['type' => 'html']); - XML::addElement($doc, $entry, 'link', '', ['rel' => 'alternate', 'type' => 'text/html', - 'href' => DI::baseUrl() . '/display/' . $item['guid']] + XML::addElement( + $doc, + $entry, + 'link', + '', + [ + 'rel' => 'alternate', 'type' => 'text/html', + 'href' => DI::baseUrl() . '/display/' . $item['guid'] + ] ); XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); @@ -1173,12 +1186,14 @@ class Feed if (isset($parent_plink)) { $attributes = [ 'ref' => $item['thr-parent'], - 'href' => $parent_plink]; + 'href' => $parent_plink + ]; XML::addElement($doc, $entry, 'thr:in-reply-to', '', $attributes); $attributes = [ 'rel' => 'related', - 'href' => $parent_plink]; + 'href' => $parent_plink + ]; XML::addElement($doc, $entry, 'link', '', $attributes); } } @@ -1220,7 +1235,7 @@ class Feed // Remove the share element before fetching the first line $title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism", "\n$1\n", $item['body'])); - $title = BBCode::toPlaintext($title)."\n"; + $title = BBCode::toPlaintext($title) . "\n"; $pos = strpos($title, "\n"); $trailer = ''; if (($pos == 0) || ($pos > 100)) { From 699be97ea124b0ae974c148ebf5497450a3bca74 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Mar 2023 06:15:30 +0000 Subject: [PATCH 07/16] Reformatted code --- src/Content/Item.php | 19 ++++++------------- src/Content/Text/BBCode.php | 3 +-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Content/Item.php b/src/Content/Item.php index 58fe945d32..25d27b26df 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -223,19 +223,13 @@ class Item // select someone by nick in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = [ - "`nick` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid - ]; + $condition = ['nick' => $name, 'network' => $network, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } // select someone by attag in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = [ - "`attag` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid - ]; + $condition = ['attag' => $name, 'network' => $network, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } @@ -247,13 +241,13 @@ class Item // select someone by nick in any network if (!DBA::isResult($contact)) { - $condition = ["`nick` = ? AND `uid` = ?", $name, $profile_uid]; + $condition = ['nick' => $name, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } // select someone by attag in any network if (!DBA::isResult($contact)) { - $condition = ["`attag` = ? AND `uid` = ?", $name, $profile_uid]; + $condition = ['attag' => $name, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } @@ -339,9 +333,8 @@ class Item default: if ($obj['resource-id']) { $post_type = $this->l10n->t('photo'); - $m = []; - preg_match("/\[url=([^]]*)\]/", $obj['body'], $m); - $rr['plink'] = $m[1]; + preg_match("/\[url=([^]]*)\]/", $obj['body'], $matches); + $rr['plink'] = $matches[1]; } else { $post_type = $this->l10n->t('status'); } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index f072e59c9d..33f91b43d1 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -870,8 +870,7 @@ class BBCode $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); } - $img_str = ' $value) { if (!empty($value)) { $img_str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT) . '"'; From c1686c486c8fcb4f94f89df869ae72509f3583fe Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Mar 2023 06:43:04 +0000 Subject: [PATCH 08/16] Fix warning --- src/Factory/Api/Mastodon/Card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php index f6f6e3b671..c0bad9beb6 100644 --- a/src/Factory/Api/Mastodon/Card.php +++ b/src/Factory/Api/Mastodon/Card.php @@ -40,7 +40,7 @@ class Card extends BaseFactory public function createFromUriId(int $uriId, array $history = []): \Friendica\Object\Api\Mastodon\Card { $media = Post\Media::getByURIId($uriId, [Post\Media::HTML]); - if (empty($media) && empty($media[0]['description']) && !empty($media[0]['image']) && !empty($media[0]['preview'])) { + if (empty($media) || (empty($media[0]['description']) && empty($media[0]['image']) && empty($media[0]['preview']))) { return new \Friendica\Object\Api\Mastodon\Card([], $history); } From e0fe3bf77d33cb589053e9c523fcf33ca3b7ee2d Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 6 Mar 2023 18:00:58 +0000 Subject: [PATCH 09/16] Fix plaintext function by partly reverting function removal --- src/Content/Text/BBCode.php | 177 +++++++++++++++++++++++++++++++++ src/Content/Text/Plaintext.php | 2 +- 2 files changed, 178 insertions(+), 1 deletion(-) diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 33f91b43d1..12fef305b1 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -209,6 +209,183 @@ class BBCode ); } + public static function getAttachedData(string $body, array $item = []): array + { + /* + - text: + - type: link, video, photo + - title: + - url: + - image: + - description: + - (thumbnail) + */ + + DI::profiler()->startRecording('rendering'); + $has_title = !empty($item['title']); + $plink = $item['plink'] ?? ''; + $post = self::getAttachmentData($body); + + // Get all linked images with alternative image description + if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { + foreach ($pictures as $picture) { + if ($id = Photo::getIdForName($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2], 'id' => $id]; + } else { + $post['remote_images'][] = ['url' => $picture[1], 'description' => $picture[2]]; + } + } + if (!empty($post['images']) && !empty($post['images'][0]['description'])) { + $post['image_description'] = $post['images'][0]['description']; + } + } + + if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { + foreach ($pictures as $picture) { + if ($id = Photo::getIdForName($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '', 'id' => $id]; + } else { + $post['remote_images'][] = ['url' => $picture[1], 'description' => '']; + } + } + } + + if (!isset($post['type'])) { + $post['text'] = $body; + } + + // Simplify image codes + $post['text'] = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $post['text']); + $post['text'] = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $post['text']); + + // if nothing is found, it maybe having an image. + if (!isset($post['type'])) { + if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) { + if ((count($pictures) == 1) && !$has_title) { + if (!empty($item['object-type']) && ($item['object-type'] == Activity\ObjectType::IMAGE)) { + // Replace the preview picture with the real picture + $url = str_replace('-1.', '-0.', $pictures[0][2]); + $data = ['url' => $url, 'type' => 'photo']; + } else { + // Checking, if the link goes to a picture + $data = ParseUrl::getSiteinfoCached($pictures[0][1]); + } + + // Workaround: + // Sometimes photo posts to the own album are not detected at the start. + // So we seem to cannot use the cache for these cases. That's strange. + if (($data['type'] != 'photo') && strstr($pictures[0][1], '/photos/')) { + $data = ParseUrl::getSiteinfo($pictures[0][1]); + } + + if ($data['type'] == 'photo') { + $post['type'] = 'photo'; + if (isset($data['images'][0])) { + $post['image'] = $data['images'][0]['src']; + $post['url'] = $data['url']; + } else { + $post['image'] = $data['url']; + } + + $post['preview'] = $pictures[0][2]; + $post['text'] = trim(str_replace($pictures[0][0], '', $post['text'])); + } else { + $imgdata = Images::getInfoFromURLCached($pictures[0][1]); + if (($imgdata) && substr($imgdata['mime'], 0, 6) == 'image/') { + $post['type'] = 'photo'; + $post['image'] = $pictures[0][1]; + $post['preview'] = $pictures[0][2]; + $post['text'] = trim(str_replace($pictures[0][0], '', $post['text'])); + } + } + } elseif (count($pictures) > 0) { + if (count($pictures) > 4) { + $post['type'] = 'link'; + $post['url'] = $plink; + } else { + $post['type'] = 'photo'; + } + + $post['image'] = $pictures[0][2]; + + foreach ($pictures as $picture) { + $post['text'] = trim(str_replace($picture[0], '', $post['text'])); + } + } + } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $post['text'], $pictures, PREG_SET_ORDER)) { + if ($has_title) { + $post['type'] = 'link'; + $post['url'] = $plink; + } else { + $post['type'] = 'photo'; + } + + $post['image'] = $pictures[0][1]; + foreach ($pictures as $picture) { + $post['text'] = trim(str_replace($picture[0], '', $post['text'])); + } + } + + // Test for the external links + preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER); + preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER); + + $links = array_merge($links1, $links2); + + // If there is only a single one, then use it. + // This should cover link posts via API. + if ((count($links) == 1) && !isset($post['preview']) && !$has_title) { + $post['type'] = 'link'; + $post['url'] = $links[0][1]; + } + + // Simplify "video" element + $post['text'] = preg_replace('(\[video.*?\ssrc\s?=\s?([^\s\]]+).*?\].*?\[/video\])ism', '[video]$1[/video]', $post['text']); + + // Now count the number of external media links + preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER); + preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER); + preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER); + preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER); + + // Add them to the other external links + $links = array_merge($links, $links1, $links2, $links3, $links4); + + // Are there more than one? + if (count($links) > 1) { + // The post will be the type "text", which means a blog post + unset($post['type']); + $post['url'] = $plink; + } + + if (!isset($post['type'])) { + $post['type'] = 'text'; + } + + if (($post['type'] == 'photo') && empty($post['images']) && !empty($post['remote_images'])) { + $post['images'] = $post['remote_images']; + $post['image'] = $post['images'][0]['url']; + if (!empty($post['images']) && !empty($post['images'][0]['description'])) { + $post['image_description'] = $post['images'][0]['description']; + } + } + unset($post['remote_images']); + } elseif (isset($post['url']) && ($post['type'] == 'video')) { + $data = ParseUrl::getSiteinfoCached($post['url']); + + if (isset($data['images'][0])) { + $post['image'] = $data['images'][0]['src']; + } + } elseif (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) { + foreach ($pictures as $picture) { + $post['text'] = trim(str_replace($picture[0], '', $post['text'])); + } + } + + DI::profiler()->stopRecording(); + return $post; + } + /** * Remove [attachment] BBCode * diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index 7e3263d127..c72dad2be5 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -132,7 +132,7 @@ class Plaintext $body = BBCode::stripAbstract($body); // At first look at data that is attached via "type-..." stuff - $post = BBCode::getAttachmentData($body, $item); + $post = BBCode::getAttachedData($body, $item); if (($item['title'] != '') && ($post['text'] != '')) { $post['text'] = trim($item['title'] . "\n\n" . $post['text']); From cf3dc9a94fb0e85331cb3431d7a05226fa5d5fcb Mon Sep 17 00:00:00 2001 From: Damian Wajer Date: Tue, 7 Mar 2023 17:57:54 +0100 Subject: [PATCH 10/16] Fix calendar attendance icons --- view/theme/frio/css/style.css | 5 ++++- view/theme/frio/templates/wall_thread.tpl | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index c7adc2c8a9..a12c2ae6a8 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -2038,7 +2038,10 @@ code > .hl-main { .wall-item-responses > div > p { margin: 0; } - +.btn-group-event { + display: flex; + flex-basis: auto; +} /* wall item hover effects */ @media (min-width: 768px) { diff --git a/view/theme/frio/templates/wall_thread.tpl b/view/theme/frio/templates/wall_thread.tpl index 5fda4d2bca..e4f87f940e 100644 --- a/view/theme/frio/templates/wall_thread.tpl +++ b/view/theme/frio/templates/wall_thread.tpl @@ -495,7 +495,7 @@ as the value of $top_child_total (this is done at the end of this file) {{* Event attendance buttons *}} {{if $item.isevent}} -
+
From 51083e9fcfd497e1c4ca8e099f91b677bef0dc06 Mon Sep 17 00:00:00 2001 From: www-data Date: Wed, 8 Mar 2023 05:48:34 +0100 Subject: [PATCH 11/16] fix typo (btn-defaul -> btn-default) --- view/theme/frio/templates/comment_item.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/theme/frio/templates/comment_item.tpl b/view/theme/frio/templates/comment_item.tpl index dc4cd589c8..7bce14ee1b 100644 --- a/view/theme/frio/templates/comment_item.tpl +++ b/view/theme/frio/templates/comment_item.tpl @@ -54,7 +54,7 @@

{{if $preview}} - + {{/if}}

From 0c8923aabdfc09447a4060a6781c76529db506a9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 9 Mar 2023 06:46:14 +0000 Subject: [PATCH 12/16] Use the built in function to create a query string --- src/Security/OAuth1/OAuthUtil.php | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/Security/OAuth1/OAuthUtil.php b/src/Security/OAuth1/OAuthUtil.php index bb78340ea0..bc30c80080 100644 --- a/src/Security/OAuth1/OAuthUtil.php +++ b/src/Security/OAuth1/OAuthUtil.php @@ -154,32 +154,7 @@ class OAuthUtil public static function build_http_query($params) { - if (!$params) return ''; - - // Urlencode both keys and values - $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); - $values = OAuthUtil::urlencode_rfc3986(array_values($params)); - $params = array_combine($keys, $values); - - // Parameters are sorted by name, using lexicographical byte value ordering. - // Ref: Spec: 9.1.1 (1) uksort($params, 'strcmp'); - - $pairs = []; - foreach ($params as $parameter => $value) { - if (is_array($value)) { - // If two or more parameters share the same name, they are sorted by their value - // Ref: Spec: 9.1.1 (1) - natsort($value); - foreach ($value as $duplicate_value) { - $pairs[] = $parameter . '=' . $duplicate_value; - } - } else { - $pairs[] = $parameter . '=' . $value; - } - } - // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) - // Each name-value pair is separated by an '&' character (ASCII code 38) - return implode('&', $pairs); + return http_build_query($params, '', null, PHP_QUERY_RFC3986); } } From a4503601e5216debc28c8363da01a73e21fbdf12 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 9 Mar 2023 07:05:45 +0000 Subject: [PATCH 13/16] Comment readded --- src/Security/OAuth1/OAuthUtil.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Security/OAuth1/OAuthUtil.php b/src/Security/OAuth1/OAuthUtil.php index bc30c80080..2547f09080 100644 --- a/src/Security/OAuth1/OAuthUtil.php +++ b/src/Security/OAuth1/OAuthUtil.php @@ -154,6 +154,8 @@ class OAuthUtil public static function build_http_query($params) { + // Parameters are sorted by name, using lexicographical byte value ordering. + // Ref: Spec: 9.1.1 (1) uksort($params, 'strcmp'); return http_build_query($params, '', null, PHP_QUERY_RFC3986); } From baac993090aef0b25ef996ed6f761fa6eace36fc Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 12 Mar 2023 03:02:46 -0400 Subject: [PATCH 14/16] [Database 1517] Increase the size of the process.hostname field --- database.sql | 4 ++-- doc/database/db_process.md | 2 +- static/dbstructure.config.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/database.sql b/database.sql index ac3eaaf1df..e05a420fa8 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.03-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1516 +-- DB_UPDATE_VERSION 1517 -- ------------------------------------------ @@ -1570,7 +1570,7 @@ CREATE TABLE IF NOT EXISTS `post-user-notification` ( -- CREATE TABLE IF NOT EXISTS `process` ( `pid` int unsigned NOT NULL COMMENT 'The ID of the process', - `hostname` varchar(32) NOT NULL COMMENT 'The name of the host the process is ran on', + `hostname` varchar(255) NOT NULL COMMENT 'The name of the host the process is ran on', `command` varbinary(32) NOT NULL DEFAULT '' COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', PRIMARY KEY(`pid`,`hostname`), diff --git a/doc/database/db_process.md b/doc/database/db_process.md index c0eb75f297..b1a52e01b7 100644 --- a/doc/database/db_process.md +++ b/doc/database/db_process.md @@ -9,7 +9,7 @@ Fields | Field | Description | Type | Null | Key | Default | Extra | | -------- | ------------------------------------------ | ------------- | ---- | --- | ------------------- | ----- | | pid | The ID of the process | int unsigned | NO | PRI | NULL | | -| hostname | The name of the host the process is ran on | varchar(32) | NO | PRI | NULL | | +| hostname | The name of the host the process is ran on | varchar(255) | NO | PRI | NULL | | | command | | varbinary(32) | NO | | | | | created | | datetime | NO | | 0001-01-01 00:00:00 | | diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index cc420a449b..6eaad609ef 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1516); + define('DB_UPDATE_VERSION', 1517); } return [ @@ -1565,7 +1565,7 @@ return [ "comment" => "Currently running system processes", "fields" => [ "pid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => "The ID of the process"], - "hostname" => ["type" => "varchar(32)", "not null" => "1", "primary" => "1", "comment" => "The name of the host the process is ran on"], + "hostname" => ["type" => "varchar(255)", "not null" => "1", "primary" => "1", "comment" => "The name of the host the process is ran on"], "command" => ["type" => "varbinary(32)", "not null" => "1", "default" => "", "comment" => ""], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], ], From a6e9f9c89e7716e969e9958ba761195e3fefb864 Mon Sep 17 00:00:00 2001 From: Hank G Date: Sun, 12 Mar 2023 11:43:59 -0400 Subject: [PATCH 15/16] Apply suggestions from code review Co-authored-by: Hypolite Petovan --- src/Module/Api/Mastodon/Statuses.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index bf5c9aa6a2..64fba420dd 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -78,14 +78,14 @@ class Statuses extends BaseApi $item['language'] = json_encode([$request['language'] => 1]); } - if ($post['gravity'] == 0) { + if ($post['gravity'] == Item::GRAVITY_PARENT) { $item['title'] = $request['friendica']['title'] ?? ''; } $spoiler_text = $request['spoiler_text']; if (!empty($spoiler_text)) { - if (!isset($request['friendica']['title']) && $post['gravity'] == 0 && DI::pConfig()->get($uid, 'system', 'api_spoiler_title', true)) { + if (!isset($request['friendica']['title']) && $post['gravity'] == Item::GRAVITY_PARENT && DI::pConfig()->get($uid, 'system', 'api_spoiler_title', true)) { $item['title'] = $spoiler_text; } else { $item['body'] = '[abstract=' . Protocol::ACTIVITYPUB . ']' . $spoiler_text . "[/abstract]\n" . $item['body']; From 30e18517473b7d4f885a1877bb1a24fecc7c917f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 12 Mar 2023 17:55:57 -0400 Subject: [PATCH 16/16] Cast the base URL as string in /friendica/json - This was causing the data.url key to have no value, which broke the directory integration --- src/Module/Friendica.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Friendica.php b/src/Module/Friendica.php index 2c669e886c..90869878e4 100644 --- a/src/Module/Friendica.php +++ b/src/Module/Friendica.php @@ -172,7 +172,7 @@ class Friendica extends BaseModule $data = [ 'version' => App::VERSION, - 'url' => DI::baseUrl(), + 'url' => (string)DI::baseUrl(), 'addons' => $visible_addons, 'locked_features' => $locked_features, 'explicit_content' => intval($config->get('system', 'explicit_content', 0)),