namespace Friendica\Model;
-use Friendica\BaseObject;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
-use Friendica\Core\Config;
use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\Lock;
use Friendica\Core\Logger;
-use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
+use Friendica\DI;
use Friendica\Protocol\Activity;
use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
-use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Map;
use Friendica\Util\Network;
use Friendica\Worker\Delivery;
use Text_LanguageDetect;
-class Item extends BaseObject
+class Item
{
// Posting types, inspired by https://www.w3.org/TR/activitystreams-vocabulary/#object-types
const PT_ARTICLE = 0;
public static function isLegacyMode()
{
if (is_null(self::$legacy_mode)) {
- self::$legacy_mode = (Config::get("system", "post_update_version") < 1279);
+ self::$legacy_mode = (DI::config()->get("system", "post_update_version") < 1279);
}
return self::$legacy_mode;
return (bool)$useritem['pinned'];
}
- public static function selectPinned(int $uid, array $selected = [])
+ /**
+ * Select pinned rows from the item table for a given user
+ *
+ * @param integer $uid User ID
+ * @param array $selected Array of selected fields, empty for all
+ * @param array $condition Array of fields for condition
+ * @param array $params Array of several parameters
+ *
+ * @return boolean|object
+ * @throws \Exception
+ */
+ public static function selectPinned(int $uid, array $selected = [], array $condition = [], $params = [])
{
$useritems = DBA::select('user-item', ['iid'], ['uid' => $uid, 'pinned' => true]);
if (!DBA::isResult($useritems)) {
}
DBA::close($useritems);
- return self::selectThreadForUser($uid, $selected, ['iid' => $pinned]);
+ if (empty($pinned)) {
+ return [];
+ }
+
+ if (empty($condition) || !is_array($condition)) {
+ $condition = ['iid' => $pinned];
+ } else {
+ reset($condition);
+ $first_key = key($condition);
+ if (!is_int($first_key)) {
+ $condition['iid'] = $pinned;
+ } else {
+ $values_string = substr(str_repeat("?, ", count($pinned)), 0, -2);
+ $condition[0] = '(' . $condition[0] . ") AND `iid` IN (" . $values_string . ")";
+ $condition = array_merge($condition, $pinned);
+ }
+ }
+
+ return self::selectThreadForUser($uid, $selected, $condition, $params);
}
/**
- * @brief returns an activity index from an activity string
+ * returns an activity index from an activity string
*
* @param string $activity activity string
* @return integer Activity index
}
/**
- * @brief returns an activity string from an activity index
+ * returns an activity string from an activity index
*
* @param integer $index activity index
* @return string Activity string
}
/**
- * @brief Fetch a single item row
+ * Fetch a single item row
*
* @param mixed $stmt statement object
* @return array current row
$row['object-type'] = Activity\ObjectType::NOTE;
}
} elseif (array_key_exists('verb', $row) && in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) {
- // Posts don't have an object or target - but having tags or files.
+ // Posts don't have a target - but having tags or files.
// We safe some performance by building tag and file strings only here.
- // We remove object and target since they aren't used for this type.
- if (array_key_exists('object', $row)) {
- $row['object'] = '';
- }
+ // We remove the target since they aren't used for this type.
+ // In mail posts we do store some mail header data in the object.
if (array_key_exists('target', $row)) {
$row['target'] = '';
}
}
/**
- * @brief Fills an array with data from an item query
+ * Fills an array with data from an item query
*
* @param object $stmt statement object
* @param bool $do_close
}
/**
- * @brief Check if item data exists
+ * Check if item data exists
*
* @param array $condition array of fields for condition
*
/**
* Retrieve a single record from the item table for a given user and returns it in an associative array
*
- * @brief Retrieve a single record from a table
* @param integer $uid User ID
* @param array $selected
* @param array $condition
}
/**
- * @brief Select rows from the item table for a given user
+ * Select rows from the item table for a given user
*
* @param integer $uid User ID
* @param array $selected Array of selected fields, empty for all
/**
* Retrieve a single record from the item table and returns it in an associative array
*
- * @brief Retrieve a single record from a table
* @param array $fields
* @param array $condition
* @param array $params
}
/**
- * @brief Select rows from the item table and returns them as an array
+ * Select rows from the item table and returns them as an array
*
* @param array $selected Array of selected fields, empty for all
* @param array $condition Array of fields for condition
}
/**
- * @brief Select rows from the item table
+ * Select rows from the item table
*
* @param array $selected Array of selected fields, empty for all
* @param array $condition Array of fields for condition
}
/**
- * @brief Select rows from the starting post in the item table
+ * Select rows from the starting post in the item table
*
* @param integer $uid User ID
* @param array $selected
/**
* Retrieve a single record from the starting post in the item table and returns it in an associative array
*
- * @brief Retrieve a single record from a table
* @param integer $uid User ID
* @param array $selected
* @param array $condition
/**
* Retrieve a single record from the starting post in the item table and returns it in an associative array
*
- * @brief Retrieve a single record from a table
* @param array $fields
* @param array $condition
* @param array $params
}
/**
- * @brief Select rows from the starting post in the item table
+ * Select rows from the starting post in the item table
*
* @param array $selected Array of selected fields, empty for all
* @param array $condition Array of fields for condition
}
/**
- * @brief Returns a list of fields that are associated with the item table
+ * Returns a list of fields that are associated with the item table
*
* @param $usermode
* @return array field list
'iaid' => 'internal-iaid'];
if ($usermode) {
- $fields['user-item'] = ['pinned', 'ignored' => 'internal-user-ignored'];
+ $fields['user-item'] = ['pinned', 'notification-type', 'ignored' => 'internal-user-ignored'];
}
$fields['item-activity'] = ['activity', 'activity' => 'internal-activity'];
}
/**
- * @brief Returns SQL condition for the "select" functions
+ * Returns SQL condition for the "select" functions
*
* @param boolean $thread_mode Called for the items (false) or for the threads (true)
*
}
/**
- * @brief Returns all needed "JOIN" commands for the "select" functions
+ * Returns all needed "JOIN" commands for the "select" functions
*
* @param integer $uid User ID
* @param string $sql_commands The parts of the built SQL commands in the "select" functions
}
/**
- * @brief Add the field list for the "select" functions
+ * Add the field list for the "select" functions
*
* @param array $fields The field definition array
* @param array $selected The array with the selected fields from the "select" functions
}
/**
- * @brief add table definition to fields in an SQL query
+ * add table definition to fields in an SQL query
*
* @param string $query SQL query
* @param array $fields The field definition array
}
/**
- * @brief Update existing item entries
+ * Update existing item entries
*
* @param array $fields The fields that are to be changed
* @param array $condition The condition for finding the item entries
}
/**
- * @brief Delete an item and notify others about it - if it was ours
+ * Delete an item and notify others about it - if it was ours
*
* @param array $condition The condition for finding the item entries
* @param integer $priority Priority for the notification
}
/**
- * @brief Delete an item for an user and notify others about it - if it was ours
+ * Delete an item for an user and notify others about it - if it was ours
*
* @param array $condition The condition for finding the item entries
* @param integer $uid User who wants to delete this item
// "Deleting" global items just means hiding them
if ($item['uid'] == 0) {
DBA::update('user-item', ['hidden' => true], ['iid' => $item['id'], 'uid' => $uid], true);
+
+ // Delete notifications
+ DBA::delete('notify', ['iid' => $item['id'], 'uid' => $uid]);
} elseif ($item['uid'] == $uid) {
self::deleteById($item['id'], PRIORITY_HIGH);
} else {
}
/**
- * @brief Delete an item and notify others about it - if it was ours
+ * Delete an item and notify others about it - if it was ours
*
* @param integer $item_id Item ID that should be delete
* @param integer $priority Priority for the notification
// Delete tags that had been attached to other items
self::deleteTagsFromItem($item);
+ // Delete notifications
+ DBA::delete('notify', ['iid' => $item['id'], 'uid' => $item['uid']]);
+
// Set the item to "deleted"
$item_fields = ['deleted' => true, 'edited' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()];
DBA::update('item', $item_fields, ['id' => $item['id']]);
if ($notify) {
// We have to avoid duplicates. So we create the GUID in form of a hash of the plink or uri.
// We add the hash of our own host because our host is the original creator of the post.
- $prefix_host = \get_app()->getHostName();
+ $prefix_host = DI::baseUrl()->getHostname();
} else {
$prefix_host = '';
$item['parent-uri'] = $item['thr-parent'];
}
- /** @var Activity $activity */
- $activity = self::getClass(Activity::class);
+ $activity = DI::activity();
if (isset($item['gravity'])) {
$item['gravity'] = intval($item['gravity']);
$uid = intval($item['uid']);
// check for create date and expire time
- $expire_interval = Config::get('system', 'dbclean-expire-days', 0);
+ $expire_interval = DI::config()->get('system', 'dbclean-expire-days', 0);
$user = DBA::selectFirst('user', ['expire'], ['uid' => $uid]);
if (DBA::isResult($user) && ($user['expire'] > 0) && (($user['expire'] < $expire_interval) || ($expire_interval == 0))) {
$item['edited'] = DateTimeFormat::utcNow();
}
- $item['plink'] = ($item['plink'] ?? '') ?: System::baseUrl() . '/display/' . urlencode($item['guid']);
+ $item['plink'] = ($item['plink'] ?? '') ?: DI::baseUrl() . '/display/' . urlencode($item['guid']);
$default = ['url' => $item['author-link'], 'name' => $item['author-name'],
'photo' => $item['author-avatar'], 'network' => $item['network']];
}
// Creates or assigns the permission set
- $item['psid'] = PermissionSet::fetchIDForPost($item);
+ $item['psid'] = PermissionSet::getIdFromACL(
+ $item['uid'],
+ $item['allow_cid'],
+ $item['allow_gid'],
+ $item['deny_cid'],
+ $item['deny_gid']
+ );
+
+ $item['allow_cid'] = null;
+ $item['allow_gid'] = null;
+ $item['deny_cid'] = null;
+ $item['deny_gid'] = null;
// We are doing this outside of the transaction to avoid timing problems
if (!self::insertActivity($item)) {
unset($item['owner-name']);
unset($item['owner-avatar']);
- $like_no_comment = Config::get('system', 'like_no_comment');
+ $like_no_comment = DI::config()->get('system', 'like_no_comment');
DBA::transaction();
$ret = DBA::insert('item', $item);
self::updateContact($item);
+ UserItem::setNotification($current_post);
+
check_user_notification($current_post);
if ($notify || ($item['visible'] && ((!empty($parent) && $parent['origin']) || $item['origin']))) {
}
/**
- * @brief Insert a new item content entry
+ * Insert a new item content entry
*
* @param array $item The item fields that are to be inserted
* @return bool
}
// To avoid timing problems, we are using locks.
- $locked = Lock::acquire('item_insert_activity');
+ $locked = DI::lock()->acquire('item_insert_activity');
if (!$locked) {
Logger::log("Couldn't acquire lock for URI " . $item['uri'] . " - proceeding anyway.");
}
} else {
// This shouldn't happen.
Logger::log('Could not insert activity for URI ' . $item['uri'] . ' - should not happen');
- Lock::release('item_insert_activity');
+ DI::lock()->release('item_insert_activity');
return false;
}
if ($locked) {
- Lock::release('item_insert_activity');
+ DI::lock()->release('item_insert_activity');
}
return true;
}
/**
- * @brief Insert a new item content entry
+ * Insert a new item content entry
*
* @param array $item The item fields that are to be inserted
* @throws \Exception
}
// To avoid timing problems, we are using locks.
- $locked = Lock::acquire('item_insert_content');
+ $locked = DI::lock()->acquire('item_insert_content');
if (!$locked) {
Logger::log("Couldn't acquire lock for URI " . $item['uri'] . " - proceeding anyway.");
}
Logger::log('Could not insert content for URI ' . $item['uri'] . ' - should not happen');
}
if ($locked) {
- Lock::release('item_insert_content');
+ DI::lock()->release('item_insert_content');
}
}
/**
- * @brief Update existing item content entries
+ * Update existing item content entries
*
* @param array $item The item fields that are to be changed
* @param array $condition The condition for finding the item content entries
}
/**
- * @brief Update existing item content entries
+ * Update existing item content entries
*
* @param array $item The item fields that are to be changed
* @param array $condition The condition for finding the item content entries
}
/**
- * @brief Distributes public items to the receivers
+ * Distributes public items to the receivers
*
* @param integer $itemid Item ID that should be added
* @param string $signed_text Original text (for Diaspora signatures), JSON encoded.
}
/**
- * @brief Store public items for the receivers
+ * Store public items for the receivers
*
* @param integer $itemid Item ID that should be added
* @param array $item The item entry that will be stored
}
/**
- * @brief Add a shadow entry for a given item id that is a thread starter
+ * Add a shadow entry for a given item id that is a thread starter
*
* We store every public item entry additionally with the user id "0".
* This is used for the community page and for the search.
}
/**
- * @brief Add a shadow entry for a given item id that is a comment
+ * Add a shadow entry for a given item id that is a comment
*
* This function does the same like the function above - but for comments
*
}
/**
- * @brief Creates an unique guid out of a given uri
+ * Creates an unique guid out of a given uri
*
* @param string $uri uri of an item entry
* @param string $host hostname for the GUID prefix
$guid = System::createUUID();
}
- return self::getApp()->getBaseURL() . '/objects/' . $guid;
+ return DI::baseUrl()->get() . '/objects/' . $guid;
}
/**
- * @brief Set "success_update" and "last-item" to the date of the last time we heard from this contact
+ * Set "success_update" and "last-item" to the date of the last time we heard from this contact
*
* This can be used to filter for inactive contacts.
* Only do this for public postings to avoid privacy problems, since poco data is public.
$URLSearchString = "^\[\]";
// All hashtags should point to the home server if "local_tags" is activated
- if (Config::get('system', 'local_tags')) {
+ if (DI::config()->get('system', 'local_tags')) {
$item["body"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
- "#[url=".System::baseUrl()."/search?tag=$2]$2[/url]", $item["body"]);
+ "#[url=".DI::baseUrl()."/search?tag=$2]$2[/url]", $item["body"]);
$item["tag"] = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
- "#[url=".System::baseUrl()."/search?tag=$2]$2[/url]", $item["tag"]);
+ "#[url=".DI::baseUrl()."/search?tag=$2]$2[/url]", $item["tag"]);
}
// mask hashtags inside of url, bookmarks and attachments to avoid urls in urls
"#$2", $item["body"]);
foreach ($tags as $tag) {
- if ((strpos($tag, '#') !== 0) || strpos($tag, '[url=') || $tag[1] == '#') {
+ if ((strpos($tag, '#') !== 0) || strpos($tag, '[url=') || strlen($tag) < 2 || $tag[1] == '#') {
continue;
}
$basetag = str_replace('_',' ',substr($tag,1));
- $newtag = '#[url=' . System::baseUrl() . '/search?tag=' . $basetag . ']' . $basetag . '[/url]';
+ $newtag = '#[url=' . DI::baseUrl() . '/search?tag=' . $basetag . ']' . $basetag . '[/url]';
$item["body"] = str_replace($tag, $newtag, $item["body"]);
return false;
}
- $link = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']);
+ $link = Strings::normaliseLink(DI::baseUrl() . '/profile/' . $user['nickname']);
/*
* Diaspora uses their own hardwired link URL in @-tags
* instead of the one we supply with webfinger
*/
- $dlink = Strings::normaliseLink(System::baseUrl() . '/u/' . $user['nickname']);
+ $dlink = Strings::normaliseLink(DI::baseUrl() . '/u/' . $user['nickname']);
$cnt = preg_match_all('/[\@\!]\[url\=(.*?)\](.*?)\[\/url\]/ism', $item['body'], $matches, PREG_SET_ORDER);
if ($cnt) {
$private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? 1 : 0;
- $psid = PermissionSet::fetchIDForPost($user);
+ $psid = PermissionSet::getIdFromACL(
+ $user['uid'],
+ $user['allow_cid'],
+ $user['allow_gid'],
+ $user['deny_cid'],
+ $user['deny_gid']
+ );
$forum_mode = ($prvgroup ? 2 : 1);
public static function isRemoteSelf($contact, &$datarray)
{
- $a = \get_app();
-
if (!$contact['remote_self']) {
return false;
}
}
// Prevent to forward already forwarded posts
- if ($datarray["app"] == $a->getHostName()) {
+ if ($datarray["app"] == DI::baseUrl()->getHostname()) {
Logger::log('Already forwarded (second test)', Logger::DEBUG);
return false;
}
*/
public static function fixPrivatePhotos($s, $uid, $item = null, $cid = 0)
{
- if (Config::get('system', 'disable_embedded')) {
+ if (DI::config()->get('system', 'disable_embedded')) {
return $s;
}
Logger::log('check for photos', Logger::DEBUG);
- $site = substr(System::baseUrl(), strpos(System::baseUrl(), '://'));
+ $site = substr(DI::baseUrl(), strpos(DI::baseUrl(), '://'));
$orig_body = $s;
$new_body = '';
*/
public static function enumeratePermissions(array $obj, bool $check_dead = false)
{
- /** @var ACLFormatter $aclFormater */
- $aclFormater = self::getClass(ACLFormatter::class);
+ $aclFormater = DI::aclFormatter();
$allow_people = $aclFormater->expand($obj['allow_cid']);
$allow_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['allow_gid']), $check_dead);
* $expire_network_only = save your own wall posts
* and just expire conversations started by others
*/
- $expire_network_only = PConfig::get($uid, 'expire', 'network_only', false);
+ $expire_network_only = DI::pConfig()->get($uid, 'expire', 'network_only', false);
if ($expire_network_only) {
$condition[0] .= " AND NOT `wall`";
return;
}
- $expire_items = PConfig::get($uid, 'expire', 'items', true);
+ $expire_items = DI::pConfig()->get($uid, 'expire', 'items', true);
// Forcing expiring of items - but not notes and marked items
if ($force) {
$expire_items = true;
}
- $expire_notes = PConfig::get($uid, 'expire', 'notes', true);
- $expire_starred = PConfig::get($uid, 'expire', 'starred', true);
- $expire_photos = PConfig::get($uid, 'expire', 'photos', false);
+ $expire_notes = DI::pConfig()->get($uid, 'expire', 'notes', true);
+ $expire_starred = DI::pConfig()->get($uid, 'expire', 'starred', true);
+ $expire_photos = DI::pConfig()->get($uid, 'expire', 'photos', false);
$expired = 0;
}
/**
- * @brief add/remove activity to an item
+ * add/remove activity to an item
*
* Toggle activities as like,dislike,attend of an item
*
public static function postType($item)
{
if (!empty($item['event-id'])) {
- return L10n::t('event');
+ return DI::l10n()->t('event');
} elseif (!empty($item['resource-id'])) {
- return L10n::t('photo');
+ return DI::l10n()->t('photo');
} elseif (!empty($item['verb']) && $item['verb'] !== Activity::POST) {
- return L10n::t('activity');
+ return DI::l10n()->t('activity');
} elseif ($item['id'] != $item['parent']) {
- return L10n::t('comment');
+ return DI::l10n()->t('comment');
}
- return L10n::t('post');
+ return DI::l10n()->t('post');
}
/**
if ($rendered_hash == ''
|| $rendered_html == ""
|| $rendered_hash != hash("md5", $item["body"])
- || Config::get("system", "ignore_cache")
+ || DI::config()->get("system", "ignore_cache")
) {
self::addRedirToImageTags($item);
}
// Only compare the HTML when we forcefully ignore the cache
- if (Config::get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) {
+ if (DI::config()->get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) {
$update = true;
}
}
/**
- * @brief Find any non-embedded images in private items and add redir links to them
+ * Find any non-embedded images in private items and add redir links to them
*
* @param array &$item The field array of an item row
*/
private static function addRedirToImageTags(array &$item)
{
- $app = self::getApp();
+ $app = DI::app();
$matches = [];
$cnt = preg_match_all('|\[img\](http[^\[]*?/photo/[a-fA-F0-9]+?(-[0-9]\.[\w]+?)?)\[\/img\]|', $item['body'], $matches, PREG_SET_ORDER);
}
/**
- * @brief Given an item array, convert the body element from bbcode to html and add smilie icons.
+ * Given an item array, convert the body element from bbcode to html and add smilie icons.
* If attach is true, also add icons for item attachments.
*
* @param array $item
*/
public static function prepareBody(array &$item, $attach = false, $is_preview = false)
{
- $a = self::getApp();
+ $a = DI::app();
Hook::callAll('prepare_body_init', $item);
// In order to provide theme developers more possibilities, event items
// Compile eventual content filter reasons
$filter_reasons = [];
if (!$is_preview && public_contact() != $item['author-id']) {
- if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) {
- $filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']);
+ if (!empty($item['content-warning']) && (!local_user() || !DI::pConfig()->get(local_user(), 'system', 'disable_cw', false))) {
+ $filter_reasons[] = DI::l10n()->t('Content warning: %s', $item['content-warning']);
}
$hook_data = [
if (strpos($mime, 'video') !== false) {
if (!$vhead) {
$vhead = true;
- $a->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('videos_head.tpl'));
+ DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('videos_head.tpl'));
}
$url_parts = explode('/', $the_url);
$as .= Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [
'$video' => [
'id' => $id,
- 'title' => L10n::t('View Video'),
+ 'title' => DI::l10n()->t('View Video'),
'src' => $the_url,
'mime' => $mime,
],
}
$title = Strings::escapeHtml(trim(($mtch[4] ?? '') ?: $mtch[1]));
- $title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes');
+ $title .= ' ' . $mtch[2] . ' ' . DI::l10n()->t('bytes');
$icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
$as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="_blank" >' . $icon . '</a>';
*/
public static function getPlink($item)
{
- $a = self::getApp();
+ $a = DI::app();
if ($a->user['nickname'] != "") {
$ret = [
'href' => "display/" . $item['guid'],
'orig' => "display/" . $item['guid'],
- 'title' => L10n::t('View on separate page'),
- 'orig_title' => L10n::t('view on separate page'),
+ 'title' => DI::l10n()->t('View on separate page'),
+ 'orig_title' => DI::l10n()->t('view on separate page'),
];
if (!empty($item['plink'])) {
- $ret["href"] = $a->removeBaseURL($item['plink']);
- $ret["title"] = L10n::t('link to source');
+ $ret["href"] = DI::baseUrl()->remove($item['plink']);
+ $ret["title"] = DI::l10n()->t('link to source');
}
} elseif (!empty($item['plink']) && ($item['private'] != 1)) {
$ret = [
'href' => $item['plink'],
'orig' => $item['plink'],
- 'title' => L10n::t('link to source'),
+ 'title' => DI::l10n()->t('link to source'),
];
} else {
$ret = [];
return 0;
}
+
+ /**
+ * Return share data from an item array (if the item is shared item)
+ * We are providing the complete Item array, because at some time in the future
+ * we hopefully will define these values not in the body anymore but in some item fields.
+ * This function is meant to replace all similar functions in the system.
+ *
+ * @param array $item
+ *
+ * @return array with share information
+ */
+ public static function getShareArray($item)
+ {
+ if (!preg_match("/(.*?)\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", $item['body'], $matches)) {
+ return [];
+ }
+
+ $attribute_string = $matches[2];
+ $attributes = ['comment' => trim($matches[1]), 'shared' => trim($matches[3])];
+ foreach (['author', 'profile', 'avatar', 'guid', 'posted', 'link'] as $field) {
+ if (preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches)) {
+ $attributes[$field] = trim(html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'));
+ }
+ }
+ return $attributes;
+ }
+
+ /**
+ * Fetch item information for shared items from the original items and adds it.
+ *
+ * @param array $item
+ *
+ * @return array item array with data from the original item
+ */
+ public static function addShareDataFromOriginal($item)
+ {
+ $shared = self::getShareArray($item);
+ if (empty($shared)) {
+ return $item;
+ }
+
+ // Real reshares always have got a GUID.
+ if (empty($shared['guid'])) {
+ return $item;
+ }
+
+ $uid = $item['uid'] ?? 0;
+
+ // first try to fetch the item via the GUID. This will work for all reshares that had been created on this system
+ $shared_item = self::selectFirst(['title', 'body', 'attach'], ['guid' => $shared['guid'], 'uid' => [0, $uid]]);
+ if (!DBA::isResult($shared_item)) {
+ // Otherwhise try to find (and possibly fetch) the item via the link. This should work for Diaspora and ActivityPub posts
+ $id = self::fetchByLink($shared['link'], $uid);
+ if (empty($id)) {
+ Logger::info('Original item not found', ['url' => $shared['link'], 'callstack' => System::callstack()]);
+ return $item;
+ }
+
+ $shared_item = self::selectFirst(['title', 'body', 'attach'], ['id' => $id]);
+ if (!DBA::isResult($shared_item)) {
+ return $item;
+ }
+ Logger::info('Got shared data from url', ['url' => $shared['link'], 'callstack' => System::callstack()]);
+ } else {
+ Logger::info('Got shared data from guid', ['guid' => $shared['guid'], 'callstack' => System::callstack()]);
+ }
+
+ if (!empty($shared_item['title'])) {
+ $body = '[h3]' . $shared_item['title'] . "[/h3]\n" . $shared_item['body'];
+ unset($shared_item['title']);
+ } else {
+ $body = $shared_item['body'];
+ }
+
+ $item['body'] = preg_replace("/\[share ([^\[\]]*)\].*\[\/share\]/ism", '[share $1]' . $body . '[/share]', $item['body']);
+ unset($shared_item['body']);
+
+ return array_merge($item, $shared_item);
+ }
}