2016-09-25 18:50:08 +02:00
< ? php
/**
* Friendica implementation of statusnet / twitter API
*
2017-12-24 03:20:50 +01:00
* @ file include / api . php
2016-09-25 18:50:08 +02:00
* @ todo Automatically detect if incoming data is HTML or BBCode
*/
2017-04-30 06:07:00 +02:00
use Friendica\App ;
2018-01-10 04:42:04 +01:00
use Friendica\Content\ContactSelector ;
2017-12-04 15:04:36 +01:00
use Friendica\Content\Feature ;
2017-08-26 08:04:21 +02:00
use Friendica\Core\System ;
2017-04-30 06:01:26 +02:00
use Friendica\Core\Config ;
2017-11-08 01:37:53 +01:00
use Friendica\Core\NotificationsManager ;
2017-12-18 20:39:35 +01:00
use Friendica\Core\PConfig ;
2017-11-05 13:15:53 +01:00
use Friendica\Core\Worker ;
2017-11-08 04:57:46 +01:00
use Friendica\Database\DBM ;
2017-12-07 15:04:24 +01:00
use Friendica\Model\Contact ;
2017-12-09 19:45:17 +01:00
use Friendica\Model\Group ;
2017-12-07 14:56:11 +01:00
use Friendica\Model\Photo ;
2017-11-26 20:46:08 +01:00
use Friendica\Model\User ;
2017-12-05 00:30:18 +01:00
use Friendica\Network\FKOAuth1 ;
2017-11-24 05:48:15 +01:00
use Friendica\Network\HTTPException ;
use Friendica\Network\HTTPException\BadRequestException ;
use Friendica\Network\HTTPException\ForbiddenException ;
use Friendica\Network\HTTPException\InternalServerErrorException ;
use Friendica\Network\HTTPException\MethodNotAllowedException ;
use Friendica\Network\HTTPException\NotFoundException ;
use Friendica\Network\HTTPException\NotImplementedException ;
use Friendica\Network\HTTPException\UnauthorizedException ;
use Friendica\Network\HTTPException\TooManyRequestsException ;
2017-12-07 14:56:11 +01:00
use Friendica\Object\Image ;
2017-11-08 14:34:48 +01:00
use Friendica\Protocol\Diaspora ;
2017-11-10 13:45:33 +01:00
use Friendica\Util\XML ;
2017-01-17 20:21:46 +01:00
2017-04-05 22:07:55 +02:00
require_once 'include/bbcode.php' ;
require_once 'include/datetime.php' ;
require_once 'include/conversation.php' ;
require_once 'include/html2plain.php' ;
require_once 'mod/share.php' ;
require_once 'mod/item.php' ;
require_once 'include/security.php' ;
require_once 'include/html2bbcode.php' ;
require_once 'mod/wall_upload.php' ;
require_once 'mod/proxy.php' ;
require_once 'include/message.php' ;
require_once 'include/like.php' ;
require_once 'include/plaintext.php' ;
define ( 'API_METHOD_ANY' , '*' );
define ( 'API_METHOD_GET' , 'GET' );
define ( 'API_METHOD_POST' , 'POST,PUT' );
define ( 'API_METHOD_DELETE' , 'POST,DELETE' );
$API = array ();
$called_api = null ;
2017-11-10 06:00:50 +01:00
/**
* It is not sufficient to use local_user () to check whether someone is allowed to use the API ,
* because this will open CSRF holes ( just embed an image with src = friendicasite . com / api / statuses / update ? status = CSRF
* into a page , and visitors will post something without noticing it ) .
2017-12-24 03:20:50 +01:00
*
* @ brief Auth API user
2017-11-10 06:00:50 +01:00
*/
function api_user ()
{
if ( x ( $_SESSION , 'allow_api' )) {
return local_user ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return false ;
}
/**
* Clients can send 'source' parameter to be show in post metadata
* as " sent via <source> " .
* Some clients doesn ' t send a source param , we support ones we know
* ( only Twidere , atm )
*
2017-12-24 03:20:50 +01:00
* @ brief Get source name from API client
*
2017-11-10 06:00:50 +01:00
* @ return string
* Client source name , default to " api " if unset / unknown
*/
function api_source ()
{
if ( requestdata ( 'source' )) {
return requestdata ( 'source' );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// Support for known clients that doesn't send a source name
if ( strpos ( $_SERVER [ 'HTTP_USER_AGENT' ], " Twidere " ) !== false ) {
return " Twidere " ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( " Unrecognized user-agent " . $_SERVER [ 'HTTP_USER_AGENT' ], LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return " api " ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Format date for API
*
* @ param string $str Source date , as UTC
* @ return string Date in UTC formatted as " D M d H:i:s +0000 Y "
*/
function api_date ( $str )
{
// Wed May 23 06:01:13 +0000 2007
return datetime_convert ( 'UTC' , 'UTC' , $str , " D M d H:i:s +0000 Y " );
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Register a function to be the endpoint for defined API path .
2017-11-10 06:00:50 +01:00
*
2017-12-24 03:20:50 +01:00
* @ brief Register API endpoint
2017-11-10 06:00:50 +01:00
*
* @ param string $path API URL path , relative to System :: baseUrl ()
* @ param string $func Function name to call on path request
* @ param bool $auth API need logged user
* @ param string $method HTTP method reqiured to call this endpoint .
* One of API_METHOD_ANY , API_METHOD_GET , API_METHOD_POST .
* Default to API_METHOD_ANY
*/
function api_register_func ( $path , $func , $auth = false , $method = API_METHOD_ANY )
{
global $API ;
$API [ $path ] = array (
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
);
// Workaround for hotot
$path = str_replace ( " api/ " , " api/1.1/ " , $path );
$API [ $path ] = array (
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
);
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* Log in user via OAuth1 or Simple HTTP Auth .
* Simple Auth allow username in form of < pre > user @ server </ pre > , ignoring server part
*
2017-12-24 03:20:50 +01:00
* @ brief Login API user
*
2017-11-10 06:00:50 +01:00
* @ param object $a App
* @ hook 'authenticate'
* array $addon_auth
* 'username' => username from login form
* 'password' => password from login form
* 'authenticated' => return status ,
* 'user_record' => return authenticated user record
* @ hook 'logged_in'
* array $user logged user record
*/
function api_login ( App $a )
{
2017-12-05 03:10:54 +01:00
$oauth1 = new FKOAuth1 ();
2017-11-10 06:00:50 +01:00
// login with oauth
try {
2017-12-05 03:10:54 +01:00
list ( $consumer , $token ) = $oauth1 -> verify_request ( OAuthRequest :: from_request ());
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $token )) {
2017-12-05 03:10:54 +01:00
$oauth1 -> loginUser ( $token -> uid );
2017-11-10 06:00:50 +01:00
call_hooks ( 'logged_in' , $a -> user );
return ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
echo __FILE__ . __LINE__ . __FUNCTION__ . " <pre> " ;
var_dump ( $consumer , $token );
die ();
} catch ( Exception $e ) {
logger ( $e );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// workaround for HTTP-auth in CGI mode
if ( x ( $_SERVER , 'REDIRECT_REMOTE_USER' )) {
$userpass = base64_decode ( substr ( $_SERVER [ " REDIRECT_REMOTE_USER " ], 6 )) ;
if ( strlen ( $userpass )) {
list ( $name , $password ) = explode ( ':' , $userpass );
$_SERVER [ 'PHP_AUTH_USER' ] = $name ;
$_SERVER [ 'PHP_AUTH_PW' ] = $password ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! x ( $_SERVER , 'PHP_AUTH_USER' )) {
2017-12-24 00:27:45 +01:00
logger ( 'API_login: ' . print_r ( $_SERVER , true ), LOGGER_DEBUG );
2017-11-10 06:00:50 +01:00
header ( 'WWW-Authenticate: Basic realm="Friendica"' );
throw new UnauthorizedException ( " This API requires login " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$user = $_SERVER [ 'PHP_AUTH_USER' ];
$password = $_SERVER [ 'PHP_AUTH_PW' ];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// allow "user@server" login (but ignore 'server' part)
$at = strstr ( $user , " @ " , true );
if ( $at ) {
$user = $at ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// next code from mod/auth.php. needs better solution
$record = null ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$addon_auth = array (
'username' => trim ( $user ),
'password' => trim ( $password ),
'authenticated' => 0 ,
'user_record' => null ,
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/*
* A plugin indicates successful login by setting 'authenticated' to non - zero value and returning a user record
* Plugins should never set 'authenticated' except to indicate success - as hooks may be chained
* and later plugins should not interfere with an earlier one that succeeded .
*/
call_hooks ( 'authenticate' , $addon_auth );
2017-12-23 00:10:32 +01:00
if ( $addon_auth [ 'authenticated' ] && count ( $addon_auth [ 'user_record' ])) {
2017-11-10 06:00:50 +01:00
$record = $addon_auth [ 'user_record' ];
} else {
2017-11-26 20:46:08 +01:00
$user_id = User :: authenticate ( trim ( $user ), trim ( $password ));
if ( $user_id ) {
2018-01-10 14:36:02 +01:00
$record = dba :: selectFirst ( 'user' , [], [ 'uid' => $user_id ]);
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-23 00:10:32 +01:00
if ( ! $record || ! count ( $record )) {
2017-11-10 06:00:50 +01:00
logger ( 'API_login failure: ' . print_r ( $_SERVER , true ), LOGGER_DEBUG );
header ( 'WWW-Authenticate: Basic realm="Friendica"' );
//header('HTTP/1.0 401 Unauthorized');
//die('This api requires login');
throw new UnauthorizedException ( " This API requires login " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
authenticate_success ( $record );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_SESSION [ " allow_api " ] = true ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
call_hooks ( 'logged_in' , $a -> user );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* API endpoints can define which HTTP method to accept when called .
* This function check the current HTTP method agains endpoint
* registered method .
*
2017-12-24 03:20:50 +01:00
* @ brief Check HTTP method of called API
*
2017-11-10 06:00:50 +01:00
* @ param string $method Required methods , uppercase , separated by comma
* @ return bool
*/
function api_check_method ( $method )
{
if ( $method == " * " ) {
return true ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
return ( strpos ( $method , $_SERVER [ 'REQUEST_METHOD' ]) !== false );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* Authenticate user , call registered API function , set HTTP headers
*
2017-12-24 03:20:50 +01:00
* @ brief Main API entry point
*
2017-11-10 06:00:50 +01:00
* @ param object $a App
* @ return string API call result
*/
function api_call ( App $a )
{
global $API , $called_api ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$type = " json " ;
if ( strpos ( $a -> query_string , " .xml " ) > 0 ) {
$type = " xml " ;
}
if ( strpos ( $a -> query_string , " .json " ) > 0 ) {
2017-04-05 22:07:55 +02:00
$type = " json " ;
2017-11-10 06:00:50 +01:00
}
if ( strpos ( $a -> query_string , " .rss " ) > 0 ) {
$type = " rss " ;
}
if ( strpos ( $a -> query_string , " .atom " ) > 0 ) {
$type = " atom " ;
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
try {
foreach ( $API as $p => $info ) {
if ( strpos ( $a -> query_string , $p ) === 0 ) {
if ( ! api_check_method ( $info [ 'method' ])) {
throw new MethodNotAllowedException ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$called_api = explode ( " / " , $p );
//unset($_SERVER['PHP_AUTH_USER']);
2017-04-05 22:17:15 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO should be "true ==[=] $info['auth']", if you miss only one = character, you assign a variable (only with ==). Let's make all this even.
if ( $info [ 'auth' ] === true && api_user () === false ) {
api_login ( $a );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( 'API call for ' . $a -> user [ 'username' ] . ': ' . $a -> query_string );
logger ( 'API parameters: ' . print_r ( $_REQUEST , true ));
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$stamp = microtime ( true );
2018-01-04 02:54:35 +01:00
$return = call_user_func ( $info [ 'func' ], $type );
2017-11-10 06:00:50 +01:00
$duration = ( float ) ( microtime ( true ) - $stamp );
logger ( " API call duration: " . round ( $duration , 2 ) . " \t " . $a -> query_string , LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( Config :: get ( " system " , " profiler " )) {
$duration = microtime ( true ) - $a -> performance [ " start " ];
2016-11-12 14:17:28 +01:00
2017-11-10 06:00:50 +01:00
/// @TODO round() really everywhere?
logger (
parse_url ( $a -> query_string , PHP_URL_PATH ) . " : " . sprintf (
" Database: %s/%s, Network: %s, I/O: %s, Other: %s, Total: %s " ,
2016-11-04 23:45:20 +01:00
round ( $a -> performance [ " database " ] - $a -> performance [ " database_write " ], 3 ),
round ( $a -> performance [ " database_write " ], 3 ),
round ( $a -> performance [ " network " ], 2 ),
round ( $a -> performance [ " file " ], 2 ),
2017-11-10 06:00:50 +01:00
round ( $duration - ( $a -> performance [ " database " ] + $a -> performance [ " network " ] + $a -> performance [ " file " ]), 2 ),
round ( $duration , 2 )
),
LOGGER_DEBUG
);
if ( Config :: get ( " rendertime " , " callstack " )) {
$o = " Database Read: \n " ;
foreach ( $a -> callstack [ " database " ] as $func => $time ) {
$time = round ( $time , 3 );
if ( $time > 0 ) {
$o .= $func . " : " . $time . " \n " ;
2016-11-04 23:45:20 +01:00
}
2017-11-10 06:00:50 +01:00
}
$o .= " \n Database Write: \n " ;
foreach ( $a -> callstack [ " database_write " ] as $func => $time ) {
$time = round ( $time , 3 );
if ( $time > 0 ) {
$o .= $func . " : " . $time . " \n " ;
2016-11-04 23:45:20 +01:00
}
2017-11-10 06:00:50 +01:00
}
2016-11-04 23:45:20 +01:00
2017-11-10 06:00:50 +01:00
$o .= " \n Network: \n " ;
foreach ( $a -> callstack [ " network " ] as $func => $time ) {
$time = round ( $time , 3 );
if ( $time > 0 ) {
$o .= $func . " : " . $time . " \n " ;
2016-11-04 23:45:20 +01:00
}
}
2017-11-10 06:00:50 +01:00
logger ( $o , LOGGER_DEBUG );
2016-11-04 23:45:20 +01:00
}
2017-11-10 06:00:50 +01:00
}
2016-11-04 23:45:20 +01:00
2018-01-04 02:54:35 +01:00
if ( false === $return ) {
2017-11-10 06:00:50 +01:00
/*
* api function returned false withour throw an
* exception . This should not happend , throw a 500
*/
throw new InternalServerErrorException ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
switch ( $type ) {
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2018-01-04 02:54:35 +01:00
foreach ( $return as $rr ) {
2017-11-10 06:00:50 +01:00
$json = json_encode ( $rr );
2017-12-24 00:27:45 +01:00
}
if ( x ( $_GET , 'callback' )) {
$json = $_GET [ 'callback' ] . " ( " . $json . " ) " ;
}
2018-01-04 02:54:35 +01:00
$return = $json ;
2017-11-10 06:00:50 +01:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
2018-01-04 02:54:35 +01:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 06:00:50 +01:00
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
2018-01-04 02:54:35 +01:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 06:00:50 +01:00
break ;
2016-09-25 18:50:08 +02:00
}
2018-01-04 02:54:35 +01:00
return $return ;
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
logger ( 'API call not implemented: ' . $a -> query_string );
throw new NotImplementedException ();
} catch ( HTTPException $e ) {
header ( " HTTP/1.1 { $e -> httpcode } { $e -> httpdesc } " );
return api_error ( $type , $e );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Format API error string
*
* @ param string $type Return type ( xml , json , rss , as )
* @ param object $e HTTPException Error object
2017-12-23 01:23:20 +01:00
* @ return string error message formatted as $type
2017-11-10 06:00:50 +01:00
*/
function api_error ( $type , $e )
{
$a = get_app ();
$error = ( $e -> getMessage () !== " " ? $e -> getMessage () : $e -> httpdesc );
/// @TODO: https://dev.twitter.com/overview/api/response-codes
$error = array ( " error " => $error ,
" code " => $e -> httpcode . " " . $e -> httpdesc ,
" request " => $a -> query_string );
2018-01-04 02:54:35 +01:00
$return = api_format_data ( 'status' , $type , array ( 'status' => $error ));
2017-11-10 06:00:50 +01:00
switch ( $type ) {
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2018-01-04 02:54:35 +01:00
$return = json_encode ( $return );
2017-11-10 06:00:50 +01:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
break ;
}
2018-01-04 02:54:35 +01:00
return $return ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Set values for RSS template
*
* @ param App $a
* @ param array $arr Array to be passed to template
* @ param array $user_info User info
* @ return array
* @ todo find proper type - hints
*/
function api_rss_extra ( App $a , $arr , $user_info )
{
if ( is_null ( $user_info )) {
$user_info = api_get_user ( $a );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$arr [ '$user' ] = $user_info ;
$arr [ '$rss' ] = array (
'alternate' => $user_info [ 'url' ],
'self' => System :: baseUrl () . " / " . $a -> query_string ,
'base' => System :: baseUrl (),
'updated' => api_date ( null ),
'atom_updated' => datetime_convert ( 'UTC' , 'UTC' , 'now' , ATOM_TIME ),
'language' => $user_info [ 'language' ],
'logo' => System :: baseUrl () . " /images/friendica-32.png " ,
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $arr ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Unique contact to contact url .
*
* @ param int $id Contact id
* @ return bool | string
* Contact url or False if contact id is unknown
*/
2017-12-17 12:11:28 +01:00
function api_unique_id_to_nurl ( $id )
2017-11-10 06:00:50 +01:00
{
2018-01-10 14:36:02 +01:00
$r = dba :: selectFirst ( 'contact' , array ( 'nurl' ), array ( 'uid' => 0 , 'id' => $id ));
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
2017-12-17 12:11:28 +01:00
return $r [ " nurl " ];
2017-11-10 06:00:50 +01:00
} else {
return false ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Get user info array .
*
* @ param object $a App
* @ param int | string $contact_id Contact ID or URL
*/
2017-12-16 16:16:25 +01:00
function api_get_user ( App $a , $contact_id = null )
2017-11-10 06:00:50 +01:00
{
global $called_api ;
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
$user = null ;
$extra_query = " " ;
$url = " " ;
logger ( " api_get_user: Fetching user data for user " . $contact_id , LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Searching for contact URL
if ( ! is_null ( $contact_id ) && ( intval ( $contact_id ) == 0 )) {
$user = dbesc ( normalise_link ( $contact_id ));
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
}
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// Searching for contact id with uid = 0
if ( ! is_null ( $contact_id ) && ( intval ( $contact_id ) != 0 )) {
2017-12-17 12:11:28 +01:00
$user = dbesc ( api_unique_id_to_nurl ( $contact_id ));
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $user == " " ) {
throw new BadRequestException ( " User not found. " );
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
2017-05-15 22:11:33 +02:00
}
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( is_null ( $user ) && x ( $_GET , 'user_id' )) {
2017-12-17 12:11:28 +01:00
$user = dbesc ( api_unique_id_to_nurl ( $_GET [ 'user_id' ]));
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $user == " " ) {
throw new BadRequestException ( " User not found. " );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
}
}
if ( is_null ( $user ) && x ( $_GET , 'screen_name' )) {
$user = dbesc ( $_GET [ 'screen_name' ]);
$extra_query = " AND `contact`.`nick` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
}
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( is_null ( $user ) && x ( $_GET , 'profileurl' )) {
$user = dbesc ( normalise_link ( $_GET [ 'profileurl' ]));
$extra_query = " AND `contact`.`nurl` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( is_null ( $user ) && ( $a -> argc > ( count ( $called_api ) - 1 )) && ( count ( $called_api ) > 0 )) {
$argid = count ( $called_api );
list ( $user , $null ) = explode ( " . " , $a -> argv [ $argid ]);
if ( is_numeric ( $user )) {
2017-12-17 12:11:28 +01:00
$user = dbesc ( api_unique_id_to_nurl ( $user ));
2016-09-25 18:50:08 +02:00
2017-04-05 22:07:55 +02:00
if ( $user == " " ) {
2017-11-10 06:00:50 +01:00
return false ;
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
2017-04-05 22:07:55 +02:00
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
}
2017-11-10 06:00:50 +01:00
} else {
$user = dbesc ( $user );
2016-09-25 18:50:08 +02:00
$extra_query = " AND `contact`.`nick` = '%s' " ;
2017-04-05 22:07:55 +02:00
if ( api_user () !== false ) {
2017-11-10 06:00:50 +01:00
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( " api_get_user: user " . $user , LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! $user ) {
if ( api_user () === false ) {
api_login ( $a );
return false ;
} else {
$user = $_SESSION [ 'uid' ];
$extra_query = " AND `contact`.`uid` = %d AND `contact`.`self` " ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( 'api_user: ' . $extra_query . ', user: ' . $user );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// user info
$uinfo = q (
" SELECT *, `contact`.`id` AS `cid` FROM `contact`
WHERE 1
$extra_query " ,
$user
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Selecting the id by priority, friendica first
api_best_nickname ( $uinfo );
2016-11-04 23:45:20 +01:00
2017-11-10 06:00:50 +01:00
// if the contact wasn't found, fetch it from the contacts with uid = 0
if ( ! DBM :: is_result ( $uinfo )) {
$r = array ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $url != " " ) {
$r = q ( " SELECT * FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' LIMIT 1 " , dbesc ( normalise_link ( $url )));
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
2018-01-10 04:42:04 +01:00
$network_name = ContactSelector :: networkToName ( $r [ 0 ][ 'network' ], $r [ 0 ][ 'url' ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// If no nick where given, extract it from the address
if (( $r [ 0 ][ 'nick' ] == " " ) || ( $r [ 0 ][ 'name' ] == $r [ 0 ][ 'nick' ])) {
$r [ 0 ][ 'nick' ] = api_get_nick ( $r [ 0 ][ " url " ]);
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$ret = array (
'id' => $r [ 0 ][ " id " ],
'id_str' => ( string ) $r [ 0 ][ " id " ],
'name' => $r [ 0 ][ " name " ],
'screen_name' => (( $r [ 0 ][ 'nick' ]) ? $r [ 0 ][ 'nick' ] : $r [ 0 ][ 'name' ]),
'location' => ( $r [ 0 ][ " location " ] != " " ) ? $r [ 0 ][ " location " ] : $network_name ,
'description' => $r [ 0 ][ " about " ],
'profile_image_url' => $r [ 0 ][ " micro " ],
'profile_image_url_https' => $r [ 0 ][ " micro " ],
'url' => $r [ 0 ][ " url " ],
'protected' => false ,
'followers_count' => 0 ,
'friends_count' => 0 ,
'listed_count' => 0 ,
'created_at' => api_date ( $r [ 0 ][ " created " ]),
'favourites_count' => 0 ,
'utc_offset' => 0 ,
'time_zone' => 'UTC' ,
'geo_enabled' => false ,
'verified' => false ,
'statuses_count' => 0 ,
'lang' => '' ,
'contributors_enabled' => false ,
'is_translator' => false ,
'is_translation_enabled' => false ,
'following' => false ,
'follow_request_sent' => false ,
'statusnet_blocking' => false ,
'notifications' => false ,
'statusnet_profile_url' => $r [ 0 ][ " url " ],
'uid' => 0 ,
2017-11-19 23:03:39 +01:00
'cid' => Contact :: getIdForURL ( $r [ 0 ][ " url " ], api_user (), true ),
2017-11-10 06:00:50 +01:00
'self' => 0 ,
'network' => $r [ 0 ][ " network " ],
2016-09-25 18:50:08 +02:00
);
2017-11-10 06:00:50 +01:00
return $ret ;
2016-11-04 23:45:20 +01:00
} else {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " User not found. " );
2016-11-04 23:45:20 +01:00
}
2017-11-10 06:00:50 +01:00
}
if ( $uinfo [ 0 ][ 'self' ]) {
if ( $uinfo [ 0 ][ 'network' ] == " " ) {
$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 ())
);
2017-04-05 22:07:55 +02:00
/// @TODO old-lost code? (twice)
2017-11-10 06:00:50 +01:00
// 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)
/*
2016-11-04 23:45:20 +01:00
// Counting is deactivated by now, due to performance issues
2016-09-25 18:50:08 +02:00
// count friends
$r = q ( " SELECT count(*) as `count` FROM `contact`
WHERE `uid` = % d AND `rel` IN ( % d , % d )
2017-02-10 03:51:01 +01:00
AND `self` = 0 AND NOT `blocked` AND NOT `pending` AND `hidden` = 0 " ,
2016-09-25 18:50:08 +02:00
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 )
2017-02-10 03:51:01 +01:00
AND `self` = 0 AND NOT `blocked` AND NOT `pending` AND `hidden` = 0 " ,
2016-09-25 18:50:08 +02:00
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' ];
2017-04-04 19:46:56 +02:00
if ( ! $uinfo [ 0 ][ 'self' ]) {
2016-09-25 18:50:08 +02:00
$countfriends = 0 ;
$countfollowers = 0 ;
$starred = 0 ;
}
2017-11-10 06:00:50 +01:00
*/
$countfriends = 0 ;
$countfollowers = 0 ;
$starred = 0 ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Add a nick if it isn't present there
if (( $uinfo [ 0 ][ 'nick' ] == " " ) || ( $uinfo [ 0 ][ 'name' ] == $uinfo [ 0 ][ 'nick' ])) {
$uinfo [ 0 ][ 'nick' ] = api_get_nick ( $uinfo [ 0 ][ " url " ]);
2016-09-25 18:50:08 +02:00
}
2018-01-10 04:42:04 +01:00
$network_name = ContactSelector :: networkToName ( $uinfo [ 0 ][ 'network' ], $uinfo [ 0 ][ 'url' ]);
2017-11-10 06:00:50 +01:00
2017-11-19 23:03:39 +01:00
$pcontact_id = Contact :: getIdForURL ( $uinfo [ 0 ][ 'url' ], 0 , true );
2017-11-10 06:00:50 +01:00
2017-12-25 06:39:11 +01:00
if ( ! empty ( $profile [ 0 ][ 'about' ])) {
$description = $profile [ 0 ][ 'about' ];
2017-12-24 12:51:38 +01:00
} else {
$description = $uinfo [ 0 ][ " about " ];
}
if ( ! empty ( $usr [ 0 ][ 'default-location' ])) {
$location = $usr [ 0 ][ 'default-location' ];
} elseif ( ! empty ( $uinfo [ 0 ][ " location " ])) {
$location = $uinfo [ 0 ][ " location " ];
} else {
2017-12-25 00:07:14 +01:00
$location = $network_name ;
2017-12-24 12:51:38 +01:00
}
2017-11-10 06:00:50 +01:00
$ret = array (
'id' => intval ( $pcontact_id ),
'id_str' => ( string ) intval ( $pcontact_id ),
'name' => (( $uinfo [ 0 ][ 'name' ]) ? $uinfo [ 0 ][ 'name' ] : $uinfo [ 0 ][ 'nick' ]),
'screen_name' => (( $uinfo [ 0 ][ 'nick' ]) ? $uinfo [ 0 ][ 'nick' ] : $uinfo [ 0 ][ 'name' ]),
2017-12-24 12:51:38 +01:00
'location' => $location ,
'description' => $description ,
2017-11-10 06:00:50 +01:00
'profile_image_url' => $uinfo [ 0 ][ 'micro' ],
'profile_image_url_https' => $uinfo [ 0 ][ 'micro' ],
'url' => $uinfo [ 0 ][ 'url' ],
'protected' => false ,
'followers_count' => intval ( $countfollowers ),
'friends_count' => intval ( $countfriends ),
'listed_count' => 0 ,
'created_at' => api_date ( $uinfo [ 0 ][ 'created' ]),
'favourites_count' => intval ( $starred ),
'utc_offset' => " 0 " ,
'time_zone' => 'UTC' ,
'geo_enabled' => false ,
'verified' => true ,
'statuses_count' => intval ( $countitms ),
'lang' => '' ,
'contributors_enabled' => false ,
'is_translator' => false ,
'is_translation_enabled' => false ,
'following' => (( $uinfo [ 0 ][ 'rel' ] == CONTACT_IS_FOLLOWER ) || ( $uinfo [ 0 ][ 'rel' ] == CONTACT_IS_FRIEND )),
'follow_request_sent' => false ,
'statusnet_blocking' => false ,
'notifications' => false ,
/// @TODO old way?
//'statusnet_profile_url' => System::baseUrl()."/contacts/".$uinfo[0]['cid'],
'statusnet_profile_url' => $uinfo [ 0 ][ 'url' ],
'uid' => intval ( $uinfo [ 0 ][ 'uid' ]),
'cid' => intval ( $uinfo [ 0 ][ 'cid' ]),
'self' => $uinfo [ 0 ][ 'self' ],
'network' => $uinfo [ 0 ][ 'network' ],
);
2017-12-18 20:39:35 +01:00
// If this is a local user and it uses Frio, we can get its color preferences.
if ( $ret [ 'self' ]) {
2018-01-10 14:36:02 +01:00
$theme_info = dba :: selectFirst ( 'user' , [ 'theme' ], [ 'uid' => $ret [ 'uid' ]]);
2017-12-18 20:39:35 +01:00
if ( $theme_info [ 'theme' ] === 'frio' ) {
$schema = PConfig :: get ( $ret [ 'uid' ], 'frio' , 'schema' );
2017-12-19 11:33:59 +01:00
if ( $schema && ( $schema != '---' )) {
2017-12-18 20:39:35 +01:00
if ( file_exists ( 'view/theme/frio/schema/' . $schema . '.php' )) {
$schemefile = 'view/theme/frio/schema/' . $schema . '.php' ;
2017-12-19 11:33:59 +01:00
require_once $schemefile ;
2017-12-18 20:39:35 +01:00
}
} else {
$nav_bg = PConfig :: get ( $ret [ 'uid' ], 'frio' , 'nav_bg' );
$link_color = PConfig :: get ( $ret [ 'uid' ], 'frio' , 'link_color' );
$bgcolor = PConfig :: get ( $ret [ 'uid' ], 'frio' , 'background_color' );
}
if ( ! $nav_bg ) {
$nav_bg = " #708fa0 " ;
}
if ( ! $link_color ) {
$link_color = " #6fdbe8 " ;
}
if ( ! $bgcolor ) {
$bgcolor = " #ededed " ;
}
$ret [ 'profile_sidebar_fill_color' ] = str_replace ( '#' , '' , $nav_bg );
$ret [ 'profile_link_color' ] = str_replace ( '#' , '' , $link_color );
$ret [ 'profile_background_color' ] = str_replace ( '#' , '' , $bgcolor );
}
}
2017-11-10 06:00:50 +01:00
return $ret ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief return api - formatted array for item ' s author and owner
*
* @ param object $a App
* @ param array $item item from db
* @ return array ( array : author , array : owner )
*/
function api_item_get_user ( App $a , $item )
{
$status_user = api_get_user ( $a , $item [ " author-link " ]);
$status_user [ " protected " ] = (( $item [ " allow_cid " ] != " " ) ||
( $item [ " allow_gid " ] != " " ) ||
( $item [ " deny_cid " ] != " " ) ||
( $item [ " deny_gid " ] != " " ) ||
$item [ " private " ]);
if ( $item [ 'thr-parent' ] == $item [ 'uri' ]) {
$owner_user = api_get_user ( $a , $item [ " owner-link " ]);
} else {
$owner_user = $status_user ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return ( array ( $status_user , $owner_user ));
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief walks recursively through an array with the possibility to change value and key
*
* @ param array $array The array to walk through
* @ param string $callback The callback function
*
* @ return array the transformed array
*/
function api_walk_recursive ( array & $array , callable $callback )
{
$new_array = array ();
foreach ( $array as $k => $v ) {
if ( is_array ( $v )) {
if ( $callback ( $v , $k )) {
$new_array [ $k ] = api_walk_recursive ( $v , $callback );
}
2017-04-17 16:38:13 +02:00
} else {
2017-11-10 06:00:50 +01:00
if ( $callback ( $v , $k )) {
$new_array [ $k ] = $v ;
}
2017-04-17 16:38:13 +02:00
}
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$array = $new_array ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $array ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Callback function to transform the array in an array that can be transformed in a XML file
*
* @ param mixed $item Array item value
* @ param string $key Array key
*
* @ return boolean Should the array item be deleted ?
*/
function api_reformat_xml ( & $item , & $key )
{
if ( is_bool ( $item )) {
$item = ( $item ? " true " : " false " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( substr ( $key , 0 , 10 ) == " statusnet_ " ) {
$key = " statusnet: " . substr ( $key , 10 );
} elseif ( substr ( $key , 0 , 10 ) == " friendica_ " ) {
$key = " friendica: " . substr ( $key , 10 );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
/// @TODO old-lost code?
//else
// $key = "default:".$key;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return true ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Creates the XML from a JSON style array
*
* @ param array $data JSON style array
* @ param string $root_element Name of the root element
*
* @ return string The XML data
*/
function api_create_xml ( $data , $root_element )
{
$childname = key ( $data );
$data2 = array_pop ( $data );
$key = key ( $data2 );
$namespaces = array ( " " => " http://api.twitter.com " ,
" statusnet " => " http://status.net/schema/api/1/ " ,
" friendica " => " http://friendi.ca/schema/api/1/ " ,
" georss " => " http://www.georss.org/georss " );
/// @todo Auto detection of needed namespaces
if ( in_array ( $root_element , array ( " ok " , " hash " , " config " , " version " , " ids " , " notes " , " photos " ))) {
$namespaces = array ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( is_array ( $data2 )) {
api_walk_recursive ( $data2 , " api_reformat_xml " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $key == " 0 " ) {
$data4 = array ();
$i = 1 ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
foreach ( $data2 as $item ) {
$data4 [ $i ++. " : " . $childname ] = $item ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$data2 = $data4 ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$data3 = array ( $root_element => $data2 );
2016-09-25 18:50:08 +02:00
2017-11-20 18:56:31 +01:00
$ret = XML :: fromArray ( $data3 , $xml , false , $namespaces );
2017-11-10 06:00:50 +01:00
return $ret ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* @ brief Formats the data according to the data type
*
* @ param string $root_element Name of the root element
* @ param string $type Return type ( atom , rss , xml , json )
* @ param array $data JSON style array
*
2017-12-23 01:25:43 +01:00
* @ return ( string | object | array ) XML data or JSON data
2017-11-10 06:00:50 +01:00
*/
function api_format_data ( $root_element , $type , $data )
{
switch ( $type ) {
case " atom " :
case " rss " :
case " xml " :
$ret = api_create_xml ( $data , $root_element );
break ;
case " json " :
$ret = $data ;
break ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
return $ret ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* TWITTER API
*/
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful ;
* returns a 401 status code and an error message if not .
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / get - account - verify_credentials
*
* @ param string $type Return type ( atom , rss , xml , json )
2017-11-10 06:00:50 +01:00
*/
function api_account_verify_credentials ( $type )
{
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
unset ( $_REQUEST [ " user_id " ]);
unset ( $_GET [ " user_id " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
unset ( $_REQUEST [ " screen_name " ]);
unset ( $_GET [ " screen_name " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$skip_status = ( x ( $_REQUEST , 'skip_status' ) ? $_REQUEST [ 'skip_status' ] : false );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$user_info = api_get_user ( $a );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// "verified" isn't used here in the standard
unset ( $user_info [ " verified " ]);
// - Adding last status
if ( ! $skip_status ) {
$user_info [ " status " ] = api_status_show ( " raw " );
if ( ! count ( $user_info [ " status " ])) {
unset ( $user_info [ " status " ]);
} else {
unset ( $user_info [ " status " ][ " user " ]);
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset ( $user_info [ " uid " ]);
unset ( $user_info [ " self " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return api_format_data ( " user " , $type , array ( 'user' => $user_info ));
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/account/verify_credentials' , 'api_account_verify_credentials' , true );
/**
* Get data from $_POST or $_GET
2017-12-24 03:20:50 +01:00
*
* @ param string $k
2017-11-10 06:00:50 +01:00
*/
function requestdata ( $k )
{
if ( x ( $_POST , $k )) {
return $_POST [ $k ];
}
if ( x ( $_GET , $k )) {
return $_GET [ $k ];
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
return null ;
}
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Waitman Gobble Mod
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 06:00:50 +01:00
function api_statuses_mediap ( $type )
{
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( api_user () === false ) {
logger ( 'api_statuses_update: no user' );
throw new ForbiddenException ();
}
$user_info = api_get_user ( $a );
$_REQUEST [ 'type' ] = 'wall' ;
$_REQUEST [ 'profile_uid' ] = api_user ();
$_REQUEST [ 'api_source' ] = true ;
$txt = requestdata ( 'status' );
/// @TODO old-lost code?
//$txt = urldecode(requestdata('status'));
if (( strpos ( $txt , '<' ) !== false ) || ( strpos ( $txt , '>' ) !== false )) {
$txt = html2bb_video ( $txt );
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$txt = html2bbcode ( $txt );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$a -> argv [ 1 ] = $user_info [ 'screen_name' ]; //should be set to username?
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// tell wall_upload function to return img info instead of echo
$_REQUEST [ 'hush' ] = 'yeah' ;
$bebop = wall_upload_post ( $a );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// 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 ;
item_post ( $a );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// this should output the last post (the one we just posted).
return api_status_show ( $type );
}
/// @TODO move this to top of file or somewhere better!
api_register_func ( 'api/statuses/mediap' , 'api_statuses_mediap' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Updates the user’ s current status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - update
*/
2017-11-10 06:00:50 +01:00
function api_statuses_update ( $type )
{
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$a = get_app ();
if ( api_user () === false ) {
logger ( 'api_statuses_update: no user' );
throw new ForbiddenException ();
}
2018-01-04 19:26:09 +01:00
api_get_user ( $a );
2017-11-10 06:00:50 +01:00
// convert $_POST array items to the form we use for web posts.
if ( requestdata ( 'htmlstatus' )) {
$txt = requestdata ( 'htmlstatus' );
if (( strpos ( $txt , '<' ) !== false ) || ( strpos ( $txt , '>' ) !== false )) {
2016-09-25 18:50:08 +02:00
$txt = html2bb_video ( $txt );
2017-11-10 06:00:50 +01:00
2016-09-25 18:50:08 +02:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
2017-11-10 06:00:50 +01:00
2016-09-25 18:50:08 +02:00
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'body' ] = html2bbcode ( $txt );
}
} else {
$_REQUEST [ 'body' ] = requestdata ( 'status' );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'title' ] = requestdata ( 'title' );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$parent = requestdata ( 'in_reply_to_status_id' );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Twidere sends "-1" if it is no reply ...
if ( $parent == - 1 ) {
$parent = " " ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( ctype_digit ( $parent )) {
$_REQUEST [ 'parent' ] = $parent ;
} else {
$_REQUEST [ 'parent_uri' ] = $parent ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( requestdata ( 'lat' ) && requestdata ( 'long' )) {
$_REQUEST [ 'coord' ] = sprintf ( " %s %s " , requestdata ( 'lat' ), requestdata ( 'long' ));
}
$_REQUEST [ 'profile_uid' ] = api_user ();
if ( $parent ) {
$_REQUEST [ 'type' ] = 'net-comment' ;
} else {
// Check for throttling (maximum posts per day, week and month)
$throttle_day = Config :: get ( 'system' , 'throttle_limit_day' );
if ( $throttle_day > 0 ) {
$datefrom = date ( " Y-m-d H:i:s " , time () - 24 * 60 * 60 );
$r = q (
" SELECT COUNT(*) AS `posts_day` FROM `item` WHERE `uid`=%d AND `wall`
AND `created` > '%s' AND `id` = `parent` " ,
intval ( api_user ()),
dbesc ( $datefrom )
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
$posts_day = $r [ 0 ][ " posts_day " ];
} else {
$posts_day = 0 ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $posts_day > $throttle_day ) {
logger ( 'Daily posting limit reached for user ' . api_user (), LOGGER_DEBUG );
// die(api_error($type, sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day)));
throw new TooManyRequestsException ( sprintf ( t ( " Daily posting limit of %d posts reached. The post was rejected. " ), $throttle_day ));
}
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$throttle_week = Config :: get ( 'system' , 'throttle_limit_week' );
if ( $throttle_week > 0 ) {
$datefrom = date ( " Y-m-d H:i:s " , time () - 24 * 60 * 60 * 7 );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$r = q (
" SELECT COUNT(*) AS `posts_week` FROM `item` WHERE `uid`=%d AND `wall`
AND `created` > '%s' AND `id` = `parent` " ,
intval ( api_user ()),
dbesc ( $datefrom )
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
$posts_week = $r [ 0 ][ " posts_week " ];
} else {
$posts_week = 0 ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $posts_week > $throttle_week ) {
logger ( 'Weekly posting limit reached for user ' . api_user (), LOGGER_DEBUG );
// die(api_error($type, sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week)));
throw new TooManyRequestsException ( sprintf ( t ( " Weekly posting limit of %d posts reached. The post was rejected. " ), $throttle_week ));
}
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$throttle_month = Config :: get ( 'system' , 'throttle_limit_month' );
if ( $throttle_month > 0 ) {
$datefrom = date ( " Y-m-d H:i:s " , time () - 24 * 60 * 60 * 30 );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$r = q (
" SELECT COUNT(*) AS `posts_month` FROM `item` WHERE `uid`=%d AND `wall`
AND `created` > '%s' AND `id` = `parent` " ,
intval ( api_user ()),
dbesc ( $datefrom )
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
$posts_month = $r [ 0 ][ " posts_month " ];
} else {
$posts_month = 0 ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( $posts_month > $throttle_month ) {
logger ( 'Monthly posting limit reached for user ' . api_user (), LOGGER_DEBUG );
// die(api_error($type, sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month)));
throw new TooManyRequestsException ( sprintf ( t ( " Monthly posting limit of %d posts reached. The post was rejected. " ), $throttle_month ));
}
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'type' ] = 'wall' ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
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 ;
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// To-Do: Multiple IDs
if ( requestdata ( 'media_ids' )) {
$r = q (
" SELECT `resource-id`, `scale`, `nickname`, `type` FROM `photo` INNER JOIN `user` ON `user`.`uid` = `photo`.`uid` WHERE `resource-id` IN (SELECT `resource-id` FROM `photo` WHERE `id` = %d) AND `scale` > 0 AND `photo`.`uid` = %d ORDER BY `photo`.`width` DESC LIMIT 1 " ,
intval ( requestdata ( 'media_ids' )),
api_user ()
);
if ( DBM :: is_result ( $r )) {
2017-12-07 14:56:11 +01:00
$phototypes = Image :: supportedTypes ();
2017-11-10 06:00:50 +01:00
$ext = $phototypes [ $r [ 0 ][ 'type' ]];
$_REQUEST [ 'body' ] .= " \n \n " . '[url=' . System :: baseUrl () . '/photos/' . $r [ 0 ][ 'nickname' ] . '/image/' . $r [ 0 ][ 'resource-id' ] . ']' ;
$_REQUEST [ 'body' ] .= '[img]' . System :: baseUrl () . '/photo/' . $r [ 0 ][ 'resource-id' ] . '-' . $r [ 0 ][ 'scale' ] . '.' . $ext . '[/img][/url]' ;
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// set this so that the item_post() function is quiet and doesn't redirect or emit json
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'api_source' ] = true ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! x ( $_REQUEST , " source " )) {
$_REQUEST [ " source " ] = api_source ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// call out normal post function
item_post ( $a );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// this should output the last post (the one we just posted).
return api_status_show ( $type );
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/statuses/update' , 'api_statuses_update' , true , API_METHOD_POST );
api_register_func ( 'api/statuses/update_with_media' , 'api_statuses_update' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Uploads an image to Friendica .
*
* @ return array
* @ see https :// developer . twitter . com / en / docs / media / upload - media / api - reference / post - media - upload
*/
2018-01-04 02:54:35 +01:00
function api_media_upload ()
2017-11-10 06:00:50 +01:00
{
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( api_user () === false ) {
logger ( 'no user' );
throw new ForbiddenException ();
}
2016-09-25 18:50:08 +02:00
2018-01-04 19:26:09 +01:00
api_get_user ( $a );
2017-11-10 06:00:50 +01:00
if ( ! x ( $_FILES , 'media' )) {
// Output error
throw new BadRequestException ( " No media. " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$media = wall_upload_post ( $a , false );
if ( ! $media ) {
// Output error
throw new InternalServerErrorException ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$returndata = array ();
$returndata [ " media_id " ] = $media [ " id " ];
$returndata [ " media_id_string " ] = ( string ) $media [ " id " ];
$returndata [ " size " ] = $media [ " size " ];
$returndata [ " image " ] = array ( " w " => $media [ " width " ],
" h " => $media [ " height " ],
" image_type " => $media [ " type " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( " Media uploaded: " . print_r ( $returndata , true ), LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return array ( " media " => $returndata );
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/media/upload' , 'api_media_upload' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 06:00:50 +01:00
function api_status_show ( $type )
{
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$user_info = api_get_user ( $a );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( 'api_status_show: user_info: ' . print_r ( $user_info , true ), LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " raw " ) {
$privacy_sql = " AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`='' " ;
} else {
$privacy_sql = " " ;
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// 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' ]))
);
if ( DBM :: is_result ( $lastwall )) {
$lastwall = $lastwall [ 0 ];
$in_reply_to = api_in_reply_to ( $lastwall );
$converted = api_convert_item ( $lastwall );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
$geo = " georss:point " ;
} else {
$geo = " geo " ;
}
$status_info = array (
'created_at' => api_date ( $lastwall [ 'created' ]),
'id' => intval ( $lastwall [ 'id' ]),
'id_str' => ( string ) $lastwall [ 'id' ],
'text' => $converted [ " text " ],
'source' => (( $lastwall [ 'app' ]) ? $lastwall [ 'app' ] : 'web' ),
'truncated' => false ,
'in_reply_to_status_id' => $in_reply_to [ 'status_id' ],
'in_reply_to_status_id_str' => $in_reply_to [ 'status_id_str' ],
'in_reply_to_user_id' => $in_reply_to [ 'user_id' ],
'in_reply_to_user_id_str' => $in_reply_to [ 'user_id_str' ],
'in_reply_to_screen_name' => $in_reply_to [ 'screen_name' ],
'user' => $user_info ,
$geo => null ,
'coordinates' => " " ,
'place' => " " ,
'contributors' => " " ,
'is_quote_status' => false ,
'retweet_count' => 0 ,
'favorite_count' => 0 ,
'favorited' => $lastwall [ 'starred' ] ? true : false ,
'retweeted' => false ,
'possibly_sensitive' => false ,
'lang' => " " ,
2017-12-17 16:16:18 +01:00
'statusnet_html' => $converted [ " html " ],
'statusnet_conversation_id' => $lastwall [ 'parent' ],
'external_url' => System :: baseUrl () . " /display/ " . $lastwall [ 'guid' ],
2017-11-10 06:00:50 +01:00
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( count ( $converted [ " attachments " ]) > 0 ) {
$status_info [ " attachments " ] = $converted [ " attachments " ];
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( count ( $converted [ " entities " ]) > 0 ) {
$status_info [ " entities " ] = $converted [ " entities " ];
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if (( $lastwall [ 'item_network' ] != " " ) && ( $status [ " source " ] == 'web' )) {
2018-01-10 04:42:04 +01:00
$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' ]) . ')' );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// "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 " ]);
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
logger ( 'status_info: ' . print_r ( $status_info , true ), LOGGER_DEBUG );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " raw " ) {
return $status_info ;
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
return api_format_data ( " statuses " , $type , array ( 'status' => $status_info ));
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* Returns extended information of a given user , specified by ID or screen name as per the required id parameter .
* The author ' s most recent status will be returned inline .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - users - show
2017-11-10 06:00:50 +01:00
*/
function api_users_show ( $type )
{
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$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 ];
$in_reply_to = api_in_reply_to ( $lastwall );
$converted = api_convert_item ( $lastwall );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
$geo = " georss:point " ;
} else {
$geo = " geo " ;
}
$user_info [ 'status' ] = array (
'text' => $converted [ " text " ],
'truncated' => false ,
'created_at' => api_date ( $lastwall [ 'created' ]),
'in_reply_to_status_id' => $in_reply_to [ 'status_id' ],
'in_reply_to_status_id_str' => $in_reply_to [ 'status_id_str' ],
'source' => (( $lastwall [ 'app' ]) ? $lastwall [ 'app' ] : 'web' ),
'id' => intval ( $lastwall [ 'contact-id' ]),
'id_str' => ( string ) $lastwall [ 'contact-id' ],
'in_reply_to_user_id' => $in_reply_to [ 'user_id' ],
'in_reply_to_user_id_str' => $in_reply_to [ 'user_id_str' ],
'in_reply_to_screen_name' => $in_reply_to [ 'screen_name' ],
$geo => null ,
'favorited' => $lastwall [ 'starred' ] ? true : false ,
'statusnet_html' => $converted [ " html " ],
2017-12-17 16:16:18 +01:00
'statusnet_conversation_id' => $lastwall [ 'parent' ],
'external_url' => System :: baseUrl () . " /display/ " . $lastwall [ 'guid' ],
2017-11-10 06:00:50 +01:00
);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( count ( $converted [ " attachments " ]) > 0 ) {
$user_info [ " status " ][ " attachments " ] = $converted [ " attachments " ];
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( count ( $converted [ " entities " ]) > 0 ) {
$user_info [ " status " ][ " entities " ] = $converted [ " entities " ];
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if (( $lastwall [ 'item_network' ] != " " ) && ( $user_info [ " status " ][ " source " ] == 'web' )) {
2018-01-10 04:42:04 +01:00
$user_info [ " status " ][ " source " ] = ContactSelector :: networkToName ( $lastwall [ 'item_network' ], $user_info [ 'url' ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2018-01-10 04:42:04 +01:00
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' ]) . ')' );
2017-11-10 06:00:50 +01:00
}
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset ( $user_info [ " uid " ]);
unset ( $user_info [ " self " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return api_format_data ( " user " , $type , array ( 'user' => $user_info ));
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/show' , 'api_users_show' );
api_register_func ( 'api/externalprofile/show' , 'api_users_show' );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Search a public user account .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - users - search
*/
2017-11-10 06:00:50 +01:00
function api_users_search ( $type )
{
$a = get_app ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$userlist = array ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( x ( $_GET , 'q' )) {
$r = q ( " SELECT id FROM `contact` WHERE `uid` = 0 AND `name` = '%s' " , dbesc ( $_GET [ " q " ]));
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! DBM :: is_result ( $r )) {
$r = q ( " SELECT `id` FROM `contact` WHERE `uid` = 0 AND `nick` = '%s' " , dbesc ( $_GET [ " q " ]));
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( DBM :: is_result ( $r )) {
$k = 0 ;
foreach ( $r as $user ) {
2017-12-23 01:27:17 +01:00
$user_info = api_get_user ( $a , $user [ " id " ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
$userlist [ $k ++. " :user " ] = $user_info ;
} else {
$userlist [] = $user_info ;
}
}
$userlist = array ( " users " => $userlist );
} else {
throw new BadRequestException ( " User not found. " );
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
} else {
throw new BadRequestException ( " User not found. " );
2016-09-25 18:50:08 +02:00
}
2018-01-04 02:54:35 +01:00
2017-11-10 06:00:50 +01:00
return api_format_data ( " users " , $type , $userlist );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/search' , 'api_users_search' );
2016-09-25 18:50:08 +02:00
2017-12-18 23:51:03 +01:00
/**