From 4874e589f199238ee7be1fd81cec0cb89efb5a92 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Jun 2018 06:03:12 +0000 Subject: [PATCH 01/15] New class function to fetch items --- include/dba.php | 63 ++++++++++++++++++++++++++++------------------ src/Model/Item.php | 34 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/include/dba.php b/include/dba.php index 5245538ced..94f93ff813 100644 --- a/include/dba.php +++ b/include/dba.php @@ -1148,29 +1148,9 @@ class dba { $condition_string = self::buildCondition($condition); - $order_string = ''; - if (isset($params['order'])) { - $order_string = " ORDER BY "; - foreach ($params['order'] AS $fields => $order) { - if (!is_int($fields)) { - $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; - } else { - $order_string .= "`" . $order . "`, "; - } - } - $order_string = substr($order_string, 0, -2); - } + $param_string = self::buildParameter($params); - $limit_string = ''; - if (isset($params['limit']) && is_int($params['limit'])) { - $limit_string = " LIMIT " . $params['limit']; - } - - if (isset($params['limit']) && is_array($params['limit'])) { - $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); - } - - $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $order_string . $limit_string; + $sql = "SELECT " . $select_fields . " FROM `" . $table . "`" . $condition_string . $param_string; $result = self::p($sql, $condition); @@ -1227,14 +1207,14 @@ class dba { * @param array $condition * @return string */ - private static function buildCondition(array &$condition = []) + public static function buildCondition(array &$condition = []) { $condition_string = ''; if (count($condition) > 0) { reset($condition); $first_key = key($condition); if (is_int($first_key)) { - $condition_string = " WHERE ".array_shift($condition); + $condition_string = " WHERE (" . array_shift($condition) . ")"; } else { $new_values = []; $condition_string = ""; @@ -1251,7 +1231,7 @@ class dba { $condition_string .= "`" . $field . "` = ?"; } } - $condition_string = " WHERE " . $condition_string; + $condition_string = " WHERE (" . $condition_string . ")"; $condition = $new_values; } } @@ -1259,6 +1239,39 @@ class dba { return $condition_string; } + /** + * @brief Returns the SQL parameter string built from the provided parameter array + * + * @param array $params + * @return string + */ + public static function buildParameter(array $params = []) + { + $order_string = ''; + if (isset($params['order'])) { + $order_string = " ORDER BY "; + foreach ($params['order'] AS $fields => $order) { + if (!is_int($fields)) { + $order_string .= "`" . $fields . "` " . ($order ? "DESC" : "ASC") . ", "; + } else { + $order_string .= "`" . $order . "`, "; + } + } + $order_string = substr($order_string, 0, -2); + } + + $limit_string = ''; + if (isset($params['limit']) && is_int($params['limit'])) { + $limit_string = " LIMIT " . $params['limit']; + } + + if (isset($params['limit']) && is_array($params['limit'])) { + $limit_string = " LIMIT " . intval($params['limit'][0]) . ", " . intval($params['limit'][1]); + } + + return $order_string.$limit_string; + } + /** * @brief Fills an array with data from a query * diff --git a/src/Model/Item.php b/src/Model/Item.php index c15d10f197..be6462eb62 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -33,6 +33,40 @@ require_once 'include/text.php'; class Item extends BaseObject { + public static function select(array $fields = [], array $condition = [], $params = [], $uid = null) + { + require_once 'include/conversation.php'; + + $item_fields = ['id', 'guid']; + + $select_fields = item_fieldlists(); + + $condition_string = dba::buildCondition($condition); + + foreach ($item_fields as $field) { + $search = [" `" . $field . "`", "(`" . $field . "`"]; + $replace = [" `item`.`" . $field . "`", "(`item`.`" . $field . "`"]; + $condition_string = str_replace($search, $replace, $condition_string); + } + + $condition_string = $condition_string . ' AND ' . item_condition(); + + if (!empty($uid)) { + $condition_string .= " AND `item`.`uid` = ?"; + $condition['uid'] = $uid; + } + + $param_string = dba::buildParameter($params); + + $table = "`item` " . item_joins($uid); + + $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string; +echo $sql; + $result = dba::p($sql, $condition); + + return dba::inArray($result); + } + /** * @brief Update existing item entries * From baf316e89808b1480f1fa69916cc2b60c343993b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 16:56:37 +0000 Subject: [PATCH 02/15] The central item fetch does work now and the API now uses these functions --- include/api.php | 435 +++++++++++++-------------------------- include/conversation.php | 6 +- include/enotify.php | 12 +- src/Model/Item.php | 186 +++++++++++++++-- 4 files changed, 324 insertions(+), 315 deletions(-) diff --git a/include/api.php b/include/api.php index 91a8d42c46..4cc9826c46 100644 --- a/include/api.php +++ b/include/api.php @@ -686,14 +686,8 @@ function api_get_user(App $a, $contact_id = null) $uinfo[0]['network'] = NETWORK_DFRN; } - $usr = q( - "SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - intval(api_user()) - ); - $profile = q( - "SELECT * FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", - intval(api_user()) - ); + $usr = dba::selectFirst('user', ['default-location'], ['uid' => api_user()]); + $profile = dba::selectFirst('profile', ['about'], ['uid' => api_user(), 'is-default' => true]); /// @TODO old-lost code? (twice) // Counting is deactivated by now, due to performance issues @@ -760,14 +754,14 @@ function api_get_user(App $a, $contact_id = null) $pcontact_id = Contact::getIdForURL($uinfo[0]['url'], 0, true); - if (!empty($profile[0]['about'])) { - $description = $profile[0]['about']; + if (!empty($profile['about'])) { + $description = $profile['about']; } else { $description = $uinfo[0]["about"]; } - if (!empty($usr[0]['default-location'])) { - $location = $usr[0]['default-location']; + if (!empty($usr['default-location'])) { + $location = $usr['default-location']; } elseif (!empty($uinfo[0]["location"])) { $location = $uinfo[0]["location"]; } else { @@ -1602,7 +1596,6 @@ function api_search($type) } $data = []; - $sql_extra = ''; if (!x($_REQUEST, 'q')) { throw new BadRequestException("q parameter is required."); @@ -1622,24 +1615,20 @@ function api_search($type) $start = $page * $count; - if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); - } + $condition = ["`verb` = ? AND `item`.`id` > ? + AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) + AND `item`.`body` LIKE CONCAT('%',?,'%')", + ACTIVITY_POST, $since_id, api_user(), $_REQUEST['q']]; - $r = dba::p( - "SELECT ".item_fieldlists()." - FROM `item` ".item_joins(api_user())." - WHERE ".item_condition()." AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) - AND `item`.`body` LIKE CONCAT('%',?,'%') - $sql_extra - AND `item`.`id`>? - ORDER BY `item`.`id` DESC LIMIT ".intval($start)." ,".intval($count)." ", - api_user(), - $_REQUEST['q'], - $since_id - ); + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } - $data['status'] = api_format_items(dba::inArray($r), $user_info); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); + + $data['status'] = api_format_items(dba::inArray($statuses), $user_info); return api_format_data("statuses", $type, $data); } @@ -1689,33 +1678,24 @@ function api_statuses_home_timeline($type) $start = $page * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ?", api_user(), ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } - $r = q("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id` > %d - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); // Set all posts from the query above to seen $idarray = []; @@ -1779,61 +1759,35 @@ function api_statuses_public_timeline($type) $sql_extra = ''; if ($exclude_replies && !$conversation_id) { - if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); - } + $condition = ["`verb` = ? AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall`", + ACTIVITY_POST, $since_id]; - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins(api_user()) . " - STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` - AND NOT `user`.`hidewall` - AND `verb` = ? - AND NOT `thread`.`private` - AND `thread`.`wall` - AND `thread`.`visible` - AND NOT `thread`.`deleted` - AND NOT `thread`.`moderated` - AND `thread`.`iid` > ? - $sql_extra - ORDER BY `thread`.`iid` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + if ($max_id > 0) { + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } - $r = dba::inArray($r); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); + + $r = dba::inArray($statuses); } else { - if ($max_id > 0) { - $sql_extra = 'AND `item`.`id` <= ' . intval($max_id); - } - if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); - } + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND NOT `user`.`hidewall` AND `item`.`origin`", + api_user(), ACTIVITY_POST, $since_id]; - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `item` - " . item_joins(api_user()) . " - STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid` - AND NOT `user`.`hidewall` - AND `verb` = ? - AND NOT `item`.`private` - AND `item`.`wall` - AND `item`.`visible` - AND NOT `item`.`deleted` - AND NOT `item`.`moderated` - AND `item`.`id` > ? - $sql_extra - ORDER BY `item`.`id` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } + if ($conversation_id > 0) { + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } - $r = dba::inArray($r); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); + + $r = dba::inArray($statuses); } $ret = api_format_items($r, $user_info, false, $type); @@ -1881,33 +1835,18 @@ function api_statuses_networkpublic_timeline($type) } $start = ($page - 1) * $count; - $sql_extra = ''; - if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); - } + $condition = ["`uid` = 0 AND `verb` = ? AND `thread`.`iid` > ? AND NOT `private`", + ACTIVITY_POST, $since_id]; - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins(api_user()) . " - WHERE `thread`.`uid` = 0 - AND `verb` = ? - AND NOT `thread`.`private` - AND `thread`.`visible` - AND NOT `thread`.`deleted` - AND NOT `thread`.`moderated` - AND `thread`.`iid` > ? - $sql_extra - ORDER BY `thread`.`iid` DESC - LIMIT " . intval($start) . ", " . intval($count), - ACTIVITY_POST, - $since_id - ); + if ($max_id > 0) { + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } - $r = dba::inArray($r); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; switch ($type) { @@ -1955,13 +1894,6 @@ function api_statuses_show($type) $conversation = (x($_REQUEST, 'conversation') ? 1 : 0); - $sql_extra = ''; - if ($conversation) { - $sql_extra .= " AND `item`.`parent` = %d ORDER BY `id` ASC "; - } else { - $sql_extra .= " AND `item`.`id` = %d"; - } - // try to fetch the item for the local user - or the public item, if there is no local one $uri_item = dba::selectFirst('item', ['uri'], ['id' => $id]); if (!DBM::is_result($uri_item)) { @@ -1975,24 +1907,22 @@ function api_statuses_show($type) $id = $item['id']; - $r = q( - "SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s' - $sql_extra", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($id) - ); + if ($conversation) { + $condition = ['parent' => $id, 'verb' => ACTIVITY_POST]; + $params = ['order' => ['id' => true]]; + } else { + $condition = ['id' => $id, 'verb' => ACTIVITY_POST]; + $params = []; + } + + $statuses = Item::select(api_user(), [], $condition, $params); /// @TODO How about copying this to above methods which don't check $r ? - if (!DBM::is_result($r)) { + if (!DBM::is_result($items)) { throw new BadRequestException("There is no status with this id."); } - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); if ($conversation) { $data = ['status' => $ret]; @@ -2057,33 +1987,22 @@ function api_conversation_show($type) $id = $parent['id']; - $sql_extra = ''; + $condition = ["`parent` = ? AND `uid` IN (0, ?) AND `verb` = ? AND `item`.`id` > ?", + $id, api_user(), ACTIVITY_POST, $since_id]; if ($max_id > 0) { - $sql_extra = ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`parent` = %d AND `item`.`visible` - AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s' - AND `item`.`id`>%d $sql_extra - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval($id), - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - if (!DBM::is_result($r)) { - throw new BadRequestException("There is no status with this id."); + if (!DBM::is_result($items)) { + throw new BadRequestException("There is no status with id $id."); } - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; return api_format_data("statuses", $type, $data); @@ -2126,24 +2045,17 @@ function api_statuses_repeat($type) logger('API: api_statuses_repeat: '.$id); - $r = q("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND NOT `item`.`private` - AND `item`.`id`=%d", - intval($id) - ); + $fields = ['body', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $item = Item::selectFirst(api_user(), $fields, ['id' => $id, 'private' => false]); - /// @TODO other style than above functions! - if (DBM::is_result($r) && $r[0]['body'] != "") { - if (strpos($r[0]['body'], "[/share]") !== false) { - $pos = strpos($r[0]['body'], "[share"); - $post = substr($r[0]['body'], $pos); + if (DBM::is_result($item) && $item['body'] != "") { + if (strpos($item['body'], "[/share]") !== false) { + $pos = strpos($item['body'], "[share"); + $post = substr($item['body'], $pos); } else { - $post = share_header($r[0]['author-name'], $r[0]['author-link'], $r[0]['author-avatar'], $r[0]['guid'], $r[0]['created'], $r[0]['plink']); + $post = share_header($item['author-name'], $item['author-link'], $item['author-avatar'], $item['guid'], $item['created'], $item['plink']); - $post .= $r[0]['body']; + $post .= $item['body']; $post .= "[/share]"; } $_REQUEST['body'] = $post; @@ -2244,32 +2156,19 @@ function api_statuses_mentions($type) $start = ($page - 1) * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ? AND `author-id` != ? + AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `uid` = ? AND `mention` AND NOT `ignored`)", + api_user(), ACTIVITY_POST, $since_id, $user_info['pid'], api_user()]; if ($max_id > 0) { - $sql_extra = ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q("SELECT `item`.* FROM `item` FORCE INDEX (`uid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `item`.`verb` = '%s' - AND `item`.`author-id` != %d - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`parent` IN (SELECT `iid` FROM `thread` WHERE `uid` = %d AND `mention` AND NOT `ignored`) - $sql_extra - AND `item`.`id` > %d - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($user_info['pid']), - intval(api_user()), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $ret]; switch ($type) { @@ -2325,41 +2224,31 @@ function api_statuses_user_timeline($type) } $start = ($page - 1) * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `item`.`id` > ? AND `item`.`contact-id` = ?", + api_user(), ACTIVITY_POST, $since_id, $user_info['cid']]; + if ($user_info['self'] == 1) { - $sql_extra .= " AND `item`.`wall` = 1 "; + $condition[0] .= ' AND `item`.`wall` '; } if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; } if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; } if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q("SELECT `item`.* FROM `item` FORCE INDEX (`uid_contactid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND `item`.`contact-id` = %d - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id` > %d - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($user_info['cid']), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, true, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, true, $type); $data = ['status' => $ret]; switch ($type) { @@ -2409,24 +2298,24 @@ function api_favorites_create_destroy($type) $itemid = intval($_REQUEST['id']); } - $item = q("SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d LIMIT 1", $itemid, api_user()); + $item = Item::selectFirst(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); - if (!DBM::is_result($item) || count($item) == 0) { + if (!DBM::is_result($item)) { throw new BadRequestException("Invalid item."); } switch ($action) { case "create": - $item[0]['starred'] = 1; + $item['starred'] = 1; break; case "destroy": - $item[0]['starred'] = 0; + $item['starred'] = 0; break; default: throw new BadRequestException("Invalid action ".$action); } - $r = Item::update(['starred' => $item[0]['starred']], ['id' => $itemid]); + $r = Item::update(['starred' => $item['starred']], ['id' => $itemid]); if ($r === false) { throw new InternalServerErrorException("DB error"); @@ -2434,7 +2323,7 @@ function api_favorites_create_destroy($type) $user_info = api_get_user($a); - $rets = api_format_items($item, $user_info, false, $type); + $rets = api_format_items([$item], $user_info, false, $type); $ret = $rets[0]; $data = ['status' => $ret]; @@ -2478,8 +2367,6 @@ function api_favorites($type) if ($user_info['self'] == 0) { $ret = []; } else { - $sql_extra = ""; - // params $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); @@ -2491,26 +2378,19 @@ function api_favorites($type) $start = $page*$count; + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `starred`", + api_user(), ACTIVITY_POST, $since_id]; + + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = q("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`starred` - $sql_extra - AND `item`.`id`>%d - ORDER BY `item`.`id` DESC LIMIT %d ,%d", - intval(api_user()), - intval($since_id), - intval($start), - intval($count) - ); + $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); } $data = ['status' => $ret]; @@ -3300,32 +3180,23 @@ function api_lists_statuses($type) $start = $page * $count; - $sql_extra = ''; - if ($max_id > 0) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); - } - if ($exclude_replies > 0) { - $sql_extra .= ' AND `item`.`parent` = `item`.`id`'; - } - if ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); - } + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `group_member`.`gid` = ?", + api_user(), ACTIVITY_POST, $since_id, $_REQUEST['list_id']]; - $statuses = dba::p("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = `item`.`contact-id` - WHERE `item`.`uid` = ? AND `verb` = ? - AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - $sql_extra - AND `item`.`id`>? - AND `group_member`.`gid` = ? - ORDER BY `item`.`id` DESC LIMIT ".intval($start)." ,".intval($count), - api_user(), - ACTIVITY_POST, - $since_id, - $_REQUEST['list_id'] - ); + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } + if ($exclude_replies > 0) { + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; + } + if ($conversation_id > 0) { + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } + + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); $items = api_format_items(dba::inArray($statuses), $user_info, false, $type); @@ -4847,19 +4718,13 @@ function prepare_photo_data($type, $scale, $photo_id) $data['photo']['friendica_activities'] = api_format_items_activities($item[0], $type); // retrieve comments on photo - $r = q("SELECT `item`.* FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`parent` = %d AND `item`.`visible` - AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` = %d AND (`item`.`verb`='%s' OR `type`='photo')", - intval($item[0]['parent']), - intval(api_user()), - dbesc(ACTIVITY_POST) - ); + $condition = ["`parent` = ? AND `uid` = ? AND (`verb` = ? OR `type`='photo')", + $item[0]['parent'], api_user(), ACTIVITY_POST]; + + $statuses = Item::select(api_user(), [], $condition); // prepare output of comments - $commentData = api_format_items($r, $user_info, false, $type); + $commentData = api_format_items(dba::inArray($statuses), $user_info, false, $type); $comments = []; if ($type == "xml") { $k = 0; @@ -5849,14 +5714,10 @@ function api_friendica_notification_seen($type) $nm->setSeen($note); if ($note['otype']=='item') { // would be really better with an ItemsManager and $im->getByID() :-P - $r = q( - "SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d", - intval($note['iid']), - intval(local_user()) - ); - if ($r!==false) { + $item = Item::selectFirst(api_user(), [], ['id' => $note['iid'], 'uid' => api_user()]); + if (DBM::is_result($$item)) { // we found the item, return it to the user - $ret = api_format_items($r, $user_info, false, $type); + $ret = api_format_items([$item], $user_info, false, $type); $data = ['status' => $ret]; return api_format_data("status", $type, $data); } diff --git a/include/conversation.php b/include/conversation.php index 6ce2004987..e63488df2d 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -467,8 +467,8 @@ function item_joins($uid = 0) { AND NOT `contact`.`blocked` AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s))) OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0) - INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked` - INNER JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked` + STRAIGHT_JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked` + STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked` LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d LEFT JOIN `event` ON `event-id` = `event`.`id`", CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid) @@ -734,7 +734,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'guid' => (($preview) ? 'Q0' : $item['guid']), 'network' => $item['item_network'], 'network_name' => ContactSelector::networkToName($item['item_network'], $profile_link), - 'linktitle' => L10n::t('View %s\'s profile @ %s', $profile_name, ((strlen($item['author-link'])) ? $item['author-link'] : $item['url'])), + 'linktitle' => L10n::t('View %s\'s profile @ %s', $profile_name, $item['author-link']), 'profile_url' => $profile_link, 'item_photo_menu' => item_photo_menu($item), 'name' => $profile_name_e, diff --git a/include/enotify.php b/include/enotify.php index 257c107207..d98465c6ec 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -129,7 +129,7 @@ function notification($params) $item = null; if ($params['otype'] === 'item' && $parent_id) { - $item = dba::selectFirst('item', [], ['id' => $parent_id]); + $item = Item::selectFirst($params['uid'], [], ['id' => $parent_id]); } $item_post_type = item_post_type($item); @@ -739,7 +739,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { // Only act if it is a "real" post // We need the additional check for the "local_profile" because of mixed situations on connector networks - $item = q("SELECT `id`, `mention`, `tag`,`parent`, `title`, `body`, `author-name`, `author-link`, `author-avatar`, `guid`, + $item = q("SELECT `id`, `mention`, `tag`,`parent`, `title`, `body`, `author-id`, `guid`, `parent-uri`, `uri`, `contact-id` FROM `item` WHERE `id` = %d AND `verb` IN ('%s', '') AND `type` != 'activity' AND NOT (`author-link` IN ($profile_list)) LIMIT 1", @@ -747,6 +747,8 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { if (!$item) return false; + $author = dba::selectFirst('contact', ['name', 'thumb', 'url'], ['id' => $item[0]['author-id']]); + // Generate the notification array $params = []; $params["uid"] = $uid; @@ -758,9 +760,9 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { $params["parent"] = $item[0]["parent"]; $params["link"] = System::baseUrl().'/display/'.urlencode($item[0]["guid"]); $params["otype"] = 'item'; - $params["source_name"] = $item[0]["author-name"]; - $params["source_link"] = $item[0]["author-link"]; - $params["source_photo"] = $item[0]["author-avatar"]; + $params["source_name"] = $author["name"]; + $params["source_link"] = $author["url"]; + $params["source_photo"] = $author["thumb"]; if ($item[0]["parent-uri"] === $item[0]["uri"]) { // Send a notification for every new post? diff --git a/src/Model/Item.php b/src/Model/Item.php index be6462eb62..1a468bfa11 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -33,38 +33,184 @@ require_once 'include/text.php'; class Item extends BaseObject { - public static function select(array $fields = [], array $condition = [], $params = [], $uid = null) + public static function selectFirst($uid, array $fields = [], array $condition = [], $params = []) { - require_once 'include/conversation.php'; + $params['limit'] = 1; + $result = self::select($uid, $fields, $condition, $params); - $item_fields = ['id', 'guid']; + if (is_bool($result)) { + return $result; + } else { + $row = dba::fetch($result); + dba::close($result); + return $row; + } + } - $select_fields = item_fieldlists(); + public static function select($uid, array $selected = [], array $condition = [], $params = []) + { + $fields = self::fieldlist(); + + $select_fields = self::constructSelectFields($fields, $selected); $condition_string = dba::buildCondition($condition); - foreach ($item_fields as $field) { - $search = [" `" . $field . "`", "(`" . $field . "`"]; - $replace = [" `item`.`" . $field . "`", "(`item`.`" . $field . "`"]; - $condition_string = str_replace($search, $replace, $condition_string); - } + $condition_string = self::addTablesToFields($condition_string, $fields); - $condition_string = $condition_string . ' AND ' . item_condition(); + $condition_string = $condition_string . ' AND ' . self::condition(); - if (!empty($uid)) { - $condition_string .= " AND `item`.`uid` = ?"; - $condition['uid'] = $uid; - } + $param_string = self::addTablesToFields(dba::buildParameter($params), $fields); - $param_string = dba::buildParameter($params); - - $table = "`item` " . item_joins($uid); + $table = "`item` " . self::constructJoins($uid, $select_fields . $condition_string . $param_string, false); $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string; -echo $sql; - $result = dba::p($sql, $condition); - return dba::inArray($result); + return dba::p($sql, $condition); + } + + public static function selectFirstThread($uid, array $fields = [], array $condition = [], $params = []) + { + $params['limit'] = 1; + $result = self::selectThread($uid, $fields, $condition, $params); + + if (is_bool($result)) { + return $result; + } else { + $row = dba::fetch($result); + dba::close($result); + return $row; + } + } + + public static function selectThread($uid, array $selected = [], array $condition = [], $params = []) + { + $fields = self::fieldlist(); + + $threadfields = ['thread' => ['iid', 'uid', 'contact-id', 'owner-id', 'author-id', + 'created', 'edited', 'commented', 'received', 'changed', 'wall', 'private', + 'pubmail', 'moderated', 'visible', 'starred', 'ignored', 'bookmark', + '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); + + $condition_string = $condition_string . ' AND ' . self::condition(); + + $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); + + $sql = "SELECT " . $select_fields . " FROM " . $table . $condition_string . $param_string; + + return dba::p($sql, $condition); + } + + private static function fieldlist() + { + $item_fields = ['author-id', 'owner-id', 'contact-id', 'uid', 'id', 'parent', + 'uri', 'thr-parent', 'parent-uri', 'content-warning', + 'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink', + 'guid', 'wall', 'private', 'starred', 'origin', 'title', 'body', 'file', 'event-id', + 'location', 'coord', 'app', 'attach', 'rendered-hash', 'rendered-html', 'object', + 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', + 'id' => 'item_id', 'network' => 'item_network']; + + $author_fields = ['url' => 'author-link', 'name' => 'author-name', 'thumb' => 'author-avatar']; + $owner_fields = ['url' => 'owner-link', 'name' => 'owner-name', 'thumb' => 'owner-avatar']; + $contact_fields = ['url' => 'contact-link', 'name' => 'contact-name', 'thumb' => 'contact-avatar', + 'network', 'url', 'name', 'writable', 'self', 'id' => 'cid', 'alias']; + + $event_fields = ['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']; + + return ['item' => $item_fields, 'author' => $author_fields, 'owner' => $owner_fields, + 'contact' => $contact_fields, 'event' => $event_fields]; + } + + private static function condition() + { + return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) "; + } + + private static function constructJoins($uid, $sql_commands, $thread_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 = ''; + } + + $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`.`id` != `item`.`parent`) 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", + CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid)); + + 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`"; + } + + return $joins; + } + + private static function constructSelectFields($fields, $selected) + { + $selection = []; + foreach ($fields as $table => $table_fields) { + foreach ($table_fields as $field => $select) { + if (empty($selected) || in_array($select, $selected)) { + if (is_int($field)) { + $selection[] = "`" . $table . "`.`".$select."`"; + } else { + $selection[] = "`" . $table . "`.`" . $field . "` AS `".$select ."`"; + } + } + } + } + return implode(", ", $selection); + } + + 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; } /** From 446a45003dff9ae861c62e997471aa9bd58e450a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 19:12:13 +0000 Subject: [PATCH 03/15] Added documentation, some indention fixes --- include/api.php | 82 +++++++++++++++++------------------ src/Model/Item.php | 106 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 136 insertions(+), 52 deletions(-) diff --git a/include/api.php b/include/api.php index 4cc9826c46..256d0431c6 100644 --- a/include/api.php +++ b/include/api.php @@ -1615,18 +1615,18 @@ function api_search($type) $start = $page * $count; - $condition = ["`verb` = ? AND `item`.`id` > ? + $condition = ["`verb` = ? AND `item`.`id` > ? AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`)) AND `item`.`body` LIKE CONCAT('%',?,'%')", ACTIVITY_POST, $since_id, api_user(), $_REQUEST['q']]; - if ($max_id > 0) { - $condition[0] .= " AND `item`.`id` <= ?"; - $condition[] = $max_id; - } + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; - $statuses = Item::select(api_user(), [], $condition, $params); + $statuses = Item::select(api_user(), [], $condition, $params); $data['status'] = api_format_items(dba::inArray($statuses), $user_info); @@ -1762,30 +1762,30 @@ function api_statuses_public_timeline($type) $condition = ["`verb` = ? AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall`", ACTIVITY_POST, $since_id]; - if ($max_id > 0) { - $condition[0] .= " AND `thread`.`iid` <= ?"; - $condition[] = $max_id; - } + if ($max_id > 0) { + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } - $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; - $statuses = Item::selectThread(api_user(), [], $condition, $params); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); $r = dba::inArray($statuses); } else { $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND NOT `user`.`hidewall` AND `item`.`origin`", api_user(), ACTIVITY_POST, $since_id]; - if ($max_id > 0) { - $condition[0] .= " AND `item`.`id` <= ?"; - $condition[] = $max_id; - } - if ($conversation_id > 0) { - $condition[0] .= " AND `item`.`parent` = ?"; - $condition[] = $conversation_id; - } + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } + if ($conversation_id > 0) { + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } - $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; - $statuses = Item::select(api_user(), [], $condition, $params); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::select(api_user(), [], $condition, $params); $r = dba::inArray($statuses); } @@ -1838,13 +1838,13 @@ function api_statuses_networkpublic_timeline($type) $condition = ["`uid` = 0 AND `verb` = ? AND `thread`.`iid` > ? AND NOT `private`", ACTIVITY_POST, $since_id]; - if ($max_id > 0) { - $condition[0] .= " AND `thread`.`iid` <= ?"; - $condition[] = $max_id; - } + if ($max_id > 0) { + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } - $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; - $statuses = Item::selectThread(api_user(), [], $condition, $params); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThread(api_user(), [], $condition, $params); $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); @@ -2298,7 +2298,7 @@ function api_favorites_create_destroy($type) $itemid = intval($_REQUEST['id']); } - $item = Item::selectFirst(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); + $item = Item::selectFirst(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); if (!DBM::is_result($item)) { throw new BadRequestException("Invalid item."); @@ -3180,20 +3180,20 @@ function api_lists_statuses($type) $start = $page * $count; - $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `group_member`.`gid` = ?", + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `group_member`.`gid` = ?", api_user(), ACTIVITY_POST, $since_id, $_REQUEST['list_id']]; - if ($max_id > 0) { - $condition[0] .= " AND `item`.`id` <= ?"; - $condition[] = $max_id; - } - if ($exclude_replies > 0) { - $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; - } - if ($conversation_id > 0) { - $condition[0] .= " AND `item`.`parent` = ?"; - $condition[] = $conversation_id; - } + if ($max_id > 0) { + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; + } + if ($exclude_replies > 0) { + $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; + } + if ($conversation_id > 0) { + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; $statuses = Item::select(api_user(), [], $condition, $params); diff --git a/src/Model/Item.php b/src/Model/Item.php index 1a468bfa11..e79f3704d3 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -33,6 +33,17 @@ require_once 'include/text.php'; class Item extends BaseObject { + /** + * Retrieve a single record from 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 $fields + * @param array $condition + * @param array $params + * @return bool|array + * @see dba::select + */ public static function selectFirst($uid, array $fields = [], array $condition = [], $params = []) { $params['limit'] = 1; @@ -47,6 +58,16 @@ class Item extends BaseObject } } + /** + * @brief Select rows from the item table + * + * @param integer $uid User ID + * @param array $fields 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 + */ public static function select($uid, array $selected = [], array $condition = [], $params = []) { $fields = self::fieldlist(); @@ -57,7 +78,7 @@ class Item extends BaseObject $condition_string = self::addTablesToFields($condition_string, $fields); - $condition_string = $condition_string . ' AND ' . self::condition(); + $condition_string = $condition_string . ' AND ' . self::condition(false); $param_string = self::addTablesToFields(dba::buildParameter($params), $fields); @@ -68,6 +89,17 @@ class Item extends BaseObject return dba::p($sql, $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 integer $uid User ID + * @param array $fields + * @param array $condition + * @param array $params + * @return bool|array + * @see dba::select + */ public static function selectFirstThread($uid, array $fields = [], array $condition = [], $params = []) { $params['limit'] = 1; @@ -82,6 +114,16 @@ class Item extends BaseObject } } + /** + * @brief Select rows from the starting post in the item table + * + * @param integer $uid User ID + * @param array $fields 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 + */ public static function selectThread($uid, array $selected = [], array $condition = [], $params = []) { $fields = self::fieldlist(); @@ -98,7 +140,7 @@ class Item extends BaseObject $condition_string = self::addTablesToFields($condition_string, $threadfields); $condition_string = self::addTablesToFields($condition_string, $fields); - $condition_string = $condition_string . ' AND ' . self::condition(); + $condition_string = $condition_string . ' AND ' . self::condition(true); $param_string = dba::buildParameter($params); $param_string = self::addTablesToFields($param_string, $threadfields); @@ -111,6 +153,11 @@ class Item extends BaseObject return dba::p($sql, $condition); } + /** + * @brief Returns a list of fields that are associated with the item table + * + * @return array field list + */ private static function fieldlist() { $item_fields = ['author-id', 'owner-id', 'contact-id', 'uid', 'id', 'parent', @@ -137,11 +184,32 @@ class Item extends BaseObject 'contact' => $contact_fields, 'event' => $event_fields]; } - private static function condition() + /** + * @brief 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) { - return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) "; + if ($thread_mode) { + $master_table = "`thread`"; + } else { + $master_table = "`item`"; + } + return "$master_table.`visible` AND NOT $master_table.`deleted` AND NOT $master_table.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) "; } + /** + * @brief 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) + * + * @return string The SQL joins for the "select" functions + */ private static function constructJoins($uid, $sql_commands, $thread_mode) { if ($thread_mode) { @@ -155,13 +223,13 @@ class Item extends BaseObject } $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`.`id` != `item`.`parent`) 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", - CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid)); + AND NOT `contact`.`blocked` + AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s))) + OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) 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", + CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid)); if (strpos($sql_commands, "`group_member`.") !== false) { $joins .= " STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = $master_table.`contact-id`"; @@ -178,6 +246,14 @@ class Item extends BaseObject return $joins; } + /** + * @brief 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($fields, $selected) { $selection = []; @@ -195,6 +271,14 @@ class Item extends BaseObject return implode(", ", $selection); } + /** + * @brief 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) { From 50dfc7d36ef08d1be8c50b0612ca0d8613c2aab5 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 19:27:44 +0000 Subject: [PATCH 04/15] Small query corrections --- include/api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/api.php b/include/api.php index 256d0431c6..95b462ae7f 100644 --- a/include/api.php +++ b/include/api.php @@ -1772,8 +1772,8 @@ function api_statuses_public_timeline($type) $r = dba::inArray($statuses); } else { - $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND NOT `user`.`hidewall` AND `item`.`origin`", - api_user(), ACTIVITY_POST, $since_id]; + $condition = ["`verb` = ? AND `id` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND `item`.`origin`", + ACTIVITY_POST, $since_id]; if ($max_id > 0) { $condition[0] .= " AND `item`.`id` <= ?"; From b6c344a80a028df3607306f1fa8928ec5ac72796 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 20:08:15 +0000 Subject: [PATCH 05/15] $r was still in use --- include/api.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/api.php b/include/api.php index 95b462ae7f..dba20d4c1b 100644 --- a/include/api.php +++ b/include/api.php @@ -1695,11 +1695,13 @@ function api_statuses_home_timeline($type) $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; $statuses = Item::select(api_user(), [], $condition, $params); - $ret = api_format_items(dba::inArray($statuses), $user_info, false, $type); + $items = dba::inArray($statuses); + + $ret = api_format_items($items, $user_info, false, $type); // Set all posts from the query above to seen $idarray = []; - foreach ($r as $item) { + foreach ($items as $item) { $idarray[] = intval($item["id"]); } From defd3d15b63236fefa5b3f880de344f213414d1b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 20:39:40 +0000 Subject: [PATCH 06/15] Possibly fixed test --- include/api.php | 4 ++-- tests/ApiTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/api.php b/include/api.php index dba20d4c1b..00c2173c38 100644 --- a/include/api.php +++ b/include/api.php @@ -1920,7 +1920,7 @@ function api_statuses_show($type) $statuses = Item::select(api_user(), [], $condition, $params); /// @TODO How about copying this to above methods which don't check $r ? - if (!DBM::is_result($items)) { + if (!DBM::is_result($statuses)) { throw new BadRequestException("There is no status with this id."); } @@ -2000,7 +2000,7 @@ function api_conversation_show($type) $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; $statuses = Item::select(api_user(), [], $condition, $params); - if (!DBM::is_result($items)) { + if (!DBM::is_result($statuses)) { throw new BadRequestException("There is no status with id $id."); } diff --git a/tests/ApiTest.php b/tests/ApiTest.php index f0e27b4af1..c21f651d5f 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -1871,7 +1871,7 @@ class ApiTest extends DatabaseTest $this->app->argv[1] = '1.1'; $this->app->argv[3] = 'create'; $this->app->argc = 10; - $_REQUEST['id'] = 1; + $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); } @@ -1885,7 +1885,7 @@ class ApiTest extends DatabaseTest $this->app->argv[1] = '1.1'; $this->app->argv[3] = 'create'; $this->app->argc = 10; - $_REQUEST['id'] = 1; + $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('rss'); $this->assertXml($result, 'status'); } @@ -1899,7 +1899,7 @@ class ApiTest extends DatabaseTest $this->app->argv[1] = '1.1'; $this->app->argv[3] = 'destroy'; $this->app->argc = 10; - $_REQUEST['id'] = 1; + $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); } From eca43895e1af80b41098b8854511812aa149f195 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Jun 2018 21:46:35 +0000 Subject: [PATCH 07/15] Fixing tests --- tests/datasets/api.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index 9cacab714b..9ba5ec387e 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -48,7 +48,7 @@ contact: network: dfrn - id: 44 - uid: 42 + uid: 0 name: Friend contact nick: friendcontact self: false @@ -74,6 +74,7 @@ item: author-link: http://localhost/profile/selfcontact wall: true starred: true + origin: true allow_cid: '' allow_gid: '' deny_cid: '' @@ -92,6 +93,7 @@ item: author-link: http://localhost/profile/selfcontact wall: true starred: false + origin: true - id: 3 visible: true @@ -106,20 +108,22 @@ item: author-link: http://localhost/profile/othercontact wall: true starred: false + origin: true - id: 4 visible: true - contact-id: 43 - author-id: 43 + contact-id: 44 + author-id: 44 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post unseen: false - body: Other user reply + body: Friend user reply parent: 1 author-link: http://localhost/profile/othercontact wall: true starred: false + origin: true - id: 5 visible: true @@ -134,6 +138,7 @@ item: author-link: http://localhost/profile/othercontact wall: true starred: false + origin: true allow_cid: '' allow_gid: '' deny_cid: '' @@ -152,24 +157,31 @@ item: author-link: http://localhost/profile/othercontact wall: true starred: false + origin: true thread: - iid: 1 visible: true contact-id: 42 + author-id: 42 + owner-id: 42 uid: 42 wall: true - iid: 3 visible: true contact-id: 43 + author-id: 43 + owner-id: 43 uid: 0 wall: true - iid: 6 visible: true contact-id: 44 + author-id: 44 + owner-id: 44 uid: 0 wall: true From 5d9083c3691b15655c403e0bffde039702b6c61e Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 07:26:37 +0000 Subject: [PATCH 08/15] Bugfix in notifications / network and display are using the new functions now --- include/conversation.php | 19 ++++++++++--------- include/enotify.php | 1 + mod/display.php | 10 +++++----- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/conversation.php b/include/conversation.php index e63488df2d..527f38e2aa 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -15,6 +15,7 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Contact; use Friendica\Model\Profile; +use Friendica\Model\Item; use Friendica\Object\Post; use Friendica\Object\Thread; use Friendica\Util\DateTimeFormat; @@ -865,21 +866,21 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order = function conversation_add_children($parents, $block_authors, $order, $uid) { $max_comments = Config::get('system', 'max_comments', 100); + $params = ['order' => ['uid', 'commented' => true]]; + if ($max_comments > 0) { - $limit = ' LIMIT '.intval($max_comments + 1); - } else { - $limit = ''; + $params['limit'] = $max_comments; } $items = []; - $block_sql = $block_authors ? "AND NOT `author`.`hidden` AND NOT `author`.`blocked`" : ""; - foreach ($parents AS $parent) { - $thread_items = dba::p(item_query(local_user())."AND `item`.`parent-uri` = ? - AND `item`.`uid` IN (0, ?) $block_sql - ORDER BY `item`.`uid` ASC, `item`.`commented` DESC" . $limit, - $parent['uri'], local_user()); + $condition = ["`item`.`parent-uri` = ? AND `item`.`uid` IN (0, ?) ", + $parent['uri'], local_user()]; + if ($block_authors) { + $condition[0] .= "AND NOT `author`.`hidden`"; + } + $thread_items = Item::select(local_user(), [], $condition, $params); $comments = dba::inArray($thread_items); diff --git a/include/enotify.php b/include/enotify.php index d98465c6ec..7eb2c80ebc 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -11,6 +11,7 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; +use Friendica\Model\Item; /** * @brief Creates a notification entry and possibly sends a mail diff --git a/mod/display.php b/mod/display.php index 6380e6f6ca..816af820a1 100644 --- a/mod/display.php +++ b/mod/display.php @@ -14,6 +14,7 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Contact; use Friendica\Model\Group; +use Friendica\Model\Item; use Friendica\Model\Profile; use Friendica\Protocol\DFRN; @@ -345,11 +346,10 @@ function display_content(App $a, $update = false, $update_uid = 0) { return ''; } - $r = dba::p(item_query(local_user())."AND `item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?) - AND `item`.`uid` IN (0, ?) $sql_extra - ORDER BY `item`.`uid` ASC, `parent` DESC, `gravity` ASC, `id` ASC", - $item_id, local_user() - ); + $condition = ["`item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?) + AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, local_user()]; + $params = ['order' => ['uid', 'parent' => true, 'gravity', 'id']]; + $r = Item::select(local_user(), [], $condition, $params); if (!DBM::is_result($r)) { notice(L10n::t('Item not found.') . EOL); From a89a1f31b55ba3708bf337b6742b131021086f95 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 08:08:53 +0000 Subject: [PATCH 09/15] Profile is now using the new function as well --- mod/profile.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/mod/profile.php b/mod/profile.php index 2fb947a836..91d04b2de9 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -337,16 +337,9 @@ function profile_content(App $a, $update = 0) $parents_arr[] = $rr['item_id']; } - $parents_str = implode(', ', $parents_arr); - - $items = q(item_query($a->profile['profile_uid']) . " AND `item`.`uid` = %d - AND `item`.`parent` IN (%s) - $sql_extra ", - intval($a->profile['profile_uid']), - dbesc($parents_str) - ); - - $items = conv_sort($items, 'created'); + $condition = ['uid' => $a->profile['profile_uid'], 'parent' => $parents_arr]; + $result = Item::select($a->profile['profile_uid'], [], $condition); + $items = conv_sort(dba::inArray($result), 'created'); } else { $items = []; } From b26c5e7f732add163c1661a3f91c089b703965aa Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 08:30:27 +0000 Subject: [PATCH 10/15] And now the notes --- mod/notes.php | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/mod/notes.php b/mod/notes.php index 96a2826089..f1a82bd457 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -7,6 +7,7 @@ use Friendica\Content\Nav; use Friendica\Core\L10n; use Friendica\Database\DBM; use Friendica\Model\Profile; +use Friendica\Model\Item; function notes_init(App $a) { @@ -112,22 +113,11 @@ function notes_content(App $a, $update = false) foreach ($r as $rr) { $parents_arr[] = $rr['item_id']; } - $parents_str = implode(', ', $parents_arr); - - $r = q("SELECT %s FROM `item` %s - WHERE %s AND `item`.`uid` = %d AND `item`.`parent` IN (%s) - $sql_extra - ORDER BY `parent` DESC, `gravity` ASC, `item`.`id` ASC ", - item_fieldlists(), - item_joins(local_user()), - item_condition(), - intval(local_user()), - dbesc($parents_str) - ); - - if (DBM::is_result($r)) { - $items = conv_sort($r, "`commented`"); + $condition = ['uid' => local_user(), 'parent' => $parents_arr]; + $result = Item::select(local_user(), [], $condition); + if (DBM::is_result($result)) { + $items = conv_sort(dba::inArray($result), 'commented'); $o .= conversation($a, $items, 'notes', $update); } } From 8375d4ac4cb32fa7de3bfe14c061bde266b822ad Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 08:58:03 +0000 Subject: [PATCH 11/15] Notes again --- mod/notes.php | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/mod/notes.php b/mod/notes.php index f1a82bd457..be9fe0d70a 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -78,6 +78,7 @@ function notes_content(App $a, $update = false) $sql_extra = " AND `item`.`allow_cid` = '<" . $a->contact['id'] . ">' "; + /// @todo We seem to need "Item::count" as function as well $r = q("SELECT COUNT(*) AS `total` FROM `item` %s WHERE %s AND `item`.`uid` = %d AND `item`.`type` = 'note' @@ -93,26 +94,21 @@ function notes_content(App $a, $update = false) $a->set_pager_itemspage(40); } - $r = q("SELECT `item`.`id` AS `item_id` FROM `item` %s - WHERE %s AND `item`.`uid` = %d AND `item`.`type` = 'note' - AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall` - $sql_extra - ORDER BY `item`.`created` DESC LIMIT %d ,%d ", - item_joins(local_user()), - item_condition(), - intval(local_user()), - intval($a->pager['start']), - intval($a->pager['itemspage']) + $condition = ["`uid` = ? AND `type` = 'note' AND NOT `wall` + AND `id` = `parent` AND `allow_cid` = ?", + local_user(), '<' . $a->contact['id'] . '>']; + $params = ['order' => ['created' => true], + 'limit' => [$a->pager['start'], $a->pager['itemspage']]]; - ); - - $parents_arr = []; - $parents_str = ''; + $r = Item::select(local_user(), ['item_id'], $condition, $params); if (DBM::is_result($r)) { - foreach ($r as $rr) { + $parents_arr = []; + + while ($rr = dba::fetch($r)) { $parents_arr[] = $rr['item_id']; } + dba::close($r); $condition = ['uid' => local_user(), 'parent' => $parents_arr]; $result = Item::select(local_user(), [], $condition); From 4d4cce48671c162a8e21138449d82f316e152be5 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 10:14:53 +0000 Subject: [PATCH 12/15] The new function is now used here as well. --- src/Model/Contact.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Model/Contact.php b/src/Model/Contact.php index bf5b276dd2..e504849f7c 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1055,22 +1055,22 @@ class Contact extends BaseObject } if (in_array($r[0]["network"], [NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""])) { - $sql = "(`item`.`uid` = 0 OR (`item`.`uid` = %d AND NOT `item`.`global`))"; + $sql = "(`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`))"; } else { - $sql = "`item`.`uid` = %d"; + $sql = "`item`.`uid` = ?"; } $author_id = intval($r[0]["author-id"]); $contact = ($r[0]["contact-type"] == ACCOUNT_TYPE_COMMUNITY ? 'owner-id' : 'author-id'); - $r = q(item_query(local_user()) . " AND `item`.`" . $contact . "` = %d AND " . $sql . - " AND `item`.`verb` = '%s' ORDER BY `item`.`created` DESC LIMIT %d, %d", - intval($author_id), intval(local_user()), dbesc(ACTIVITY_POST), - intval($a->pager['start']), intval($a->pager['itemspage']) - ); + $condition = ["`$contact` = ? AND `verb` = ? AND " . $sql, + $author_id, ACTIVITY_POST, local_user()]; + $params = ['order' => ['created' => true], + 'limit' => [$a->pager['start'], $a->pager['itemspage']]]; + $r = Item::select(local_user(), [], $condition, $params); - $o = conversation($a, $r, 'contact-posts', false); + $o = conversation($a, dba::inArray($r), 'contact-posts', false); $o .= alt_pager($a, count($r)); From c1d9c29eeac4356e578c06fdb6cd5151dcf49b5a Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 14:36:22 +0000 Subject: [PATCH 13/15] Search is now changed as well. --- mod/search.php | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/mod/search.php b/mod/search.php index a600965e46..c42bcacfa0 100644 --- a/mod/search.php +++ b/mod/search.php @@ -10,6 +10,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\Database\DBM; +use Friendica\Model\Item; require_once 'include/security.php'; require_once 'include/conversation.php'; @@ -197,34 +198,34 @@ function search_content(App $a) { if ($tag) { logger("Start tag search for '".$search."'", LOGGER_DEBUG); - $r = q("SELECT %s - FROM `term` - STRAIGHT_JOIN `item` ON `item`.`id`=`term`.`oid` %s - WHERE %s AND (`term`.`uid` = 0 OR (`term`.`uid` = %d AND NOT `term`.`global`)) - AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`term` = '%s' AND `item`.`verb` = '%s' - AND NOT `author`.`blocked` AND NOT `author`.`hidden` - ORDER BY term.created DESC LIMIT %d , %d ", - item_fieldlists(), item_joins(local_user()), item_condition(), - intval(local_user()), - intval(TERM_OBJ_POST), intval(TERM_HASHTAG), dbesc(protect_sprintf($search)), dbesc(ACTIVITY_POST), - intval($a->pager['start']), intval($a->pager['itemspage'])); + $condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`)) + AND `otype` = ? AND `type` = ? AND `term` = ?", + local_user(), TERM_OBJ_POST, TERM_HASHTAG, $search]; + $params = ['order' => ['created' => true], + 'limit' => [$a->pager['start'], $a->pager['itemspage']]]; + $terms = dba::select('term', ['oid'], $condition, $params); + + $itemids = []; + while ($term = dba::fetch($terms)) { + $itemids[] = $term['oid']; + } + dba::close($terms); + + $items = Item::select(local_user(), [], ['id' => array_reverse($itemids)]); + $r = dba::inArray($items); } else { logger("Start fulltext search for '".$search."'", LOGGER_DEBUG); - $sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search)))); - - $r = q("SELECT %s - FROM `item` %s - WHERE %s AND (`item`.`uid` = 0 OR (`item`.`uid` = %s AND NOT `item`.`global`)) - AND NOT `author`.`blocked` AND NOT `author`.`hidden` - $sql_extra - GROUP BY `item`.`uri`, `item`.`id` ORDER BY `item`.`id` DESC LIMIT %d , %d", - item_fieldlists(), item_joins(local_user()), item_condition(), - intval(local_user()), - intval($a->pager['start']), intval($a->pager['itemspage'])); + $condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`)) + AND `body` LIKE CONCAT('%',?,'%')", + local_user(), $search]; + $params = ['order' => ['id' => true], + 'limit' => [$a->pager['start'], $a->pager['itemspage']]]; + $items = Item::select(local_user(), [], $condition, $params); + $r = dba::inArray($items); } - if (! DBM::is_result($r)) { + if (!DBM::is_result($r)) { info(L10n::t('No results.') . EOL); return $o; } From 5bfd424fd27471b59b80d051a1f50971c45466d9 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 15:19:52 +0000 Subject: [PATCH 14/15] Clean up tag claud (remove "item_condition()" call) --- src/Content/Widget/TagCloud.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Content/Widget/TagCloud.php b/src/Content/Widget/TagCloud.php index 7d96587c25..53c4daae45 100644 --- a/src/Content/Widget/TagCloud.php +++ b/src/Content/Widget/TagCloud.php @@ -74,7 +74,6 @@ class TagCloud */ private static function tagadelic($uid, $count = 0, $owner_id = 0, $flags = '', $type = TERM_HASHTAG) { - $item_condition = item_condition(); $sql_options = item_permissions_sql($uid); $limit = $count ? sprintf('LIMIT %d', intval($count)) : ''; @@ -91,13 +90,12 @@ class TagCloud // Fetch tags $r = dba::p("SELECT `term`, COUNT(`term`) AS `total` FROM `term` LEFT JOIN `item` ON `term`.`oid` = `item`.`id` - LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = ? WHERE `term`.`uid` = ? AND `term`.`type` = ? AND `term`.`otype` = ? - AND $item_condition $sql_options + AND `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` + $sql_options GROUP BY `term` ORDER BY `total` DESC $limit", $uid, - $uid, $type, TERM_OBJ_POST ); From 060997feda6ec700137d576eaf438dfac32e93de Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 10 Jun 2018 19:29:34 +0000 Subject: [PATCH 15/15] (Partly) reworked notes --- mod/notes.php | 50 +++++++++----------------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/mod/notes.php b/mod/notes.php index be9fe0d70a..fb42408c60 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -27,36 +27,21 @@ function notes_init(App $a) function notes_content(App $a, $update = false) { - if (! local_user()) { + if (!local_user()) { notice(L10n::t('Permission denied.') . EOL); return; } require_once 'include/security.php'; require_once 'include/conversation.php'; - $groups = []; - - $o = ''; - - $remote_contact = false; - - $contact_id = $_SESSION['cid']; - $contact = $a->contact; - - $is_owner = true; - - $o =""; - $o .= Profile::getTabs($a, true); + $o = Profile::getTabs($a, true); if (!$update) { $o .= '

' . L10n::t('Personal Notes') . '

'; - $commpage = false; - $commvisitor = false; - $x = [ - 'is_owner' => $is_owner, + 'is_owner' => true, 'allow_location' => (($a->user['allow_location']) ? true : false), 'default_location' => $a->user['default-location'], 'nickname' => $a->user['nickname'], @@ -72,34 +57,17 @@ function notes_content(App $a, $update = false) $o .= status_editor($a, $x, $a->contact['id']); } - // Construct permissions + $condition = ["`uid` = ? AND `type` = 'note' AND `id` = `parent` AND NOT `wall` + AND `allow_cid` = ? AND `contact-id` = ?", + local_user(), '<' . $a->contact['id'] . '>', $a->contact['id']]; - // default permissions - anonymous user + $notes = dba::count('item', $condition); - $sql_extra = " AND `item`.`allow_cid` = '<" . $a->contact['id'] . ">' "; + $a->set_pager_total($notes); + $a->set_pager_itemspage(40); - /// @todo We seem to need "Item::count" as function as well - $r = q("SELECT COUNT(*) AS `total` - FROM `item` %s - WHERE %s AND `item`.`uid` = %d AND `item`.`type` = 'note' - AND `contact`.`self` AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall` - $sql_extra ", - item_joins(local_user()), - item_condition(), - intval(local_user()) - ); - - if (DBM::is_result($r)) { - $a->set_pager_total($r[0]['total']); - $a->set_pager_itemspage(40); - } - - $condition = ["`uid` = ? AND `type` = 'note' AND NOT `wall` - AND `id` = `parent` AND `allow_cid` = ?", - local_user(), '<' . $a->contact['id'] . '>']; $params = ['order' => ['created' => true], 'limit' => [$a->pager['start'], $a->pager['itemspage']]]; - $r = Item::select(local_user(), ['item_id'], $condition, $params); if (DBM::is_result($r)) {