X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fapi.php;h=764664ff6d6db94609fd6d37acbc261b31bb17fa;hb=8b2c51baf21707a3ea8bd9f339d2174de3ab200d;hp=43659db079a6fe974276716d45ba3c76464b9c75;hpb=dde2cf6ac0cef2a51c149774e810d8a1151846d4;p=friendica.git diff --git a/include/api.php b/include/api.php index 43659db079..764664ff6d 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; @@ -23,8 +39,8 @@ use Friendica\Model\Contact; use Friendica\Model\Group; 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\Network\FKOAuth1; @@ -170,23 +186,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));
@@ -198,6 +197,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");
@@ -767,7 +784,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);
@@ -1293,7 +1310,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)
@@ -1326,7 +1343,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);
@@ -1521,31 +1538,24 @@ 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;
-		}
-		$terms = DBA::select('term', ['oid'], $condition, []);
-		$itemIds = [];
-		while ($term = DBA::fetch($terms)) {
-			$itemIds[] = $term['oid'];
+		$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'];
 		}
-		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` " : ' ') . "
@@ -1716,8 +1726,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` <= ?";
@@ -1729,8 +1739,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` <= ?";
@@ -1795,8 +1805,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` <= ?";
@@ -2023,8 +2033,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) {
@@ -2041,7 +2051,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;
@@ -2051,6 +2060,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();
 	}
@@ -2905,60 +2916,6 @@ function api_format_items_activities($item, $type = "json")
 	return $activities;
 }
 
