X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FItem.php;h=3e0faddf75bac667b98427023366150c5b02fc18;hb=0e54d35f6562fb63bcf280a07f07ef90a1d9efca;hp=f6bec1561cb0f0ed0e6e010a74bb1e75f133d73c;hpb=8a9f633ce26d4fcb74557891282572b372d5d223;p=friendica.git diff --git a/src/Model/Item.php b/src/Model/Item.php index f6bec1561c..3e0faddf75 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -159,6 +159,10 @@ class Item $fields['vid'] = Verb::getID($fields['verb']); } + if (!empty($fields['edited'])) { + $previous = Post::selectFirst(['edited'], $condition); + } + $rows = Post::update($fields, $condition); if (is_bool($rows)) { return $rows; @@ -203,8 +207,8 @@ class Item } // We only need to notfiy others when it is an original entry from us. - // Only call the notifier when the item has some content relevant change. - if ($item['origin'] && in_array('edited', array_keys($fields))) { + // Only call the notifier when the item had been edited and records had been changed. + if ($item['origin'] && !empty($fields['edited']) && ($previous['edited'] != $fields['edited'])) { $notify_items[] = $item['id']; } } @@ -359,7 +363,7 @@ class Item return true; } - private static function guid($item, $notify) + public static function guid($item, $notify) { if (!empty($item['guid'])) { return Strings::escapeTags(trim($item['guid'])); @@ -464,18 +468,14 @@ class Item // Checking if there is already an item with the same guid $condition = ['guid' => $item['guid'], 'network' => $item['network'], 'uid' => $item['uid']]; if (Post::exists($condition)) { - Logger::notice('Found already existing item', [ - 'guid' => $item['guid'], - 'uid' => $item['uid'], - 'network' => $item['network'] - ]); + Logger::notice('Found already existing item', $condition); return true; } $condition = ['uri-id' => $item['uri-id'], 'uid' => $item['uid'], 'network' => [$item['network'], Protocol::DFRN]]; if (Post::exists($condition)) { - Logger::notice('duplicated item with the same uri found.', $item); + Logger::notice('duplicated item with the same uri found.', $condition); return true; } @@ -483,7 +483,7 @@ class Item if (in_array($item['network'], [Protocol::DFRN, Protocol::DIASPORA])) { $condition = ['guid' => $item['guid'], 'uid' => $item['uid']]; if (Post::exists($condition)) { - Logger::notice('duplicated item with the same guid found.', $item); + Logger::notice('duplicated item with the same guid found.', $condition); return true; } } elseif ($item['network'] == Protocol::OSTATUS) { @@ -518,7 +518,7 @@ class Item public static function isValid(array $item) { // When there is no content then we don't post it - if (($item['body'] . $item['title'] == '') && !Post\Media::existsByURIId($item['uri-id'])) { + if (($item['body'] . $item['title'] == '') && (empty($item['uri-id']) || !Post\Media::existsByURIId($item['uri-id']))) { Logger::notice('No body, no title.'); return false; } @@ -1004,9 +1004,6 @@ class Item // Check for hashtags in the body and repair or add hashtag links $item['body'] = self::setHashtags($item['body']); - // Fill the cache field - self::putInCache($item); - if (stristr($item['verb'], Activity::POKE)) { $notify_type = Delivery::POKE; } else { @@ -1032,17 +1029,19 @@ class Item $ev['guid'] = $item['guid']; $ev['plink'] = $item['plink']; $ev['network'] = $item['network']; - $ev['protocol'] = $item['protocol']; - $ev['direction'] = $item['direction']; - $ev['source'] = $item['source']; + $ev['protocol'] = $item['protocol'] ?? Conversation::PARCEL_UNKNOWN; + $ev['direction'] = $item['direction'] ?? Conversation::UNKNOWN; + $ev['source'] = $item['source'] ?? ''; $event = DBA::selectFirst('event', ['id'], ['uri' => $item['uri'], 'uid' => $item['uid']]); if (DBA::isResult($event)) { $ev['id'] = $event['id']; } - $item['event-id'] = Event::store($ev); - Logger::info('Event was stored', ['id' => $item['event-id']]); + $event_id = Event::store($ev); + $item = Event::getItemArrayForId($event_id, $item); + + Logger::info('Event was stored', ['id' => $event_id]); } } @@ -1062,7 +1061,7 @@ class Item // Create Diaspora signature if ($item['origin'] && empty($item['diaspora_signed_text']) && ($item['gravity'] != GRAVITY_PARENT)) { - $signed = Diaspora::createCommentSignature($uid, $item); + $signed = Diaspora::createCommentSignature($item); if (!empty($signed)) { $item['diaspora_signed_text'] = json_encode($signed); } @@ -1144,6 +1143,9 @@ class Item if (!$dontcache) { if ($notify) { + if (!\Friendica\Content\Feature::isEnabled($posted_item['uid'], 'explicit_mentions') && ($posted_item['gravity'] == GRAVITY_COMMENT)) { + Tag::createImplicitMentions($posted_item['uri-id'], $posted_item['thr-parent-id']); + } Hook::callAll('post_local_end', $posted_item); } else { Hook::callAll('post_remote_end', $posted_item); @@ -1639,7 +1641,13 @@ class Item return ''; } - $ld = new Language(DI::l10n()->getAvailableLanguages()); + $availableLanguages = DI::l10n()->getAvailableLanguages(); + // See https://github.com/friendica/friendica/issues/10511 + // Persian is manually added to language detection until a persian translation is provided for the interface, at + // which point it will be automatically available through `getAvailableLanguages()` and this should be removed. + $availableLanguages['fa'] = 'fa'; + + $ld = new Language($availableLanguages); $languages = $ld->detect($naked_body)->limit(0, 3)->close(); if (is_array($languages)) { return json_encode($languages); @@ -1909,6 +1917,15 @@ class Item return false; } + self::performActivity($item['id'], 'announce', $uid); + + /** + * All the following lines are only needed for private forums and compatibility to older systems without AP support. + * A possible way would be that the followers list of a forum would always be readable by all followers. + * So this would mean that the comment distribution could be done exactly for the intended audience. + * Or possibly we could store the receivers that had been in the "announce" message above and use this. + */ + // now change this copy of the post to a forum head message and deliver to all the tgroup members $self = DBA::selectFirst('contact', ['id', 'name', 'url', 'thumb'], ['uid' => $uid, 'self' => true]); if (!DBA::isResult($self)) { @@ -1918,8 +1935,13 @@ class Item $owner_id = Contact::getIdForURL($self['url']); // also reset all the privacy bits to the forum default permissions - - $private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? self::PRIVATE : self::PUBLIC; + if ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) { + $private = self::PRIVATE; + } elseif (DI::pConfig()->get($user['uid'], 'system', 'unlisted')) { + $private = self::UNLISTED; + } else { + $private = self::PUBLIC; + } $psid = PermissionSet::getIdFromACL( $user['uid'], @@ -1937,8 +1959,6 @@ class Item Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']); - self::performActivity($item['id'], 'announce', $uid); - return false; } @@ -2627,7 +2647,7 @@ class Item ) { self::addRedirToImageTags($item); - $item['rendered-html'] = BBCode::convert($item['body']); + $item['rendered-html'] = BBCode::convertForUriId($item['uri-id'], $item['body']); $item['rendered-hash'] = hash('md5', BBCode::VERSION . '::' . $body); $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; @@ -2668,7 +2688,7 @@ class Item continue; } - if ((local_user() == $item['uid']) && ($item['private'] == self::PRIVATE) && ($item['contact-id'] != $app->contact['id']) && ($item['network'] == Protocol::DFRN)) { + if ((local_user() == $item['uid']) && ($item['private'] == self::PRIVATE) && ($item['contact-id'] != $app->getContactId()) && ($item['network'] == Protocol::DFRN)) { $img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]); $item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']); } @@ -2709,6 +2729,29 @@ class Item $item['hashtags'] = $tags['hashtags']; $item['mentions'] = $tags['mentions']; + $body = $item['body'] ?? ''; + $shared = BBCode::fetchShareAttributes($body); + if (!empty($shared['guid'])) { + $shared_item = Post::selectFirst(['uri-id', 'plink'], ['guid' => $shared['guid']]); + $shared_uri_id = $shared_item['uri-id'] ?? 0; + $shared_links = [strtolower($shared_item['plink'] ?? '')]; + $shared_attachments = Post\Media::splitAttachments($shared_uri_id, $shared['guid']); + $shared_links = array_merge($shared_links, array_column($shared_attachments['visual'], 'url')); + $shared_links = array_merge($shared_links, array_column($shared_attachments['link'], 'url')); + $shared_links = array_merge($shared_links, array_column($shared_attachments['additional'], 'url')); + $item['body'] = self::replaceVisualAttachments($shared_attachments, $item['body']); + } else { + $shared_uri_id = 0; + $shared_links = []; + } + $attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links); + $item['body'] = self::replaceVisualAttachments($attachments, $item['body'] ?? ''); + + $item['body'] = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", "\n", $item['body']); + self::putInCache($item); + $item['body'] = $body; + $s = $item["rendered-html"]; + // Compile eventual content filter reasons $filter_reasons = []; if (!$is_preview && public_contact() != $item['author-id']) { @@ -2725,12 +2768,6 @@ class Item unset($hook_data); } - $body = $item['body'] ?? ''; - $item['body'] = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", "\n", $item['body']); - self::putInCache($item); - $item['body'] = $body; - $s = $item["rendered-html"]; - $hook_data = [ 'item' => $item, 'html' => $s, @@ -2748,27 +2785,15 @@ class Item return $s; } - $shared = BBCode::fetchShareAttributes($item['body']); - if (!empty($shared['guid'])) { - $shared_item = Post::selectFirst(['uri-id', 'plink'], ['guid' => $shared['guid']]); - $shared_uri_id = $shared_item['uri-id'] ?? 0; - $shared_links = [strtolower($shared_item['plink'] ?? '')]; - $attachments = Post\Media::splitAttachments($shared_uri_id, $shared['guid']); - $s = self::addVisualAttachments($attachments, $item, $s, true); - $s = self::addLinkAttachment($attachments, $body, $s, true, []); - $s = self::addNonVisualAttachments($attachments, $item, $s, true); - $shared_links = array_merge($shared_links, array_column($attachments['visual'], 'url')); - $shared_links = array_merge($shared_links, array_column($attachments['link'], 'url')); - $shared_links = array_merge($shared_links, array_column($attachments['additional'], 'url')); + if (!empty($shared_attachments)) { + $s = self::addVisualAttachments($shared_attachments, $item, $s, true); + $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, []); + $s = self::addNonVisualAttachments($shared_attachments, $item, $s, true); $body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); - } else { - $shared_uri_id = 0; - $shared_links = []; } - $attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links); $s = self::addVisualAttachments($attachments, $item, $s, false); - $s = self::addLinkAttachment($attachments, $body, $s, false, $shared_links); + $s = self::addLinkAttachment($item['uri-id'], $attachments, $body, $s, false, $shared_links); $s = self::addNonVisualAttachments($attachments, $item, $s, false); // Map. @@ -2780,8 +2805,8 @@ class Item } // Replace friendica image url size with theme preference. - if (!empty($a->theme_info['item_image_size'])) { - $ps = $a->theme_info['item_image_size']; + if (!empty($a->getThemeInfoValue('item_image_size'))) { + $ps = $a->getThemeInfoValue('item_image_size'); $s = preg_replace('|(]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s); } @@ -2827,6 +2852,28 @@ class Item return false; } + /** + * Replace visual attachments in the body + * + * @param array $attachments + * @param string $body + * @return string modified body + */ + private static function replaceVisualAttachments(array $attachments, string $body) + { + DI::profiler()->startRecording('rendering'); + + foreach ($attachments['visual'] as $attachment) { + if (!empty($attachment['preview'])) { + $body = str_replace($attachment['preview'], Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_LARGE), $body); + } elseif ($attachment['filetype'] == 'image') { + $body = str_replace($attachment['url'], Post\Media::getUrlForId($attachment['id']), $body); + } + } + DI::profiler()->stopRecording(); + return $body; + } + /** * Add visual attachments to the content * @@ -2837,22 +2884,18 @@ class Item */ private static function addVisualAttachments(array $attachments, array $item, string $content, bool $shared) { - $stamp1 = microtime(true); + DI::profiler()->startRecording('rendering'); $leading = ''; $trailing = ''; // @todo In the future we should make a single for the template engine with all media in it. This allows more flexibilty. foreach ($attachments['visual'] as $attachment) { - if (self::containsLink($item['body'], $attachment['url'], $attachment['type'])) { + if (self::containsLink($item['body'], $attachment['preview'] ?? $attachment['url'], $attachment['type'])) { continue; } - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; - $the_url = Contact::magicLinkByContact($author, $attachment['url']); - if (!empty($attachment['preview'])) { - $preview_url = Proxy::proxifyUrl(Contact::magicLinkByContact($author, $attachment['preview'])); + $preview_url = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_LARGE); } else { $preview_url = ''; } @@ -2862,7 +2905,7 @@ class Item $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [ '$video' => [ 'id' => $attachment['id'], - 'src' => $the_url, + 'src' => $attachment['url'], 'name' => $attachment['name'] ?: $attachment['url'], 'preview' => $preview_url, 'mime' => $attachment['mimetype'], @@ -2877,8 +2920,8 @@ class Item $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/audio.tpl'), [ '$audio' => [ 'id' => $attachment['id'], - 'src' => $the_url, - 'name' => $attachment['name'] ?: $attachment['url'], + 'src' => $attachment['url'], + 'name' => $attachment['name'] ?: $attachment['url'], 'mime' => $attachment['mimetype'], ], ]); @@ -2888,14 +2931,11 @@ class Item $trailing .= $media; } } elseif ($attachment['filetype'] == 'image') { - if (empty($preview_url) && (max($attachment['width'], $attachment['height']) > 600)) { - $preview_url = Proxy::proxifyUrl($the_url, false, ($attachment['width'] > $attachment['height']) ? Proxy::SIZE_MEDIUM : Proxy::SIZE_LARGE); - } $media = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image.tpl'), [ '$image' => [ - 'src' => Proxy::proxifyUrl($the_url), - 'preview' => $preview_url, - 'attachment' => $attachment, + 'src' => Post\Media::getUrlForId($attachment['id']), + 'preview' => Post\Media::getPreviewUrlForId($attachment['id'], ($attachment['width'] > $attachment['height']) ? Proxy::SIZE_MEDIUM : Proxy::SIZE_LARGE), + 'attachment' => $attachment, ], ]); // On Diaspora posts the attached pictures are leading @@ -2920,7 +2960,7 @@ class Item } } - DI::profiler()->saveTimestamp($stamp1, 'rendering'); + DI::profiler()->stopRecording(); return $content; } @@ -2934,9 +2974,9 @@ class Item * @param array $ignore_links A list of URLs to ignore * @return string modified content */ - private static function addLinkAttachment(array $attachments, string $body, string $content, bool $shared, array $ignore_links) + private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links) { - $stamp1 = microtime(true); + DI::profiler()->startRecording('rendering'); // @ToDo Check only for audio and video $preview = empty($attachments['visual']); @@ -2973,11 +3013,11 @@ class Item 'type' => 'link', 'url' => $attachment['url']]; - if ($preview) { + if ($preview && !empty($attachment['preview'])) { if ($attachment['preview-width'] >= 500) { - $data['image'] = $attachment['preview'] ?? ''; + $data['image'] = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_MEDIUM); } else { - $data['preview'] = $attachment['preview'] ?? ''; + $data['preview'] = Post\Media::getPreviewUrlForId($attachment['id'], Proxy::SIZE_MEDIUM); } } @@ -3001,7 +3041,7 @@ class Item } elseif (preg_match("/.*(\[attachment.*?\].*?\[\/attachment\]).*/ism", $body, $match)) { $data = BBCode::getAttachmentData($match[1]); } - DI::profiler()->saveTimestamp($stamp1, 'rendering'); + DI::profiler()->stopRecording(); if (isset($data['url']) && !in_array($data['url'], $ignore_links)) { if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview'])) { @@ -3020,7 +3060,7 @@ class Item } // @todo Use a template - $rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data); + $rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data, $uriid); } elseif (!self::containsLink($content, $data['url'], Post\Media::HTML)) { $rendered = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/link.tpl'), [ '$url' => $data['url'], @@ -3049,7 +3089,7 @@ class Item */ private static function addNonVisualAttachments(array $attachments, array $item, string $content) { - $stamp1 = microtime(true); + DI::profiler()->startRecording('rendering'); $trailing = ''; foreach ($attachments['additional'] as $attachment) { if (strpos($item['body'], $attachment['url'])) { @@ -3075,7 +3115,7 @@ class Item $content .= '
' . $trailing . '
'; } - DI::profiler()->saveTimestamp($stamp1, 'rendering'); + DI::profiler()->stopRecording(); return $content; }