X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=include%2Fapi.php;h=808e34065b35c2894a899aa8c73b02f262c2c7bf;hb=5f43f56f7205d61b5bd867ff6c984636893187f2;hp=6f5120691cffe56f9e9ea9de52c763635d40b2cc;hpb=42775d53b2c5177cae2e0e1dacb0a32f92e4a83b;p=friendica.git diff --git a/include/api.php b/include/api.php index 6f5120691c..808e34065b 100644 --- a/include/api.php +++ b/include/api.php @@ -1,5 +1,22 @@ . + * * Friendica implementation of statusnet/twitter API * * @file include/api.php @@ -8,7 +25,6 @@ use Friendica\App; use Friendica\Content\ContactSelector; -use Friendica\Content\Feature; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -25,9 +41,9 @@ use Friendica\Model\Item; use Friendica\Model\Mail; use Friendica\Model\Notify; use Friendica\Model\Photo; -use Friendica\Model\Profile; use Friendica\Model\User; use Friendica\Model\UserItem; +use Friendica\Model\Verb; use Friendica\Network\FKOAuth1; use Friendica\Network\HTTPException; use Friendica\Network\HTTPException\BadRequestException; @@ -171,23 +187,6 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY */ function api_login(App $a) { - $oauth1 = new FKOAuth1(); - // login with oauth - try { - $request = OAuthRequest::from_request(); - list($consumer, $token) = $oauth1->verify_request($request); - if (!is_null($token)) { - $oauth1->loginUser($token->uid); - Session::set('allow_api', true); - return; - } - echo __FILE__.__LINE__.__FUNCTION__ . "
"; - var_dump($consumer, $token); - die(); - } catch (Exception $e) { - Logger::warning(API_LOG_PREFIX . 'error', ['module' => 'api', 'action' => 'login', 'exception' => $e->getMessage()]); - } - // workaround for HTTP-auth in CGI mode if (!empty($_SERVER['REDIRECT_REMOTE_USER'])) { $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); @@ -199,6 +198,24 @@ function api_login(App $a) } if (empty($_SERVER['PHP_AUTH_USER'])) { + // Try OAuth when no user is provided + $oauth1 = new FKOAuth1(); + // login with oauth + try { + $request = OAuthRequest::from_request(); + list($consumer, $token) = $oauth1->verify_request($request); + if (!is_null($token)) { + $oauth1->loginUser($token->uid); + Session::set('allow_api', true); + return; + } + echo __FILE__.__LINE__.__FUNCTION__ . ""; + var_dump($consumer, $token); + die(); + } catch (Exception $e) { + Logger::warning(API_LOG_PREFIX . 'OAuth error', ['module' => 'api', 'action' => 'login', 'exception' => $e->getMessage()]); + } + Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]); header('WWW-Authenticate: Basic realm="Friendica"'); throw new UnauthorizedException("This API requires login"); @@ -607,7 +624,7 @@ function api_get_user(App $a, $contact_id = null) 'name' => $contact["name"], 'screen_name' => (($contact['nick']) ? $contact['nick'] : $contact['name']), 'location' => ($contact["location"] != "") ? $contact["location"] : ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol']), - 'description' => BBCode::toPlaintext($contact["about"]), + 'description' => BBCode::toPlaintext($contact["about"] ?? ''), 'profile_image_url' => $contact["micro"], 'profile_image_url_https' => $contact["micro"], 'profile_image_url_profile_size' => $contact["thumb"], @@ -681,7 +698,7 @@ function api_get_user(App $a, $contact_id = null) 'name' => (($uinfo[0]['name']) ? $uinfo[0]['name'] : $uinfo[0]['nick']), 'screen_name' => (($uinfo[0]['nick']) ? $uinfo[0]['nick'] : $uinfo[0]['name']), 'location' => $location, - 'description' => BBCode::toPlaintext($description), + 'description' => BBCode::toPlaintext($description ?? ''), 'profile_image_url' => $uinfo[0]['micro'], 'profile_image_url_https' => $uinfo[0]['micro'], 'profile_image_url_profile_size' => $uinfo[0]["thumb"], @@ -768,7 +785,7 @@ function api_item_get_user(App $a, $item) $author_user = $status_user; - $status_user["protected"] = $item['private'] ?? 0; + $status_user["protected"] = isset($item['private']) && ($item['private'] == Item::PRIVATE); if (($item['thr-parent'] ?? '') == ($item['uri'] ?? '')) { $owner_user = api_get_user($a, $item['owner-id'] ?? null); @@ -1294,7 +1311,7 @@ api_register_func('api/media/metadata/create', 'api_media_metadata_create', true /** * @param string $type Return format (atom, rss, xml, json) * @param int $item_id - * @return string + * @return array|string * @throws Exception */ function api_status_show($type, $item_id) @@ -1327,7 +1344,7 @@ function api_get_last_status($ownerId, $uid) 'author-id'=> $ownerId, 'uid' => $uid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], - 'private' => false + 'private' => [Item::PUBLIC, Item::UNLISTED] ]; $item = api_get_item($condition); @@ -1522,34 +1539,27 @@ function api_search($type) $params = ['order' => ['id' => true], 'limit' => [$start, $count]]; if (preg_match('/^#(\w+)$/', $searchTerm, $matches) === 1 && isset($matches[1])) { $searchTerm = $matches[1]; - $condition = ["`oid` > ? - AND (`uid` = 0 OR (`uid` = ? AND NOT `global`)) - AND `otype` = ? AND `type` = ? AND `term` = ?", - $since_id, local_user(), TERM_OBJ_POST, TERM_HASHTAG, $searchTerm]; - if ($max_id > 0) { - $condition[0] .= ' AND `oid` <= ?'; - $condition[] = $max_id; + $condition = ["`iid` > ? AND `name` = ? AND (NOT `private` OR (`private` AND `uid` = ?))", $since_id, $searchTerm, local_user()]; + $tags = DBA::select('tag-search-view', ['uri-id'], $condition); + $uriids = []; + while ($tag = DBA::fetch($tags)) { + $uriids[] = $tag['uri-id']; } - $terms = DBA::select('term', ['oid'], $condition, []); - $itemIds = []; - while ($term = DBA::fetch($terms)) { - $itemIds[] = $term['oid']; - } - DBA::close($terms); + DBA::close($tags); - if (empty($itemIds)) { + if (empty($uriids)) { return api_format_data('statuses', $type, $data); } - $preCondition = ['`id` IN (' . implode(', ', $itemIds) . ')']; + $condition = ['uri-id' => $uriids]; if ($exclude_replies) { - $preCondition[] = '`id` = `parent`'; + $condition['gravity'] = GRAVITY_PARENT; } - $condition = [implode(' AND ', $preCondition)]; + $params['group_by'] = ['uri-id']; } else { $condition = ["`id` > ? - " . ($exclude_replies ? " AND `id` = `parent` " : ' ') . " + " . ($exclude_replies ? " AND `gravity` = " . GRAVITY_PARENT : ' ') . " AND (`uid` = 0 OR (`uid` = ? AND NOT `global`)) AND `body` LIKE CONCAT('%',?,'%')", $since_id, api_user(), $_REQUEST['q']]; @@ -1637,7 +1647,8 @@ function api_statuses_home_timeline($type) $condition[] = $max_id; } if ($exclude_replies) { - $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`gravity` = ?'; + $condition[] = GRAVITY_PARENT; } if ($conversation_id > 0) { $condition[0] .= " AND `item`.`parent` = ?"; @@ -1717,8 +1728,8 @@ function api_statuses_public_timeline($type) $start = max(0, ($page - 1) * $count); if ($exclude_replies && !$conversation_id) { - $condition = ["`gravity` IN (?, ?) AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND NOT `author`.`hidden`", - GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; + $condition = ["`gravity` IN (?, ?) AND `iid` > ? AND `private` = ? AND `wall` AND NOT `author`.`hidden`", + GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC]; if ($max_id > 0) { $condition[0] .= " AND `thread`.`iid` <= ?"; @@ -1730,8 +1741,8 @@ function api_statuses_public_timeline($type) $r = Item::inArray($statuses); } else { - $condition = ["`gravity` IN (?, ?) AND `id` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND `item`.`origin` AND NOT `author`.`hidden`", - GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; + $condition = ["`gravity` IN (?, ?) AND `id` > ? AND `private` = ? AND `wall` AND `item`.`origin` AND NOT `author`.`hidden`", + GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC]; if ($max_id > 0) { $condition[0] .= " AND `item`.`id` <= ?"; @@ -1796,8 +1807,8 @@ function api_statuses_networkpublic_timeline($type) $start = max(0, ($page - 1) * $count); - $condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND NOT `private`", - GRAVITY_PARENT, GRAVITY_COMMENT, $since_id]; + $condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND `private` = ?", + GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC]; if ($max_id > 0) { $condition[0] .= " AND `thread`.`iid` <= ?"; @@ -2024,8 +2035,8 @@ function api_statuses_repeat($type) Logger::log('API: api_statuses_repeat: '.$id); - $fields = ['body', 'title', 'attach', 'tag', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; - $item = Item::selectFirst($fields, ['id' => $id, 'private' => false]); + $fields = ['uri-id', 'body', 'title', 'attach', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; + $item = Item::selectFirst($fields, ['id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED]]); if (DBA::isResult($item) && $item['body'] != "") { if (strpos($item['body'], "[/share]") !== false) { @@ -2042,7 +2053,6 @@ function api_statuses_repeat($type) $post .= "[/share]"; } $_REQUEST['body'] = $post; - $_REQUEST['tag'] = $item['tag']; $_REQUEST['attach'] = $item['attach']; $_REQUEST['profile_uid'] = api_user(); $_REQUEST['api_source'] = true; @@ -2052,6 +2062,8 @@ function api_statuses_repeat($type) } $item_id = item_post($a); + + /// @todo Copy tags from the original post to the new one } else { throw new ForbiddenException(); } @@ -2244,7 +2256,8 @@ function api_statuses_user_timeline($type) } if ($exclude_replies) { - $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`gravity` = ?'; + $condition[] = GRAVITY_PARENT; } if ($conversation_id > 0) { @@ -2481,10 +2494,10 @@ function api_format_messages($item, $recipient, $sender) if ($_GET['getText'] == 'html') { $ret['text'] = BBCode::convert($item['body'], false); } elseif ($_GET['getText'] == 'plain') { - $ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0)); + $ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, BBCode::API, true), 0)); } } else { - $ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0); + $ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, BBCode::API, true), 0); } if (!empty($_GET['getUserObjects']) && $_GET['getUserObjects'] == 'false') { unset($ret['sender']); @@ -2510,7 +2523,7 @@ function api_convert_item($item) $attachments = api_get_attachments($body); // Workaround for ostatus messages where the title is identically to the body - $html = BBCode::convert(api_clean_plain_items($body), false, 2, true); + $html = BBCode::convert(api_clean_plain_items($body), false, BBCode::API, true); $statusbody = trim(HTML::toPlaintext($html, 0)); // handle data: images @@ -2990,7 +3003,7 @@ function api_format_item($item, $type = "json", $status_user = null, $author_use 'user' => $status_user, 'friendica_author' => $author_user, 'friendica_owner' => $owner_user, - 'friendica_private' => $item['private'] == 1, + 'friendica_private' => $item['private'] == Item::PRIVATE, //'entities' => NULL, 'statusnet_html' => $converted["html"], 'statusnet_conversation_id' => $item['parent'], @@ -3017,7 +3030,7 @@ function api_format_item($item, $type = "json", $status_user = null, $author_use $retweeted_item = []; $quoted_item = []; - if ($item["id"] == $item["parent"]) { + if ($item['gravity'] == GRAVITY_PARENT) { $body = $item['body']; $retweeted_item = api_share_as_retweet($item); if ($body != $item['body']) { @@ -3294,7 +3307,8 @@ function api_lists_statuses($type) $condition[] = $max_id; } if ($exclude_replies > 0) { - $condition[0] .= ' AND `item`.`parent` = `item`.`id`'; + $condition[0] .= ' AND `item`.`gravity` = ?'; + $condition[] = GRAVITY_PARENT; } if ($conversation_id > 0) { $condition[0] .= " AND `item`.`parent` = ?"; @@ -3566,96 +3580,6 @@ function api_statusnet_version($type) api_register_func('api/gnusocial/version', 'api_statusnet_version', false); api_register_func('api/statusnet/version', 'api_statusnet_version', false); -/** - * - * @param string $type Return type (atom, rss, xml, json) - * - * @param int $rel A contact relationship constant - * @return array|string|void - * @throws BadRequestException - * @throws ForbiddenException - * @throws ImagickException - * @throws InternalServerErrorException - * @throws UnauthorizedException - * @todo use api_format_data() to return data - */ -function api_ff_ids($type, int $rel) -{ - if (!api_user()) { - throw new ForbiddenException(); - } - - $a = DI::app(); - - api_get_user($a); - - $stringify_ids = $_REQUEST['stringify_ids'] ?? false; - - $contacts = DBA::p("SELECT `pcontact`.`id` - FROM `contact` - INNER JOIN `contact` AS `pcontact` - ON `contact`.`nurl` = `pcontact`.`nurl` - AND `pcontact`.`uid` = 0 - WHERE `contact`.`uid` = ? - AND NOT `contact`.`self` - AND `contact`.`rel` IN (?, ?)", - api_user(), - $rel, - Contact::FRIEND - ); - - $ids = []; - foreach (DBA::toArray($contacts) as $contact) { - if ($stringify_ids) { - $ids[] = $contact['id']; - } else { - $ids[] = intval($contact['id']); - } - } - - return api_format_data('ids', $type, ['id' => $ids]); -} - -/** - * Returns the ID of every user the user is following. - * - * @param string $type Return type (atom, rss, xml, json) - * - * @return array|string - * @throws BadRequestException - * @throws ForbiddenException - * @throws ImagickException - * @throws InternalServerErrorException - * @throws UnauthorizedException - * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids - */ -function api_friends_ids($type) -{ - return api_ff_ids($type, Contact::SHARING); -} - -/** - * Returns the ID of every user following the user. - * - * @param string $type Return type (atom, rss, xml, json) - * - * @return array|string - * @throws BadRequestException - * @throws ForbiddenException - * @throws ImagickException - * @throws InternalServerErrorException - * @throws UnauthorizedException - * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids - */ -function api_followers_ids($type) -{ - return api_ff_ids($type, Contact::FOLLOWER); -} - -/// @TODO move to top of file or somewhere better -api_register_func('api/friends/ids', 'api_friends_ids', true); -api_register_func('api/followers/ids', 'api_followers_ids', true); - /** * Sends a new direct message. * @@ -4718,13 +4642,8 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ } } - if ($filetype == "") { - $filetype = Images::guessType($filename); - } - $imagedata = @getimagesize($src); - if ($imagedata) { - $filetype = $imagedata['mime']; - } + $filetype = Images::getMimeTypeBySource($src, $filename, $filetype); + Logger::log( "File upload src: " . $src . " - filename: " . $filename . " - size: " . $filesize . " - type: " . $filetype, @@ -5097,8 +5016,7 @@ function api_get_announce($item) } $fields = ['author-id', 'author-name', 'author-link', 'author-avatar']; - $activity = Item::activityToIndex(Activity::ANNOUNCE); - $condition = ['parent-uri' => $item['uri'], 'gravity' => GRAVITY_ACTIVITY, 'uid' => [0, $item['uid']], 'activity' => $activity]; + $condition = ['parent-uri' => $item['uri'], 'gravity' => GRAVITY_ACTIVITY, 'uid' => [0, $item['uid']], 'vid' => Verb::getID(Activity::ANNOUNCE)]; $announce = Item::selectFirstForUser($item['uid'], $fields, $condition, ['order' => ['received' => true]]); if (!DBA::isResult($announce)) { return []; @@ -5194,7 +5112,7 @@ function api_in_reply_to($item) $in_reply_to['user_id_str'] = null; $in_reply_to['screen_name'] = null; - if (($item['thr-parent'] != $item['uri']) && (intval($item['parent']) != intval($item['id']))) { + if (($item['thr-parent'] != $item['uri']) && ($item['gravity'] != GRAVITY_PARENT)) { $parent = Item::selectFirst(['id'], ['uid' => $item['uid'], 'uri' => $item['thr-parent']]); if (DBA::isResult($parent)) { $in_reply_to['status_id'] = intval($parent['id']); @@ -5808,7 +5726,7 @@ function api_friendica_activity($type) $id = $_REQUEST['id'] ?? 0; - $res = Item::performLike($id, $verb); + $res = Item::performActivity($id, $verb); if ($res) { if ($type == "xml") { @@ -5903,10 +5821,10 @@ function api_friendica_notification_seen($type) $id = (!empty($_REQUEST['id']) ? intval($_REQUEST['id']) : 0); try { - $notify = DI::notify()->getByID($id); + $notify = DI::notify()->getByID($id, api_user()); DI::notify()->setSeen(true, $notify); - if ($notify->otype === Notify::OTYPE_ITEM) { + if ($notify->otype === Notify\ObjectType::ITEM) { $item = Item::selectFirstForUser(api_user(), [], ['id' => $notify->iid, 'uid' => api_user()]); if (DBA::isResult($item)) { // we found the item, return it to the user