-
-/**
- * return data from profiles
- *
- * @param array $profile_row array containing data from db table 'profile'
- * @return array
- * @throws InternalServerErrorException
- */
-function api_format_items_profiles($profile_row)
-{
-	$profile = [
-		'profile_id'       => $profile_row['id'],
-		'profile_name'     => $profile_row['profile-name'],
-		'is_default'       => $profile_row['is-default'] ? true : false,
-		'hide_friends'     => $profile_row['hide-friends'] ? true : false,
-		'profile_photo'    => $profile_row['photo'],
-		'profile_thumb'    => $profile_row['thumb'],
-		'publish'          => $profile_row['publish'] ? true : false,
-		'net_publish'      => $profile_row['net-publish'] ? true : false,
-		'description'      => $profile_row['pdesc'],
-		'date_of_birth'    => $profile_row['dob'],
-		'address'          => $profile_row['address'],
-		'city'             => $profile_row['locality'],
-		'region'           => $profile_row['region'],
-		'postal_code'      => $profile_row['postal-code'],
-		'country'          => $profile_row['country-name'],
-		'hometown'         => $profile_row['hometown'],
-		'gender'           => $profile_row['gender'],
-		'marital'          => $profile_row['marital'],
-		'marital_with'     => $profile_row['with'],
-		'marital_since'    => $profile_row['howlong'],
-		'sexual'           => $profile_row['sexual'],
-		'politic'          => $profile_row['politic'],
-		'religion'         => $profile_row['religion'],
-		'public_keywords'  => $profile_row['pub_keywords'],
-		'private_keywords' => $profile_row['prv_keywords'],
-		'likes'            => BBCode::convert(api_clean_plain_items($profile_row['likes'])    , false, 2),
-		'dislikes'         => BBCode::convert(api_clean_plain_items($profile_row['dislikes']) , false, 2),
-		'about'            => BBCode::convert(api_clean_plain_items($profile_row['about'])    , false, 2),
-		'music'            => BBCode::convert(api_clean_plain_items($profile_row['music'])    , false, 2),
-		'book'             => BBCode::convert(api_clean_plain_items($profile_row['book'])     , false, 2),
-		'tv'               => BBCode::convert(api_clean_plain_items($profile_row['tv'])       , false, 2),
-		'film'             => BBCode::convert(api_clean_plain_items($profile_row['film'])     , false, 2),
-		'interest'         => BBCode::convert(api_clean_plain_items($profile_row['interest']) , false, 2),
-		'romance'          => BBCode::convert(api_clean_plain_items($profile_row['romance'])  , false, 2),
-		'work'             => BBCode::convert(api_clean_plain_items($profile_row['work'])     , false, 2),
-		'education'        => BBCode::convert(api_clean_plain_items($profile_row['education']), false, 2),
-		'social_networks'  => BBCode::convert(api_clean_plain_items($profile_row['contact'])  , false, 2),
-		'homepage'         => $profile_row['homepage'],
-		'users'            => null
-	];
-	return $profile;
-}
-
 /**
  * format items to be returned by api
  *
@@ -3043,7 +3000,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'],
@@ -4771,13 +4728,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,
@@ -5861,7 +5813,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") {
@@ -5891,10 +5843,11 @@ api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activit
  * Returns notifications
  *
  * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
+ *
  * @return string|array
- * @throws BadRequestException
  * @throws ForbiddenException
- * @throws InternalServerErrorException
+ * @throws BadRequestException
+ * @throws Exception
  */
 function api_friendica_notification($type)
 {
@@ -5906,19 +5859,25 @@ function api_friendica_notification($type)
 	if ($a->argc!==3) {
 		throw new BadRequestException("Invalid argument count");
 	}
-	$notes = DI::notify()->getAll([], ['seen' => 'ASC', 'date' => 'DESC'], 50);
+
+	$notifications = DI::notification()->getApiList(local_user());
 
 	if ($type == "xml") {
-		$xmlnotes = [];
-		if (!empty($notes)) {
-			foreach ($notes as $note) {
-				$xmlnotes[] = ["@attributes" => $note];
+		$xmlnotes = false;
+		if (!empty($notifications)) {
+			foreach ($notifications as $notification) {
+				$xmlnotes[] = ["@attributes" => $notification->toArray()];
 			}
 		}
 
-		$notes = $xmlnotes;
+		$result = $xmlnotes;
+	} elseif (count($notifications) > 0) {
+		$result = $notifications->getArrayCopy();
+	} else {
+		$result = false;
 	}
-	return api_format_data("notes", $type, ['note' => $notes]);
+
+	return api_format_data("notes", $type, ['note' => $result]);
 }
 
 /**
@@ -5936,37 +5895,38 @@ function api_friendica_notification($type)
  */
 function api_friendica_notification_seen($type)
 {
-	$a = DI::app();
+	$a         = DI::app();
 	$user_info = api_get_user($a);
 
 	if (api_user() === false || $user_info === false) {
 		throw new ForbiddenException();
 	}
-	if ($a->argc!==4) {
+	if ($a->argc !== 4) {
 		throw new BadRequestException("Invalid argument count");
 	}
 
 	$id = (!empty($_REQUEST['id']) ? intval($_REQUEST['id']) : 0);
 
-	$nm = DI::notify();
-	$note = $nm->getByID($id);
-	if (is_null($note)) {
-		throw new BadRequestException("Invalid argument");
-	}
-
-	$nm->setSeen($note);
-	if ($note['otype']=='item') {
-		// would be really better with an ItemsManager and $im->getByID() :-P
-		$item = Item::selectFirstForUser(api_user(), [], ['id' => $note['iid'], 'uid' => api_user()]);
-		if (DBA::isResult($item)) {
-			// we found the item, return it to the user
-			$ret = api_format_items([$item], $user_info, false, $type);
-			$data = ['status' => $ret];
-			return api_format_data("status", $type, $data);
+	try {
+		$notify = DI::notify()->getByID($id, api_user());
+		DI::notify()->setSeen(true, $notify);
+
+		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
+				$ret  = api_format_items([$item], $user_info, false, $type);
+				$data = ['status' => $ret];
+				return api_format_data("status", $type, $data);
+			}
+			// the item can't be found, but we set the notification as seen, so we count this as a success
 		}
-		// the item can't be found, but we set the note as seen, so we count this as a success
+		return api_format_data('result', $type, ['result' => "success"]);
+	} catch (NotFoundException $e) {
+		throw new BadRequestException('Invalid argument', $e);
+	} catch (Exception $e) {
+		throw new InternalServerErrorException('Internal Server exception', $e);
 	}
-	return api_format_data('result', $type, ['result' => "success"]);
 }
 
 /// @TODO move to top of file or somewhere better
@@ -6095,78 +6055,6 @@ function api_friendica_direct_messages_search($type, $box = "")
 /// @TODO move to top of file or somewhere better
 api_register_func('api/friendica/direct_messages_search', 'api_friendica_direct_messages_search', true);
 
-/**
- * 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|array
- * @throws BadRequestException
- * @throws ForbiddenException
- * @throws ImagickException
- * @throws InternalServerErrorException
- * @throws UnauthorizedException
- */
-function api_friendica_profile_show($type)
-{
-	$a = DI::app();
-
-	if (api_user() === false) {
-		throw new ForbiddenException();
-	}
-
-	// input params
-	$profile_id = $_REQUEST['profile_id'] ?? 0;
-
-	// retrieve general information about profiles for user
-	$multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles');
-	$directory = DI::config()->get('system', 'directory');
-
-	// get data of the specified profile id or all profiles of the user if not specified
-	if ($profile_id != 0) {
-		$r = Profile::getById(api_user(), $profile_id);
-		// error message if specified gid is not in database
-		if (!DBA::isResult($r)) {
-			throw new BadRequestException("profile_id not available");
-		}
-	} else {
-		$r = Profile::getListByUser(api_user());
-	}
-	// loop through all returned profiles and retrieve data and users
-	$k = 0;
-	$profiles = [];
-	if (DBA::isResult($r)) {
-		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 = [];
-			$nurls = Contact::selectToArray(['id', 'nurl'], ['uid' => api_user(), 'profile-id' => $rr['id']]);
-			foreach ($nurls as $nurl) {
-				$user = api_get_user($a, $nurl['nurl']);
-				($type == "xml") ? $users[$k++ . ":user"] = $user : $users[] = $user;
-			}
-			$profile['users'] = $users;
-
-			// add prepared profile data to array for final return
-			if ($type == "xml") {
-				$profiles[$k++ . ":profile"] = $profile;
-			} else {
-				$profiles[] = $profile;
-			}
-		}
-	}
-
-	// return settings, authenticated user and profiles data
-	$self = DBA::selectFirst('contact', ['nurl'], ['uid' => api_user(), 'self' => true]);
-
-	$result = ['multi_profiles' => $multi_profiles ? true : false,
-					'global_dir' => $directory,
-					'friendica_owner' => api_get_user($a, $self['nurl']),
-					'profiles' => $profiles];
-	return api_format_data("friendica_profiles", $type, ['$result' => $result]);
-}
-api_register_func('api/friendica/profile/show', 'api_friendica_profile_show', true, API_METHOD_GET);
-
 /**
  * Returns a list of saved searches.
  *