X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FItem.php;h=70bd8b5c293ae8eb401f59e3cdacc7e4555b8ac9;hb=47bbe16d13b1a0710ef4269311dd13955cc7a3b7;hp=dec3716d0169206637cddfb1ebe898caa4c8c8ae;hpb=e4228c6218db70d600641430f4895f76cc049c5b;p=friendica.git diff --git a/src/Model/Item.php b/src/Model/Item.php index dec3716d01..70bd8b5c29 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -31,6 +31,7 @@ use Friendica\Core\Session; use Friendica\Core\System; use Friendica\Model\Tag; use Friendica\Core\Worker; +use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; use Friendica\DI; @@ -43,7 +44,6 @@ use Friendica\Util\Map; use Friendica\Util\Network; use Friendica\Util\Strings; use Friendica\Worker\Delivery; -use Friendica\Repository\PermissionSet as RepPermissionSet; use LanguageDetection\Language; class Item @@ -82,7 +82,7 @@ class Item 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network', 'causer-id', 'causer-link', 'causer-name', 'causer-avatar', 'causer-contact-type', 'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar', - 'writable', 'self', 'cid', 'alias', 'pinned', + 'writable', 'self', 'cid', 'alias', 'event-id', 'event-created', 'event-edited', 'event-start', 'event-finish', 'event-summary', 'event-desc', 'event-location', 'event-type', 'event-nofinish', 'event-adjust', 'event-ignore', 'event-id', @@ -96,7 +96,7 @@ class Item 'deleted', 'extid', 'post-type', 'gravity', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'author-id', 'author-link', 'owner-link', 'contact-uid', - 'signed_text', 'signature', 'signer', 'network']; + 'signed_text', 'network']; // Field list for "item-content" table that is mixed with the item table const MIXED_CONTENT_FIELDLIST = ['title', 'content-warning', 'body', 'location', @@ -109,7 +109,7 @@ class Item // All fields in the item table const ITEM_FIELDLIST = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'vid', - 'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'psid', + 'contact-id', 'type', 'wall', 'gravity', 'extid', 'psid', 'created', 'edited', 'commented', 'received', 'changed', 'verb', 'postopts', 'plink', 'resource-id', 'event-id', 'inform', 'file', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', @@ -134,8 +134,6 @@ class Item const TABLES = ['item', 'user-item', 'item-content', 'post-delivery-data', 'diaspora-interaction']; - private static $legacy_mode = null; - private static function getItemFields() { $definition = DBStructure::definition('', false); @@ -148,15 +146,6 @@ class Item return $postfields; } - public static function isLegacyMode() - { - if (is_null(self::$legacy_mode)) { - self::$legacy_mode = (DI::config()->get("system", "post_update_version") < 1279); - } - - return self::$legacy_mode; - } - /** * Set the pinned state of an item * @@ -186,712 +175,6 @@ class Item return (bool)$useritem['pinned']; } - /** - * 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)) { - return $useritems; - } - - $pinned = []; - while ($useritem = DBA::fetch($useritems)) { - $pinned[] = $useritem['iid']; - } - DBA::close($useritems); - - if (empty($pinned)) { - return []; - } - - $condition = DBA::mergeConditions(['iid' => $pinned], $condition); - - return self::selectThreadForUser($uid, $selected, $condition, $params); - } - - /** - * Fetch a single item row - * - * @param mixed $stmt statement object - * @return array|false current row or false - * @throws \Exception - */ - public static function fetch($stmt) - { - $row = DBA::fetch($stmt); - - if (!is_array($row)) { - return $row; - } - - $row = DBA::castFields('item', $row); - - // ---------------------- Transform item structure data ---------------------- - - // We prefer the data from the user's contact over the public one - if (!empty($row['author-link']) && !empty($row['contact-link']) && - ($row['author-link'] == $row['contact-link'])) { - if (isset($row['author-avatar']) && !empty($row['contact-avatar'])) { - $row['author-avatar'] = $row['contact-avatar']; - } - if (isset($row['author-name']) && !empty($row['contact-name'])) { - $row['author-name'] = $row['contact-name']; - } - } - - if (!empty($row['owner-link']) && !empty($row['contact-link']) && - ($row['owner-link'] == $row['contact-link'])) { - if (isset($row['owner-avatar']) && !empty($row['contact-avatar'])) { - $row['owner-avatar'] = $row['contact-avatar']; - } - if (isset($row['owner-name']) && !empty($row['contact-name'])) { - $row['owner-name'] = $row['contact-name']; - } - } - - // We can always comment on posts from these networks - if (array_key_exists('writable', $row) && - in_array($row['internal-network'], Protocol::FEDERATED)) { - $row['writable'] = true; - } - - // ---------------------- Transform item content data ---------------------- - - // Fetch data from the item-content table whenever there is content there - if (self::isLegacyMode()) { - $legacy_fields = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST); - foreach ($legacy_fields as $field) { - if (empty($row[$field]) && !empty($row['internal-item-' . $field])) { - $row[$field] = $row['internal-item-' . $field]; - } - unset($row['internal-item-' . $field]); - } - } - - if (array_key_exists('verb', $row)) { - if (!is_null($row['internal-verb'])) { - $row['verb'] = $row['internal-verb']; - } - - if (in_array($row['verb'], self::ACTIVITIES)) { - if (array_key_exists('title', $row)) { - $row['title'] = ''; - } - if (array_key_exists('body', $row)) { - $row['body'] = $row['verb']; - } - if (array_key_exists('object', $row)) { - $row['object'] = ''; - } - if (array_key_exists('object-type', $row)) { - $row['object-type'] = Activity\ObjectType::NOTE; - } - } elseif (in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) { - // Posts don't have a target - but having tags or files. - if (array_key_exists('target', $row)) { - $row['target'] = ''; - } - } - } - - if (array_key_exists('vid', $row) && is_null($row['vid']) && !empty($row['verb'])) { - $row['vid'] = Verb::getID($row['verb']); - } - - if (!array_key_exists('verb', $row) || in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) { - // Build the file string out of the term entries - if (array_key_exists('file', $row) && empty($row['file'])) { - $row['file'] = Post\Category::getTextByURIId($row['internal-uri-id'], $row['internal-uid']); - } - } - - if ($row['internal-psid'] == RepPermissionSet::PUBLIC) { - if (array_key_exists('allow_cid', $row)) { - $row['allow_cid'] = ''; - } - if (array_key_exists('allow_gid', $row)) { - $row['allow_gid'] = ''; - } - if (array_key_exists('deny_cid', $row)) { - $row['deny_cid'] = ''; - } - if (array_key_exists('deny_gid', $row)) { - $row['deny_gid'] = ''; - } - } - - if (array_key_exists('ignored', $row) && array_key_exists('internal-user-ignored', $row) && !is_null($row['internal-user-ignored'])) { - $row['ignored'] = $row['internal-user-ignored']; - } - - // Remove internal fields - unset($row['internal-network']); - unset($row['internal-uri-id']); - unset($row['internal-uid']); - unset($row['internal-psid']); - unset($row['internal-verb']); - unset($row['internal-user-ignored']); - unset($row['interaction']); - - return $row; - } - - /** - * Fills an array with data from an item query - * - * @param object $stmt statement object - * @param bool $do_close - * @return array Data array - */ - public static function inArray($stmt, $do_close = true) { - if (is_bool($stmt)) { - return $stmt; - } - - $data = []; - while ($row = self::fetch($stmt)) { - $data[] = $row; - } - if ($do_close) { - DBA::close($stmt); - } - return $data; - } - - /** - * Check if item data exists - * - * @param array $condition array of fields for condition - * - * @return boolean Are there rows for that condition? - * @throws \Exception - */ - public static function exists($condition) { - $stmt = self::select(['id'], $condition, ['limit' => 1]); - - if (is_bool($stmt)) { - $retval = $stmt; - } else { - $retval = (DBA::numRows($stmt) > 0); - } - - DBA::close($stmt); - - return $retval; - } - - /** - * Retrieve a single record from the item table for a given user and returns it in an associative array - * - * @param integer $uid User ID - * @param array $selected - * @param array $condition - * @param array $params - * @return bool|array - * @throws \Exception - * @see DBA::select - */ - public static function selectFirstForUser($uid, array $selected = [], array $condition = [], $params = []) - { - $params['uid'] = $uid; - - if (empty($selected)) { - $selected = Item::DISPLAY_FIELDLIST; - } - - return self::selectFirst($selected, $condition, $params); - } - - /** - * 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 - * @param array $condition Array of fields for condition - * @param array $params Array of several parameters - * - * @return boolean|object - * @throws \Exception - */ - public static function selectForUser($uid, array $selected = [], array $condition = [], $params = []) - { - $params['uid'] = $uid; - - if (empty($selected)) { - $selected = Item::DISPLAY_FIELDLIST; - } - - return self::select($selected, $condition, $params); - } - - /** - * Retrieve a single record from the item table and returns it in an associative array - * - * @param array $fields - * @param array $condition - * @param array $params - * @return bool|array - * @throws \Exception - * @see DBA::select - */ - public static function selectFirst(array $fields = [], array $condition = [], $params = []) - { - $params['limit'] = 1; - - $result = self::select($fields, $condition, $params); - - if (is_bool($result)) { - return $result; - } else { - $row = self::fetch($result); - DBA::close($result); - return $row; - } - } - - /** - * 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 - * @param array $params Array of several parameters - * - * @return array - * @throws \Exception - */ - public static function selectToArray(array $fields = [], array $condition = [], $params = []) - { - $result = self::select($fields, $condition, $params); - - if (is_bool($result)) { - return []; - } - - $data = []; - while ($row = self::fetch($result)) { - $data[] = $row; - } - DBA::close($result); - - return $data; - } - - /** - * Select rows from the item table - * - * @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 select(array $selected = [], array $condition = [], $params = []) - { - $uid = 0; - $usermode = false; - - if (isset($params['uid'])) { - $uid = $params['uid']; - $usermode = true; - } - - $fields = self::fieldlist($usermode); - - $select_fields = self::constructSelectFields($fields, $selected); - - $condition_string = DBA::buildCondition($condition); - - $condition_string = self::addTablesToFields($condition_string, $fields); - - if ($usermode) { - $condition_string = $condition_string . ' AND ' . self::condition(false); - } - - $param_string = self::addTablesToFields(DBA::buildParameter($params), $fields); - - $table = "`item` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, false, $usermode); - - $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string; - - return DBA::p($sql, $condition); - } - - /** - * Select rows from the starting post in the item table - * - * @param integer $uid User ID - * @param array $selected - * @param array $condition Array of fields for condition - * @param array $params Array of several parameters - * - * @return boolean|object - * @throws \Exception - */ - public static function selectThreadForUser($uid, array $selected = [], array $condition = [], $params = []) - { - $params['uid'] = $uid; - - if (empty($selected)) { - $selected = Item::DISPLAY_FIELDLIST; - } - - return self::selectThread($selected, $condition, $params); - } - - /** - * Retrieve a single record from the starting post in the item table and returns it in an associative array - * - * @param integer $uid User ID - * @param array $selected - * @param array $condition - * @param array $params - * @return bool|array - * @throws \Exception - * @see DBA::select - */ - public static function selectFirstThreadForUser($uid, array $selected = [], array $condition = [], $params = []) - { - $params['uid'] = $uid; - - if (empty($selected)) { - $selected = Item::DISPLAY_FIELDLIST; - } - - return self::selectFirstThread($selected, $condition, $params); - } - - /** - * Retrieve a single record from the starting post in the item table and returns it in an associative array - * - * @param array $fields - * @param array $condition - * @param array $params - * @return bool|array - * @throws \Exception - * @see DBA::select - */ - public static function selectFirstThread(array $fields = [], array $condition = [], $params = []) - { - $params['limit'] = 1; - $result = self::selectThread($fields, $condition, $params); - - if (is_bool($result)) { - return $result; - } else { - $row = self::fetch($result); - DBA::close($result); - return $row; - } - } - - /** - * 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 - * @param array $params Array of several parameters - * - * @return boolean|object - * @throws \Exception - */ - public static function selectThread(array $selected = [], array $condition = [], $params = []) - { - $uid = 0; - $usermode = false; - - if (isset($params['uid'])) { - $uid = $params['uid']; - $usermode = true; - } - - $fields = self::fieldlist($usermode); - - $fields['thread'] = ['mention', 'ignored', 'iid']; - - $threadfields = ['thread' => ['iid', 'uid', 'contact-id', 'owner-id', 'author-id', - 'created', 'edited', 'commented', 'received', 'changed', 'wall', 'private', - 'pubmail', 'moderated', 'visible', 'starred', 'ignored', 'post-type', - 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'network']]; - - $select_fields = self::constructSelectFields($fields, $selected); - - $condition_string = DBA::buildCondition($condition); - - $condition_string = self::addTablesToFields($condition_string, $threadfields); - $condition_string = self::addTablesToFields($condition_string, $fields); - - if ($usermode) { - $condition_string = $condition_string . ' AND ' . self::condition(true); - } - - $param_string = DBA::buildParameter($params); - $param_string = self::addTablesToFields($param_string, $threadfields); - $param_string = self::addTablesToFields($param_string, $fields); - - $table = "`thread` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, true, $usermode); - - $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string; - - return DBA::p($sql, $condition); - } - - /** - * Returns a list of fields that are associated with the item table - * - * @param $usermode - * @return array field list - */ - private static function fieldlist($usermode) - { - $fields = []; - - $fields['item'] = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', - 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'vid', 'causer-id', - 'contact-id', 'owner-id', 'author-id', 'type', 'wall', 'gravity', 'extid', - 'created', 'edited', 'commented', 'received', 'changed', 'psid', - 'resource-id', 'event-id', 'post-type', 'file', - 'private', 'pubmail', 'moderated', 'visible', 'starred', 'bookmark', - 'unseen', 'deleted', 'origin', 'forum_mode', 'mention', 'global', - 'id' => 'item_id', 'network', 'icid', - 'uri-id' => 'internal-uri-id', 'uid' => 'internal-uid', - 'network' => 'internal-network', 'psid' => 'internal-psid']; - - if ($usermode) { - $fields['user-item'] = ['pinned', 'notification-type', 'ignored' => 'internal-user-ignored']; - } - - $fields['item-content'] = array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST); - - $fields['post-delivery-data'] = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, Post\DeliveryData::FIELD_LIST); - - $fields['verb'] = ['name' => 'internal-verb']; - - $fields['permissionset'] = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']; - - $fields['author'] = ['url' => 'author-link', 'name' => 'author-name', 'addr' => 'author-addr', - 'thumb' => 'author-avatar', 'nick' => 'author-nick', 'network' => 'author-network']; - - $fields['owner'] = ['url' => 'owner-link', 'name' => 'owner-name', 'addr' => 'owner-addr', - 'thumb' => 'owner-avatar', 'nick' => 'owner-nick', 'network' => 'owner-network']; - - $fields['causer'] = ['url' => 'causer-link', 'name' => 'causer-name', 'addr' => 'causer-addr', - 'thumb' => 'causer-avatar', 'nick' => 'causer-nick', 'network' => 'causer-network', - 'contact-type' => 'causer-contact-type']; - - $fields['contact'] = ['url' => 'contact-link', 'name' => 'contact-name', 'thumb' => 'contact-avatar', - 'writable', 'self', 'id' => 'cid', 'alias', 'uid' => 'contact-uid', - 'photo', 'name-date', 'uri-date', 'avatar-date', 'thumb', 'dfrn-id']; - - $fields['parent-item'] = ['guid' => 'parent-guid', 'network' => 'parent-network', 'author-id' => 'parent-author-id']; - - $fields['parent-item-author'] = ['url' => 'parent-author-link', 'name' => 'parent-author-name', - 'network' => 'parent-author-network']; - - $fields['event'] = ['created' => 'event-created', 'edited' => 'event-edited', - 'start' => 'event-start','finish' => 'event-finish', - 'summary' => 'event-summary','desc' => 'event-desc', - 'location' => 'event-location', 'type' => 'event-type', - 'nofinish' => 'event-nofinish','adjust' => 'event-adjust', - 'ignore' => 'event-ignore', 'id' => 'event-id']; - - $fields['diaspora-interaction'] = ['interaction', 'interaction' => 'signed_text']; - - return $fields; - } - - /** - * Returns SQL condition for the "select" functions - * - * @param boolean $thread_mode Called for the items (false) or for the threads (true) - * - * @return string SQL condition - */ - private static function condition($thread_mode) - { - if ($thread_mode) { - $master_table = "`thread`"; - } else { - $master_table = "`item`"; - } - return sprintf("$master_table.`visible` AND NOT $master_table.`deleted` AND NOT $master_table.`moderated` - AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) - AND (`user-author`.`blocked` IS NULL OR NOT `user-author`.`blocked`) - AND (`user-author`.`ignored` IS NULL OR NOT `user-author`.`ignored` OR `item`.`gravity` != %d) - AND (`user-owner`.`blocked` IS NULL OR NOT `user-owner`.`blocked`) - AND (`user-owner`.`ignored` IS NULL OR NOT `user-owner`.`ignored` OR `item`.`gravity` != %d) ", - GRAVITY_PARENT, GRAVITY_PARENT); - } - - /** - * 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 - * @param boolean $thread_mode Called for the items (false) or for the threads (true) - * - * @param $user_mode - * @return string The SQL joins for the "select" functions - */ - private static function constructJoins($uid, $sql_commands, $thread_mode, $user_mode) - { - if ($thread_mode) { - $master_table = "`thread`"; - $master_table_key = "`thread`.`iid`"; - $joins = "STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` "; - } else { - $master_table = "`item`"; - $master_table_key = "`item`.`id`"; - $joins = ''; - } - - if ($user_mode) { - $joins .= sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = $master_table.`contact-id` - AND NOT `contact`.`blocked` - AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s))) - OR `contact`.`self` OR `item`.`gravity` != %d OR `contact`.`uid` = 0) - STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id` AND NOT `author`.`blocked` - STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id` AND NOT `owner`.`blocked` - LEFT JOIN `user-item` ON `user-item`.`iid` = $master_table_key AND `user-item`.`uid` = %d - LEFT JOIN `user-contact` AS `user-author` ON `user-author`.`cid` = $master_table.`author-id` AND `user-author`.`uid` = %d - LEFT JOIN `user-contact` AS `user-owner` ON `user-owner`.`cid` = $master_table.`owner-id` AND `user-owner`.`uid` = %d", - Contact::SHARING, Contact::FRIEND, GRAVITY_PARENT, intval($uid), intval($uid), intval($uid)); - } else { - if (strpos($sql_commands, "`contact`.") !== false) { - $joins .= "LEFT JOIN `contact` ON `contact`.`id` = $master_table.`contact-id`"; - } - if (strpos($sql_commands, "`author`.") !== false) { - $joins .= " LEFT JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id`"; - } - if (strpos($sql_commands, "`owner`.") !== false) { - $joins .= " LEFT JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id`"; - } - } - if (strpos($sql_commands, "`causer`.") !== false) { - $joins .= " LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `item`.`causer-id`"; - } - - if (strpos($sql_commands, "`group_member`.") !== false) { - $joins .= " STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = $master_table.`contact-id`"; - } - - if (strpos($sql_commands, "`user`.") !== false) { - $joins .= " STRAIGHT_JOIN `user` ON `user`.`uid` = $master_table.`uid`"; - } - - if (strpos($sql_commands, "`event`.") !== false) { - $joins .= " LEFT JOIN `event` ON `event-id` = `event`.`id`"; - } - - if (strpos($sql_commands, "`diaspora-interaction`.") !== false) { - $joins .= " LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `item`.`uri-id`"; - } - - if (strpos($sql_commands, "`item-content`.") !== false) { - $joins .= " LEFT JOIN `item-content` ON `item-content`.`uri-id` = `item`.`uri-id`"; - } - - if (strpos($sql_commands, "`post-delivery-data`.") !== false) { - $joins .= " LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `item`.`uri-id` AND `item`.`origin`"; - } - - if (strpos($sql_commands, "`verb`.") !== false) { - $joins .= " LEFT JOIN `verb` ON `verb`.`id` = `item`.`vid`"; - } - - if (strpos($sql_commands, "`permissionset`.") !== false) { - $joins .= " LEFT JOIN `permissionset` ON `permissionset`.`id` = `item`.`psid`"; - } - - if ((strpos($sql_commands, "`parent-item`.") !== false) || (strpos($sql_commands, "`parent-item-author`.") !== false)) { - $joins .= " STRAIGHT_JOIN `item` AS `parent-item` ON `parent-item`.`id` = `item`.`parent`"; - - if (strpos($sql_commands, "`parent-item-author`.") !== false) { - $joins .= " STRAIGHT_JOIN `contact` AS `parent-item-author` ON `parent-item-author`.`id` = `parent-item`.`author-id`"; - } - } - - return $joins; - } - - /** - * 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 - * - * @return string The field list - */ - private static function constructSelectFields(array $fields, array $selected) - { - if (!empty($selected)) { - $selected = array_merge($selected, ['internal-uri-id', 'internal-uid', 'internal-psid', 'internal-network']); - } - - if (in_array('verb', $selected)) { - $selected = array_merge($selected, ['internal-verb']); - } - - if (in_array('ignored', $selected)) { - $selected[] = 'internal-user-ignored'; - } - - $legacy_fields = array_merge(Post\DeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST); - - $selection = []; - foreach ($fields as $table => $table_fields) { - foreach ($table_fields as $field => $select) { - if (empty($selected) || in_array($select, $selected)) { - if (self::isLegacyMode() && in_array($select, $legacy_fields)) { - $selection[] = "`item`.`".$select."` AS `internal-item-" . $select . "`"; - } - if (is_int($field)) { - $selection[] = "`" . $table . "`.`" . $select . "`"; - } else { - $selection[] = "`" . $table . "`.`" . $field . "` AS `" . $select . "`"; - } - } - } - } - return implode(", ", $selection); - } - - /** - * add table definition to fields in an SQL query - * - * @param string $query SQL query - * @param array $fields The field definition array - * - * @return string the changed SQL query - */ - private static function addTablesToFields($query, $fields) - { - foreach ($fields as $table => $table_fields) { - foreach ($table_fields as $alias => $field) { - if (is_int($alias)) { - $replace_field = $field; - } else { - $replace_field = $alias; - } - - $search = "/([^\.])`" . $field . "`/i"; - $replace = "$1`" . $table . "`.`" . $replace_field . "`"; - $query = preg_replace($search, $replace, $query); - } - } - return $query; - } - /** * Update existing item entries * @@ -920,13 +203,13 @@ class Item // We cannot simply expand the condition to check for origin entries // The condition needn't to be a simple array but could be a complex condition. // And we have to execute this query before the update to ensure to fetch the same data. - $items = DBA::select('item', ['id', 'origin', 'uri', 'uri-id', 'icid', 'uid', 'file'], $condition); + $items = DBA::select('item', ['id', 'origin', 'uri', 'uri-id', 'uid', 'file'], $condition); $content_fields = []; foreach (array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST) as $field) { if (isset($fields[$field])) { $content_fields[$field] = $fields[$field]; - if (in_array($field, self::CONTENT_FIELDLIST) || !self::isLegacyMode()) { + if (in_array($field, self::CONTENT_FIELDLIST)) { unset($fields[$field]); } else { $fields[$field] = null; @@ -982,22 +265,6 @@ class Item } self::updateContent($content_fields, ['uri-id' => $item['uri-id']]); - - if (empty($item['icid'])) { - $item_content = DBA::selectFirst('item-content', [], ['uri-id' => $item['uri-id']]); - if (DBA::isResult($item_content)) { - $item_fields = ['icid' => $item_content['id']]; - // Clear all fields in the item table that have a content in the item-content table - if (self::isLegacyMode()) { - foreach ($item_content as $field => $content) { - if (in_array($field, self::MIXED_CONTENT_FIELDLIST) && !empty($content)) { - $item_fields[$field] = null; - } - } - } - DBA::update('item', $item_fields, ['id' => $item['id']]); - } - } } if (!is_null($files)) { @@ -1041,8 +308,8 @@ class Item */ public static function markForDeletion($condition, $priority = PRIORITY_HIGH) { - $items = self::select(['id'], $condition); - while ($item = self::fetch($items)) { + $items = Post::select(['id'], $condition); + while ($item = Post::fetch($items)) { self::markForDeletionById($item['id'], $priority); } DBA::close($items); @@ -1061,8 +328,8 @@ class Item return; } - $items = self::select(['id', 'uid', 'uri-id'], $condition); - while ($item = self::fetch($items)) { + $items = Post::select(['id', 'uid', 'uri-id'], $condition); + while ($item = Post::fetch($items)) { Post\User::update($item['uri-id'], $item['uid'], ['hidden' => true]); // "Deleting" global items just means hiding them @@ -1092,9 +359,8 @@ class Item // locate item to be deleted $fields = ['id', 'uri', 'uri-id', 'uid', 'parent', 'parent-uri', 'origin', 'deleted', 'file', 'resource-id', 'event-id', - 'verb', 'object-type', 'object', 'target', 'contact-id', - 'icid', 'psid', 'gravity']; - $item = self::selectFirst($fields, ['id' => $item_id]); + 'verb', 'object-type', 'object', 'target', 'contact-id', 'psid', 'gravity']; + $item = Post::selectFirst($fields, ['id' => $item_id]); if (!DBA::isResult($item)) { Logger::info('Item not found.', ['id' => $item_id]); return false; @@ -1105,7 +371,7 @@ class Item return false; } - $parent = self::selectFirst(['origin'], ['id' => $item['parent']]); + $parent = Post::selectFirst(['origin'], ['id' => $item['parent']]); if (!DBA::isResult($parent)) { $parent = ['origin' => false]; } @@ -1162,7 +428,7 @@ class Item Post\Category::storeTextByURIId($item['uri-id'], $item['uid'], ''); self::deleteThread($item['id'], $item['parent-uri']); - if (!self::exists(["`uri` = ? AND `uid` != 0 AND NOT `deleted`", $item['uri']])) { + if (!Post::exists(["`uri` = ? AND `uid` != 0 AND NOT `deleted`", $item['uri']])) { self::markForDeletion(['uri' => $item['uri'], 'uid' => 0, 'deleted' => false], $priority); } @@ -1194,7 +460,7 @@ class Item Post\User::update($item['uri-id'], $item['uid'], ['hidden' => true]); // When we delete just our local user copy of an item, we have to set a marker to hide it - $global_item = self::selectFirst(['id'], ['uri' => $item['uri'], 'uid' => 0, 'deleted' => false]); + $global_item = Post::selectFirst(['id'], ['uri' => $item['uri'], 'uid' => 0, 'deleted' => false]); if (DBA::isResult($global_item)) { DBA::update('user-item', ['hidden' => true], ['iid' => $global_item['id'], 'uid' => $item['uid']], true); } @@ -1278,21 +544,6 @@ class Item return $item['author-id']; } - // This function will finally cover most of the preparation functionality in mod/item.php - public static function prepare(&$item) - { - /* - * @TODO: Unused code triggering inspection errors - * - $data = BBCode::getAttachmentData($item['body']); - if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $item['body'], $match, PREG_SET_ORDER) || isset($data["type"])) - && ($posttype != Item::PT_PERSONAL_NOTE)) { - $posttype = Item::PT_PAGE; - $objecttype = ACTIVITY_OBJ_BOOKMARK; - } - */ - } - /** * Write an item array into a spool file to be inserted later. * This command is called whenever there are issues storing an item. @@ -1325,7 +576,7 @@ class Item { // Checking if there is already an item with the same guid $condition = ['guid' => $item['guid'], 'network' => $item['network'], 'uid' => $item['uid']]; - if (self::exists($condition)) { + if (Post::exists($condition)) { Logger::notice('Found already existing item', [ 'guid' => $item['guid'], 'uid' => $item['uid'], @@ -1336,7 +587,7 @@ class Item $condition = ["`uri` = ? AND `network` IN (?, ?) AND `uid` = ?", $item['uri'], $item['network'], Protocol::DFRN, $item['uid']]; - if (self::exists($condition)) { + if (Post::exists($condition)) { Logger::notice('duplicated item with the same uri found.', $item); return true; } @@ -1344,7 +595,7 @@ class Item // On Friendica and Diaspora the GUID is unique if (in_array($item['network'], [Protocol::DFRN, Protocol::DIASPORA])) { $condition = ['guid' => $item['guid'], 'uid' => $item['uid']]; - if (self::exists($condition)) { + if (Post::exists($condition)) { Logger::notice('duplicated item with the same guid found.', $item); return true; } @@ -1352,7 +603,7 @@ class Item // Check for an existing post with the same content. There seems to be a problem with OStatus. $condition = ["`body` = ? AND `network` = ? AND `created` = ? AND `contact-id` = ? AND `uid` = ?", $item['body'], $item['network'], $item['created'], $item['contact-id'], $item['uid']]; - if (self::exists($condition)) { + if (Post::exists($condition)) { Logger::notice('duplicated item with the same body found.', $item); return true; } @@ -1363,7 +614,7 @@ class Item * There is a timing issue here that sometimes creates double postings. * An unique index would help - but the limitations of MySQL (maximum size of index values) prevent this. */ - if (($item['uid'] == 0) && self::exists(['uri' => trim($item['uri']), 'uid' => 0])) { + if (($item['uid'] == 0) && Post::exists(['uri' => trim($item['uri']), 'uid' => 0])) { Logger::notice('Global item already stored.', ['uri' => $item['uri'], 'network' => $item['network']]); return true; } @@ -1385,6 +636,19 @@ class Item return false; } + if (!empty($item['uid'])) { + $owner = User::getOwnerDataById($item['uid'], false); + if (!$owner) { + Logger::notice('Missing item user owner data', ['uid' => $item['uid']]); + return false; + } + + if ($owner['account_expired'] || $owner['account_removed']) { + Logger::notice('Item user has been deleted/expired/removed', ['uid' => $item['uid'], 'deleted' => $owner['deleted'], 'account_expired' => $owner['account_expired'], 'account_removed' => $owner['account_removed']]); + return false; + } + } + if (!empty($item['author-id']) && Contact::isBlocked($item['author-id'])) { Logger::notice('Author is blocked node-wide', ['author-link' => $item['author-link'], 'item-uri' => $item['uri']]); return false; @@ -1418,7 +682,7 @@ class Item $condition = ['verb' => Activity::FOLLOW, 'uid' => $item['uid'], 'parent-uri' => $item['parent-uri'], 'author-id' => $item['author-id']]; - if (self::exists($condition)) { + if (Post::exists($condition)) { // It happens that we receive multiple follow requests by the same author - we only store one. Logger::info('Follow: Found existing follow request from author', ['author-id' => $item['author-id'], 'parent-uri' => $item['parent-uri']]); return false; @@ -1472,7 +736,7 @@ class Item $condition = ["`uri` = ? AND `uid` = ? AND `network` IN (?, ?, ?, ?)", trim($item['uri']), $item['uid'], Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::DFRN, Protocol::OSTATUS]; - $existing = self::selectFirst(['id', 'network'], $condition); + $existing = Post::selectFirst(['id', 'network'], $condition); if (DBA::isResult($existing)) { // We only log the entries with a different user id than 0. Otherwise we would have too many false positives if ($item['uid'] != 0) { @@ -1505,7 +769,7 @@ class Item 'wall', 'private', 'forum_mode', 'origin', 'author-id']; $condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid']]; $params = ['order' => ['id' => false]]; - $parent = self::selectFirst($fields, $condition, $params); + $parent = Post::selectFirst($fields, $condition, $params); if (!DBA::isResult($parent)) { Logger::notice('item parent was not found - ignoring item', ['thr-parent' => $item['thr-parent'], 'uid' => $item['uid']]); @@ -1520,7 +784,7 @@ class Item 'parent-uri' => $parent['parent-uri'], 'uid' => $parent['uid']]; $params = ['order' => ['id' => false]]; - $toplevel_parent = self::selectFirst($fields, $condition, $params); + $toplevel_parent = Post::selectFirst($fields, $condition, $params); if (!DBA::isResult($toplevel_parent)) { Logger::notice('item top level parent was not found - ignoring item', ['parent-uri' => $parent['parent-uri'], 'uid' => $parent['uid']]); return []; @@ -1568,6 +832,7 @@ class Item $item['origin'] = 1; $item['network'] = Protocol::DFRN; $item['protocol'] = Conversation::PARCEL_DIRECT; + $item['direction'] = Conversation::PUSH; if (in_array($notify, PRIORITIES)) { $priority = $notify; @@ -1684,6 +949,12 @@ class Item // The contact-id should be set before "self::insert" was called - but there seems to be issues sometimes $item["contact-id"] = self::contactId($item); + if (!empty($item['direction']) && in_array($item['direction'], [Conversation::PUSH, Conversation::RELAY]) && + self::isTooOld($item)) { + Logger::info('Item is too old', ['item' => $item]); + return 0; + } + if (!self::isValid($item)) { return 0; } @@ -1696,7 +967,7 @@ class Item // If the thread originated from this node, we check the permission against the thread starter $condition = ['uri' => $toplevel_parent['uri'], 'wall' => true]; - $localTopLevelParent = self::selectFirst(['uid'], $condition); + $localTopLevelParent = Post::selectFirst(['uid'], $condition); if (!empty($localTopLevelParent['uid']) && !self::isAllowedByUser($item, $localTopLevelParent['uid'])) { return 0; } @@ -1773,7 +1044,7 @@ class Item // Set the global flag on all items if this was a global item entry DBA::update('item', ['global' => true], ['uri' => $item["uri"]]); } else { - $item["global"] = self::exists(['uid' => 0, 'uri' => $item["uri"]]); + $item["global"] = Post::exists(['uid' => 0, 'uri' => $item["uri"]]); } // ACL settings @@ -1844,13 +1115,10 @@ class Item $notify_type = Delivery::POST; } - if (!in_array($item['verb'], self::ACTIVITIES)) { - $item['icid'] = self::insertContent($item); - if (empty($item['icid'])) { - // This shouldn't happen - Logger::warning('No content stored, quitting', ['guid' => $item['guid'], 'uri-id' => $item['uri-id'], 'causer-id' => ($item['causer-id'] ?? 0), 'post-type' => $item['post-type'], 'network' => $item['network']]); - return 0; - } + if (!in_array($item['verb'], self::ACTIVITIES) && !self::insertContent($item)) { + // This shouldn't happen + Logger::warning('No content stored, quitting', ['guid' => $item['guid'], 'uri-id' => $item['uri-id'], 'causer-id' => ($item['causer-id'] ?? 0), 'post-type' => $item['post-type'], 'network' => $item['network']]); + return 0; } $body = $item['body']; @@ -1966,7 +1234,7 @@ class Item } if (!$dontcache) { - $posted_item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $current_post]); + $posted_item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $current_post]); if (DBA::isResult($posted_item)) { if ($notify) { Hook::callAll('post_local_end', $posted_item); @@ -1999,7 +1267,7 @@ class Item $transmit = $notify || ($item['visible'] && ($parent_origin || $item['origin'])); if ($transmit) { - $transmit_item = Item::selectFirst(['verb', 'origin'], ['id' => $item['id']]); + $transmit_item = Post::selectFirst(['verb', 'origin'], ['id' => $item['id']]); // Don't relay participation messages if (($transmit_item['verb'] == Activity::FOLLOW) && (!$transmit_item['origin'] || ($item['author-id'] != Contact::getPublicIdByUserId($uid)))) { @@ -2027,7 +1295,7 @@ class Item */ private static function setOwnerforResharedItem(array $item) { - $parent = self::selectFirst(['id', 'causer-id', 'owner-id', 'author-id', 'author-link', 'origin', 'post-type'], + $parent = Post::selectFirst(['id', 'causer-id', 'owner-id', 'author-id', 'author-link', 'origin', 'post-type'], ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']]); if (!DBA::isResult($parent)) { Logger::error('Parent not found', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']]); @@ -2093,6 +1361,7 @@ class Item * Insert a new item content entry * * @param array $item The item fields that are to be inserted + * @return bool "true" if content was inserted or already existed * @throws \Exception */ private static function insertContent(array $item) @@ -2105,25 +1374,23 @@ class Item } } - $item_content = DBA::selectFirst('item-content', ['id'], ['uri-id' => $item['uri-id']]); - if (DBA::isResult($item_content)) { - $icid = $item_content['id']; - Logger::info('Existing content found', ['icid' => $icid, 'uri' => $item['uri']]); - return $icid; + $found = DBA::exists('item-content', ['uri-id' => $item['uri-id']]); + if ($found) { + Logger::info('Existing content found', ['uri-id' => $item['uri-id'], 'uri' => $item['uri']]); + return true; } - DBA::replace('item-content', $fields); + DBA::insert('item-content', $fields, Database::INSERT_IGNORE); - $item_content = DBA::selectFirst('item-content', ['id'], ['uri-id' => $item['uri-id']]); - if (DBA::isResult($item_content)) { - $icid = $item_content['id']; - Logger::notice('Content inserted', ['icid' => $icid, 'uri' => $item['uri']]); - return $icid; + $found = DBA::exists('item-content', ['uri-id' => $item['uri-id']]); + if ($found) { + Logger::notice('Content inserted', ['uri-id' => $item['uri-id'], 'uri' => $item['uri']]); + return true; } // This shouldn't happen. Logger::error("Content wasn't inserted", $item); - return null; + return false; } /** @@ -2160,8 +1427,8 @@ class Item */ public static function distribute($itemid, $signed_text = '') { - $condition = ["`id` IN (SELECT `parent` FROM `item` WHERE `id` = ?)", $itemid]; - $parent = self::selectFirst(['owner-id'], $condition); + $condition = ["`id` IN (SELECT `parent` FROM `post-view` WHERE `id` = ?)", $itemid]; + $parent = Post::selectFirst(['owner-id'], $condition); if (!DBA::isResult($parent)) { return; } @@ -2170,7 +1437,7 @@ class Item $condition = ['id' => $itemid, 'uid' => 0, 'network' => array_merge(Protocol::FEDERATED ,['']), 'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => [self::PUBLIC, self::UNLISTED]]; - $item = self::selectFirst(self::ITEM_FIELDLIST, $condition); + $item = Post::selectFirst(self::ITEM_FIELDLIST, $condition); if (!DBA::isResult($item)) { return; } @@ -2223,13 +1490,14 @@ class Item $origin_uid = 0; if ($item['uri'] != $item['parent-uri']) { - $parents = self::select(['uid', 'origin'], ["`uri` = ? AND `uid` != 0", $item['parent-uri']]); - while ($parent = self::fetch($parents)) { + $parents = Post::select(['uid', 'origin'], ["`uri` = ? AND `uid` != 0", $item['parent-uri']]); + while ($parent = Post::fetch($parents)) { $users[$parent['uid']] = $parent['uid']; if ($parent['origin'] && !$origin) { $origin_uid = $parent['uid']; } } + DBA::close($parents); } foreach ($users as $uid) { @@ -2250,7 +1518,7 @@ class Item */ public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = []) { - $item = self::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => 0]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['uri-id' => $uri_id, 'uid' => 0]); if (!DBA::isResult($item)) { return 0; } @@ -2279,7 +1547,7 @@ class Item */ private static function storeForUser(array $item, int $uid) { - if (self::exists(['uri-id' => $item['uri-id'], 'uid' => $uid])) { + if (Post::exists(['uri-id' => $item['uri-id'], 'uid' => $uid])) { Logger::info('Item already exists', ['uri-id' => $item['uri-id'], 'uid' => $uid]); return 0; } @@ -2349,7 +1617,7 @@ class Item { $fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network', 'uri']; $condition = ['id' => $itemid, 'parent' => [0, $itemid]]; - $item = self::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); if (!DBA::isResult($item)) { return; @@ -2361,7 +1629,7 @@ class Item } // Is it a visible public post? - if (!$item["visible"] || $item["deleted"] || $item["moderated"] || ($item["private"] == Item::PRIVATE)) { + if (!$item["visible"] || $item["deleted"] || $item["moderated"] || ($item["private"] == self::PRIVATE)) { return; } @@ -2370,11 +1638,11 @@ class Item return; } - if (self::exists(['uri' => $item['uri'], 'uid' => 0])) { + if (Post::exists(['uri' => $item['uri'], 'uid' => 0])) { return; } - $item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $itemid]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $itemid]); if (DBA::isResult($item)) { // Preparing public shadow (removing user specific data) @@ -2410,7 +1678,7 @@ class Item */ private static function addShadowPost($itemid) { - $item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $itemid]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $itemid]); if (!DBA::isResult($item)) { return; } @@ -2427,12 +1695,12 @@ class Item } // Is there a shadow parent? - if (!self::exists(['uri' => $item['parent-uri'], 'uid' => 0])) { + if (!Post::exists(['uri' => $item['parent-uri'], 'uid' => 0])) { return; } // Is there already a shadow entry? - if (self::exists(['uri' => $item['uri'], 'uid' => 0])) { + if (Post::exists(['uri' => $item['uri'], 'uid' => 0])) { return; } @@ -2459,7 +1727,7 @@ class Item // If this was a comment to a Diaspora post we don't get our comment back. // This means that we have to distribute the comment by ourselves. - if ($origin && self::exists(['id' => $parent, 'network' => Protocol::DIASPORA])) { + if ($origin && Post::exists(['id' => $parent, 'network' => Protocol::DIASPORA])) { self::distribute($public_shadow); } } @@ -2707,7 +1975,7 @@ class Item $community_page = (($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false); $prvgroup = (($user['page-flags'] == User::PAGE_FLAGS_PRVGROUP) ? true : false); - $item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $item_id]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $item_id]); if (!DBA::isResult($item)) { return false; } @@ -2795,7 +2063,7 @@ class Item Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, $item_id); - Item::performActivity($item_id, 'announce', $uid); + self::performActivity($item_id, 'announce', $uid); return false; } @@ -2822,7 +2090,7 @@ class Item Logger::info('Automatically reshare item', ['uid' => $item['uid'], 'id' => $item['id'], 'guid' => $item['guid'], 'uri-id' => $item['uri-id']]); - Item::performActivity($item['id'], 'announce', $item['uid']); + self::performActivity($item['id'], 'announce', $item['uid']); } public static function isRemoteSelf($contact, &$datarray) @@ -3095,7 +2363,7 @@ class Item $condition[0] .= " AND `received` < UTC_TIMESTAMP() - INTERVAL ? DAY"; $condition[] = $days; - $items = self::select(['file', 'resource-id', 'starred', 'type', 'id', 'post-type'], $condition); + $items = Post::select(['file', 'resource-id', 'starred', 'type', 'id', 'post-type'], $condition); if (!DBA::isResult($items)) { return; @@ -3116,7 +2384,7 @@ class Item $priority = DI::config()->get('system', 'expire-notify-priority'); - while ($item = Item::fetch($items)) { + while ($item = Post::fetch($items)) { // don't expire filed items if (strpos($item['file'], '[') !== false) { @@ -3129,9 +2397,9 @@ class Item continue; } elseif (!$expire_starred && intval($item['starred'])) { continue; - } elseif (!$expire_notes && (($item['type'] == 'note') || ($item['post-type'] == Item::PT_PERSONAL_NOTE))) { + } elseif (!$expire_notes && (($item['type'] == 'note') || ($item['post-type'] == self::PT_PERSONAL_NOTE))) { continue; - } elseif (!$expire_items && ($item['type'] != 'note') && ($item['post-type'] != Item::PT_PERSONAL_NOTE)) { + } elseif (!$expire_items && ($item['type'] != 'note') && ($item['post-type'] != self::PT_PERSONAL_NOTE)) { continue; } @@ -3180,7 +2448,7 @@ class Item Logger::notice('Start create activity', ['verb' => $verb, 'item' => $item_id, 'user' => $uid]); - $item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $item_id]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $item_id]); if (!DBA::isResult($item)) { Logger::log('like: unknown item ' . $item_id); return false; @@ -3192,10 +2460,10 @@ class Item return false; } - if (!Item::exists(['uri-id' => $item['parent-uri-id'], 'uid' => $uid])) { + if (!Post::exists(['uri-id' => $item['parent-uri-id'], 'uid' => $uid])) { $stored = self::storeForUserByUriId($item['parent-uri-id'], $uid); if (($item['parent-uri-id'] == $item['uri-id']) && !empty($stored)) { - $item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $stored]); + $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $stored]); if (!DBA::isResult($item)) { Logger::info('Could not fetch just created item - should not happen', ['stored' => $stored, 'uid' => $uid, 'item-uri' => $item_uri]); return false; @@ -3273,7 +2541,7 @@ class Item $condition = ['vid' => $vids, 'deleted' => false, 'gravity' => GRAVITY_ACTIVITY, 'author-id' => $author_id, 'uid' => $item['uid'], 'thr-parent' => $item_uri]; - $like_item = self::selectFirst(['id', 'guid', 'verb'], $condition); + $like_item = Post::selectFirst(['id', 'guid', 'verb'], $condition); if (DBA::isResult($like_item)) { /** @@ -3323,6 +2591,8 @@ class Item 'wall' => $item['wall'], 'origin' => 1, 'network' => Protocol::DFRN, + 'protocol' => Conversation::PARCEL_DIRECT, + 'direction' => Conversation::PUSH, 'gravity' => GRAVITY_ACTIVITY, 'parent' => $item['id'], 'thr-parent' => $item['uri'], @@ -3364,7 +2634,7 @@ class Item 'moderated', 'visible', 'starred', 'contact-id', 'post-type', 'uri-id', 'deleted', 'origin', 'forum_mode', 'mention', 'network', 'author-id', 'owner-id']; $condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid]; - $item = self::selectFirst($fields, $condition); + $item = Post::selectFirst($fields, $condition); if (!DBA::isResult($item)) { return; @@ -3385,7 +2655,7 @@ class Item 'wall', 'private', 'pubmail', 'moderated', 'visible', 'starred', 'contact-id', 'uri-id', 'deleted', 'origin', 'forum_mode', 'network', 'author-id', 'owner-id']; - $item = self::selectFirst($fields, ['id' => $itemid, 'gravity' => GRAVITY_PARENT]); + $item = Post::selectFirst($fields, ['id' => $itemid, 'gravity' => GRAVITY_PARENT]); if (!DBA::isResult($item)) { return; } @@ -3421,7 +2691,7 @@ class Item if ($itemuri != "") { $condition = ["`uri` = ? AND NOT `deleted` AND NOT (`uid` IN (?, 0))", $itemuri, $item["uid"]]; - if (!self::exists($condition)) { + if (!Post::exists($condition)) { DBA::delete('item', ['uri' => $itemuri, 'uid' => 0]); Logger::debug('Deleted shadow item', ['id' => $itemid, 'uri' => $itemuri]); } @@ -3451,7 +2721,7 @@ class Item if (!empty($set)) { $condition = ["(`private` != ? OR (`private` = ? AND `wall` AND `psid` IN (" . implode(', ', array_fill(0, count($set), '?')) . ")))", - Item::PRIVATE, Item::PRIVATE]; + self::PRIVATE, self::PRIVATE]; $condition = array_merge($condition, $set); } } @@ -3459,17 +2729,28 @@ class Item return $condition; } - public static function getPermissionsSQLByUserId($owner_id) + /** + * Get a permission SQL string for the given user + * + * @param int $owner_id + * @param string $table + * @return string + */ + public static function getPermissionsSQLByUserId(int $owner_id, string $table = '') { $local_user = local_user(); $remote_user = Session::getRemoteContactID($owner_id); + if (!empty($table)) { + $table = DBA::quoteIdentifier($table) . '.'; + } + /* * Construct permissions * * default permissions - anonymous user */ - $sql = sprintf(" AND `item`.`private` != %d", self::PRIVATE); + $sql = sprintf(" AND " . $table . "`private` != %d", self::PRIVATE); // Profile owner - everything is visible if ($local_user && ($local_user == $owner_id)) { @@ -3485,12 +2766,12 @@ class Item $set = PermissionSet::get($owner_id, $remote_user); if (!empty($set)) { - $sql_set = sprintf(" OR (`item`.`private` = %d AND `item`.`wall` AND `item`.`psid` IN (", self::PRIVATE) . implode(',', $set) . "))"; + $sql_set = sprintf(" OR (" . $table . "`private` = %d AND " . $table . "`wall` AND " . $table . "`psid` IN (", self::PRIVATE) . implode(',', $set) . "))"; } else { $sql_set = ''; } - $sql = sprintf(" AND (`item`.`private` != %d", self::PRIVATE) . $sql_set . ")"; + $sql = sprintf(" AND (" . $table . "`private` != %d", self::PRIVATE) . $sql_set . ")"; } return $sql; @@ -3950,7 +3231,7 @@ class 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'], ['guid' => $shared['guid'], 'uid' => [0, $uid]]); + $shared_item = Post::selectFirst(['title', 'body'], ['guid' => $shared['guid'], 'uid' => [0, $uid]]); if (!DBA::isResult($shared_item)) { if (empty($shared['link'])) { return $item; @@ -3963,7 +3244,7 @@ class Item return $item; } - $shared_item = self::selectFirst(['title', 'body'], ['id' => $id]); + $shared_item = Post::selectFirst(['title', 'body'], ['id' => $id]); if (!DBA::isResult($shared_item)) { return $item; }