X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fapi.php;h=1fbdd8f7fc458fbaf7e26f0e51bfed5089d434b0;hb=68ab3764e95d00d88954b9aa6385bf229ec99e0f;hp=806e953e9141b3270f6c5b1c5f703bf9c95b3b28;hpb=b775cba8c2c6d1e7b9c5bd8e431df0f23233fd06;p=friendica.git diff --git a/include/api.php b/include/api.php index 806e953e91..1fbdd8f7fc 100644 --- a/include/api.php +++ b/include/api.php @@ -54,7 +54,7 @@ define('API_METHOD_POST', 'POST,PUT'); define('API_METHOD_DELETE', 'POST,DELETE'); $API = []; -$called_api = null; +$called_api = []; /** * It is not sufficient to use local_user() to check whether someone is allowed to use the API, @@ -223,7 +223,7 @@ function api_login(App $a) $record = $addon_auth['user_record']; } else { $user_id = User::authenticate(trim($user), trim($password)); - if ($user_id) { + if ($user_id !== false) { $record = dba::selectFirst('user', [], ['uid' => $user_id]); } } @@ -267,7 +267,7 @@ function api_check_method($method) * @brief Main API entry point * * @param object $a App - * @return string API call result + * @return string|array API call result */ function api_call(App $a) { @@ -387,9 +387,7 @@ function api_call(App $a) break; case "json": header("Content-Type: application/json"); - foreach ($return as $rr) { - $json = json_encode($rr); - } + $json = json_encode(end($return)); if (x($_GET, 'callback')) { $json = $_GET['callback'] . "(" . $json . ")"; } @@ -421,7 +419,7 @@ function api_call(App $a) * * @param string $type Return type (xml, json, rss, as) * @param object $e HTTPException Error object - * @return string error message formatted as $type + * @return string|array error message formatted as $type */ function api_error($type, $e) { @@ -494,7 +492,7 @@ function api_rss_extra(App $a, $arr, $user_info) */ function api_unique_id_to_nurl($id) { - $r = dba::selectFirst('contact', ['nurl'], ['uid' => 0, 'id' => $id]); + $r = dba::selectFirst('contact', ['nurl'], ['id' => $id]); if (DBM::is_result($r)) { return $r["nurl"]; @@ -531,10 +529,10 @@ function api_get_user(App $a, $contact_id = null) // Searching for contact id with uid = 0 if (!is_null($contact_id) && (intval($contact_id) != 0)) { - $user = dbesc(api_unique_id_to_nurl($contact_id)); + $user = dbesc(api_unique_id_to_nurl(intval($contact_id))); if ($user == "") { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ID ".$contact_id." not found."); } $url = $user; @@ -548,7 +546,7 @@ function api_get_user(App $a, $contact_id = null) $user = dbesc(api_unique_id_to_nurl($_GET['user_id'])); if ($user == "") { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ID ".$_GET['user_id']." not found."); } $url = $user; @@ -577,16 +575,14 @@ function api_get_user(App $a, $contact_id = null) $argid = count($called_api); list($user, $null) = explode(".", $a->argv[$argid]); if (is_numeric($user)) { - $user = dbesc(api_unique_id_to_nurl($user)); - - if ($user == "") { - return false; - } + $user = dbesc(api_unique_id_to_nurl(intval($user))); - $url = $user; - $extra_query = "AND `contact`.`nurl` = '%s' "; - if (api_user() !== false) { - $extra_query .= "AND `contact`.`uid`=" . intval(api_user()); + if ($user != "") { + $url = $user; + $extra_query = "AND `contact`.`nurl` = '%s' "; + if (api_user() !== false) { + $extra_query .= "AND `contact`.`uid`=" . intval(api_user()); + } } } else { $user = dbesc($user); @@ -620,7 +616,9 @@ function api_get_user(App $a, $contact_id = null) ); // Selecting the id by priority, friendica first - api_best_nickname($uinfo); + if (is_array($uinfo)) { + api_best_nickname($uinfo); + } // if the contact wasn't found, fetch it from the contacts with uid = 0 if (!DBM::is_result($uinfo)) { @@ -672,13 +670,14 @@ function api_get_user(App $a, $contact_id = null) 'statusnet_profile_url' => $r[0]["url"], 'uid' => 0, 'cid' => Contact::getIdForURL($r[0]["url"], api_user(), true), + 'pid' => Contact::getIdForURL($r[0]["url"], 0, true), 'self' => 0, 'network' => $r[0]["network"], ]; return $ret; } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ".$url." not found."); } } @@ -687,67 +686,10 @@ 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()) - ); - - /// @TODO old-lost code? (twice) - // Counting is deactivated by now, due to performance issues - // count public wall messages - //$r = q("SELECT COUNT(*) as `count` FROM `item` WHERE `uid` = %d AND `wall`", - // intval($uinfo[0]['uid']) - //); - //$countitms = $r[0]['count']; - $countitms = 0; - } else { - // Counting is deactivated by now, due to performance issues - //$r = q("SELECT count(*) as `count` FROM `item` - // WHERE `contact-id` = %d", - // intval($uinfo[0]['id']) - //); - //$countitms = $r[0]['count']; - $countitms = 0; - } - - /// @TODO old-lost code? (twice) - /* - // Counting is deactivated by now, due to performance issues - // count friends - $r = q("SELECT count(*) as `count` FROM `contact` - WHERE `uid` = %d AND `rel` IN ( %d, %d ) - AND `self`=0 AND NOT `blocked` AND NOT `pending` AND `hidden`=0", - intval($uinfo[0]['uid']), - intval(CONTACT_IS_SHARING), - intval(CONTACT_IS_FRIEND) - ); - $countfriends = $r[0]['count']; - - $r = q("SELECT count(*) as `count` FROM `contact` - WHERE `uid` = %d AND `rel` IN ( %d, %d ) - AND `self`=0 AND NOT `blocked` AND NOT `pending` AND `hidden`=0", - intval($uinfo[0]['uid']), - intval(CONTACT_IS_FOLLOWER), - intval(CONTACT_IS_FRIEND) - ); - $countfollowers = $r[0]['count']; - - $r = q("SELECT count(*) as `count` FROM item where starred = 1 and uid = %d and deleted = 0", - intval($uinfo[0]['uid']) - ); - $starred = $r[0]['count']; - - - if (! $uinfo[0]['self']) { - $countfriends = 0; - $countfollowers = 0; - $starred = 0; - } - */ + $usr = dba::selectFirst('user', ['default-location'], ['uid' => api_user()]); + $profile = dba::selectFirst('profile', ['about'], ['uid' => api_user(), 'is-default' => true]); + } + $countitms = 0; $countfriends = 0; $countfollowers = 0; $starred = 0; @@ -761,14 +703,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 { @@ -811,6 +753,7 @@ function api_get_user(App $a, $contact_id = null) 'statusnet_profile_url' => $uinfo[0]['url'], 'uid' => intval($uinfo[0]['uid']), 'cid' => intval($uinfo[0]['cid']), + 'pid' => Contact::getIdForURL($uinfo[0]["url"], 0, true), 'self' => $uinfo[0]['self'], 'network' => $uinfo[0]['network'], ]; @@ -858,16 +801,12 @@ function api_get_user(App $a, $contact_id = null) */ function api_item_get_user(App $a, $item) { - $status_user = api_get_user($a, $item["author-link"]); + $status_user = api_get_user($a, $item["author-id"]); - $status_user["protected"] = (($item["allow_cid"] != "") || - ($item["allow_gid"] != "") || - ($item["deny_cid"] != "") || - ($item["deny_gid"] != "") || - $item["private"]); + $status_user["protected"] = $item["private"]; if ($item['thr-parent'] == $item['uri']) { - $owner_user = api_get_user($a, $item["owner-link"]); + $owner_user = api_get_user($a, $item["owner-id"]); } else { $owner_user = $status_user; } @@ -937,7 +876,7 @@ function api_reformat_xml(&$item, &$key) * * @return string The XML data */ -function api_create_xml($data, $root_element) +function api_create_xml(array $data, $root_element) { $childname = key($data); $data2 = array_pop($data); @@ -962,7 +901,7 @@ function api_create_xml($data, $root_element) $i = 1; foreach ($data2 as $item) { - $data4[$i++.":".$childname] = $item; + $data4[$i++ . ":" . $childname] = $item; } $data2 = $data4; @@ -981,7 +920,7 @@ function api_create_xml($data, $root_element) * @param string $type Return type (atom, rss, xml, json) * @param array $data JSON style array * - * @return (string|object|array) XML data or JSON data + * @return (string|array) XML data or JSON data */ function api_format_data($root_element, $type, $data) { @@ -992,6 +931,7 @@ function api_format_data($root_element, $type, $data) $ret = api_create_xml($data, $root_element); break; case "json": + default: $ret = $data; break; } @@ -1069,7 +1009,7 @@ function requestdata($k) } /** - * Waitman Gobble Mod + * Deprecated function to upload media. * * @param string $type Return type (atom, rss, xml, json) * @@ -1101,14 +1041,12 @@ function api_statuses_mediap($type) } $txt = HTML::toBBCode($txt); - $a->argv[1]=$user_info['screen_name']; //should be set to username? + $a->argv[1] = $user_info['screen_name']; //should be set to username? - // tell wall_upload function to return img info instead of echo - $_REQUEST['hush'] = 'yeah'; - $bebop = wall_upload_post($a); + $picture = wall_upload_post($a, false); // now that we have the img url in bbcode we can add it to the status and insert the wall item. - $_REQUEST['body'] = $txt . "\n\n" . $bebop; + $_REQUEST['body'] = $txt . "\n\n" . '[url=' . $picture["albumpage"] . '][img]' . $picture["preview"] . "[/img][/url]"; item_post($a); // this should output the last post (the one we just posted). @@ -1257,10 +1195,9 @@ function api_statuses_update($type) if (x($_FILES, 'media')) { // upload the image if we have one - $_REQUEST['hush'] = 'yeah'; //tell wall_upload function to return img info instead of echo - $media = wall_upload_post($a); - if (strlen($media) > 0) { - $_REQUEST['body'] .= "\n\n" . $media; + $picture = wall_upload_post($a, false); + if (is_array($picture)) { + $_REQUEST['body'] .= "\n\n" . '[url=' . $picture["albumpage"] . '][img]' . $picture["preview"] . "[/img][/url]"; } } @@ -1357,31 +1294,17 @@ function api_status_show($type) logger('api_status_show: user_info: '.print_r($user_info, true), LOGGER_DEBUG); if ($type == "raw") { - $privacy_sql = "AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''"; + $privacy_sql = "AND NOT `private`"; } else { $privacy_sql = ""; } // get last public wall message - $lastwall = q( - "SELECT `item`.* - FROM `item` - WHERE `item`.`contact-id` = %d AND `item`.`uid` = %d - AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s'))) - AND `item`.`type` != 'activity' $privacy_sql - ORDER BY `item`.`id` DESC - LIMIT 1", - intval($user_info['cid']), - intval(api_user()), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])) - ); + $condition = ["`owner-id` = ? AND `uid` = ? AND `type` != 'activity' ".$privacy_sql, + $user_info['pid'], api_user()]; + $lastwall = dba::selectFirst('item', [], $condition, ['order' => ['id' => true]]); if (DBM::is_result($lastwall)) { - $lastwall = $lastwall[0]; - $in_reply_to = api_in_reply_to($lastwall); $converted = api_convert_item($lastwall); @@ -1429,24 +1352,24 @@ function api_status_show($type) $status_info["entities"] = $converted["entities"]; } - if (($lastwall['item_network'] != "") && ($status["source"] == 'web')) { - $status_info["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']); - } elseif (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $status_info["source"])) { - $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['item_network'], $user_info['url']).')'); + if ($status_info["source"] == 'web') { + $status_info["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); + } elseif (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $status_info["source"]) { + $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['network'], $user_info['url']).')'); } // "uid" and "self" are only needed for some internal stuff, so remove it from here unset($status_info["user"]["uid"]); unset($status_info["user"]["self"]); - } - logger('status_info: '.print_r($status_info, true), LOGGER_DEBUG); + logger('status_info: '.print_r($status_info, true), LOGGER_DEBUG); - if ($type == "raw") { - return $status_info; - } + if ($type == "raw") { + return $status_info; + } - return api_format_data("statuses", $type, ['status' => $status_info]); + return api_format_data("statuses", $type, ['status' => $status_info]); + } } /** @@ -1461,28 +1384,12 @@ function api_users_show($type) $a = get_app(); $user_info = api_get_user($a); - $lastwall = q( - "SELECT `item`.* - FROM `item` - INNER JOIN `contact` ON `contact`.`id`=`item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - WHERE `item`.`uid` = %d AND `verb` = '%s' AND `item`.`contact-id` = %d - AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s'))) - AND `type`!='activity' - AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`='' - ORDER BY `id` DESC - LIMIT 1", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($user_info['cid']), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])), - dbesc($user_info['url']), - dbesc(normalise_link($user_info['url'])) - ); - if (DBM::is_result($lastwall)) { - $lastwall = $lastwall[0]; + $condition = ["`owner-id` = ? AND `uid` = ? AND `verb` = ? AND `type` != 'activity' AND NOT `private`", + $user_info['pid'], api_user(), ACTIVITY_POST]; + $lastwall = dba::selectFirst('item', [], $condition, ['order' => ['id' => true]]); + if (DBM::is_result($lastwall)) { $in_reply_to = api_in_reply_to($lastwall); $converted = api_convert_item($lastwall); @@ -1520,12 +1427,12 @@ function api_users_show($type) $user_info["status"]["entities"] = $converted["entities"]; } - if (($lastwall['item_network'] != "") && ($user_info["status"]["source"] == 'web')) { - $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']); + if ($user_info["status"]["source"] == 'web') { + $user_info["status"]["source"] = ContactSelector::networkToName($lastwall['network'], $user_info['url']); } - if (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $user_info["status"]["source"])) { - $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) . ')'); + if (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $user_info["status"]["source"]) { + $user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['network'], $user_info['url']) . ')'); } } @@ -1574,10 +1481,10 @@ function api_users_search($type) } $userlist = ["users" => $userlist]; } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("User ".$_GET["q"]." not found."); } } else { - throw new BadRequestException("User not found."); + throw new BadRequestException("No user specified."); } return api_format_data("users", $type, $userlist); @@ -1630,8 +1537,14 @@ api_register_func('api/users/lookup', 'api_users_lookup', true); */ function api_search($type) { + $a = get_app(); + $user_info = api_get_user($a); + + if (api_user() === false || $user_info === false) { + throw new ForbiddenException(); + } + $data = []; - $sql_extra = ''; if (!x($_REQUEST, 'q')) { throw new BadRequestException("q parameter is required."); @@ -1651,24 +1564,20 @@ function api_search($type) $start = $page * $count; + $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) { - $sql_extra .= ' AND `item`.`id` <= ' . intval($max_id); + $condition[0] .= " AND `item`.`id` <= ?"; + $condition[] = $max_id; } - $r = dba::p( - "SELECT ".item_fieldlists()." - FROM `item` ".item_joins()." - 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 - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectForUser(api_user(), [], $condition, $params); - $data['status'] = api_format_items(dba::inArray($r), api_get_user(get_app())); + $data['status'] = api_format_items(dba::inArray($statuses), $user_info); return api_format_data("statuses", $type, $data); } @@ -1690,8 +1599,9 @@ api_register_func('api/search', 'api_search', true); function api_statuses_home_timeline($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } @@ -1701,7 +1611,6 @@ function api_statuses_home_timeline($type) unset($_REQUEST["screen_name"]); unset($_GET["screen_name"]); - $user_info = api_get_user($a); // get last network messages // params @@ -1718,52 +1627,37 @@ 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`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - 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::selectForUser(api_user(), [], $condition, $params); - $ret = api_format_items($r, $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"]); } - $idlist = implode(",", $idarray); - - if ($idlist != "") { - $unseen = q("SELECT `id` FROM `item` WHERE `unseen` AND `id` IN (%s)", $idlist); - + if (!empty($idarray)) { + $unseen = dba::exists('item', ['unseen' => true, 'id' => $idarray]); if ($unseen) { - q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist); + Item::update(['unseen' => false], ['unseen' => true, 'id' => $idarray]); } } @@ -1792,12 +1686,12 @@ api_register_func('api/statuses/friends_timeline', 'api_statuses_home_timeline', function api_statuses_public_timeline($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } - $user_info = api_get_user($a); // get last network messages // params @@ -1816,61 +1710,35 @@ function api_statuses_public_timeline($type) $sql_extra = ''; if ($exclude_replies && !$conversation_id) { + $condition = ["`verb` = ? AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall`", + ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); - } - - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " - 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 - ); + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } + + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThreadForUser(api_user(), Item::DISPLAY_FIELDLIST, $condition, $params); - $r = dba::inArray($r); + $r = dba::inArray($statuses); } else { + $condition = ["`verb` = ? AND `id` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND `item`.`origin`", + 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 ($conversation_id > 0) { - $sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id); - } - - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `item` - " . item_joins() . " - 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 - ); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } + + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectForUser(api_user(), [], $condition, $params); - $r = dba::inArray($r); + $r = dba::inArray($statuses); } $ret = api_format_items($r, $user_info, false, $type); @@ -1901,13 +1769,12 @@ api_register_func('api/statuses/public_timeline', 'api_statuses_public_timeline' function api_statuses_networkpublic_timeline($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } - $user_info = api_get_user($a); - $since_id = x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0; $max_id = x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0; @@ -1919,33 +1786,18 @@ function api_statuses_networkpublic_timeline($type) } $start = ($page - 1) * $count; - $sql_extra = ''; + $condition = ["`uid` = 0 AND `verb` = ? AND `thread`.`iid` > ? AND NOT `private`", + ACTIVITY_POST, $since_id]; + if ($max_id > 0) { - $sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id); - } - - $r = dba::p( - "SELECT " . item_fieldlists() . " - FROM `thread` - STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` - " . item_joins() . " - 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 - ); + $condition[0] .= " AND `thread`.`iid` <= ?"; + $condition[] = $max_id; + } - $r = dba::inArray($r); + $params = ['order' => ['iid' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectThreadForUser(api_user(), Item::DISPLAY_FIELDLIST, $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) { @@ -1971,13 +1823,12 @@ api_register_func('api/statuses/networkpublic_timeline', 'api_statuses_networkpu function api_statuses_show($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } - $user_info = api_get_user($a); - // params $id = intval($a->argv[3]); @@ -1994,35 +1845,35 @@ function api_statuses_show($type) $conversation = (x($_REQUEST, 'conversation') ? 1 : 0); - $sql_extra = ''; + // 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)) { + throw new BadRequestException("There is no status with this id."); + } + + $item = dba::selectFirst('item', ['id'], ['uri' => $uri_item['uri'], 'uid' => [0, api_user()]], ['order' => ['uid' => true]]); + if (!DBM::is_result($item)) { + throw new BadRequestException("There is no status with this id."); + } + + $id = $item['id']; + if ($conversation) { - $sql_extra .= " AND `item`.`parent` = %d ORDER BY `id` ASC "; + $condition = ['parent' => $id, 'verb' => ACTIVITY_POST]; + $params = ['order' => ['id' => true]]; } else { - $sql_extra .= " AND `item`.`id` = %d"; + $condition = ['id' => $id, 'verb' => ACTIVITY_POST]; + $params = []; } - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND `item`.`uid` = %d AND `item`.`verb` = '%s' - $sql_extra", - intval(api_user()), - dbesc(ACTIVITY_POST), - intval($id) - ); + $statuses = Item::selectForUser(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($statuses)) { 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]; @@ -2045,13 +1896,12 @@ api_register_func('api/statuses/show', 'api_statuses_show', true); function api_conversation_show($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } - $user_info = api_get_user($a); - // params $id = intval($a->argv[3]); $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); @@ -2075,48 +1925,35 @@ function api_conversation_show($type) logger('API: api_conversation_show: '.$id); - $r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($id)); - if (DBM::is_result($r)) { - $id = $r[0]["parent"]; + // try to fetch the item for the local user - or the public item, if there is no local one + $item = dba::selectFirst('item', ['parent-uri'], ['id' => $id]); + if (!DBM::is_result($item)) { + throw new BadRequestException("There is no status with this id."); } - $sql_extra = ''; + $parent = dba::selectFirst('item', ['id'], ['uri' => $item['parent-uri'], 'uid' => [0, api_user()]], ['order' => ['uid' => true]]); + if (!DBM::is_result($parent)) { + throw new BadRequestException("There is no status with this id."); + } + + $id = $parent['id']; + + $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; } - // Not sure why this query was so complicated. We should keep it here for a while, - // just to make sure that we really don't need it. - // FROM `item` INNER JOIN (SELECT `uri`,`parent` FROM `item` WHERE `id` = %d) AS `temp1` - // ON (`item`.`thr-parent` = `temp1`.`uri` AND `item`.`parent` = `temp1`.`parent`) - - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - 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' - 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::selectForUser(api_user(), [], $condition, $params); - if (!DBM::is_result($r)) { - throw new BadRequestException("There is no status with this id."); + if (!DBM::is_result($statuses)) { + 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); @@ -2159,30 +1996,17 @@ function api_statuses_repeat($type) logger('API: api_statuses_repeat: '.$id); - $r = q( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`nick` as `reply_author`, - `contact`.`name`, `contact`.`photo` as `reply_photo`, `contact`.`url` as `reply_url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted` - AND NOT `item`.`private` AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' - AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' - AND `item`.`id`=%d", - intval($id) - ); + $fields = ['body', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $item = Item::selectFirst($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; @@ -2200,7 +2024,7 @@ function api_statuses_repeat($type) } // this should output the last post (the one we just posted). - $called_api = null; + $called_api = []; return api_status_show($type); } @@ -2240,7 +2064,7 @@ function api_statuses_destroy($type) $ret = api_statuses_show($type); - Item::deleteById($id); + Item::deleteForUser(['id' => $id], api_user()); return $ret; } @@ -2258,8 +2082,9 @@ api_register_func('api/statuses/destroy', 'api_statuses_destroy', true, API_METH function api_statuses_mentions($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } @@ -2269,10 +2094,8 @@ function api_statuses_mentions($type) unset($_REQUEST["screen_name"]); unset($_GET["screen_name"]); - $user_info = api_get_user($a); // get last network messages - // params $since_id = defaults($_REQUEST, 'since_id', 0); $max_id = defaults($_REQUEST, 'max_id' , 0); @@ -2284,43 +2107,19 @@ function api_statuses_mentions($type) $start = ($page - 1) * $count; - // Ugly code - should be changed - $myurl = System::baseUrl() . '/profile/'. $a->user['nickname']; - $myurl = substr($myurl, strpos($myurl, '://') + 3); - $myurl = str_replace('www.', '', $myurl); - - $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`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` FORCE INDEX (`uid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - WHERE `item`.`uid` = %d AND `verb` = '%s' - AND NOT (`item`.`author-link` IN ('https://%s', 'http://%s')) - 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 !`ignored`) - $sql_extra - AND `item`.`id`>%d - ORDER BY `item`.`id` DESC LIMIT %d ,%d ", - intval(api_user()), - dbesc(ACTIVITY_POST), - dbesc(protect_sprintf($myurl)), - dbesc(protect_sprintf($myurl)), - intval(api_user()), - intval($since_id), - intval($start), - intval($count) - ); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectForUser(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) { @@ -2350,13 +2149,12 @@ api_register_func('api/statuses/replies', 'api_statuses_mentions', true); function api_statuses_user_timeline($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } - $user_info = api_get_user($a); - logger( "api_statuses_user_timeline: api_user: ". api_user() . "\nuser_info: ".print_r($user_info, true) . @@ -2377,46 +2175,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`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` FORCE INDEX (`uid_contactid_id`) - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - 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::selectForUser(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) { @@ -2466,24 +2249,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::selectFirstForUser(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"); @@ -2491,7 +2274,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]; @@ -2520,15 +2303,14 @@ function api_favorites($type) global $called_api; $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } $called_api = []; - $user_info = api_get_user($a); - // in friendica starred item are private // return favorites only for self logger('api_favorites: self:' . $user_info['self']); @@ -2536,8 +2318,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); @@ -2549,31 +2329,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`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item`, `contact` - WHERE `item`.`uid` = %d - AND `item`.`visible` = 1 AND `item`.`moderated` = 0 AND `item`.`deleted` = 0 - AND `item`.`starred` = 1 - AND `contact`.`id` = `item`.`contact-id` - AND (NOT `contact`.`blocked` OR `contact`.`pending`) - $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::selectForUser(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]; @@ -2719,7 +2487,7 @@ function api_convert_item($item) * * @param string $body * - * @return array|false + * @return array */ function api_get_attachments(&$body) { @@ -2730,7 +2498,7 @@ function api_get_attachments(&$body) $ret = preg_match_all("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $text, $images); if (!$ret) { - return false; + return []; } $attachments = []; @@ -2988,8 +2756,8 @@ function api_format_items_activities(&$item, $type = "json") ]; $items = q( - 'SELECT * FROM item - WHERE uid=%d AND `thr-parent`="%s" AND visible AND NOT deleted', + 'SELECT * FROM `item` + WHERE `uid` = %d AND `thr-parent` = "%s" AND `visible` AND NOT `deleted`', intval($item['uid']), dbesc($item['uri']) ); @@ -2999,7 +2767,7 @@ function api_format_items_activities(&$item, $type = "json") //builtin_activity_puller($i, $activities); // get user data and add it to the array of the activity - $user = api_get_user($a, $i['author-link']); + $user = api_get_user($a, $i['author-id']); switch ($i['verb']) { case ACTIVITY_LIKE: $activities['like'][] = $user; @@ -3155,26 +2923,18 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") $status["entities"] = $converted["entities"]; } - if (($item['item_network'] != "") && ($status["source"] == 'web')) { - $status["source"] = ContactSelector::networkToName($item['item_network'], $user_info['url']); - } elseif (($item['item_network'] != "") && (ContactSelector::networkToName($item['item_network'], $user_info['url']) != $status["source"])) { - $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['item_network'], $user_info['url']).')'); + if ($status["source"] == 'web') { + $status["source"] = ContactSelector::networkToName($item['network'], $user_info['url']); + } elseif (ContactSelector::networkToName($item['network'], $user_info['url']) != $status["source"]) { + $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $user_info['url']).')'); } - - // Retweets are only valid for top postings - // It doesn't work reliable with the link if its a feed - //$IsRetweet = ($item['owner-link'] != $item['author-link']); - //if ($IsRetweet) - // $IsRetweet = (($item['owner-name'] != $item['author-name']) || ($item['owner-avatar'] != $item['author-avatar'])); - - if ($item["id"] == $item["parent"]) { $retweeted_item = api_share_as_retweet($item); if ($retweeted_item !== false) { $retweeted_status = $status; try { - $retweeted_status["user"] = api_get_user($a, $retweeted_item["author-link"]); + $retweeted_status["user"] = api_get_user($a, $retweeted_item["author-id"]); } catch (BadRequestException $e) { // user not found. should be found? /// @todo check if the user should be always found @@ -3343,7 +3103,8 @@ function api_lists_statuses($type) { $a = get_app(); - if (api_user() === false) { + $user_info = api_get_user($a); + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } @@ -3353,8 +3114,7 @@ function api_lists_statuses($type) unset($_REQUEST["screen_name"]); unset($_GET["screen_name"]); - $user_info = api_get_user($a); - if (!x($_REQUEST, 'list_id')) { + if (empty($_REQUEST['list_id'])) { throw new BadRequestException('list_id not specified'); } @@ -3371,38 +3131,25 @@ function api_lists_statuses($type) $start = $page * $count; - $sql_extra = ''; + $condition = ["`uid` = ? AND `verb` = ? AND `id` > ? AND `group_member`.`gid` = ?", + api_user(), ACTIVITY_POST, $since_id, $_REQUEST['list_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); - } - - $statuses = dba::p( - "SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid`, `group_member`.`gid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - 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` - 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'] - ); + $condition[0] .= " AND `item`.`parent` = ?"; + $condition[] = $conversation_id; + } - $items = api_format_items($statuses, $user_info, false, $type); + $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; + $statuses = Item::selectForUser(api_user(), [], $condition, $params); + + $items = api_format_items(dba::inArray($statuses), $user_info, false, $type); $data = ['status' => $items]; switch ($type) { @@ -3816,7 +3563,7 @@ api_register_func('api/direct_messages/new', 'api_direct_messages_new', true, AP * @brief delete a direct_message from mail table through api * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message */ function api_direct_messages_destroy($type) @@ -3902,8 +3649,9 @@ api_register_func('api/direct_messages/destroy', 'api_direct_messages_destroy', function api_direct_messages_box($type, $box, $verbose) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } @@ -3927,7 +3675,6 @@ function api_direct_messages_box($type, $box, $verbose) unset($_REQUEST["screen_name"]); unset($_GET["screen_name"]); - $user_info = api_get_user($a); $profile_url = $user_info["url"]; // pagination @@ -3978,7 +3725,9 @@ function api_direct_messages_box($type, $box, $verbose) $sender = $user_info; } - $ret[] = api_format_messages($item, $recipient, $sender); + if (isset($recipient) && isset($sender)) { + $ret[] = api_format_messages($item, $recipient, $sender); + } } @@ -4096,7 +3845,7 @@ api_register_func('api/oauth/access_token', 'api_oauth_access_token', false); * @brief delete a complete photoalbum with all containing photos from database through api * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photoalbum_delete($type) { @@ -4132,7 +3881,7 @@ function api_fr_photoalbum_delete($type) if (!DBM::is_result($photo_item)) { throw new InternalServerErrorException("problem with deleting items occured"); } - Item::deleteById($photo_item[0]['id']); + Item::deleteForUser(['id' => $photo_item[0]['id']], api_user()); } // now let's delete all photos from the album @@ -4151,7 +3900,7 @@ function api_fr_photoalbum_delete($type) * @brief update the name of the album for all photos of an album * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photoalbum_update($type) { @@ -4170,21 +3919,11 @@ function api_fr_photoalbum_update($type) throw new BadRequestException("no new albumname specified"); } // check if album is existing - $r = q( - "SELECT `id` FROM `photo` WHERE `uid` = %d AND `album` = '%s'", - intval(api_user()), - dbesc($album) - ); - if (!DBM::is_result($r)) { + if (!dba::exists('photo', ['uid' => api_user(), 'album' => $album])) { throw new BadRequestException("album not available"); } // now let's update all photos to the albumname - $result = q( - "UPDATE `photo` SET `album` = '%s' WHERE `uid` = %d AND `album` = '%s'", - dbesc($album_new), - intval(api_user()), - dbesc($album) - ); + $result = dba::update('photo', ['album' => $album_new], ['uid' => api_user(), 'album' => $album]); // return success of updating or error message if ($result) { @@ -4200,7 +3939,7 @@ function api_fr_photoalbum_update($type) * @brief list all photos of the authenticated user * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photos_list($type) { @@ -4246,7 +3985,7 @@ function api_fr_photos_list($type) * @brief upload a new photo or change an existing photo * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photo_create_update($type) { @@ -4389,12 +4128,11 @@ function api_fr_photo_create_update($type) throw new InternalServerErrorException("unknown error - this error on uploading or updating a photo should never happen"); } - /** * @brief delete a single photo from the database through api * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photo_delete($type) { @@ -4435,7 +4173,7 @@ function api_fr_photo_delete($type) } // function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore // to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion) - Item::deleteById($photo_item[0]['id']); + Item::deleteForUser(['id' => $photo_item[0]['id']], api_user()); $answer = ['result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.']; return api_format_data("photo_delete", $type, ['$result' => $answer]); @@ -4477,7 +4215,7 @@ function api_fr_photo_detail($type) * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * - * @return string + * @return string|array * @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image */ function api_account_update_profile_image($type) @@ -4486,7 +4224,7 @@ function api_account_update_profile_image($type) throw new ForbiddenException(); } // input params - $profileid = defaults($_REQUEST, 'profile_id', 0); + $profile_id = defaults($_REQUEST, 'profile_id', 0); // error if image data is missing if (!x($_FILES, 'image')) { @@ -4494,17 +4232,13 @@ function api_account_update_profile_image($type) } // check if specified profile id is valid - if ($profileid != 0) { - $r = q( - "SELECT `id` FROM `profile` WHERE `uid` = %d AND `id` = %d", - intval(api_user()), - intval($profileid) - ); + if ($profile_id != 0) { + $profile = dba::selectFirst('profile', ['is-default'], ['uid' => api_user(), 'id' => $profile_id]); // error message if specified profile id is not in database - if (!DBM::is_result($r)) { + if (!DBM::is_result($profile)) { throw new BadRequestException("profile_id not available"); } - $is_default_profile = $r['profile']; + $is_default_profile = $profile['is-default']; } else { $is_default_profile = 1; } @@ -4529,43 +4263,23 @@ function api_account_update_profile_image($type) $fileext = "jpg"; } elseif ($filetype == "image/png") { $fileext = "png"; + } else { + throw new InternalServerErrorException('Unsupported filetype'); } + // change specified profile or all profiles to the new resource-id if ($is_default_profile) { - q( - "UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d", - dbesc($data['photo']['id']), - intval(local_user()) - ); - - q( - "UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s' WHERE `self` AND `uid` = %d", - dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-4.' . $fileext), - dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-5.' . $fileext), - dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-6.' . $fileext), - intval(local_user()) - ); + $condition = ["`profile` AND `resource-id` != ? AND `uid` = ?", $data['photo']['id'], api_user()]; + dba::update('photo', ['profile' => false], $condition); } else { - q( - "UPDATE `profile` SET `photo` = '%s', `thumb` = '%s' WHERE `id` = %d AND `uid` = %d", - dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-4.' . $filetype), - dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-5.' . $filetype), - intval($_REQUEST['profile']), - intval(local_user()) - ); + $fields = ['photo' => System::baseUrl() . '/photo/' . $data['photo']['id'] . '-4.' . $filetype, + 'thumb' => System::baseUrl() . '/photo/' . $data['photo']['id'] . '-5.' . $filetype]; + dba::update('profile', $fields, ['id' => $_REQUEST['profile'], 'uid' => api_user()]); } - // we'll set the updated profile-photo timestamp even if it isn't the default profile, - // so that browsers will do a cache update unconditionally - - q( - "UPDATE `contact` SET `avatar-date` = '%s' WHERE `self` = 1 AND `uid` = %d", - dbesc(DateTimeFormat::utcNow()), - intval(local_user()) - ); + Contact::updateSelfFromUserID(api_user(), true); // Update global directory in background - //$user = api_get_user(get_app()); $url = System::baseUrl() . '/profile/' . get_app()->user['nickname']; if ($url && strlen(Config::get('system', 'directory'))) { Worker::add(PRIORITY_LOW, "Directory", $url); @@ -4809,7 +4523,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ logger("photo upload: new profile image upload ended", LOGGER_DEBUG); } - if ($r) { + if (isset($r) && $r) { // create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo if ($photo_id == null && $mediatype == "photo") { post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility); @@ -4834,7 +4548,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility = false) { // get data about the api authenticated user - $uri = item_new_uri(get_app()->get_hostname(), intval(api_user())); + $uri = Item::newURI(intval(api_user())); $owner_record = q("SELECT * FROM `contact` WHERE `uid`= %d AND `self` LIMIT 1", intval(api_user())); $arr = []; @@ -4885,6 +4599,13 @@ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $f */ function prepare_photo_data($type, $scale, $photo_id) { + $a = get_app(); + $user_info = api_get_user($a); + + if ($user_info === false) { + throw new ForbiddenException(); + } + $scale_sql = ($scale === false ? "" : sprintf("AND scale=%d", intval($scale))); $data_sql = ($scale === false ? "" : "data, "); @@ -4948,24 +4669,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`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, - `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, - `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `cid` - FROM `item` - STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid` - 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::selectForUser(api_user(), [], $condition); // prepare output of comments - $commentData = api_format_items($r, api_get_user(get_app()), false, $type); + $commentData = api_format_items(dba::inArray($statuses), $user_info, false, $type); $comments = []; if ($type == "xml") { $k = 0; @@ -5035,15 +4745,9 @@ function api_friendica_remoteauth() $sec = random_string(); - q( - "INSERT INTO `profile_check` ( `uid`, `cid`, `dfrn_id`, `sec`, `expire`) - VALUES( %d, %s, '%s', '%s', %d )", - intval(api_user()), - intval($cid), - dbesc($dfrn_id), - dbesc($sec), - intval(time() + 45) - ); + $fields = ['uid' => api_user(), 'cid' => $cid, 'dfrn_id' => $dfrn_id, + 'sec' => $sec, 'expire' => time() + 45]; + dba::insert('profile_check', $fields); logger($contact['name'] . ' ' . $sec, LOGGER_DEBUG); $dest = ($url ? '&destination_url=' . $url : ''); @@ -5272,7 +4976,7 @@ function api_in_reply_to($item) $in_reply_to['status_id_str'] = (string) intval($in_reply_to['status_id']); $r = q( - "SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item + "SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM `item` STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id` WHERE `item`.`id` = %d LIMIT 1", intval($in_reply_to['status_id']) @@ -5306,27 +5010,27 @@ function api_in_reply_to($item) /** * - * @param string $Text + * @param string $text * * @return string */ -function api_clean_plain_items($Text) +function api_clean_plain_items($text) { $include_entities = strtolower(x($_REQUEST, 'include_entities') ? $_REQUEST['include_entities'] : "false"); - $Text = BBCode::cleanPictureLinks($Text); + $text = BBCode::cleanPictureLinks($text); $URLSearchString = "^\[\]"; - $Text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $Text); + $text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $text); if ($include_entities == "true") { - $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url=$1]$1[/url]', $Text); + $text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url=$1]$1[/url]', $text); } // Simplify "attachment" element - $Text = api_clean_attachments($Text); + $text = api_clean_attachments($text); - return($Text); + return $text; } /** @@ -5340,7 +5044,7 @@ function api_clean_attachments($body) { $data = BBCode::getAttachmentData($body); - if (!$data) { + if (empty($data)) { return $body; } $body = ""; @@ -5466,6 +5170,7 @@ function api_friendica_group_show($type) } // loop through all groups and retrieve all members for adding data in the user array + $grps = []; foreach ($r as $rr) { $members = Contact::getByGroupId($rr['id']); $users = []; @@ -5664,7 +5369,7 @@ function group_create($name, $uid, $users = []) } // return success message incl. missing users in array - $status = ($erroraddinguser ? "missing user" : ($reactivate_group ? "reactivated" : "ok")); + $status = ($erroraddinguser ? "missing user" : ((isset($reactivate_group) && $reactivate_group) ? "reactivated" : "ok")); return ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers]; } @@ -5772,7 +5477,7 @@ function api_friendica_group_update($type) foreach ($users as $user) { $found = ($user['cid'] == $cid ? true : false); } - if (!$found) { + if (!isset($found) || !$found) { Group::removeMemberByName($uid, $name, $cid); } } @@ -5849,8 +5554,6 @@ function api_lists_update($type) return api_format_data("lists", $type, ['lists' => $list]); } - - return api_format_data("group_update", $type, ['result' => $success]); } api_register_func('api/lists/update', 'api_lists_update', true, API_METHOD_POST); @@ -5903,7 +5606,7 @@ api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activit * @brief Returns notifications * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_friendica_notification($type) { @@ -5937,13 +5640,14 @@ function api_friendica_notification($type) * @brief Set notification as seen and returns associated item (if possible) * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_friendica_notification_seen($type) { $a = get_app(); + $user_info = api_get_user($a); - if (api_user() === false) { + if (api_user() === false || $user_info === false) { throw new ForbiddenException(); } if ($a->argc!==4) { @@ -5961,15 +5665,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::selectFirstForUser(api_user(), [], ['id' => $note['iid'], 'uid' => api_user()]); + if (DBM::is_result($$item)) { // we found the item, return it to the user - $user_info = api_get_user($a); - $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); } @@ -5986,7 +5685,7 @@ api_register_func('api/friendica/notification', 'api_friendica_notification', tr * @brief update a direct_message to seen state * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string (success result=ok, error result=error with error message) + * @return string|array (success result=ok, error result=error with error message) */ function api_friendica_direct_messages_setseen($type) { @@ -6006,25 +5705,14 @@ function api_friendica_direct_messages_setseen($type) return api_format_data("direct_messages_setseen", $type, ['$result' => $answer]); } - // get data of the specified message id - $r = q( - "SELECT `id` FROM `mail` WHERE `id` = %d AND `uid` = %d", - intval($id), - intval($uid) - ); - // error message if specified id is not in database - if (!DBM::is_result($r)) { + if (!dba::exists('mail', ['id' => $id, 'uid' => $uid])) { $answer = ['result' => 'error', 'message' => 'message id not in database']; return api_format_data("direct_messages_setseen", $type, ['$result' => $answer]); } // update seen indicator - $result = q( - "UPDATE `mail` SET `seen` = 1 WHERE `id` = %d AND `uid` = %d", - intval($id), - intval($uid) - ); + $result = dba::update('mail', ['seen' => true], ['id' => $id]); if ($result) { // return success @@ -6044,7 +5732,7 @@ api_register_func('api/friendica/direct_messages_setseen', 'api_friendica_direct * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $box - * @return string (success: success=true if found and search_result contains found messages, + * @return string|array (success: success=true if found and search_result contains found messages, * success=false if nothing was found, search_result='nothing found', * error: result=error with error message) */ @@ -6092,7 +5780,9 @@ function api_friendica_direct_messages_search($type, $box = "") $sender = $user_info; } - $ret[] = api_format_messages($item, $recipient, $sender); + if (isset($recipient) && isset($sender)) { + $ret[] = api_format_messages($item, $recipient, $sender); + } } $success = ['success' => true, 'search_results' => $ret]; } @@ -6107,7 +5797,7 @@ api_register_func('api/friendica/direct_messages_search', 'api_friendica_direct_ * @brief return data of all the profiles a user has to the client * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_friendica_profile_show($type) { @@ -6118,18 +5808,18 @@ function api_friendica_profile_show($type) } // input params - $profileid = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0); + $profile_id = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0); // retrieve general information about profiles for user $multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles'); $directory = Config::get('system', 'directory'); // get data of the specified profile id or all profiles of the user if not specified - if ($profileid != 0) { + if ($profile_id != 0) { $r = q( "SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d", intval(api_user()), - intval($profileid) + intval($profile_id) ); // error message if specified gid is not in database @@ -6144,19 +5834,20 @@ function api_friendica_profile_show($type) } // loop through all returned profiles and retrieve data and users $k = 0; + $profiles = []; foreach ($r as $rr) { $profile = api_format_items_profiles($rr); // select all users from contact table, loop and prepare standard return for user data $users = []; - $r = q( + $nurls = q( "SELECT `id`, `nurl` FROM `contact` WHERE `uid`= %d AND `profile-id` = %d", intval(api_user()), intval($rr['profile_id']) ); - foreach ($r as $rr) { - $user = api_get_user($a, $rr['nurl']); + foreach ($nurls as $nurl) { + $user = api_get_user($a, $nurl['nurl']); ($type == "xml") ? $users[$k++ . ":user"] = $user : $users[] = $user; } $profile['users'] = $users;