2016-09-25 16:50:08 +00:00
< ? php
/**
* Friendica implementation of statusnet / twitter API
*
2017-12-24 02:20:50 +00:00
* @ file include / api . php
2016-09-25 16:50:08 +00:00
* @ todo Automatically detect if incoming data is HTML or BBCode
*/
2017-04-30 04:07:00 +00:00
use Friendica\App ;
2018-01-10 03:42:04 +00:00
use Friendica\Content\ContactSelector ;
2017-12-04 14:04:36 +00:00
use Friendica\Content\Feature ;
2018-01-27 01:01:32 +00:00
use Friendica\Content\Text\BBCode ;
2018-01-17 18:42:40 +00:00
use Friendica\Core\Addon ;
2017-08-26 06:04:21 +00:00
use Friendica\Core\System ;
2017-04-30 04:01:26 +00:00
use Friendica\Core\Config ;
2017-11-08 00:37:53 +00:00
use Friendica\Core\NotificationsManager ;
2018-01-21 16:38:01 +00:00
use Friendica\Core\L10n ;
2017-12-18 19:39:35 +00:00
use Friendica\Core\PConfig ;
2017-11-05 12:15:53 +00:00
use Friendica\Core\Worker ;
2017-11-08 03:57:46 +00:00
use Friendica\Database\DBM ;
2017-12-07 14:04:24 +00:00
use Friendica\Model\Contact ;
2017-12-09 18:45:17 +00:00
use Friendica\Model\Group ;
2018-01-15 17:14:09 +00:00
use Friendica\Model\Mail ;
2017-12-07 13:56:11 +00:00
use Friendica\Model\Photo ;
2017-11-26 19:46:08 +00:00
use Friendica\Model\User ;
2018-01-17 23:22:01 +00:00
use Friendica\Model\Item ;
2017-12-04 23:30:18 +00:00
use Friendica\Network\FKOAuth1 ;
2017-11-24 04:48:15 +00: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 13:56:11 +00:00
use Friendica\Object\Image ;
2017-11-08 13:34:48 +00:00
use Friendica\Protocol\Diaspora ;
2018-01-27 04:09:48 +00:00
use Friendica\Util\Network ;
2017-11-10 12:45:33 +00:00
use Friendica\Util\XML ;
2017-01-17 19:21:46 +00:00
2017-04-05 20:07:55 +00: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/like.php' ;
define ( 'API_METHOD_ANY' , '*' );
define ( 'API_METHOD_GET' , 'GET' );
define ( 'API_METHOD_POST' , 'POST,PUT' );
define ( 'API_METHOD_DELETE' , 'POST,DELETE' );
2018-01-15 13:05:12 +00:00
$API = [];
2017-04-05 20:07:55 +00:00
$called_api = null ;
2017-11-10 05:00:50 +00: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 02:20:50 +00:00
*
* @ brief Auth API user
2017-11-10 05:00:50 +00:00
*/
function api_user ()
{
if ( x ( $_SESSION , 'allow_api' )) {
return local_user ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 02:20:50 +00:00
* @ brief Get source name from API client
*
2017-11-10 05:00:50 +00:00
* @ return string
* Client source name , default to " api " if unset / unknown
*/
function api_source ()
{
if ( requestdata ( 'source' )) {
return requestdata ( 'source' );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( " Unrecognized user-agent " . $_SERVER [ 'HTTP_USER_AGENT' ], LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return " api " ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Register a function to be the endpoint for defined API path .
2017-11-10 05:00:50 +00:00
*
2017-12-24 02:20:50 +00:00
* @ brief Register API endpoint
2017-11-10 05:00:50 +00: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 ;
2018-01-15 13:05:12 +00:00
$API [ $path ] = [
2017-11-10 05:00:50 +00:00
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
// Workaround for hotot
$path = str_replace ( " api/ " , " api/1.1/ " , $path );
2018-01-15 13:05:12 +00:00
$API [ $path ] = [
2017-11-10 05:00:50 +00:00
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 02:20:50 +00:00
* @ brief Login API user
*
2017-11-10 05:00:50 +00: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 02:10:54 +00:00
$oauth1 = new FKOAuth1 ();
2017-11-10 05:00:50 +00:00
// login with oauth
try {
2017-12-05 02:10:54 +00:00
list ( $consumer , $token ) = $oauth1 -> verify_request ( OAuthRequest :: from_request ());
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $token )) {
2017-12-05 02:10:54 +00:00
$oauth1 -> loginUser ( $token -> uid );
2018-01-17 18:42:40 +00:00
Addon :: callHooks ( 'logged_in' , $a -> user );
2017-11-10 05:00:50 +00:00
return ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
echo __FILE__ . __LINE__ . __FUNCTION__ . " <pre> " ;
var_dump ( $consumer , $token );
die ();
} catch ( Exception $e ) {
logger ( $e );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! x ( $_SERVER , 'PHP_AUTH_USER' )) {
2017-12-23 23:27:45 +00:00
logger ( 'API_login: ' . print_r ( $_SERVER , true ), LOGGER_DEBUG );
2017-11-10 05:00:50 +00:00
header ( 'WWW-Authenticate: Basic realm="Friendica"' );
throw new UnauthorizedException ( " This API requires login " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user = $_SERVER [ 'PHP_AUTH_USER' ];
$password = $_SERVER [ 'PHP_AUTH_PW' ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// allow "user@server" login (but ignore 'server' part)
$at = strstr ( $user , " @ " , true );
if ( $at ) {
$user = $at ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// next code from mod/auth.php. needs better solution
$record = null ;
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$addon_auth = [
2017-11-10 05:00:50 +00:00
'username' => trim ( $user ),
'password' => trim ( $password ),
'authenticated' => 0 ,
'user_record' => null ,
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/*
2018-01-17 19:22:38 +00:00
* An addon indicates successful login by setting 'authenticated' to non - zero value and returning a user record
* Addons should never set 'authenticated' except to indicate success - as hooks may be chained
* and later addons should not interfere with an earlier one that succeeded .
*/
2018-01-17 18:42:40 +00:00
Addon :: callHooks ( 'authenticate' , $addon_auth );
2017-11-10 05:00:50 +00:00
2017-12-22 23:10:32 +00:00
if ( $addon_auth [ 'authenticated' ] && count ( $addon_auth [ 'user_record' ])) {
2017-11-10 05:00:50 +00:00
$record = $addon_auth [ 'user_record' ];
} else {
2017-11-26 19:46:08 +00:00
$user_id = User :: authenticate ( trim ( $user ), trim ( $password ));
if ( $user_id ) {
2018-01-10 13:36:02 +00:00
$record = dba :: selectFirst ( 'user' , [], [ 'uid' => $user_id ]);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2018-01-13 08:22:40 +00:00
if ( ! DBM :: is_result ( $record )) {
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
authenticate_success ( $record );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$_SESSION [ " allow_api " ] = true ;
2016-09-25 16:50:08 +00:00
2018-01-17 18:42:40 +00:00
Addon :: callHooks ( 'logged_in' , $a -> user );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 02:20:50 +00:00
* @ brief Check HTTP method of called API
*
2017-11-10 05:00:50 +00:00
* @ param string $method Required methods , uppercase , separated by comma
* @ return bool
*/
function api_check_method ( $method )
{
if ( $method == " * " ) {
return true ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
return ( strpos ( $method , $_SERVER [ 'REQUEST_METHOD' ]) !== false );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* Authenticate user , call registered API function , set HTTP headers
*
2017-12-24 02:20:50 +00:00
* @ brief Main API entry point
*
2017-11-10 05:00:50 +00:00
* @ param object $a App
* @ return string API call result
*/
function api_call ( App $a )
{
global $API , $called_api ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$type = " json " ;
if ( strpos ( $a -> query_string , " .xml " ) > 0 ) {
$type = " xml " ;
}
if ( strpos ( $a -> query_string , " .json " ) > 0 ) {
2017-04-05 20:07:55 +00:00
$type = " json " ;
2017-11-10 05:00:50 +00:00
}
if ( strpos ( $a -> query_string , " .rss " ) > 0 ) {
$type = " rss " ;
}
if ( strpos ( $a -> query_string , " .atom " ) > 0 ) {
$type = " atom " ;
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$called_api = explode ( " / " , $p );
//unset($_SERVER['PHP_AUTH_USER']);
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'API call for ' . $a -> user [ 'username' ] . ': ' . $a -> query_string );
logger ( 'API parameters: ' . print_r ( $_REQUEST , true ));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$stamp = microtime ( true );
2018-01-04 01:54:35 +00:00
$return = call_user_func ( $info [ 'func' ], $type );
2017-11-10 05:00:50 +00:00
$duration = ( float ) ( microtime ( true ) - $stamp );
logger ( " API call duration: " . round ( $duration , 2 ) . " \t " . $a -> query_string , LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( Config :: get ( " system " , " profiler " )) {
$duration = microtime ( true ) - $a -> performance [ " start " ];
2016-11-12 13:17:28 +00:00
2017-11-10 05:00:50 +00: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 22:45:20 +00: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 05:00:50 +00: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 22:45:20 +00:00
}
2017-11-10 05:00:50 +00: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 22:45:20 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00: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 22:45:20 +00:00
}
}
2017-11-10 05:00:50 +00:00
logger ( $o , LOGGER_DEBUG );
2016-11-04 22:45:20 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-11-04 22:45:20 +00:00
2018-01-04 01:54:35 +00:00
if ( false === $return ) {
2017-11-10 05:00:50 +00:00
/*
* api function returned false withour throw an
* exception . This should not happend , throw a 500
*/
throw new InternalServerErrorException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2018-01-04 01:54:35 +00:00
foreach ( $return as $rr ) {
2017-11-10 05:00:50 +00:00
$json = json_encode ( $rr );
2017-12-23 23:27:45 +00:00
}
if ( x ( $_GET , 'callback' )) {
$json = $_GET [ 'callback' ] . " ( " . $json . " ) " ;
}
2018-01-04 01:54:35 +00:00
$return = $json ;
2017-11-10 05:00:50 +00:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
2018-01-04 01:54:35 +00:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 05:00:50 +00:00
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
2018-01-04 01:54:35 +00:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 05:00:50 +00:00
break ;
2016-09-25 16:50:08 +00:00
}
2018-01-04 01:54:35 +00:00
return $return ;
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief Format API error string
*
* @ param string $type Return type ( xml , json , rss , as )
* @ param object $e HTTPException Error object
2017-12-23 00:23:20 +00:00
* @ return string error message formatted as $type
2017-11-10 05:00:50 +00: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
2018-01-15 13:05:12 +00:00
$error = [ " error " => $error ,
2017-11-10 05:00:50 +00:00
" code " => $e -> httpcode . " " . $e -> httpdesc ,
2018-01-15 13:05:12 +00:00
" request " => $a -> query_string ];
2017-11-10 05:00:50 +00:00
2018-01-15 13:05:12 +00:00
$return = api_format_data ( 'status' , $type , [ 'status' => $error ]);
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2018-01-04 01:54:35 +00:00
$return = json_encode ( $return );
2017-11-10 05:00:50 +00:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
break ;
}
2018-01-04 01:54:35 +00:00
return $return ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$arr [ '$user' ] = $user_info ;
2018-01-15 13:05:12 +00:00
$arr [ '$rss' ] = [
2017-11-10 05:00:50 +00:00
'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 " ,
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $arr ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 11:11:28 +00:00
function api_unique_id_to_nurl ( $id )
2017-11-10 05:00:50 +00:00
{
2018-01-15 13:05:12 +00:00
$r = dba :: selectFirst ( 'contact' , [ 'nurl' ], [ 'uid' => 0 , 'id' => $id ]);
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
2017-12-17 11:11:28 +00:00
return $r [ " nurl " ];
2017-11-10 05:00:50 +00:00
} else {
return false ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief Get user info array .
*
* @ param object $a App
* @ param int | string $contact_id Contact ID or URL
*/
2017-12-16 15:16:25 +00:00
function api_get_user ( App $a , $contact_id = null )
2017-11-10 05:00:50 +00:00
{
global $called_api ;
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
$user = null ;
$extra_query = " " ;
$url = " " ;
logger ( " api_get_user: Fetching user data for user " . $contact_id , LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// Searching for contact id with uid = 0
if ( ! is_null ( $contact_id ) && ( intval ( $contact_id ) != 0 )) {
2017-12-17 11:11:28 +00:00
$user = dbesc ( api_unique_id_to_nurl ( $contact_id ));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $user == " " ) {
throw new BadRequestException ( " User not found. " );
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
2017-05-15 20:11:33 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( is_null ( $user ) && x ( $_GET , 'user_id' )) {
2017-12-17 11:11:28 +00:00
$user = dbesc ( api_unique_id_to_nurl ( $_GET [ 'user_id' ]));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $user == " " ) {
throw new BadRequestException ( " User not found. " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 11:11:28 +00:00
$user = dbesc ( api_unique_id_to_nurl ( $user ));
2016-09-25 16:50:08 +00:00
2017-04-05 20:07:55 +00:00
if ( $user == " " ) {
2017-11-10 05:00:50 +00:00
return false ;
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
$url = $user ;
$extra_query = " AND `contact`.`nurl` = '%s' " ;
2017-04-05 20:07:55 +00:00
if ( api_user () !== false ) {
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
}
2017-11-10 05:00:50 +00:00
} else {
$user = dbesc ( $user );
2016-09-25 16:50:08 +00:00
$extra_query = " AND `contact`.`nick` = '%s' " ;
2017-04-05 20:07:55 +00:00
if ( api_user () !== false ) {
2017-11-10 05:00:50 +00:00
$extra_query .= " AND `contact`.`uid`= " . intval ( api_user ());
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( " api_get_user: user " . $user , LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'api_user: ' . $extra_query . ', user: ' . $user );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// user info
$uinfo = q (
" SELECT *, `contact`.`id` AS `cid` FROM `contact`
WHERE 1
$extra_query " ,
$user
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Selecting the id by priority, friendica first
api_best_nickname ( $uinfo );
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
// if the contact wasn't found, fetch it from the contacts with uid = 0
if ( ! DBM :: is_result ( $uinfo )) {
2018-01-15 13:05:12 +00:00
$r = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $url != " " ) {
$r = q ( " SELECT * FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' LIMIT 1 " , dbesc ( normalise_link ( $url )));
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
2018-01-10 03:42:04 +00:00
$network_name = ContactSelector :: networkToName ( $r [ 0 ][ 'network' ], $r [ 0 ][ 'url' ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$ret = [
2017-11-10 05:00:50 +00:00
'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 22:03:39 +00:00
'cid' => Contact :: getIdForURL ( $r [ 0 ][ " url " ], api_user (), true ),
2017-11-10 05:00:50 +00:00
'self' => 0 ,
'network' => $r [ 0 ][ " network " ],
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $ret ;
2016-11-04 22:45:20 +00:00
} else {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( " User not found. " );
2016-11-04 22:45:20 +00:00
}
2017-11-10 05:00:50 +00: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 20:07:55 +00:00
/// @TODO old-lost code? (twice)
2017-11-10 05:00:50 +00: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 22:45:20 +00:00
// Counting is deactivated by now, due to performance issues
2016-09-25 16:50:08 +00:00
// count friends
$r = q ( " SELECT count(*) as `count` FROM `contact`
WHERE `uid` = % d AND `rel` IN ( % d , % d )
2017-02-10 02:51:01 +00:00
AND `self` = 0 AND NOT `blocked` AND NOT `pending` AND `hidden` = 0 " ,
2016-09-25 16:50:08 +00: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 02:51:01 +00:00
AND `self` = 0 AND NOT `blocked` AND NOT `pending` AND `hidden` = 0 " ,
2016-09-25 16:50:08 +00: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 17:46:56 +00:00
if ( ! $uinfo [ 0 ][ 'self' ]) {
2016-09-25 16:50:08 +00:00
$countfriends = 0 ;
$countfollowers = 0 ;
$starred = 0 ;
}
2017-11-10 05:00:50 +00:00
*/
$countfriends = 0 ;
$countfollowers = 0 ;
$starred = 0 ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2018-01-10 03:42:04 +00:00
$network_name = ContactSelector :: networkToName ( $uinfo [ 0 ][ 'network' ], $uinfo [ 0 ][ 'url' ]);
2017-11-10 05:00:50 +00:00
2017-11-19 22:03:39 +00:00
$pcontact_id = Contact :: getIdForURL ( $uinfo [ 0 ][ 'url' ], 0 , true );
2017-11-10 05:00:50 +00:00
2017-12-25 05:39:11 +00:00
if ( ! empty ( $profile [ 0 ][ 'about' ])) {
$description = $profile [ 0 ][ 'about' ];
2017-12-24 11:51:38 +00: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-24 23:07:14 +00:00
$location = $network_name ;
2017-12-24 11:51:38 +00:00
}
2018-01-15 13:05:12 +00:00
$ret = [
2017-11-10 05:00:50 +00:00
'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 11:51:38 +00:00
'location' => $location ,
'description' => $description ,
2017-11-10 05:00:50 +00: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' ],
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
2017-12-18 19:39:35 +00:00
// If this is a local user and it uses Frio, we can get its color preferences.
if ( $ret [ 'self' ]) {
2018-01-10 13:36:02 +00:00
$theme_info = dba :: selectFirst ( 'user' , [ 'theme' ], [ 'uid' => $ret [ 'uid' ]]);
2017-12-18 19:39:35 +00:00
if ( $theme_info [ 'theme' ] === 'frio' ) {
$schema = PConfig :: get ( $ret [ 'uid' ], 'frio' , 'schema' );
2017-12-19 10:33:59 +00:00
if ( $schema && ( $schema != '---' )) {
2017-12-18 19:39:35 +00:00
if ( file_exists ( 'view/theme/frio/schema/' . $schema . '.php' )) {
$schemefile = 'view/theme/frio/schema/' . $schema . '.php' ;
2017-12-19 10:33:59 +00:00
require_once $schemefile ;
2017-12-18 19:39:35 +00: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 05:00:50 +00:00
return $ret ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return ([ $status_user , $owner_user ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 )
{
2018-01-15 13:05:12 +00:00
$new_array = [];
2017-11-10 05:00:50 +00:00
foreach ( $array as $k => $v ) {
if ( is_array ( $v )) {
if ( $callback ( $v , $k )) {
$new_array [ $k ] = api_walk_recursive ( $v , $callback );
}
2017-04-17 14:38:13 +00:00
} else {
2017-11-10 05:00:50 +00:00
if ( $callback ( $v , $k )) {
$new_array [ $k ] = $v ;
}
2017-04-17 14:38:13 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$array = $new_array ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $array ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
/// @TODO old-lost code?
//else
// $key = "default:".$key;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return true ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 );
2018-01-15 13:05:12 +00:00
$namespaces = [ " " => " http://api.twitter.com " ,
2017-11-10 05:00:50 +00:00
" statusnet " => " http://status.net/schema/api/1/ " ,
" friendica " => " http://friendi.ca/schema/api/1/ " ,
2018-01-15 13:05:12 +00:00
" georss " => " http://www.georss.org/georss " ];
2017-11-10 05:00:50 +00:00
/// @todo Auto detection of needed namespaces
2018-01-15 13:05:12 +00:00
if ( in_array ( $root_element , [ " ok " , " hash " , " config " , " version " , " ids " , " notes " , " photos " ])) {
$namespaces = [];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( is_array ( $data2 )) {
api_walk_recursive ( $data2 , " api_reformat_xml " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $key == " 0 " ) {
2018-01-15 13:05:12 +00:00
$data4 = [];
2017-11-10 05:00:50 +00:00
$i = 1 ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
foreach ( $data2 as $item ) {
$data4 [ $i ++. " : " . $childname ] = $item ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$data2 = $data4 ;
2016-09-25 16:50:08 +00:00
}
2018-01-15 13:05:12 +00:00
$data3 = [ $root_element => $data2 ];
2016-09-25 16:50:08 +00:00
2017-11-20 17:56:31 +00:00
$ret = XML :: fromArray ( $data3 , $xml , false , $namespaces );
2017-11-10 05:00:50 +00:00
return $ret ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 00:25:43 +00:00
* @ return ( string | object | array ) XML data or JSON data
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
return $ret ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* TWITTER API
*/
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 02:20:50 +00: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 05:00:50 +00:00
*/
function api_account_verify_credentials ( $type )
{
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " user_id " ]);
unset ( $_GET [ " user_id " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " screen_name " ]);
unset ( $_GET [ " screen_name " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$skip_status = ( x ( $_REQUEST , 'skip_status' ) ? $_REQUEST [ 'skip_status' ] : false );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( " user " , $type , [ 'user' => $user_info ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/account/verify_credentials' , 'api_account_verify_credentials' , true );
/**
* Get data from $_POST or $_GET
2017-12-24 02:20:50 +00:00
*
* @ param string $k
2017-11-10 05:00:50 +00:00
*/
function requestdata ( $k )
{
if ( x ( $_POST , $k )) {
return $_POST [ $k ];
}
if ( x ( $_GET , $k )) {
return $_GET [ $k ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
return null ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Waitman Gobble Mod
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_statuses_mediap ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$txt = html2bbcode ( $txt );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a -> argv [ 1 ] = $user_info [ 'screen_name' ]; //should be set to username?
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// tell wall_upload function to return img info instead of echo
$_REQUEST [ 'hush' ] = 'yeah' ;
$bebop = wall_upload_post ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-12-24 02:20:50 +00: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 05:00:50 +00:00
function api_statuses_update ( $type )
{
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a = get_app ();
if ( api_user () === false ) {
logger ( 'api_statuses_update: no user' );
throw new ForbiddenException ();
}
2018-01-04 18:26:09 +00:00
api_get_user ( $a );
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
$txt = html2bb_video ( $txt );
2017-11-10 05:00:50 +00:00
2016-09-25 16:50:08 +00:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
2017-11-10 05:00:50 +00:00
2016-09-25 16:50:08 +00:00
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
2017-11-10 05:00:50 +00:00
$_REQUEST [ 'body' ] = html2bbcode ( $txt );
}
} else {
$_REQUEST [ 'body' ] = requestdata ( 'status' );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$_REQUEST [ 'title' ] = requestdata ( 'title' );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$parent = requestdata ( 'in_reply_to_status_id' );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Twidere sends "-1" if it is no reply ...
if ( $parent == - 1 ) {
$parent = " " ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( ctype_digit ( $parent )) {
$_REQUEST [ 'parent' ] = $parent ;
} else {
$_REQUEST [ 'parent_uri' ] = $parent ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$posts_day = $r [ 0 ][ " posts_day " ];
} else {
$posts_day = 0 ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $posts_day > $throttle_day ) {
logger ( 'Daily posting limit reached for user ' . api_user (), LOGGER_DEBUG );
2018-01-24 02:59:16 +00:00
// die(api_error($type, L10n::t("Daily posting limit of %d posts reached. The post was rejected.", $throttle_day));
2018-01-24 03:38:47 +00:00
throw new TooManyRequestsException ( L10n :: tt ( " Daily posting limit of %d post reached. The post was rejected. " , " Daily posting limit of %d posts reached. The post was rejected. " , $throttle_day ));
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$posts_week = $r [ 0 ][ " posts_week " ];
} else {
$posts_week = 0 ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $posts_week > $throttle_week ) {
logger ( 'Weekly posting limit reached for user ' . api_user (), LOGGER_DEBUG );
2018-01-24 02:59:16 +00:00
// die(api_error($type, L10n::t("Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week)));
2018-01-24 03:38:47 +00:00
throw new TooManyRequestsException ( L10n :: tt ( " Weekly posting limit of %d post reached. The post was rejected. " , " Weekly posting limit of %d posts reached. The post was rejected. " , $throttle_week ));
2017-11-10 05:00:50 +00:00
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$posts_month = $r [ 0 ][ " posts_month " ];
} else {
$posts_month = 0 ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( $posts_month > $throttle_month ) {
logger ( 'Monthly posting limit reached for user ' . api_user (), LOGGER_DEBUG );
2018-01-24 02:59:16 +00:00
// die(api_error($type, L10n::t("Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month));
2018-01-24 03:43:22 +00:00
throw new TooManyRequestsException ( L10n :: t ( " Monthly posting limit of %d post reached. The post was rejected. " , " Monthly posting limit of %d posts reached. The post was rejected. " , $throttle_month ));
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$_REQUEST [ 'type' ] = 'wall' ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 13:56:11 +00:00
$phototypes = Image :: supportedTypes ();
2017-11-10 05:00:50 +00: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 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// set this so that the item_post() function is quiet and doesn't redirect or emit json
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$_REQUEST [ 'api_source' ] = true ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! x ( $_REQUEST , " source " )) {
$_REQUEST [ " source " ] = api_source ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// call out normal post function
item_post ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// this should output the last post (the one we just posted).
return api_status_show ( $type );
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-12-24 02:20:50 +00: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 01:54:35 +00:00
function api_media_upload ()
2017-11-10 05:00:50 +00:00
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
logger ( 'no user' );
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2018-01-04 18:26:09 +00:00
api_get_user ( $a );
2017-11-10 05:00:50 +00:00
if ( ! x ( $_FILES , 'media' )) {
// Output error
throw new BadRequestException ( " No media. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$media = wall_upload_post ( $a , false );
if ( ! $media ) {
// Output error
throw new InternalServerErrorException ();
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$returndata = [];
2017-11-10 05:00:50 +00:00
$returndata [ " media_id " ] = $media [ " id " ];
$returndata [ " media_id_string " ] = ( string ) $media [ " id " ];
$returndata [ " size " ] = $media [ " size " ];
2018-01-15 13:05:12 +00:00
$returndata [ " image " ] = [ " w " => $media [ " width " ],
2017-11-10 05:00:50 +00:00
" h " => $media [ " height " ],
2018-01-15 13:05:12 +00:00
" image_type " => $media [ " type " ]];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( " Media uploaded: " . print_r ( $returndata , true ), LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return [ " media " => $returndata ];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/media/upload' , 'api_media_upload' , true , API_METHOD_POST );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_status_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'api_status_show: user_info: ' . print_r ( $user_info , true ), LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$geo = " georss:point " ;
} else {
$geo = " geo " ;
}
2018-01-15 13:05:12 +00:00
$status_info = [
2017-11-10 05:00:50 +00:00
'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 15:16:18 +00:00
'statusnet_html' => $converted [ " html " ],
'statusnet_conversation_id' => $lastwall [ 'parent' ],
'external_url' => System :: baseUrl () . " /display/ " . $lastwall [ 'guid' ],
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " attachments " ]) > 0 ) {
$status_info [ " attachments " ] = $converted [ " attachments " ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " entities " ]) > 0 ) {
$status_info [ " entities " ] = $converted [ " entities " ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if (( $lastwall [ 'item_network' ] != " " ) && ( $status [ " source " ] == 'web' )) {
2018-01-10 03:42:04 +00: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 16:50:08 +00:00
}
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'status_info: ' . print_r ( $status_info , true ), LOGGER_DEBUG );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " raw " ) {
return $status_info ;
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( " statuses " , $type , [ 'status' => $status_info ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 02:20:50 +00: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 05:00:50 +00:00
*/
function api_users_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$geo = " georss:point " ;
} else {
$geo = " geo " ;
}
2018-01-15 13:05:12 +00:00
$user_info [ 'status' ] = [
2017-11-10 05:00:50 +00:00
'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 15:16:18 +00:00
'statusnet_conversation_id' => $lastwall [ 'parent' ],
'external_url' => System :: baseUrl () . " /display/ " . $lastwall [ 'guid' ],
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " attachments " ]) > 0 ) {
$user_info [ " status " ][ " attachments " ] = $converted [ " attachments " ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " entities " ]) > 0 ) {
$user_info [ " status " ][ " entities " ] = $converted [ " entities " ];
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $lastwall [ 'item_network' ] != " " ) && ( $user_info [ " status " ][ " source " ] == 'web' )) {
2018-01-10 03:42:04 +00:00
$user_info [ " status " ][ " source " ] = ContactSelector :: networkToName ( $lastwall [ 'item_network' ], $user_info [ 'url' ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2018-01-10 03:42:04 +00: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 05:00:50 +00:00
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( " user " , $type , [ 'user' => $user_info ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00: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 16:50:08 +00:00
2017-12-24 02:20:50 +00: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 05:00:50 +00:00
function api_users_search ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$userlist = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( x ( $_GET , 'q' )) {
$r = q ( " SELECT id FROM `contact` WHERE `uid` = 0 AND `name` = '%s' " , dbesc ( $_GET [ " q " ]));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! DBM :: is_result ( $r )) {
$r = q ( " SELECT `id` FROM `contact` WHERE `uid` = 0 AND `nick` = '%s' " , dbesc ( $_GET [ " q " ]));
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$k = 0 ;
foreach ( $r as $user ) {
2017-12-23 00:27:17 +00:00
$user_info = api_get_user ( $a , $user [ " id " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$userlist [ $k ++. " :user " ] = $user_info ;
} else {
$userlist [] = $user_info ;
}
}
2018-01-15 13:05:12 +00:00
$userlist = [ " users " => $userlist ];
2017-11-10 05:00:50 +00:00
} else {
throw new BadRequestException ( " User not found. " );
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
} else {
throw new BadRequestException ( " User not found. " );
2016-09-25 16:50:08 +00:00
}
2018-01-04 01:54:35 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " users " , $type , $userlist );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/search' , 'api_users_search' );
2016-09-25 16:50:08 +00:00
2017-12-18 22:51:03 +00:00
/**
* Return user objects
*
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - users - lookup
*
* @ param string $type Return format : json or xml
*
* @ return array | string
2017-12-19 13:52:46 +00:00
* @ throws NotFoundException if the results are empty .
2017-12-18 22:51:03 +00:00
*/
function api_users_lookup ( $type )
{
2018-01-15 13:05:12 +00:00
$users = [];
2017-12-19 10:37:55 +00:00
if ( x ( $_REQUEST [ 'user_id' ])) {
foreach ( explode ( ',' , $_REQUEST [ 'user_id' ]) as $id ) {
if ( ! empty ( $id )) {
$users [] = api_get_user ( get_app (), $id );
}
2017-12-18 22:51:03 +00:00
}
}
2017-12-19 10:37:55 +00:00
if ( empty ( $users )) {
throw new NotFoundException ;
}
2018-01-15 13:05:12 +00:00
return api_format_data ( " users " , $type , [ 'users' => $users ]);
2017-12-18 22:51:03 +00:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/lookup' , 'api_users_lookup' , true );
2017-12-18 01:59:11 +00:00
/**
* Returns statuses that match a specified query .
*
* @ see https :// developer . twitter . com / en / docs / tweets / search / api - reference / get - search - tweets
*
* @ param string $type Return format : json , xml , atom , rss
*
* @ return array | string
2017-12-19 13:52:46 +00:00
* @ throws BadRequestException if the " q " parameter is missing .
2017-12-18 01:59:11 +00:00
*/
function api_search ( $type )
{
2018-01-15 13:05:12 +00:00
$data = [];
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
if ( ! x ( $_REQUEST , 'q' )) {
throw new BadRequestException ( " q parameter is required. " );
}
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
if ( x ( $_REQUEST , 'rpp' )) {
$count = $_REQUEST [ 'rpp' ];
} elseif ( x ( $_REQUEST , 'count' )) {
$count = $_REQUEST [ 'count' ];
} else {
$count = 15 ;
}
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
$start = $page * $count ;
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
if ( $max_id > 0 ) {
$sql_extra .= ' AND `item`.`id` <= ' . intval ( $max_id );
}
2017-12-18 01:59:11 +00:00
2017-12-18 12:35:36 +00:00
$r = dba :: p (
" SELECT " . item_fieldlists () . "
FROM `item` " .item_joins(). "
WHERE " .item_condition(). " AND ( `item` . `uid` = 0 OR ( `item` . `uid` = ? AND NOT `item` . `global` ))
2017-12-18 14:23:15 +00:00
AND `item` . `body` LIKE CONCAT ( '%' , ? , '%' )
2017-12-18 12:35:36 +00:00
$sql_extra
AND `item` . `id` > ?
ORDER BY `item` . `id` DESC LIMIT " .intval( $start ). " , " .intval( $count ). " " ,
2017-12-18 13:36:06 +00:00
api_user (),
2017-12-18 12:35:36 +00:00
$_REQUEST [ 'q' ],
2017-12-18 13:36:06 +00:00
$since_id
2017-12-18 12:35:36 +00:00
);
2017-12-18 13:28:04 +00:00
$data [ 'status' ] = api_format_items ( dba :: inArray ( $r ), api_get_user ( get_app ()));
2017-12-18 12:35:36 +00:00
2017-12-18 01:59:11 +00:00
return api_format_data ( " statuses " , $type , $data );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/search/tweets' , 'api_search' , true );
api_register_func ( 'api/search' , 'api_search' , true );
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the most recent statuses posted by the user and the users they follow .
*
* @ see https :// developer . twitter . com / en / docs / tweets / timelines / api - reference / get - statuses - home_timeline
2017-11-10 05:00:50 +00:00
*
2017-12-24 02:20:50 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
2017-11-10 05:00:50 +00:00
*
2017-12-24 02:20:50 +00:00
* @ todo Optional parameters
* @ todo Add reply info
2017-11-10 05:00:50 +00:00
*/
function api_statuses_home_timeline ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " user_id " ]);
unset ( $_GET [ " user_id " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " screen_name " ]);
unset ( $_GET [ " screen_name " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
// get last newtork messages
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$count = ( x ( $_REQUEST , 'count' ) ? $_REQUEST [ 'count' ] : 20 );
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
if ( $page < 0 ) {
$page = 0 ;
}
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
//$since_id = 0;//$since_id = (x($_REQUEST, 'since_id')?$_REQUEST['since_id'] : 0);
$exclude_replies = ( x ( $_REQUEST , 'exclude_replies' ) ? 1 : 0 );
$conversation_id = ( x ( $_REQUEST , 'conversation_id' ) ? $_REQUEST [ 'conversation_id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$start = $page * $count ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sql_extra = '' ;
if ( $max_id > 0 ) {
$sql_extra .= ' AND `item`.`id` <= ' . intval ( $max_id );
}
if ( $exclude_replies > 0 ) {
$sql_extra .= ' AND `item`.`parent` = `item`.`id`' ;
}
if ( $conversation_id > 0 ) {
$sql_extra .= ' AND `item`.`parent` = ' . intval ( $conversation_id );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item`
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `uid` = % d AND `verb` = '%s'
AND `item` . `visible` AND NOT `item` . `moderated` AND NOT `item` . `deleted`
$sql_extra
AND `item` . `id` >% d
ORDER BY `item` . `id` DESC LIMIT % d , % d " ,
intval ( api_user ()),
dbesc ( ACTIVITY_POST ),
intval ( $since_id ),
intval ( $start ),
intval ( $count )
);
$ret = api_format_items ( $r , $user_info , false , $type );
// Set all posts from the query above to seen
2018-01-15 13:05:12 +00:00
$idarray = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $item ) {
$idarray [] = intval ( $item [ " id " ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$idlist = implode ( " , " , $idarray );
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
if ( $idlist != " " ) {
$unseen = q ( " SELECT `id` FROM `item` WHERE `unseen` AND `id` IN (%s) " , $idlist );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $unseen ) {
2018-01-04 01:54:35 +00:00
q ( " UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s) " , $idlist );
2016-09-25 16:50:08 +00:00
}
}
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
break ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/home_timeline' , 'api_statuses_home_timeline' , true );
api_register_func ( 'api/statuses/friends_timeline' , 'api_statuses_home_timeline' , true );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns the most recent statuses from public users .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_statuses_public_timeline ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
// get last newtork messages
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$count = ( x ( $_REQUEST , 'count' ) ? $_REQUEST [ 'count' ] : 20 );
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
if ( $page < 0 ) {
$page = 0 ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
//$since_id = 0;//$since_id = (x($_REQUEST, 'since_id')?$_REQUEST['since_id'] : 0);
$exclude_replies = ( x ( $_REQUEST , 'exclude_replies' ) ? 1 : 0 );
$conversation_id = ( x ( $_REQUEST , 'conversation_id' ) ? $_REQUEST [ 'conversation_id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$start = $page * $count ;
2016-09-25 16:50:08 +00:00
2017-12-17 17:47:15 +00:00
if ( $exclude_replies && ! $conversation_id ) {
if ( $max_id > 0 ) {
$sql_extra = 'AND `thread`.`iid` <= ' . intval ( $max_id );
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
$r = dba :: p (
" SELECT " . item_fieldlists () . "
2017-12-17 17:47:15 +00:00
FROM `thread`
STRAIGHT_JOIN `item` ON `item` . `id` = `thread` . `iid`
" . item_joins() . "
STRAIGHT_JOIN `user` ON `user` . `uid` = `thread` . `uid`
AND NOT `user` . `hidewall`
AND `verb` = ?
AND NOT `thread` . `private`
AND `thread` . `wall`
AND `thread` . `visible`
AND NOT `thread` . `deleted`
AND NOT `thread` . `moderated`
AND `thread` . `iid` > ?
$sql_extra
ORDER BY `thread` . `iid` DESC
LIMIT " . intval( $start ) . " , " . intval( $count ),
ACTIVITY_POST ,
$since_id
);
$r = dba :: inArray ( $r );
} else {
if ( $max_id > 0 ) {
$sql_extra = 'AND `item`.`id` <= ' . intval ( $max_id );
}
if ( $conversation_id > 0 ) {
$sql_extra .= ' AND `item`.`parent` = ' . intval ( $conversation_id );
}
2017-12-23 23:27:45 +00:00
$r = dba :: p (
" SELECT " . item_fieldlists () . "
2017-12-17 17:47:15 +00:00
FROM `item`
" . item_joins() . "
STRAIGHT_JOIN `user` ON `user` . `uid` = `item` . `uid`
AND NOT `user` . `hidewall`
AND `verb` = ?
AND NOT `item` . `private`
AND `item` . `wall`
AND `item` . `visible`
AND NOT `item` . `deleted`
AND NOT `item` . `moderated`
AND `item` . `id` > ?
$sql_extra
ORDER BY `item` . `id` DESC
LIMIT " . intval( $start ) . " , " . intval( $count ),
ACTIVITY_POST ,
$since_id
);
$r = dba :: inArray ( $r );
}
2017-11-10 05:00:50 +00:00
$ret = api_format_items ( $r , $user_info , false , $type );
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
break ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/public_timeline' , 'api_statuses_public_timeline' , true );
2016-09-25 16:50:08 +00:00
2017-12-16 20:41:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the most recent statuses posted by users this node knows about .
*
2017-12-16 20:41:50 +00:00
* @ brief Returns the list of public federated posts this node knows about
*
* @ param string $type Return format : json , xml , atom , rss
* @ return array | string
* @ throws ForbiddenException
*/
function api_statuses_networkpublic_timeline ( $type )
{
$a = get_app ();
if ( api_user () === false ) {
throw new ForbiddenException ();
}
$user_info = api_get_user ( $a );
$since_id = x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 ;
$max_id = x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 ;
// pagination
$count = x ( $_REQUEST , 'count' ) ? $_REQUEST [ 'count' ] : 20 ;
$page = x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] : 1 ;
if ( $page < 1 ) {
$page = 1 ;
}
$start = ( $page - 1 ) * $count ;
$sql_extra = '' ;
if ( $max_id > 0 ) {
2017-12-17 15:06:12 +00:00
$sql_extra = 'AND `thread`.`iid` <= ' . intval ( $max_id );
2017-12-16 20:41:50 +00:00
}
2017-12-23 23:27:45 +00:00
$r = dba :: p (
" SELECT " . item_fieldlists () . "
2017-12-16 20:41:50 +00:00
FROM `thread`
2017-12-17 17:47:15 +00:00
STRAIGHT_JOIN `item` ON `item` . `id` = `thread` . `iid`
2017-12-16 20:41:50 +00:00
" . item_joins() . "
WHERE `thread` . `uid` = 0
AND `verb` = ?
2017-12-17 17:47:15 +00:00
AND NOT `thread` . `private`
AND `thread` . `visible`
AND NOT `thread` . `deleted`
AND NOT `thread` . `moderated`
AND `thread` . `iid` > ?
2017-12-16 20:41:50 +00:00
$sql_extra
2017-12-17 15:06:12 +00:00
ORDER BY `thread` . `iid` DESC
2017-12-16 20:41:50 +00:00
LIMIT " . intval( $start ) . " , " . intval( $count ),
ACTIVITY_POST ,
$since_id
);
$r = dba :: inArray ( $r );
$ret = api_format_items ( $r , $user_info , false , $type );
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-12-16 20:41:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
break ;
}
return api_format_data ( " statuses " , $type , $data );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/networkpublic_timeline' , 'api_statuses_networkpublic_timeline' , true );
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns a single status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / get - statuses - show - id
2017-11-10 05:00:50 +00:00
*/
function api_statuses_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$id = intval ( $a -> argv [ 3 ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $id == 0 ) {
$id = intval ( $_REQUEST [ " id " ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Hotot workaround
if ( $id == 0 ) {
$id = intval ( $a -> argv [ 4 ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'API: api_statuses_show: ' . $id );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$conversation = ( x ( $_REQUEST , 'conversation' ) ? 1 : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sql_extra = '' ;
if ( $conversation ) {
$sql_extra .= " AND `item`.`parent` = %d ORDER BY `id` ASC " ;
} else {
$sql_extra .= " AND `item`.`id` = %d " ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item`
INNER JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `visible` AND NOT `item` . `moderated` AND NOT `item` . `deleted`
AND `item` . `uid` = % d AND `item` . `verb` = '%s'
$sql_extra " ,
intval ( api_user ()),
dbesc ( ACTIVITY_POST ),
intval ( $id )
);
/// @TODO How about copying this to above methods which don't check $r ?
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " There is no status with this id. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$ret = api_format_items ( $r , $user_info , false , $type );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $conversation ) {
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-04-05 20:07:55 +00:00
return api_format_data ( " statuses " , $type , $data );
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret [ 0 ]];
2017-11-10 05:00:50 +00:00
return api_format_data ( " status " , $type , $data );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/show' , 'api_statuses_show' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ todo nothing to say ?
2017-11-10 05:00:50 +00:00
*/
function api_conversation_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$id = intval ( $a -> argv [ 3 ]);
$count = ( x ( $_REQUEST , 'count' ) ? $_REQUEST [ 'count' ] : 20 );
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
if ( $page < 0 ) {
$page = 0 ;
}
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$start = $page * $count ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $id == 0 ) {
$id = intval ( $_REQUEST [ " id " ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Hotot workaround
if ( $id == 0 ) {
$id = intval ( $a -> argv [ 4 ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'API: api_conversation_show: ' . $id );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q ( " SELECT `parent` FROM `item` WHERE `id` = %d " , intval ( $id ));
if ( DBM :: is_result ( $r )) {
$id = $r [ 0 ][ " parent " ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sql_extra = '' ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $max_id > 0 ) {
$sql_extra = ' AND `item`.`id` <= ' . intval ( $max_id );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// Not sure why this query was so complicated. We should keep it here for a while,
// just to make sure that we really don't need it.
// FROM `item` INNER JOIN (SELECT `uri`,`parent` FROM `item` WHERE `id` = %d) AS `temp1`
// ON (`item`.`thr-parent` = `temp1`.`uri` AND `item`.`parent` = `temp1`.`parent`)
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item`
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `parent` = % d AND `item` . `visible`
AND NOT `item` . `moderated` AND NOT `item` . `deleted`
AND `item` . `uid` = % d AND `item` . `verb` = '%s'
AND `item` . `id` >% d $sql_extra
ORDER BY `item` . `id` DESC LIMIT % d , % d " ,
2017-12-23 23:27:45 +00:00
intval ( $id ),
intval ( api_user ()),
2017-11-10 05:00:50 +00:00
dbesc ( ACTIVITY_POST ),
intval ( $since_id ),
2017-12-23 23:27:45 +00:00
intval ( $start ),
intval ( $count )
2017-11-10 05:00:50 +00:00
);
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " There is no status with this id. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$ret = api_format_items ( $r , $user_info , false , $type );
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/conversation/show' , 'api_conversation_show' , true );
api_register_func ( 'api/statusnet/conversation' , 'api_conversation_show' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Repeats a status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - retweet - id
2017-11-10 05:00:50 +00:00
*/
function api_statuses_repeat ( $type )
{
global $called_api ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2018-01-04 18:26:09 +00:00
api_get_user ( $a );
2017-11-10 05:00:50 +00:00
// params
$id = intval ( $a -> argv [ 3 ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $id == 0 ) {
$id = intval ( $_REQUEST [ " id " ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Hotot workaround
if ( $id == 0 ) {
$id = intval ( $a -> argv [ 4 ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'API: api_statuses_repeat: ' . $id );
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`, `contact`.`nick` as `reply_author`,
`contact` . `name` , `contact` . `photo` as `reply_photo` , `contact` . `url` as `reply_url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item`
INNER JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `visible` AND NOT `item` . `moderated` AND NOT `item` . `deleted`
AND NOT `item` . `private` AND `item` . `allow_cid` = '' AND `item` . `allow_gid` = ''
AND `item` . `deny_cid` = '' AND `item` . `deny_gid` = ''
$sql_extra
AND `item` . `id` =% d " ,
intval ( $id )
);
/// @TODO other style than above functions!
if ( DBM :: is_result ( $r ) && $r [ 0 ][ 'body' ] != " " ) {
if ( strpos ( $r [ 0 ][ 'body' ], " [/share] " ) !== false ) {
$pos = strpos ( $r [ 0 ][ 'body' ], " [share " );
$post = substr ( $r [ 0 ][ 'body' ], $pos );
} else {
$post = share_header ( $r [ 0 ][ 'author-name' ], $r [ 0 ][ 'author-link' ], $r [ 0 ][ 'author-avatar' ], $r [ 0 ][ 'guid' ], $r [ 0 ][ 'created' ], $r [ 0 ][ 'plink' ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$post .= $r [ 0 ][ 'body' ];
$post .= " [/share] " ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$_REQUEST [ 'body' ] = $post ;
$_REQUEST [ 'profile_uid' ] = api_user ();
$_REQUEST [ 'type' ] = 'wall' ;
$_REQUEST [ 'api_source' ] = true ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! x ( $_REQUEST , " source " )) {
$_REQUEST [ " source " ] = api_source ();
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
item_post ( $a );
} else {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// this should output the last post (the one we just posted).
$called_api = null ;
return api_status_show ( $type );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/retweet' , 'api_statuses_repeat' , true , API_METHOD_POST );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Destroys a specific status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - destroy - id
2017-11-10 05:00:50 +00:00
*/
function api_statuses_destroy ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2018-01-04 18:26:09 +00:00
api_get_user ( $a );
2017-11-10 05:00:50 +00:00
// params
$id = intval ( $a -> argv [ 3 ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $id == 0 ) {
$id = intval ( $_REQUEST [ " id " ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Hotot workaround
if ( $id == 0 ) {
$id = intval ( $a -> argv [ 4 ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
logger ( 'API: api_statuses_destroy: ' . $id );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$ret = api_statuses_show ( $type );
2016-09-25 16:50:08 +00:00
2018-01-17 23:22:01 +00:00
Item :: delete ( $id );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $ret ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/destroy' , 'api_statuses_destroy' , true , API_METHOD_DELETE );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the most recent mentions .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ see http :// developer . twitter . com / doc / get / statuses / mentions
2017-11-10 05:00:50 +00:00
*/
function api_statuses_mentions ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " user_id " ]);
unset ( $_GET [ " user_id " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " screen_name " ]);
unset ( $_GET [ " screen_name " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
// get last newtork messages
2017-04-05 20:07:55 +00:00
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
2018-01-04 01:54:35 +00:00
$since_id = defaults ( $_REQUEST , 'since_id' , 0 );
$max_id = defaults ( $_REQUEST , 'max_id' , 0 );
$count = defaults ( $_REQUEST , 'count' , 20 );
$page = defaults ( $_REQUEST , 'page' , 1 );
if ( $page < 1 ) {
$page = 1 ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2018-01-04 01:54:35 +00:00
$start = ( $page - 1 ) * $count ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Ugly code - should be changed
$myurl = System :: baseUrl () . '/profile/' . $a -> user [ 'nickname' ];
$myurl = substr ( $myurl , strpos ( $myurl , '://' ) + 3 );
$myurl = str_replace ( 'www.' , '' , $myurl );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $max_id > 0 ) {
$sql_extra = ' AND `item`.`id` <= ' . intval ( $max_id );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item` FORCE INDEX ( `uid_id` )
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `uid` = % d AND `verb` = '%s'
AND NOT ( `item` . `author-link` IN ( 'https://%s' , 'http://%s' ))
AND `item` . `visible` AND NOT `item` . `moderated` AND NOT `item` . `deleted`
AND `item` . `parent` IN ( SELECT `iid` FROM `thread` WHERE `uid` = % d AND `mention` AND ! `ignored` )
$sql_extra
AND `item` . `id` >% d
ORDER BY `item` . `id` DESC LIMIT % d , % d " ,
intval ( api_user ()),
dbesc ( ACTIVITY_POST ),
dbesc ( protect_sprintf ( $myurl )),
dbesc ( protect_sprintf ( $myurl )),
intval ( api_user ()),
intval ( $since_id ),
intval ( $start ),
intval ( $count )
);
$ret = api_format_items ( $r , $user_info , false , $type );
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
break ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/mentions' , 'api_statuses_mentions' , true );
api_register_func ( 'api/statuses/replies' , 'api_statuses_mentions' , true );
2016-09-25 16:50:08 +00:00
2017-12-16 16:34:44 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the most recent statuses posted by the user .
*
2017-12-16 16:34:44 +00:00
* @ brief Returns a user ' s public timeline
*
* @ param string $type Either " json " or " xml "
* @ return string | array
* @ throws ForbiddenException
2017-12-24 02:20:50 +00:00
* @ see https :// developer . twitter . com / en / docs / tweets / timelines / api - reference / get - statuses - user_timeline
2017-12-16 16:34:44 +00:00
*/
2017-11-10 05:00:50 +00:00
function api_statuses_user_timeline ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
logger (
" api_statuses_user_timeline: api_user: " . api_user () .
" \n user_info: " . print_r ( $user_info , true ) .
" \n _REQUEST: " . print_r ( $_REQUEST , true ),
LOGGER_DEBUG
);
2017-12-16 16:34:44 +00:00
$since_id = x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 ;
$max_id = x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 ;
$exclude_replies = x ( $_REQUEST , 'exclude_replies' ) ? 1 : 0 ;
$conversation_id = x ( $_REQUEST , 'conversation_id' ) ? $_REQUEST [ 'conversation_id' ] : 0 ;
2016-09-25 16:50:08 +00:00
2017-12-16 16:34:44 +00:00
// pagination
$count = x ( $_REQUEST , 'count' ) ? $_REQUEST [ 'count' ] : 20 ;
$page = x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] : 1 ;
if ( $page < 1 ) {
$page = 1 ;
}
$start = ( $page - 1 ) * $count ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sql_extra = '' ;
if ( $user_info [ 'self' ] == 1 ) {
$sql_extra .= " AND `item`.`wall` = 1 " ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $exclude_replies > 0 ) {
$sql_extra .= ' AND `item`.`parent` = `item`.`id`' ;
}
2017-12-16 16:34:44 +00:00
2017-11-10 05:00:50 +00:00
if ( $conversation_id > 0 ) {
$sql_extra .= ' AND `item`.`parent` = ' . intval ( $conversation_id );
}
2016-09-25 16:50:08 +00:00
2017-12-16 16:34:44 +00:00
if ( $max_id > 0 ) {
$sql_extra .= ' AND `item`.`id` <= ' . intval ( $max_id );
}
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item` FORCE INDEX ( `uid_contactid_id` )
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `uid` = % d AND `verb` = '%s'
AND `item` . `contact-id` = % d
AND `item` . `visible` AND NOT `item` . `moderated` AND NOT `item` . `deleted`
$sql_extra
2017-12-16 16:34:44 +00:00
AND `item` . `id` > % d
2017-11-10 05:00:50 +00:00
ORDER BY `item` . `id` DESC LIMIT % d , % d " ,
intval ( api_user ()),
dbesc ( ACTIVITY_POST ),
intval ( $user_info [ 'cid' ]),
intval ( $since_id ),
intval ( $start ),
intval ( $count )
);
$ret = api_format_items ( $r , $user_info , true , $type );
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
break ;
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-12-23 23:27:45 +00:00
api_register_func ( 'api/statuses/user_timeline' , 'api_statuses_user_timeline' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Star / unstar an item .
2017-11-10 05:00:50 +00:00
* param : id : id of the item
*
2017-12-24 02:20:50 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ see https :// web . archive . org / web / 20131019055350 / https :// dev . twitter . com / docs / api / 1 / post / favorites / create /% 3 Aid
2017-11-10 05:00:50 +00:00
*/
function api_favorites_create_destroy ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// for versioned api.
/// @TODO We need a better global soluton
$action_argv_id = 2 ;
if ( $a -> argv [ 1 ] == " 1.1 " ) {
$action_argv_id = 3 ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $a -> argc <= $action_argv_id ) {
throw new BadRequestException ( " Invalid request. " );
}
$action = str_replace ( " . " . $type , " " , $a -> argv [ $action_argv_id ]);
if ( $a -> argc == $action_argv_id + 2 ) {
$itemid = intval ( $a -> argv [ $action_argv_id + 1 ]);
} else {
/// @TODO use x() to check if _REQUEST contains 'id'
$itemid = intval ( $_REQUEST [ 'id' ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$item = q ( " SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d LIMIT 1 " , $itemid , api_user ());
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! DBM :: is_result ( $item ) || count ( $item ) == 0 ) {
throw new BadRequestException ( " Invalid item. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
switch ( $action ) {
case " create " :
$item [ 0 ][ 'starred' ] = 1 ;
break ;
case " destroy " :
$item [ 0 ][ 'starred' ] = 0 ;
break ;
default :
throw new BadRequestException ( " Invalid action " . $action );
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
$r = q ( " UPDATE item SET starred=%d WHERE id=%d AND uid=%d " , $item [ 0 ][ 'starred' ], $itemid , api_user ());
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
q ( " UPDATE thread SET starred=%d WHERE iid=%d AND uid=%d " , $item [ 0 ][ 'starred' ], $itemid , api_user ());
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $r === false ) {
throw new InternalServerErrorException ( " DB error " );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
$rets = api_format_items ( $item , $user_info , false , $type );
$ret = $rets [ 0 ];
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " status " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/favorites/create' , 'api_favorites_create_destroy' , true , API_METHOD_POST );
api_register_func ( 'api/favorites/destroy' , 'api_favorites_create_destroy' , true , API_METHOD_DELETE );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns the most recent favorite statuses .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return string | array
*/
2017-11-10 05:00:50 +00:00
function api_favorites ( $type )
{
global $called_api ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a = get_app ();
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2018-01-15 13:05:12 +00:00
$called_api = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
// in friendica starred item are private
// return favorites only for self
logger ( 'api_favorites: self:' . $user_info [ 'self' ]);
if ( $user_info [ 'self' ] == 0 ) {
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
} else {
$sql_extra = " " ;
2016-09-25 16:50:08 +00:00
// params
2017-11-10 05:00:50 +00:00
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
$count = ( x ( $_GET , 'count' ) ? $_GET [ 'count' ] : 20 );
2017-04-05 20:07:55 +00:00
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
if ( $page < 0 ) {
$page = 0 ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$start = $page * $count ;
2016-09-25 16:50:08 +00:00
2017-04-05 20:07:55 +00:00
if ( $max_id > 0 ) {
2017-11-10 05:00:50 +00:00
$sql_extra .= ' AND `item`.`id` <= ' . intval ( $max_id );
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
2016-09-25 16:50:08 +00:00
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
2017-11-10 05:00:50 +00:00
FROM `item` , `contact`
WHERE `item` . `uid` = % d
AND `item` . `visible` = 1 AND `item` . `moderated` = 0 AND `item` . `deleted` = 0
AND `item` . `starred` = 1
AND `contact` . `id` = `item` . `contact-id`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
2016-09-25 16:50:08 +00:00
$sql_extra
AND `item` . `id` >% d
ORDER BY `item` . `id` DESC LIMIT % d , % d " ,
intval ( api_user ()),
intval ( $since_id ),
2017-11-10 05:00:50 +00:00
intval ( $start ),
intval ( $count )
2016-09-25 16:50:08 +00:00
);
2017-04-05 20:07:55 +00:00
$ret = api_format_items ( $r , $user_info , false , $type );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " statuses " , $type , $data );
}
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/favorites' , 'api_favorites' , true );
2017-12-24 02:20:50 +00:00
/**
*
* @ param array $item
* @ param array $recipient
* @ param array $sender
*
* @ return array
*/
2017-11-10 05:00:50 +00:00
function api_format_messages ( $item , $recipient , $sender )
{
// standard meta information
2018-01-15 13:05:12 +00:00
$ret = [
2017-11-10 05:00:50 +00:00
'id' => $item [ 'id' ],
'sender_id' => $sender [ 'id' ] ,
'text' => " " ,
'recipient_id' => $recipient [ 'id' ],
'created_at' => api_date ( $item [ 'created' ]),
'sender_screen_name' => $sender [ 'screen_name' ],
'recipient_screen_name' => $recipient [ 'screen_name' ],
'sender' => $sender ,
'recipient' => $recipient ,
'title' => " " ,
'friendica_seen' => $item [ 'seen' ],
'friendica_parent_uri' => $item [ 'parent-uri' ],
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset ( $ret [ " sender " ][ " uid " ]);
unset ( $ret [ " sender " ][ " self " ]);
unset ( $ret [ " recipient " ][ " uid " ]);
unset ( $ret [ " recipient " ][ " self " ]);
//don't send title to regular StatusNET requests to avoid confusing these apps
if ( x ( $_GET , 'getText' )) {
$ret [ 'title' ] = $item [ 'title' ];
if ( $_GET [ 'getText' ] == 'html' ) {
$ret [ 'text' ] = bbcode ( $item [ 'body' ], false , false );
} elseif ( $_GET [ 'getText' ] == 'plain' ) {
//$ret['text'] = html2plain(bbcode($item['body'], false, false, true), 0);
$ret [ 'text' ] = trim ( html2plain ( bbcode ( api_clean_plain_items ( $item [ 'body' ]), false , false , 2 , true ), 0 ));
}
} else {
$ret [ 'text' ] = $item [ 'title' ] . " \n " . html2plain ( bbcode ( api_clean_plain_items ( $item [ 'body' ]), false , false , 2 , true ), 0 );
}
if ( x ( $_GET , 'getUserObjects' ) && $_GET [ 'getUserObjects' ] == 'false' ) {
unset ( $ret [ 'sender' ]);
unset ( $ret [ 'recipient' ]);
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $ret ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param array $item
*
* @ return array
*/
2017-11-10 05:00:50 +00:00
function api_convert_item ( $item )
{
$body = $item [ 'body' ];
$attachments = api_get_attachments ( $body );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Workaround for ostatus messages where the title is identically to the body
$html = bbcode ( api_clean_plain_items ( $body ), false , false , 2 , true );
$statusbody = trim ( html2plain ( $html , 0 ));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// handle data: images
$statusbody = api_format_items_embeded_images ( $item , $statusbody );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$statustitle = trim ( $item [ 'title' ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $statustitle != '' ) && ( strpos ( $statusbody , $statustitle ) !== false )) {
$statustext = trim ( $statusbody );
} else {
$statustext = trim ( $statustitle . " \n \n " . $statusbody );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $item [ " network " ] == NETWORK_FEED ) && ( strlen ( $statustext ) > 1000 )) {
$statustext = substr ( $statustext , 0 , 1000 ) . " ... \n " . $item [ " plink " ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$statushtml = trim ( bbcode ( $body , false , false ));
// Workaround for clients with limited HTML parser functionality
2018-01-15 13:05:12 +00:00
$search = [ " <br> " , " <blockquote> " , " </blockquote> " ,
2017-11-10 05:00:50 +00:00
" <h1> " , " </h1> " , " <h2> " , " </h2> " ,
" <h3> " , " </h3> " , " <h4> " , " </h4> " ,
2018-01-15 13:05:12 +00:00
" <h5> " , " </h5> " , " <h6> " , " </h6> " ];
$replace = [ " <br> " , " <br><blockquote> " , " </blockquote><br> " ,
2017-11-10 05:00:50 +00:00
" <br><h1> " , " </h1><br> " , " <br><h2> " , " </h2><br> " ,
" <br><h3> " , " </h3><br> " , " <br><h4> " , " </h4><br> " ,
2018-01-15 13:05:12 +00:00
" <br><h5> " , " </h5><br> " , " <br><h6> " , " </h6><br> " ];
2017-11-10 05:00:50 +00:00
$statushtml = str_replace ( $search , $replace , $statushtml );
if ( $item [ 'title' ] != " " ) {
$statushtml = " <br><h4> " . bbcode ( $item [ 'title' ]) . " </h4><br> " . $statushtml ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
do {
$oldtext = $statushtml ;
$statushtml = str_replace ( " <br><br> " , " <br> " , $statushtml );
} while ( $oldtext != $statushtml );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( substr ( $statushtml , 0 , 4 ) == '<br>' ) {
$statushtml = substr ( $statushtml , 4 );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( substr ( $statushtml , 0 , - 4 ) == '<br>' ) {
$statushtml = substr ( $statushtml , - 4 );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// feeds without body should contain the link
if (( $item [ 'network' ] == NETWORK_FEED ) && ( strlen ( $item [ 'body' ]) == 0 )) {
$statushtml .= bbcode ( $item [ 'plink' ]);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$entities = api_get_entitities ( $statustext , $body );
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return [
2017-11-10 05:00:50 +00:00
" text " => $statustext ,
" html " => $statushtml ,
" attachments " => $attachments ,
" entities " => $entities
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $body
*
2017-12-25 20:14:02 +00:00
* @ return array | false
2017-12-24 02:20:50 +00:00
*/
2017-11-10 05:00:50 +00:00
function api_get_attachments ( & $body )
{
$text = $body ;
$text = preg_replace ( " / \ [img \ =([0-9]*)x([0-9]*) \ ](.*?) \ [ \ /img \ ]/ism " , '[img]$3[/img]' , $text );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$URLSearchString = " ^ \ [ \ ] " ;
$ret = preg_match_all ( " / \ [img \ ]([ $URLSearchString ]*) \ [ \ /img \ ]/ism " , $text , $images );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $ret ) {
return false ;
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$attachments = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
foreach ( $images [ 1 ] as $image ) {
2017-12-07 13:56:11 +00:00
$imagedata = Image :: getInfoFromURL ( $image );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $imagedata ) {
2018-01-15 13:05:12 +00:00
$attachments [] = [ " url " => $image , " mimetype " => $imagedata [ " mime " ], " size " => $imagedata [ " size " ]];
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( strstr ( $_SERVER [ 'HTTP_USER_AGENT' ], " AndStatus " )) {
foreach ( $images [ 0 ] as $orig ) {
$body = str_replace ( $orig , " " , $body );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
return $attachments ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $text
* @ param string $bbcode
*
* @ return array
* @ todo Links at the first character of the post
*/
2017-11-10 05:00:50 +00:00
function api_get_entitities ( & $text , $bbcode )
{
$include_entities = strtolower ( x ( $_REQUEST , 'include_entities' ) ? $_REQUEST [ 'include_entities' ] : " false " );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $include_entities != " true " ) {
preg_match_all ( " / \ [img](.*?) \ [ \ /img \ ]/ism " , $bbcode , $images );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
foreach ( $images [ 1 ] as $image ) {
$replace = proxy_url ( $image );
$text = str_replace ( $image , $replace , $text );
2016-09-25 16:50:08 +00:00
}
2018-01-15 13:05:12 +00:00
return [];
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = bb_CleanPictureLinks ( $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Change pure links in text to bbcode uris
$bbcode = preg_replace ( " /([^ \ ] \ =' " . '"' . " ]|^)(https? \ : \ / \ /[a-zA-Z0-9 \ : \ / \ - \ ? \ & \ ; \ . \ = \ _ \ ~ \ # \ % \$ \ ! \ + \ ,]+)/ism " , '$1[url=$2]$2[/url]' , $bbcode );
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$entities = [];
$entities [ " hashtags " ] = [];
$entities [ " symbols " ] = [];
$entities [ " urls " ] = [];
$entities [ " user_mentions " ] = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$URLSearchString = " ^ \ [ \ ] " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = preg_replace ( " /# \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '#$2' , $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = preg_replace ( " / \ [bookmark \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /bookmark \ ]/ism " , '[url=$1]$2[/url]' , $bbcode );
//$bbcode = preg_replace("/\[url\](.*?)\[\/url\]/ism",'[url=$1]$1[/url]',$bbcode);
$bbcode = preg_replace ( " / \ [video \ ](.*?) \ [ \ /video \ ]/ism " , '[url=$1]$1[/url]' , $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = preg_replace (
" / \ [youtube \ ]([A-Za-z0-9 \ -_=]+)(.*?) \ [ \ /youtube \ ]/ism " ,
'[url=https://www.youtube.com/watch?v=$1]https://www.youtube.com/watch?v=$1[/url]' ,
$bbcode
);
$bbcode = preg_replace ( " / \ [youtube \ ](.*?) \ [ \ /youtube \ ]/ism " , '[url=$1]$1[/url]' , $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = preg_replace (
" / \ [vimeo \ ]([0-9]+)(.*?) \ [ \ /vimeo \ ]/ism " ,
'[url=https://vimeo.com/$1]https://vimeo.com/$1[/url]' ,
$bbcode
);
$bbcode = preg_replace ( " / \ [vimeo \ ](.*?) \ [ \ /vimeo \ ]/ism " , '[url=$1]$1[/url]' , $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$bbcode = preg_replace ( " / \ [img \ =([0-9]*)x([0-9]*) \ ](.*?) \ [ \ /img \ ]/ism " , '[img]$3[/img]' , $bbcode );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
//preg_match_all("/\[url\]([$URLSearchString]*)\[\/url\]/ism", $bbcode, $urls1);
preg_match_all ( " / \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , $bbcode , $urls );
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$ordered_urls = [];
2017-11-10 05:00:50 +00:00
foreach ( $urls [ 1 ] as $id => $url ) {
//$start = strpos($text, $url, $offset);
$start = iconv_strpos ( $text , $url , 0 , " UTF-8 " );
if ( ! ( $start === false )) {
2018-01-15 13:05:12 +00:00
$ordered_urls [ $start ] = [ " url " => $url , " title " => $urls [ 2 ][ $id ]];
2017-11-10 05:00:50 +00:00
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
ksort ( $ordered_urls );
$offset = 0 ;
//foreach ($urls[1] AS $id=>$url) {
foreach ( $ordered_urls as $url ) {
if (( substr ( $url [ " title " ], 0 , 7 ) != " http:// " ) && ( substr ( $url [ " title " ], 0 , 8 ) != " https:// " )
&& ! strpos ( $url [ " title " ], " http:// " ) && ! strpos ( $url [ " title " ], " https:// " )
2017-12-22 23:10:32 +00:00
) {
2017-11-10 05:00:50 +00:00
$display_url = $url [ " title " ];
2017-12-22 23:10:32 +00:00
} else {
2018-01-15 13:05:12 +00:00
$display_url = str_replace ([ " http://www. " , " https://www. " ], [ " " , " " ], $url [ " url " ]);
$display_url = str_replace ([ " http:// " , " https:// " ], [ " " , " " ], $display_url );
2016-09-25 16:50:08 +00:00
2017-12-22 23:10:32 +00:00
if ( strlen ( $display_url ) > 26 ) {
2017-11-10 05:00:50 +00:00
$display_url = substr ( $display_url , 0 , 25 ) . " … " ;
2017-12-22 23:10:32 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
//$start = strpos($text, $url, $offset);
$start = iconv_strpos ( $text , $url [ " url " ], $offset , " UTF-8 " );
if ( ! ( $start === false )) {
2018-01-15 13:05:12 +00:00
$entities [ " urls " ][] = [ " url " => $url [ " url " ],
2017-11-10 05:00:50 +00:00
" expanded_url " => $url [ " url " ],
" display_url " => $display_url ,
2018-01-15 13:05:12 +00:00
" indices " => [ $start , $start + strlen ( $url [ " url " ])]];
2017-11-10 05:00:50 +00:00
$offset = $start + 1 ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match_all ( " / \ [img](.*?) \ [ \ /img \ ]/ism " , $bbcode , $images );
2018-01-15 13:05:12 +00:00
$ordered_images = [];
2017-11-10 05:00:50 +00:00
foreach ( $images [ 1 ] as $image ) {
//$start = strpos($text, $url, $offset);
$start = iconv_strpos ( $text , $image , 0 , " UTF-8 " );
2017-12-23 23:27:45 +00:00
if ( ! ( $start === false )) {
2017-11-10 05:00:50 +00:00
$ordered_images [ $start ] = $image ;
2017-12-23 23:27:45 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
//$entities["media"] = array();
$offset = 0 ;
foreach ( $ordered_images as $url ) {
2018-01-15 13:05:12 +00:00
$display_url = str_replace ([ " http://www. " , " https://www. " ], [ " " , " " ], $url );
$display_url = str_replace ([ " http:// " , " https:// " ], [ " " , " " ], $display_url );
2017-11-10 05:00:50 +00:00
2017-12-23 23:27:45 +00:00
if ( strlen ( $display_url ) > 26 ) {
2017-11-10 05:00:50 +00:00
$display_url = substr ( $display_url , 0 , 25 ) . " … " ;
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
$start = iconv_strpos ( $text , $url , $offset , " UTF-8 " );
if ( ! ( $start === false )) {
2017-12-07 13:56:11 +00:00
$image = Image :: getInfoFromURL ( $url );
2017-11-10 05:00:50 +00:00
if ( $image ) {
// If image cache is activated, then use the following sizes:
// thumb (150), small (340), medium (600) and large (1024)
if ( ! Config :: get ( " system " , " proxy_disabled " )) {
$media_url = proxy_url ( $url );
2018-01-15 13:05:12 +00:00
$sizes = [];
2017-12-07 13:56:11 +00:00
$scale = Image :: getScalingDimensions ( $image [ 0 ], $image [ 1 ], 150 );
2018-01-15 13:05:12 +00:00
$sizes [ " thumb " ] = [ " w " => $scale [ " width " ], " h " => $scale [ " height " ], " resize " => " fit " ];
2017-11-10 05:00:50 +00:00
if (( $image [ 0 ] > 150 ) || ( $image [ 1 ] > 150 )) {
2017-12-07 13:56:11 +00:00
$scale = Image :: getScalingDimensions ( $image [ 0 ], $image [ 1 ], 340 );
2018-01-15 13:05:12 +00:00
$sizes [ " small " ] = [ " w " => $scale [ " width " ], " h " => $scale [ " height " ], " resize " => " fit " ];
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
2017-12-07 13:56:11 +00:00
$scale = Image :: getScalingDimensions ( $image [ 0 ], $image [ 1 ], 600 );
2018-01-15 13:05:12 +00:00
$sizes [ " medium " ] = [ " w " => $scale [ " width " ], " h " => $scale [ " height " ], " resize " => " fit " ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $image [ 0 ] > 600 ) || ( $image [ 1 ] > 600 )) {
2017-12-07 13:56:11 +00:00
$scale = Image :: getScalingDimensions ( $image [ 0 ], $image [ 1 ], 1024 );
2018-01-15 13:05:12 +00:00
$sizes [ " large " ] = [ " w " => $scale [ " width " ], " h " => $scale [ " height " ], " resize " => " fit " ];
2017-11-10 05:00:50 +00:00
}
} else {
$media_url = $url ;
2018-01-15 13:05:12 +00:00
$sizes [ " medium " ] = [ " w " => $image [ 0 ], " h " => $image [ 1 ], " resize " => " fit " ];
2017-11-10 05:00:50 +00:00
}
2018-01-15 13:05:12 +00:00
$entities [ " media " ][] = [
2017-11-10 05:00:50 +00:00
" id " => $start + 1 ,
" id_str " => ( string ) $start + 1 ,
2018-01-15 13:05:12 +00:00
" indices " => [ $start , $start + strlen ( $url )],
2017-11-10 05:00:50 +00:00
" media_url " => normalise_link ( $media_url ),
" media_url_https " => $media_url ,
" url " => $url ,
" display_url " => $display_url ,
" expanded_url " => $url ,
" type " => " photo " ,
2018-01-15 13:05:12 +00:00
" sizes " => $sizes ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$offset = $start + 1 ;
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
return $entities ;
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param array $item
* @ param string $text
*
* @ return string
*/
2018-01-04 01:54:35 +00:00
function api_format_items_embeded_images ( $item , $text )
2017-11-10 05:00:50 +00:00
{
$text = preg_replace_callback (
2018-01-04 01:54:35 +00:00
'|data:image/([^;]+)[^=]+=*|m' ,
function () use ( $item ) {
return System :: baseUrl () . '/display/' . $item [ 'guid' ];
2017-11-10 05:00:50 +00:00
},
$text
);
return $text ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief return < a href = 'url' > name </ a > as array
*
* @ param string $txt text
* @ return array
2017-12-24 02:20:50 +00:00
* 'name' => 'name' ,
2017-11-10 05:00:50 +00:00
* 'url => ' url '
*/
function api_contactlink_to_array ( $txt )
{
2018-01-15 13:05:12 +00:00
$match = [];
2017-11-10 05:00:50 +00:00
$r = preg_match_all ( '|<a href="([^"]*)">([^<]*)</a>|' , $txt , $match );
if ( $r && count ( $match ) == 3 ) {
2018-01-15 13:05:12 +00:00
$res = [
2017-11-10 05:00:50 +00:00
'name' => $match [ 2 ],
'url' => $match [ 1 ]
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$res = [
2017-11-10 05:00:50 +00:00
'name' => $text ,
'url' => " "
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
}
return $res ;
}
2017-09-14 05:16:23 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief return likes , dislikes and attend status for item
*
* @ param array $item array
2017-12-24 02:20:50 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
*
2017-11-10 05:00:50 +00:00
* @ return array
2017-12-24 02:20:50 +00:00
* likes => int count ,
2017-11-10 05:00:50 +00:00
* dislikes => int count
*/
function api_format_items_activities ( & $item , $type = " json " )
{
$a = get_app ();
2018-01-15 13:05:12 +00:00
$activities = [
'like' => [],
'dislike' => [],
'attendyes' => [],
'attendno' => [],
'attendmaybe' => [],
];
2017-11-10 05:00:50 +00:00
$items = q (
' SELECT * FROM item
WHERE uid =% d AND `thr-parent` = " %s " AND visible AND NOT deleted ' ,
intval ( $item [ 'uid' ]),
dbesc ( $item [ 'uri' ])
);
foreach ( $items as $i ) {
// not used as result should be structured like other user data
//builtin_activity_puller($i, $activities);
// get user data and add it to the array of the activity
$user = api_get_user ( $a , $i [ 'author-link' ]);
switch ( $i [ 'verb' ]) {
case ACTIVITY_LIKE :
$activities [ 'like' ][] = $user ;
break ;
case ACTIVITY_DISLIKE :
$activities [ 'dislike' ][] = $user ;
break ;
case ACTIVITY_ATTEND :
$activities [ 'attendyes' ][] = $user ;
break ;
case ACTIVITY_ATTENDNO :
$activities [ 'attendno' ][] = $user ;
break ;
case ACTIVITY_ATTENDMAYBE :
$activities [ 'attendmaybe' ][] = $user ;
break ;
default :
break ;
2017-09-14 05:16:23 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-09-14 05:16:23 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
2018-01-15 13:05:12 +00:00
$xml_activities = [];
2017-11-10 05:00:50 +00:00
foreach ( $activities as $k => $v ) {
// change xml element from "like" to "friendica:like"
$xml_activities [ " friendica: " . $k ] = $v ;
// add user data into xml output
$k_user = 0 ;
2017-12-23 23:27:45 +00:00
foreach ( $v as $user ) {
2017-11-10 05:00:50 +00:00
$xml_activities [ " friendica: " . $k ][ $k_user ++. " :user " ] = $user ;
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
}
$activities = $xml_activities ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $activities ;
}
2017-06-08 02:00:59 +00:00
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief return data from profiles
*
2018-01-04 01:54:35 +00:00
* @ param array $profile_row array containing data from db table 'profile'
2017-11-10 05:00:50 +00:00
* @ return array
*/
2018-01-04 01:54:35 +00:00
function api_format_items_profiles ( $profile_row )
2017-11-10 05:00:50 +00:00
{
2018-01-15 13:05:12 +00:00
$profile = [
2018-01-04 01:54:35 +00:00
'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 ( api_clean_plain_items ( $profile_row [ 'likes' ]) , false , false , 2 , false ),
'dislikes' => bbcode ( api_clean_plain_items ( $profile_row [ 'dislikes' ]) , false , false , 2 , false ),
'about' => bbcode ( api_clean_plain_items ( $profile_row [ 'about' ]) , false , false , 2 , false ),
'music' => bbcode ( api_clean_plain_items ( $profile_row [ 'music' ]) , false , false , 2 , false ),
'book' => bbcode ( api_clean_plain_items ( $profile_row [ 'book' ]) , false , false , 2 , false ),
'tv' => bbcode ( api_clean_plain_items ( $profile_row [ 'tv' ]) , false , false , 2 , false ),
'film' => bbcode ( api_clean_plain_items ( $profile_row [ 'film' ]) , false , false , 2 , false ),
'interest' => bbcode ( api_clean_plain_items ( $profile_row [ 'interest' ]) , false , false , 2 , false ),
'romance' => bbcode ( api_clean_plain_items ( $profile_row [ 'romance' ]) , false , false , 2 , false ),
'work' => bbcode ( api_clean_plain_items ( $profile_row [ 'work' ]) , false , false , 2 , false ),
'education' => bbcode ( api_clean_plain_items ( $profile_row [ 'education' ]), false , false , 2 , false ),
'social_networks' => bbcode ( api_clean_plain_items ( $profile_row [ 'contact' ]) , false , false , 2 , false ),
'homepage' => $profile_row [ 'homepage' ],
'users' => null
2018-01-15 13:05:12 +00:00
];
2018-01-04 01:54:35 +00:00
return $profile ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief format items to be returned by api
*
2017-12-24 02:20:50 +00:00
* @ param array $r array of items
* @ param array $user_info
* @ param bool $filter_user filter items by $user_info
* @ param string $type Return type ( atom , rss , xml , json )
2017-11-10 05:00:50 +00:00
*/
function api_format_items ( $r , $user_info , $filter_user = false , $type = " json " )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$ret = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
foreach ( $r as $item ) {
localize_item ( $item );
list ( $status_user , $owner_user ) = api_item_get_user ( $a , $item );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Look if the posts are matching if they should be filtered by user id
if ( $filter_user && ( $status_user [ " id " ] != $user_info [ " id " ])) {
continue ;
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$in_reply_to = api_in_reply_to ( $item );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$converted = api_convert_item ( $item );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$geo = " georss:point " ;
} else {
$geo = " geo " ;
}
2018-01-15 13:05:12 +00:00
$status = [
2017-11-10 05:00:50 +00:00
'text' => $converted [ " text " ],
'truncated' => false ,
'created_at' => api_date ( $item [ 'created' ]),
'in_reply_to_status_id' => $in_reply_to [ 'status_id' ],
'in_reply_to_status_id_str' => $in_reply_to [ 'status_id_str' ],
'source' => (( $item [ 'app' ]) ? $item [ 'app' ] : 'web' ),
'id' => intval ( $item [ 'id' ]),
'id_str' => ( string ) intval ( $item [ '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' => $item [ 'starred' ] ? true : false ,
'user' => $status_user ,
'friendica_owner' => $owner_user ,
//'entities' => NULL,
2017-12-17 15:16:18 +00:00
'statusnet_html' => $converted [ " html " ],
'statusnet_conversation_id' => $item [ 'parent' ],
'external_url' => System :: baseUrl () . " /display/ " . $item [ 'guid' ],
2017-11-10 05:00:50 +00:00
'friendica_activities' => api_format_items_activities ( $item , $type ),
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " attachments " ]) > 0 ) {
$status [ " attachments " ] = $converted [ " attachments " ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( count ( $converted [ " entities " ]) > 0 ) {
$status [ " entities " ] = $converted [ " entities " ];
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $item [ 'item_network' ] != " " ) && ( $status [ " source " ] == 'web' )) {
2018-01-10 03:42:04 +00:00
$status [ " source " ] = ContactSelector :: networkToName ( $item [ 'item_network' ], $user_info [ 'url' ]);
} elseif (( $item [ 'item_network' ] != " " ) && ( ContactSelector :: networkToName ( $item [ 'item_network' ], $user_info [ 'url' ]) != $status [ " source " ])) {
$status [ " source " ] = trim ( $status [ " source " ] . ' (' . ContactSelector :: networkToName ( $item [ 'item_network' ], $user_info [ 'url' ]) . ')' );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Retweets are only valid for top postings
// It doesn't work reliable with the link if its a feed
//$IsRetweet = ($item['owner-link'] != $item['author-link']);
//if ($IsRetweet)
// $IsRetweet = (($item['owner-name'] != $item['author-name']) || ($item['owner-avatar'] != $item['author-avatar']));
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $item [ " id " ] == $item [ " parent " ]) {
$retweeted_item = api_share_as_retweet ( $item );
if ( $retweeted_item !== false ) {
$retweeted_status = $status ;
try {
$retweeted_status [ " user " ] = api_get_user ( $a , $retweeted_item [ " author-link " ]);
} catch ( BadRequestException $e ) {
// user not found. should be found?
/// @todo check if the user should be always found
2018-01-15 13:05:12 +00:00
$retweeted_status [ " user " ] = [];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$rt_converted = api_convert_item ( $retweeted_item );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$retweeted_status [ 'text' ] = $rt_converted [ " text " ];
$retweeted_status [ 'statusnet_html' ] = $rt_converted [ " html " ];
$retweeted_status [ 'friendica_activities' ] = api_format_items_activities ( $retweeted_item , $type );
$retweeted_status [ 'created_at' ] = api_date ( $retweeted_item [ 'created' ]);
$status [ 'retweeted_status' ] = $retweeted_status ;
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset ( $status [ " user " ][ " uid " ]);
unset ( $status [ " user " ][ " self " ]);
if ( $item [ " coord " ] != " " ) {
$coords = explode ( ' ' , $item [ " coord " ]);
if ( count ( $coords ) == 2 ) {
2017-12-22 23:10:32 +00:00
if ( $type == " json " ) {
2018-01-15 13:05:12 +00:00
$status [ " geo " ] = [ 'type' => 'Point' ,
'coordinates' => [( float ) $coords [ 0 ],
( float ) $coords [ 1 ]]];
2017-12-22 23:10:32 +00:00
} else { // Not sure if this is the official format - if someone founds a documentation we can check
2017-11-10 05:00:50 +00:00
$status [ " georss:point " ] = $item [ " coord " ];
2017-12-22 23:10:32 +00:00
}
2017-11-10 05:00:50 +00:00
}
}
$ret [] = $status ;
};
return $ret ;
}
2017-12-24 02:20:50 +00:00
/**
* Returns the remaining number of API requests available to the user before the API limit is reached .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_account_rate_limit_status ( $type )
{
if ( $type == " xml " ) {
2018-01-15 13:05:12 +00:00
$hash = [
2017-11-10 05:00:50 +00:00
'remaining-hits' => '150' ,
2018-01-15 13:05:12 +00:00
'@attributes' => [ " type " => " integer " ],
2017-11-10 05:00:50 +00:00
'hourly-limit' => '150' ,
2018-01-15 13:05:12 +00:00
'@attributes2' => [ " type " => " integer " ],
2017-11-10 05:00:50 +00:00
'reset-time' => datetime_convert ( 'UTC' , 'UTC' , 'now + 1 hour' , ATOM_TIME ),
2018-01-15 13:05:12 +00:00
'@attributes3' => [ " type " => " datetime " ],
2017-11-10 05:00:50 +00:00
'reset_time_in_seconds' => strtotime ( 'now + 1 hour' ),
2018-01-15 13:05:12 +00:00
'@attributes4' => [ " type " => " integer " ],
];
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$hash = [
2017-11-10 05:00:50 +00:00
'reset_time_in_seconds' => strtotime ( 'now + 1 hour' ),
'remaining_hits' => '150' ,
'hourly_limit' => '150' ,
'reset_time' => api_date ( datetime_convert ( 'UTC' , 'UTC' , 'now + 1 hour' , ATOM_TIME )),
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( 'hash' , $type , [ 'hash' => $hash ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/account/rate_limit_status' , 'api_account_rate_limit_status' , true );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns the string " ok " in the requested format with a 200 OK HTTP status code .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_help_test ( $type )
{
if ( $type == 'xml' ) {
$ok = " true " ;
} else {
$ok = " ok " ;
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( 'ok' , $type , [ " ok " => $ok ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/help/test' , 'api_help_test' , false );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_lists ( $type )
{
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
/// @TODO $ret is not filled here?
2018-01-15 13:05:12 +00:00
return api_format_data ( 'lists' , $type , [ " lists_list " => $ret ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/lists' , 'api_lists' , true );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns all lists the user subscribes to .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - list
*/
2017-11-10 05:00:50 +00:00
function api_lists_list ( $type )
{
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
/// @TODO $ret is not filled here?
2018-01-15 13:05:12 +00:00
return api_format_data ( 'lists' , $type , [ " lists_list " => $ret ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/lists/list' , 'api_lists_list' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Considers friends and followers lists to be private and won ' t return
2017-12-16 15:16:25 +00:00
* anything if any user_id parameter is passed .
*
2017-12-24 02:20:50 +00:00
* @ brief Returns either the friends of the follower list
*
2017-12-16 15:16:25 +00:00
* @ param string $qtype Either " friends " or " followers "
* @ return boolean | array
* @ throws ForbiddenException
2017-11-10 05:00:50 +00:00
*/
2017-12-16 15:16:25 +00:00
function api_statuses_f ( $qtype )
2017-11-10 05:00:50 +00:00
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-12-16 15:16:25 +00:00
// pagination
$count = x ( $_GET , 'count' ) ? $_GET [ 'count' ] : 20 ;
$page = x ( $_GET , 'page' ) ? $_GET [ 'page' ] : 1 ;
if ( $page < 1 ) {
$page = 1 ;
}
$start = ( $page - 1 ) * $count ;
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-12-16 15:16:25 +00:00
if ( x ( $_GET , 'cursor' ) && $_GET [ 'cursor' ] == 'undefined' ) {
2017-11-10 05:00:50 +00:00
/* this is to stop Hotot to load friends multiple times
* I 'm not sure if I' m missing return something or
* is a bug in hotot . Workaround , meantime
*/
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/* $ret = Array ();
return array ( '$users' => $ret ); */
return false ;
}
2016-09-25 16:50:08 +00:00
2017-12-23 00:30:50 +00:00
$sql_extra = '' ;
2017-11-10 05:00:50 +00:00
if ( $qtype == 'friends' ) {
$sql_extra = sprintf ( " AND ( `rel` = %d OR `rel` = %d ) " , intval ( CONTACT_IS_SHARING ), intval ( CONTACT_IS_FRIEND ));
2017-12-23 00:30:50 +00:00
} elseif ( $qtype == 'followers' ) {
2017-11-10 05:00:50 +00:00
$sql_extra = sprintf ( " AND ( `rel` = %d OR `rel` = %d ) " , intval ( CONTACT_IS_FOLLOWER ), intval ( CONTACT_IS_FRIEND ));
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// friends and followers only for self
if ( $user_info [ 'self' ] == 0 ) {
$sql_extra = " AND false " ;
}
2016-09-25 16:50:08 +00:00
2017-12-18 14:18:31 +00:00
if ( $qtype == 'blocks' ) {
2017-12-18 22:51:03 +00:00
$sql_filter = 'AND `blocked` AND NOT `pending`' ;
} elseif ( $qtype == 'incoming' ) {
$sql_filter = 'AND `pending`' ;
2017-12-18 14:18:31 +00:00
} else {
2017-12-18 22:51:03 +00:00
$sql_filter = 'AND (NOT `blocked` OR `pending`)' ;
2017-12-18 14:18:31 +00:00
}
2017-11-10 05:00:50 +00:00
$r = q (
2017-12-16 15:16:25 +00:00
" SELECT `nurl`
FROM `contact`
WHERE `uid` = % d
AND NOT `self`
2017-12-18 22:51:03 +00:00
$sql_filter
2017-12-16 15:16:25 +00:00
$sql_extra
ORDER BY `nick`
LIMIT % d , % d " ,
intval ( api_user ()),
intval ( $start ),
intval ( $count )
2017-11-10 05:00:50 +00:00
);
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $cid ) {
$user = api_get_user ( $a , $cid [ 'nurl' ]);
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset ( $user [ " uid " ]);
unset ( $user [ " self " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $user ) {
$ret [] = $user ;
2016-09-25 16:50:08 +00:00
}
}
2018-01-15 13:05:12 +00:00
return [ 'user' => $ret ];
2017-11-10 05:00:50 +00:00
}
2017-01-16 20:59:16 +00:00
2017-12-16 15:16:25 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the user ' s friends .
*
2017-12-16 15:16:25 +00:00
* @ brief Returns the list of friends of the provided user
*
* @ deprecated By Twitter API in favor of friends / list
*
* @ param string $type Either " json " or " xml "
* @ return boolean | string | array
*/
2017-11-10 05:00:50 +00:00
function api_statuses_friends ( $type )
{
2017-12-16 15:16:25 +00:00
$data = api_statuses_f ( " friends " );
2017-11-10 05:00:50 +00:00
if ( $data === false ) {
return false ;
}
return api_format_data ( " users " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-12-16 15:16:25 +00:00
/**
2017-12-24 02:20:50 +00:00
* Returns the user ' s followers .
*
* @ brief Returns the list of followers of the provided user
2017-12-16 15:16:25 +00:00
*
* @ deprecated By Twitter API in favor of friends / list
*
* @ param string $type Either " json " or " xml "
* @ return boolean | string | array
*/
2017-11-10 05:00:50 +00:00
function api_statuses_followers ( $type )
{
2017-12-16 15:16:25 +00:00
$data = api_statuses_f ( " followers " );
2017-11-10 05:00:50 +00:00
if ( $data === false ) {
return false ;
}
return api_format_data ( " users " , $type , $data );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/friends' , 'api_statuses_friends' , true );
api_register_func ( 'api/statuses/followers' , 'api_statuses_followers' , true );
2017-12-18 14:18:31 +00:00
/**
* Returns the list of blocked users
*
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / mute - block - report - users / api - reference / get - blocks - list
*
* @ param string $type Either " json " or " xml "
*
* @ return boolean | string | array
*/
function api_blocks_list ( $type )
{
$data = api_statuses_f ( 'blocks' );
if ( $data === false ) {
return false ;
}
return api_format_data ( " users " , $type , $data );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/blocks/list' , 'api_blocks_list' , true );
2017-12-18 22:51:03 +00:00
/**
* Returns the list of pending users IDs
*
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - friendships - incoming
*
* @ param string $type Either " json " or " xml "
*
* @ return boolean | string | array
*/
function api_friendships_incoming ( $type )
{
$data = api_statuses_f ( 'incoming' );
if ( $data === false ) {
return false ;
}
2018-01-15 13:05:12 +00:00
$ids = [];
2017-12-18 22:51:03 +00:00
foreach ( $data [ 'user' ] as $user ) {
$ids [] = $user [ 'id' ];
}
2018-01-15 13:05:12 +00:00
return api_format_data ( " ids " , $type , [ 'id' => $ids ]);
2017-12-18 22:51:03 +00:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/friendships/incoming' , 'api_friendships_incoming' , true );
2017-12-24 02:20:50 +00:00
/**
* Returns the instance ' s configuration information .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_statusnet_config ( $type )
{
$a = get_app ();
$name = $a -> config [ 'sitename' ];
$server = $a -> get_hostname ();
$logo = System :: baseUrl () . '/images/friendica-64.png' ;
$email = $a -> config [ 'admin_email' ];
$closed = (( $a -> config [ 'register_policy' ] == REGISTER_CLOSED ) ? 'true' : 'false' );
$private = (( Config :: get ( 'system' , 'block_public' )) ? 'true' : 'false' );
$textlimit = ( string ) (( $a -> config [ 'max_import_size' ]) ? $a -> config [ 'max_import_size' ] : 200000 );
if ( $a -> config [ 'api_import_size' ]) {
2017-12-23 00:32:47 +00:00
$textlimit = ( string ) $a -> config [ 'api_import_size' ];
2017-11-10 05:00:50 +00:00
}
$ssl = (( Config :: get ( 'system' , 'have_ssl' )) ? 'true' : 'false' );
$sslserver = (( $ssl === 'true' ) ? str_replace ( 'http:' , 'https:' , System :: baseUrl ()) : '' );
2018-01-15 13:05:12 +00:00
$config = [
'site' => [ 'name' => $name , 'server' => $server , 'theme' => 'default' , 'path' => '' ,
2017-11-10 05:00:50 +00:00
'logo' => $logo , 'fancy' => true , 'language' => 'en' , 'email' => $email , 'broughtby' => '' ,
'broughtbyurl' => '' , 'timezone' => 'UTC' , 'closed' => $closed , 'inviteonly' => false ,
'private' => $private , 'textlimit' => $textlimit , 'sslserver' => $sslserver , 'ssl' => $ssl ,
'shorturllength' => '30' ,
2018-01-15 13:05:12 +00:00
'friendica' => [
2017-11-10 05:00:50 +00:00
'FRIENDICA_PLATFORM' => FRIENDICA_PLATFORM ,
'FRIENDICA_VERSION' => FRIENDICA_VERSION ,
'DFRN_PROTOCOL_VERSION' => DFRN_PROTOCOL_VERSION ,
'DB_UPDATE_VERSION' => DB_UPDATE_VERSION
2018-01-15 13:05:12 +00:00
]
],
];
2017-11-10 05:00:50 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( 'config' , $type , [ 'config' => $config ]);
2017-11-10 05:00:50 +00:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/gnusocial/config' , 'api_statusnet_config' , false );
api_register_func ( 'api/statusnet/config' , 'api_statusnet_config' , false );
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_statusnet_version ( $type )
{
// liar
$fake_statusnet_version = " 0.9.7 " ;
2018-01-15 13:05:12 +00:00
return api_format_data ( 'version' , $type , [ 'version' => $fake_statusnet_version ]);
2017-11-10 05:00:50 +00:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/gnusocial/version' , 'api_statusnet_version' , false );
api_register_func ( 'api/statusnet/version' , 'api_statusnet_version' , false );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2017-11-10 05:00:50 +00:00
* @ todo use api_format_data () to return data
*/
2018-01-04 01:54:35 +00:00
function api_ff_ids ( $type )
2017-11-10 05:00:50 +00:00
{
if ( ! api_user ()) {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2018-01-04 18:26:09 +00:00
api_get_user ( $a );
2018-01-04 01:54:35 +00:00
$stringify_ids = defaults ( $_REQUEST , 'stringify_ids' , false );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `pcontact`.`id` FROM `contact`
INNER JOIN `contact` AS `pcontact` ON `contact` . `nurl` = `pcontact` . `nurl` AND `pcontact` . `uid` = 0
WHERE `contact` . `uid` = % s AND NOT `contact` . `self` " ,
intval ( api_user ())
);
if ( ! DBM :: is_result ( $r )) {
return ;
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$ids = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $rr ) {
if ( $stringify_ids ) {
$ids [] = $rr [ 'id' ];
} else {
$ids [] = intval ( $rr [ 'id' ]);
}
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( " ids " , $type , [ 'id' => $ids ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns the ID of every user the user is following .
*
* @ 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 - friends - ids
*/
2017-11-10 05:00:50 +00:00
function api_friends_ids ( $type )
{
2018-01-04 01:54:35 +00:00
return api_ff_ids ( $type );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Returns the ID of every user following the user .
*
* @ 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 - followers - ids
*/
2017-11-10 05:00:50 +00:00
function api_followers_ids ( $type )
{
2018-01-04 01:54:35 +00:00
return api_ff_ids ( $type );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @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 );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Sends a new direct message .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / new - message
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_new ( $type )
{
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( ! x ( $_POST , " text " ) || ( ! x ( $_POST , " screen_name " ) && ! x ( $_POST , " user_id " ))) {
return ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sender = api_get_user ( $a );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $_POST [ 'screen_name' ]) {
$r = q (
" SELECT `id`, `nurl`, `network` FROM `contact` WHERE `uid`=%d AND `nick`='%s' " ,
intval ( api_user ()),
dbesc ( $_POST [ 'screen_name' ])
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// Selecting the id by priority, friendica first
api_best_nickname ( $r );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$recipient = api_get_user ( $a , $r [ 0 ][ 'nurl' ]);
} else {
$recipient = api_get_user ( $a , $_POST [ 'user_id' ]);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$replyto = '' ;
$sub = '' ;
if ( x ( $_REQUEST , 'replyto' )) {
$r = q (
'SELECT `parent-uri`, `title` FROM `mail` WHERE `uid`=%d AND `id`=%d' ,
intval ( api_user ()),
intval ( $_REQUEST [ 'replyto' ])
);
$replyto = $r [ 0 ][ 'parent-uri' ];
$sub = $r [ 0 ][ 'title' ];
} else {
if ( x ( $_REQUEST , 'title' )) {
$sub = $_REQUEST [ 'title' ];
2017-04-05 20:07:55 +00:00
} else {
2017-11-10 05:00:50 +00:00
$sub = (( strlen ( $_POST [ 'text' ]) > 10 ) ? substr ( $_POST [ 'text' ], 0 , 10 ) . " ... " : $_POST [ 'text' ]);
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2018-01-15 17:14:09 +00:00
$id = Mail :: send ( $recipient [ 'cid' ], $_POST [ 'text' ], $sub , $replyto );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $id > - 1 ) {
$r = q ( " SELECT * FROM `mail` WHERE id=%d " , intval ( $id ));
$ret = api_format_messages ( $r [ 0 ], $recipient , $sender );
} else {
2018-01-15 13:05:12 +00:00
$ret = [ " error " => $id ];
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2018-01-15 13:05:12 +00:00
$data = [ 'direct_message' => $ret ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " direct-messages " , $type , $data );
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/direct_messages/new' , 'api_direct_messages_new' , true , API_METHOD_POST );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Destroys a direct message .
*
2017-11-10 05:00:50 +00:00
* @ brief delete a direct_message from mail table through api
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
2017-12-24 02:20:50 +00:00
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / delete - message
2017-11-10 05:00:50 +00:00
*/
function api_direct_messages_destroy ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
//required
$id = ( x ( $_REQUEST , 'id' ) ? $_REQUEST [ 'id' ] : 0 );
// optional
$parenturi = ( x ( $_REQUEST , 'friendica_parenturi' ) ? $_REQUEST [ 'friendica_parenturi' ] : " " );
$verbose = ( x ( $_GET , 'friendica_verbose' ) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
/// @todo optional parameter 'include_entities' from Twitter API not yet implemented
$uid = $user_info [ 'uid' ];
// error if no id or parenturi specified (for clients posting parent-uri as well)
if ( $verbose == " true " && ( $id == 0 || $parenturi == " " )) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'message id or parenturi not specified' ];
return api_format_data ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// BadRequestException if no id specified (for clients using Twitter API)
if ( $id == 0 ) {
throw new BadRequestException ( 'Message id not specified' );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// add parent-uri to sql command if specified by calling app
$sql_extra = ( $parenturi != " " ? " AND `parent-uri` = ' " . dbesc ( $parenturi ) . " ' " : " " );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// get data of the specified message id
$r = q (
" SELECT `id` FROM `mail` WHERE `uid` = %d AND `id` = %d " . $sql_extra ,
intval ( $uid ),
intval ( $id )
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// error message if specified id is not in database
if ( ! DBM :: is_result ( $r )) {
if ( $verbose == " true " ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'message id not in database' ];
return api_format_data ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-04-05 20:17:15 +00:00
}
2017-11-10 05:00:50 +00:00
/// @todo BadRequestException ok for Twitter API clients?
throw new BadRequestException ( 'message id not in database' );
}
// delete message
$result = q (
" DELETE FROM `mail` WHERE `uid` = %d AND `id` = %d " . $sql_extra ,
intval ( $uid ),
intval ( $id )
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $verbose == " true " ) {
if ( $result ) {
// return success
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'ok' , 'message' => 'message deleted' ];
return api_format_data ( " direct_message_delete " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'unknown error' ];
return api_format_data ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-04-05 20:17:15 +00:00
}
2017-11-10 05:00:50 +00:00
}
/// @todo return JSON data like Twitter API not yet implemented
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/direct_messages/destroy' , 'api_direct_messages_destroy' , true , API_METHOD_DELETE );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
* @ param string $box
* @ param string $verbose
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_box ( $type , $box , $verbose )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
// params
$count = ( x ( $_GET , 'count' ) ? $_GET [ 'count' ] : 20 );
$page = ( x ( $_REQUEST , 'page' ) ? $_REQUEST [ 'page' ] - 1 : 0 );
if ( $page < 0 ) {
$page = 0 ;
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
$since_id = ( x ( $_REQUEST , 'since_id' ) ? $_REQUEST [ 'since_id' ] : 0 );
$max_id = ( x ( $_REQUEST , 'max_id' ) ? $_REQUEST [ 'max_id' ] : 0 );
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
$user_id = ( x ( $_REQUEST , 'user_id' ) ? $_REQUEST [ 'user_id' ] : " " );
$screen_name = ( x ( $_REQUEST , 'screen_name' ) ? $_REQUEST [ 'screen_name' ] : " " );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// caller user info
unset ( $_REQUEST [ " user_id " ]);
unset ( $_GET [ " user_id " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
unset ( $_REQUEST [ " screen_name " ]);
unset ( $_GET [ " screen_name " ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$user_info = api_get_user ( $a );
$profile_url = $user_info [ " url " ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// pagination
$start = $page * $count ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// filters
if ( $box == " sentbox " ) {
$sql_extra = " `mail`.`from-url`=' " . dbesc ( $profile_url ) . " ' " ;
} elseif ( $box == " conversation " ) {
$sql_extra = " `mail`.`parent-uri`=' " . dbesc ( $_GET [ " uri " ]) . " ' " ;
} elseif ( $box == " all " ) {
$sql_extra = " true " ;
} elseif ( $box == " inbox " ) {
$sql_extra = " `mail`.`from-url`!=' " . dbesc ( $profile_url ) . " ' " ;
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
if ( $max_id > 0 ) {
$sql_extra .= ' AND `mail`.`id` <= ' . intval ( $max_id );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $user_id != " " ) {
$sql_extra .= ' AND `mail`.`contact-id` = ' . intval ( $user_id );
} elseif ( $screen_name != " " ) {
$sql_extra .= " AND `contact`.`nick` = ' " . dbesc ( $screen_name ) . " ' " ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `mail`.*, `contact`.`nurl` AS `contact-url` FROM `mail`,`contact` WHERE `mail`.`contact-id` = `contact`.`id` AND `mail`.`uid`=%d AND $sql_extra AND `mail`.`id` > %d ORDER BY `mail`.`id` DESC LIMIT %d,%d " ,
intval ( api_user ()),
intval ( $since_id ),
intval ( $start ),
intval ( $count )
);
if ( $verbose == " true " && ! DBM :: is_result ( $r )) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'no mails available' ];
return api_format_data ( " direct_messages_all " , $type , [ '$result' => $answer ]);
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:17:15 +00:00
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
$sender = api_get_user ( $a , normalise_link ( $item [ 'contact-url' ]));
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
$recipient = api_get_user ( $a , normalise_link ( $item [ 'contact-url' ]));
$sender = $user_info ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$data = [ 'direct_message' => $ret ];
2017-11-10 05:00:50 +00:00
switch ( $type ) {
case " atom " :
case " rss " :
$data = api_rss_extra ( $a , $data , $user_info );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " direct-messages " , $type , $data );
}
2017-12-24 02:20:50 +00:00
/**
* Returns the most recent direct messages sent by the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - sent - message
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_sentbox ( $type )
{
$verbose = ( x ( $_GET , 'friendica_verbose' ) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
return api_direct_messages_box ( $type , " sentbox " , $verbose );
}
2017-12-24 02:20:50 +00:00
/**
* Returns the most recent direct messages sent to the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - messages
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_inbox ( $type )
{
$verbose = ( x ( $_GET , 'friendica_verbose' ) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
return api_direct_messages_box ( $type , " inbox " , $verbose );
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_all ( $type )
{
$verbose = ( x ( $_GET , 'friendica_verbose' ) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
return api_direct_messages_box ( $type , " all " , $verbose );
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_direct_messages_conversation ( $type )
{
$verbose = ( x ( $_GET , 'friendica_verbose' ) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
return api_direct_messages_box ( $type , " conversation " , $verbose );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/direct_messages/conversation' , 'api_direct_messages_conversation' , true );
api_register_func ( 'api/direct_messages/all' , 'api_direct_messages_all' , true );
api_register_func ( 'api/direct_messages/sent' , 'api_direct_messages_sentbox' , true );
api_register_func ( 'api/direct_messages' , 'api_direct_messages_inbox' , true );
2017-12-24 02:20:50 +00:00
/**
* Returns an OAuth Request Token .
*
* @ see https :// oauth . net / core / 1.0 / #auth_step1
*/
2018-01-04 01:54:35 +00:00
function api_oauth_request_token ()
2017-11-10 05:00:50 +00:00
{
2017-12-05 02:10:54 +00:00
$oauth1 = new FKOAuth1 ();
2017-11-10 05:00:50 +00:00
try {
2017-12-05 02:10:54 +00:00
$r = $oauth1 -> fetch_request_token ( OAuthRequest :: from_request ());
2017-11-10 05:00:50 +00:00
} catch ( Exception $e ) {
echo " error= " . OAuthUtil :: urlencode_rfc3986 ( $e -> getMessage ());
killme ();
}
echo $r ;
killme ();
}
2017-12-24 02:20:50 +00:00
/**
* Returns an OAuth Access Token .
*
* @ return array | string
* @ see https :// oauth . net / core / 1.0 / #auth_step3
*/
2018-01-04 14:51:05 +00:00
function api_oauth_access_token ()
2017-11-10 05:00:50 +00:00
{
2017-12-05 02:10:54 +00:00
$oauth1 = new FKOAuth1 ();
2017-11-10 05:00:50 +00:00
try {
2017-12-05 02:10:54 +00:00
$r = $oauth1 -> fetch_access_token ( OAuthRequest :: from_request ());
2017-11-10 05:00:50 +00:00
} catch ( Exception $e ) {
echo " error= " . OAuthUtil :: urlencode_rfc3986 ( $e -> getMessage ());
killme ();
}
echo $r ;
killme ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/oauth/request_token' , 'api_oauth_request_token' , false );
api_register_func ( 'api/oauth/access_token' , 'api_oauth_access_token' , false );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief delete a complete photoalbum with all containing photos from database through api
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_fr_photoalbum_delete ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
}
// input params
$album = ( x ( $_REQUEST , 'album' ) ? $_REQUEST [ 'album' ] : " " );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// we do not allow calls without album string
if ( $album == " " ) {
throw new BadRequestException ( " no albumname specified " );
}
// check if album is existing
$r = q (
" SELECT DISTINCT `resource-id` FROM `photo` WHERE `uid` = %d AND `album` = '%s' " ,
intval ( api_user ()),
dbesc ( $album )
);
2017-12-23 23:27:45 +00:00
if ( ! DBM :: is_result ( $r )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( " album not available " );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore
// to the user and the contacts of the users (drop_items() performs the federation of the deletion to other networks
foreach ( $r as $rr ) {
$photo_item = q (
" SELECT `id` FROM `item` WHERE `uid` = %d AND `resource-id` = '%s' AND `type` = 'photo' " ,
intval ( local_user ()),
dbesc ( $rr [ 'resource-id' ])
2016-09-25 16:50:08 +00:00
);
2017-11-10 05:00:50 +00:00
if ( ! DBM :: is_result ( $photo_item )) {
throw new InternalServerErrorException ( " problem with deleting items occured " );
2017-04-19 21:03:44 +00:00
}
2018-01-17 23:22:01 +00:00
Item :: delete ( $photo_item [ 0 ][ 'id' ]);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// now let's delete all photos from the album
2018-01-15 13:05:12 +00:00
$result = dba :: delete ( 'photo' , [ 'uid' => api_user (), 'album' => $album ]);
2017-11-10 05:00:50 +00:00
// return success of deletion or error message
if ( $result ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'deleted' , 'message' => 'album `' . $album . '` with all containing photos has been deleted.' ];
return api_format_data ( " photoalbum_delete " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
throw new InternalServerErrorException ( " unknown error - deleting from database failed " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief update the name of the album for all photos of an album
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_fr_photoalbum_update ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// input params
$album = ( x ( $_REQUEST , 'album' ) ? $_REQUEST [ 'album' ] : " " );
$album_new = ( x ( $_REQUEST , 'album_new' ) ? $_REQUEST [ 'album_new' ] : " " );
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// we do not allow calls without album string
if ( $album == " " ) {
throw new BadRequestException ( " no albumname specified " );
}
if ( $album_new == " " ) {
throw new BadRequestException ( " no new albumname specified " );
}
// check if album is existing
$r = q (
" SELECT `id` FROM `photo` WHERE `uid` = %d AND `album` = '%s' " ,
intval ( api_user ()),
dbesc ( $album )
);
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " album not available " );
}
// now let's update all photos to the albumname
$result = q (
" UPDATE `photo` SET `album` = '%s' WHERE `uid` = %d AND `album` = '%s' " ,
dbesc ( $album_new ),
intval ( api_user ()),
dbesc ( $album )
);
// return success of updating or error message
if ( $result ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'updated' , 'message' => 'album `' . $album . '` with all containing photos has been renamed to `' . $album_new . '`.' ];
return api_format_data ( " photoalbum_update " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
throw new InternalServerErrorException ( " unknown error - updating in database failed " );
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief list all photos of the authenticated user
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_fr_photos_list ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
}
$r = q (
" SELECT `resource-id`, MAX(scale) AS `scale`, `album`, `filename`, `type`, MAX(`created`) AS `created`,
MAX ( `edited` ) AS `edited` , MAX ( `desc` ) AS `desc` FROM `photo`
WHERE `uid` = % d AND `album` != 'Contact Photos' GROUP BY `resource-id` " ,
intval ( local_user ())
);
2018-01-15 13:05:12 +00:00
$typetoext = [
2017-11-10 05:00:50 +00:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 13:05:12 +00:00
];
$data = [ 'photo' => []];
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
foreach ( $r as $rr ) {
2018-01-15 13:05:12 +00:00
$photo = [];
2017-11-10 05:00:50 +00:00
$photo [ 'id' ] = $rr [ 'resource-id' ];
$photo [ 'album' ] = $rr [ 'album' ];
$photo [ 'filename' ] = $rr [ 'filename' ];
$photo [ 'type' ] = $rr [ 'type' ];
$thumb = System :: baseUrl () . " /photo/ " . $rr [ 'resource-id' ] . " - " . $rr [ 'scale' ] . " . " . $typetoext [ $rr [ 'type' ]];
$photo [ 'created' ] = $rr [ 'created' ];
$photo [ 'edited' ] = $rr [ 'edited' ];
$photo [ 'desc' ] = $rr [ 'desc' ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
2018-01-15 13:05:12 +00:00
$data [ 'photo' ][] = [ " @attributes " => $photo , " 1 " => $thumb ];
2017-04-05 20:07:55 +00:00
} else {
2017-11-10 05:00:50 +00:00
$photo [ 'thumb' ] = $thumb ;
$data [ 'photo' ][] = $photo ;
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
}
return api_format_data ( " photos " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief upload a new photo or change an existing photo
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_fr_photo_create_update ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
}
// input params
$photo_id = ( x ( $_REQUEST , 'photo_id' ) ? $_REQUEST [ 'photo_id' ] : null );
$desc = ( x ( $_REQUEST , 'desc' ) ? $_REQUEST [ 'desc' ] : ( array_key_exists ( 'desc' , $_REQUEST ) ? " " : null )); // extra check necessary to distinguish between 'not provided' and 'empty string'
$album = ( x ( $_REQUEST , 'album' ) ? $_REQUEST [ 'album' ] : null );
$album_new = ( x ( $_REQUEST , 'album_new' ) ? $_REQUEST [ 'album_new' ] : null );
$allow_cid = ( x ( $_REQUEST , 'allow_cid' ) ? $_REQUEST [ 'allow_cid' ] : ( array_key_exists ( 'allow_cid' , $_REQUEST ) ? " " : null ));
$deny_cid = ( x ( $_REQUEST , 'deny_cid' ) ? $_REQUEST [ 'deny_cid' ] : ( array_key_exists ( 'deny_cid' , $_REQUEST ) ? " " : null ));
$allow_gid = ( x ( $_REQUEST , 'allow_gid' ) ? $_REQUEST [ 'allow_gid' ] : ( array_key_exists ( 'allow_gid' , $_REQUEST ) ? " " : null ));
$deny_gid = ( x ( $_REQUEST , 'deny_gid' ) ? $_REQUEST [ 'deny_gid' ] : ( array_key_exists ( 'deny_gid' , $_REQUEST ) ? " " : null ));
$visibility = ( x ( $_REQUEST , 'visibility' ) ? (( $_REQUEST [ 'visibility' ] == " true " || $_REQUEST [ 'visibility' ] == 1 ) ? true : false ) : false );
// do several checks on input parameters
// we do not allow calls without album string
if ( $album == null ) {
throw new BadRequestException ( " no albumname specified " );
}
// if photo_id == null --> we are uploading a new photo
if ( $photo_id == null ) {
$mode = " create " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// error if no media posted in create-mode
if ( ! x ( $_FILES , 'media' )) {
// Output error
throw new BadRequestException ( " no media data submitted " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// album_new will be ignored in create-mode
$album_new = " " ;
} else {
$mode = " update " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// check if photo is existing in database
$r = q (
" SELECT `id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' AND `album` = '%s' " ,
intval ( api_user ()),
dbesc ( $photo_id ),
dbesc ( $album )
);
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " photo not available " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// checks on acl strings provided by clients
$acl_input_error = false ;
$acl_input_error |= check_acl_input ( $allow_cid );
$acl_input_error |= check_acl_input ( $deny_cid );
$acl_input_error |= check_acl_input ( $allow_gid );
$acl_input_error |= check_acl_input ( $deny_gid );
if ( $acl_input_error ) {
throw new BadRequestException ( " acl data invalid " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// now let's upload the new media in create-mode
if ( $mode == " create " ) {
$media = $_FILES [ 'media' ];
$data = save_media_to_database ( " photo " , $media , $type , $album , trim ( $allow_cid ), trim ( $deny_cid ), trim ( $allow_gid ), trim ( $deny_gid ), $desc , $visibility );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// return success of updating or error message
if ( ! is_null ( $data )) {
return api_format_data ( " photo_create " , $type , $data );
} else {
throw new InternalServerErrorException ( " unknown error - uploading photo failed, see Friendica log for more information " );
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// now let's do the changes in update-mode
if ( $mode == " update " ) {
$sql_extra = " " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $desc )) {
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `desc` = ' $desc ' " ;
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $album_new )) {
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `album` = ' $album_new ' " ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $allow_cid )) {
$allow_cid = trim ( $allow_cid );
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `allow_cid` = ' $allow_cid ' " ;
2017-04-05 20:07:55 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $deny_cid )) {
$deny_cid = trim ( $deny_cid );
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `deny_cid` = ' $deny_cid ' " ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $allow_gid )) {
$allow_gid = trim ( $allow_gid );
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `allow_gid` = ' $allow_gid ' " ;
}
2017-01-09 12:09:01 +00:00
2017-11-10 05:00:50 +00:00
if ( ! is_null ( $deny_gid )) {
$deny_gid = trim ( $deny_gid );
$sql_extra .= (( $sql_extra != " " ) ? " , " : " " ) . " `deny_gid` = ' $deny_gid ' " ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$result = false ;
if ( $sql_extra != " " ) {
$nothingtodo = false ;
$result = q (
" UPDATE `photo` SET %s, `edited`='%s' WHERE `uid` = %d AND `resource-id` = '%s' AND `album` = '%s' " ,
$sql_extra ,
datetime_convert (), // update edited timestamp
intval ( api_user ()),
dbesc ( $photo_id ),
dbesc ( $album )
);
} else {
$nothingtodo = true ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( x ( $_FILES , 'media' )) {
$nothingtodo = false ;
$media = $_FILES [ 'media' ];
$data = save_media_to_database ( " photo " , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , 0 , $visibility , $photo_id );
if ( ! is_null ( $data )) {
return api_format_data ( " photo_update " , $type , $data );
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
// return success of updating or error message
if ( $result ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'updated' , 'message' => 'Image id `' . $photo_id . '` has been updated.' ];
return api_format_data ( " photo_update " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
if ( $nothingtodo ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'cancelled' , 'message' => 'Nothing to update for image id `' . $photo_id . '`.' ];
return api_format_data ( " photo_update " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
throw new InternalServerErrorException ( " unknown error - update photo entry in database failed " );
}
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
throw new InternalServerErrorException ( " unknown error - this error on uploading or updating a photo should never happen " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief delete a single photo from the database through api
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_fr_photo_delete ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
}
// input params
$photo_id = ( x ( $_REQUEST , 'photo_id' ) ? $_REQUEST [ 'photo_id' ] : null );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// do several checks on input parameters
// we do not allow calls without photo id
if ( $photo_id == null ) {
throw new BadRequestException ( " no photo_id specified " );
}
// check if photo is existing in database
$r = q (
" SELECT `id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' " ,
intval ( api_user ()),
dbesc ( $photo_id )
);
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " photo not available " );
}
// now we can perform on the deletion of the photo
2018-01-15 13:05:12 +00:00
$result = dba :: delete ( 'photo' , [ 'uid' => api_user (), 'resource-id' => $photo_id ]);
2017-11-10 05:00:50 +00:00
// return success of deletion or error message
if ( $result ) {
// retrieve the id of the parent element (the photo element)
$photo_item = q (
" SELECT `id` FROM `item` WHERE `uid` = %d AND `resource-id` = '%s' AND `type` = 'photo' " ,
intval ( local_user ()),
dbesc ( $photo_id )
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! DBM :: is_result ( $photo_item )) {
throw new InternalServerErrorException ( " problem with deleting items occured " );
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
// function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore
// to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion)
2018-01-17 23:22:01 +00:00
Item :: delete ( $photo_item [ 0 ][ 'id' ]);
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'deleted' , 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.' ];
return api_format_data ( " photo_delete " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
throw new InternalServerErrorException ( " unknown error on deleting photo from database table " );
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief returns the details of a specified photo id , if scale is given , returns the photo data in base 64
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-25 20:14:02 +00:00
* @ return string | array
2017-11-10 05:00:50 +00:00
*/
function api_fr_photo_detail ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
}
if ( ! x ( $_REQUEST , 'photo_id' )) {
throw new BadRequestException ( " No photo id. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$scale = ( x ( $_REQUEST , 'scale' ) ? intval ( $_REQUEST [ 'scale' ]) : false );
$photo_id = $_REQUEST [ 'photo_id' ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// prepare json/xml output with data from database for the requested photo
$data = prepare_photo_data ( $type , $scale , $photo_id );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return api_format_data ( " photo_detail " , $type , $data );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Updates the user’ s profile image .
*
2017-11-10 05:00:50 +00:00
* @ brief updates the profile image for the user ( either a specified profile or the default profile )
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-24 02:20:50 +00:00
*
2017-11-10 05:00:50 +00:00
* @ return string
2017-12-24 02:20:50 +00:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / post - account - update_profile_image
2017-11-10 05:00:50 +00:00
*/
function api_account_update_profile_image ( $type )
{
if ( api_user () === false ) {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// input params
2018-01-04 01:54:35 +00:00
$profileid = defaults ( $_REQUEST , 'profile_id' , 0 );
2017-04-05 20:17:15 +00:00
2017-11-10 05:00:50 +00:00
// error if image data is missing
if ( ! x ( $_FILES , 'image' )) {
throw new BadRequestException ( " no media data submitted " );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// check if specified profile id is valid
if ( $profileid != 0 ) {
$r = q (
" SELECT `id` FROM `profile` WHERE `uid` = %d AND `id` = %d " ,
intval ( api_user ()),
intval ( $profileid )
);
// error message if specified profile id is not in database
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " profile_id not available " );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$is_default_profile = $r [ 'profile' ];
} else {
$is_default_profile = 1 ;
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// get mediadata from image or media (Twitter call api/account/update_profile_image provides image)
$media = null ;
if ( x ( $_FILES , 'image' )) {
$media = $_FILES [ 'image' ];
} elseif ( x ( $_FILES , 'media' )) {
$media = $_FILES [ 'media' ];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// save new profile image
2018-01-21 16:38:01 +00:00
$data = save_media_to_database ( " profileimage " , $media , $type , L10n :: t ( 'Profile Photos' ), " " , " " , " " , " " , " " , $is_default_profile );
2017-11-10 05:00:50 +00:00
// get filetype
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
if ( $filetype == " image/jpeg " ) {
$fileext = " jpg " ;
} elseif ( $filetype == " image/png " ) {
$fileext = " png " ;
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
// change specified profile or all profiles to the new resource-id
if ( $is_default_profile ) {
2018-01-04 01:54:35 +00:00
q (
2017-11-10 05:00:50 +00:00
" UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d " ,
dbesc ( $data [ 'photo' ][ 'id' ]),
intval ( local_user ())
);
2017-04-05 20:07:55 +00:00
2018-01-04 01:54:35 +00:00
q (
2017-11-10 05:00:50 +00:00
" UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s' WHERE `self` AND `uid` = %d " ,
dbesc ( System :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-4.' . $fileext ),
dbesc ( System :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-5.' . $fileext ),
dbesc ( System :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-6.' . $fileext ),
2016-09-25 16:50:08 +00:00
intval ( local_user ())
);
2017-11-10 05:00:50 +00:00
} else {
2018-01-04 01:54:35 +00:00
q (
2017-11-10 05:00:50 +00:00
" UPDATE `profile` SET `photo` = '%s', `thumb` = '%s' WHERE `id` = %d AND `uid` = %d " ,
dbesc ( System :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-4.' . $filetype ),
dbesc ( System :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-5.' . $filetype ),
intval ( $_REQUEST [ 'profile' ]),
intval ( local_user ())
2016-09-25 16:50:08 +00:00
);
}
2017-11-10 05:00:50 +00:00
// we'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
2017-05-01 20:19:48 +00:00
2018-01-04 01:54:35 +00:00
q (
2017-11-10 05:00:50 +00:00
" UPDATE `contact` SET `avatar-date` = '%s' WHERE `self` = 1 AND `uid` = %d " ,
dbesc ( datetime_convert ()),
intval ( local_user ())
);
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
// Update global directory in background
//$user = api_get_user(get_app());
$url = System :: baseUrl () . '/profile/' . get_app () -> user [ 'nickname' ];
if ( $url && strlen ( Config :: get ( 'system' , 'directory' ))) {
2017-11-18 07:59:30 +00:00
Worker :: add ( PRIORITY_LOW , " Directory " , $url );
2017-05-01 20:19:48 +00:00
}
2017-11-19 16:59:37 +00:00
Worker :: add ( PRIORITY_LOW , 'ProfileUpdate' , api_user ());
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
// output for client
if ( $data ) {
return api_account_verify_credentials ( $type );
} else {
// SaveMediaToDatabase failed for some reason
throw new InternalServerErrorException ( " image upload failed " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
}
// place api-register for photoalbum calls before 'api/friendica/photo', otherwise this function is never reached
api_register_func ( 'api/friendica/photoalbum/delete' , 'api_fr_photoalbum_delete' , true , API_METHOD_DELETE );
api_register_func ( 'api/friendica/photoalbum/update' , 'api_fr_photoalbum_update' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/photos/list' , 'api_fr_photos_list' , true );
api_register_func ( 'api/friendica/photo/create' , 'api_fr_photo_create_update' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/photo/update' , 'api_fr_photo_create_update' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/photo/delete' , 'api_fr_photo_delete' , true , API_METHOD_DELETE );
api_register_func ( 'api/friendica/photo' , 'api_fr_photo_detail' , true );
api_register_func ( 'api/account/update_profile_image' , 'api_account_update_profile_image' , true , API_METHOD_POST );
2017-12-22 23:46:01 +00:00
/**
* Update user profile
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
*
* @ return array | string
*/
function api_account_update_profile ( $type )
{
2017-12-26 00:05:00 +00:00
$local_user = api_user ();
2017-12-22 23:46:01 +00:00
$api_user = api_get_user ( get_app ());
2017-12-26 00:05:00 +00:00
if ( ! empty ( $_POST [ 'name' ])) {
2017-12-22 23:46:01 +00:00
dba :: update ( 'profile' , [ 'name' => $_POST [ 'name' ]], [ 'uid' => $local_user ]);
dba :: update ( 'user' , [ 'username' => $_POST [ 'name' ]], [ 'uid' => $local_user ]);
dba :: update ( 'contact' , [ 'name' => $_POST [ 'name' ]], [ 'uid' => $local_user , 'self' => 1 ]);
dba :: update ( 'contact' , [ 'name' => $_POST [ 'name' ]], [ 'id' => $api_user [ 'id' ]]);
}
2017-12-26 00:05:00 +00:00
if ( isset ( $_POST [ 'description' ])) {
2017-12-22 23:46:01 +00:00
dba :: update ( 'profile' , [ 'about' => $_POST [ 'description' ]], [ 'uid' => $local_user ]);
dba :: update ( 'contact' , [ 'about' => $_POST [ 'description' ]], [ 'uid' => $local_user , 'self' => 1 ]);
dba :: update ( 'contact' , [ 'about' => $_POST [ 'description' ]], [ 'id' => $api_user [ 'id' ]]);
}
2017-12-26 20:49:43 +00:00
Worker :: add ( PRIORITY_LOW , 'ProfileUpdate' , $local_user );
2017-12-26 00:08:51 +00:00
// Update global directory in background
2017-12-26 20:49:43 +00:00
if ( $api_user [ 'url' ] && strlen ( Config :: get ( 'system' , 'directory' ))) {
Worker :: add ( PRIORITY_LOW , " Directory " , $api_user [ 'url' ]);
2017-12-26 00:08:51 +00:00
}
2017-12-22 23:46:01 +00:00
return api_account_verify_credentials ( $type );
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/account/update_profile' , 'api_account_update_profile' , true , API_METHOD_POST );
2017-11-10 05:00:50 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $acl_string
*/
2017-11-10 05:00:50 +00:00
function check_acl_input ( $acl_string )
{
if ( $acl_string == null || $acl_string == " " ) {
return false ;
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
$contact_not_found = false ;
// split <x><y><z> into array of cid's
preg_match_all ( " /<[A-Za-z0-9]+>/ " , $acl_string , $array );
// check for each cid if it is available on server
$cid_array = $array [ 0 ];
foreach ( $cid_array as $cid ) {
$cid = str_replace ( " < " , " " , $cid );
$cid = str_replace ( " > " , " " , $cid );
$contact = q (
" SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d " ,
intval ( $cid ),
intval ( api_user ())
);
$contact_not_found |= ! DBM :: is_result ( $contact );
}
return $contact_not_found ;
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $mediatype
* @ param array $media
* @ param string $type
* @ param string $album
* @ param string $allow_cid
* @ param string $deny_cid
* @ param string $allow_gid
* @ param string $deny_gid
* @ param string $desc
* @ param integer $profile
* @ param boolean $visibility
* @ param string $photo_id
*/
2017-11-10 05:00:50 +00:00
function save_media_to_database ( $mediatype , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , $profile = 0 , $visibility = false , $photo_id = null )
{
$visitor = 0 ;
$src = " " ;
$filetype = " " ;
$filename = " " ;
$filesize = 0 ;
if ( is_array ( $media )) {
if ( is_array ( $media [ 'tmp_name' ])) {
$src = $media [ 'tmp_name' ][ 0 ];
} else {
$src = $media [ 'tmp_name' ];
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
if ( is_array ( $media [ 'name' ])) {
$filename = basename ( $media [ 'name' ][ 0 ]);
2017-05-01 20:19:48 +00:00
} else {
2017-11-10 05:00:50 +00:00
$filename = basename ( $media [ 'name' ]);
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
if ( is_array ( $media [ 'size' ])) {
$filesize = intval ( $media [ 'size' ][ 0 ]);
} else {
$filesize = intval ( $media [ 'size' ]);
2017-05-01 20:19:48 +00:00
}
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
}
}
2017-11-10 05:00:50 +00:00
if ( $filetype == " " ) {
2017-12-07 13:56:11 +00:00
$filetype = Image :: guessType ( $filename );
2017-11-10 05:00:50 +00:00
}
$imagedata = getimagesize ( $src );
if ( $imagedata ) {
$filetype = $imagedata [ 'mime' ];
}
logger (
" File upload src: " . $src . " - filename: " . $filename .
2017-12-23 23:27:45 +00:00
" - size: " . $filesize . " - type: " . $filetype ,
LOGGER_DEBUG
2017-11-10 05:00:50 +00:00
);
// check if there was a php upload error
if ( $filesize == 0 && $media [ 'error' ] == 1 ) {
throw new InternalServerErrorException ( " image size exceeds PHP config settings, file was rejected by server " );
}
// check against max upload size within Friendica instance
$maximagesize = Config :: get ( 'system' , 'maximagesize' );
2017-12-22 23:10:32 +00:00
if ( $maximagesize && ( $filesize > $maximagesize )) {
2017-11-10 05:00:50 +00:00
$formattedBytes = formatBytes ( $maximagesize );
throw new InternalServerErrorException ( " image size exceeds Friendica config setting (uploaded size: $formattedBytes ) " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
// create Photo instance with the data of the image
$imagedata = @ file_get_contents ( $src );
2017-12-07 13:56:11 +00:00
$Image = new Image ( $imagedata , $filetype );
if ( ! $Image -> isValid ()) {
2017-11-10 05:00:50 +00:00
throw new InternalServerErrorException ( " unable to process image data " );
}
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
// check orientation of image
2017-12-07 13:56:11 +00:00
$Image -> orient ( $src );
2017-11-10 05:00:50 +00:00
@ unlink ( $src );
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
// check max length of images on server
$max_length = Config :: get ( 'system' , 'max_image_length' );
if ( ! $max_length ) {
$max_length = MAX_IMAGE_LENGTH ;
}
if ( $max_length > 0 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( $max_length );
2017-11-10 05:00:50 +00:00
logger ( " File upload: Scaling picture to new size " . $max_length , LOGGER_DEBUG );
}
2017-12-07 13:56:11 +00:00
$width = $Image -> getWidth ();
$height = $Image -> getHeight ();
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
// create a new resource-id if not already provided
$hash = ( $photo_id == null ) ? photo_new_resource () : $photo_id ;
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
if ( $mediatype == " photo " ) {
// upload normal image (scales 0, 1, 2)
logger ( " photo upload: starting new photo upload " , LOGGER_DEBUG );
2017-05-01 20:19:48 +00:00
2017-12-07 13:56:11 +00:00
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 0 , 0 , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-11-10 05:00:50 +00:00
if ( ! $r ) {
logger ( " photo upload: image upload with scale 0 (original size) failed " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
if ( $width > 640 || $height > 640 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( 640 );
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 1 , 0 , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-05-01 20:19:48 +00:00
if ( ! $r ) {
2017-11-10 05:00:50 +00:00
logger ( " photo upload: image upload with scale 1 (640x640) failed " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
if ( $width > 320 || $height > 320 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( 320 );
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 2 , 0 , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-11-10 05:00:50 +00:00
if ( ! $r ) {
logger ( " photo upload: image upload with scale 2 (320x320) failed " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
}
logger ( " photo upload: new photo upload ended " , LOGGER_DEBUG );
} elseif ( $mediatype == " profileimage " ) {
// upload profile image (scales 4, 5, 6)
logger ( " photo upload: starting new profile image upload " , LOGGER_DEBUG );
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
if ( $width > 175 || $height > 175 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( 175 );
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 4 , $profile , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-11-10 05:00:50 +00:00
if ( ! $r ) {
logger ( " photo upload: profile image upload with scale 4 (175x175) failed " );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2017-11-10 05:00:50 +00:00
if ( $width > 80 || $height > 80 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( 80 );
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 5 , $profile , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-11-10 05:00:50 +00:00
if ( ! $r ) {
logger ( " photo upload: profile image upload with scale 5 (80x80) failed " );
2017-05-01 20:19:48 +00:00
}
}
2017-11-10 05:00:50 +00:00
if ( $width > 48 || $height > 48 ) {
2017-12-07 13:56:11 +00:00
$Image -> scaleDown ( 48 );
$r = Photo :: store ( $Image , local_user (), $visitor , $hash , $filename , $album , 6 , $profile , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2017-11-10 05:00:50 +00:00
if ( ! $r ) {
logger ( " photo upload: profile image upload with scale 6 (48x48) failed " );
2017-05-01 20:19:48 +00:00
}
}
2017-12-07 13:56:11 +00:00
$Image -> __destruct ();
2017-11-10 05:00:50 +00:00
logger ( " photo upload: new profile image upload ended " , LOGGER_DEBUG );
2017-05-01 20:19:48 +00:00
}
2017-11-10 05:00:50 +00:00
if ( $r ) {
// create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo
if ( $photo_id == null && $mediatype == " photo " ) {
post_photo_item ( $hash , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility );
}
// on success return image data in json/xml format (like /api/friendica/photo does when no scale is given)
return prepare_photo_data ( $type , false , $hash );
} else {
throw new InternalServerErrorException ( " image upload failed " );
}
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $hash
* @ param string $allow_cid
* @ param string $deny_cid
* @ param string $allow_gid
* @ param string $deny_gid
* @ param string $filetype
* @ param boolean $visibility
*/
2017-11-10 05:00:50 +00:00
function post_photo_item ( $hash , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility = false )
{
// get data about the api authenticated user
$uri = item_new_uri ( get_app () -> get_hostname (), intval ( api_user ()));
$owner_record = q ( " SELECT * FROM `contact` WHERE `uid`= %d AND `self` LIMIT 1 " , intval ( api_user ()));
2018-01-15 13:05:12 +00:00
$arr = [];
2017-11-10 05:00:50 +00:00
$arr [ 'guid' ] = get_guid ( 32 );
$arr [ 'uid' ] = intval ( api_user ());
$arr [ 'uri' ] = $uri ;
$arr [ 'parent-uri' ] = $uri ;
$arr [ 'type' ] = 'photo' ;
$arr [ 'wall' ] = 1 ;
$arr [ 'resource-id' ] = $hash ;
$arr [ 'contact-id' ] = $owner_record [ 0 ][ 'id' ];
$arr [ 'owner-name' ] = $owner_record [ 0 ][ 'name' ];
$arr [ 'owner-link' ] = $owner_record [ 0 ][ 'url' ];
$arr [ 'owner-avatar' ] = $owner_record [ 0 ][ 'thumb' ];
$arr [ 'author-name' ] = $owner_record [ 0 ][ 'name' ];
$arr [ 'author-link' ] = $owner_record [ 0 ][ 'url' ];
$arr [ 'author-avatar' ] = $owner_record [ 0 ][ 'thumb' ];
$arr [ 'title' ] = " " ;
$arr [ 'allow_cid' ] = $allow_cid ;
$arr [ 'allow_gid' ] = $allow_gid ;
$arr [ 'deny_cid' ] = $deny_cid ;
$arr [ 'deny_gid' ] = $deny_gid ;
$arr [ 'visible' ] = $visibility ;
$arr [ 'origin' ] = 1 ;
2018-01-15 13:05:12 +00:00
$typetoext = [
2017-04-05 20:07:55 +00:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 13:05:12 +00:00
];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// adds link to the thumbnail scale photo
$arr [ 'body' ] = '[url=' . System :: baseUrl () . '/photos/' . $owner_record [ 0 ][ 'nick' ] . '/image/' . $hash . ']'
. '[img]' . System :: baseUrl () . '/photo/' . $hash . '-' . " 2 " . '.' . $typetoext [ $filetype ] . '[/img]'
. '[/url]' ;
// do the magic for storing the item in the database and trigger the federation to other contacts
item_store ( $arr );
}
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type
* @ param int $scale
* @ param string $photo_id
*
* @ return array
*/
2017-11-10 05:00:50 +00:00
function prepare_photo_data ( $type , $scale , $photo_id )
{
$scale_sql = ( $scale === false ? " " : sprintf ( " AND scale=%d " , intval ( $scale )));
$data_sql = ( $scale === false ? " " : " data, " );
// added allow_cid, allow_gid, deny_cid, deny_gid to output as string like stored in database
// clients needs to convert this in their way for further processing
$r = q (
" SELECT %s `resource-id`, `created`, `edited`, `title`, `desc`, `album`, `filename`,
`type` , `height` , `width` , `datasize` , `profile` , `allow_cid` , `deny_cid` , `allow_gid` , `deny_gid` ,
MIN ( `scale` ) AS `minscale` , MAX ( `scale` ) AS `maxscale`
FROM `photo` WHERE `uid` = % d AND `resource-id` = '%s' % s GROUP BY `resource-id` " ,
$data_sql ,
intval ( local_user ()),
dbesc ( $photo_id ),
$scale_sql
);
2018-01-15 13:05:12 +00:00
$typetoext = [
2017-11-10 05:00:50 +00:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
// prepare output data for photo
if ( DBM :: is_result ( $r )) {
2018-01-15 13:05:12 +00:00
$data = [ 'photo' => $r [ 0 ]];
2017-11-10 05:00:50 +00:00
$data [ 'photo' ][ 'id' ] = $data [ 'photo' ][ 'resource-id' ];
if ( $scale !== false ) {
$data [ 'photo' ][ 'data' ] = base64_encode ( $data [ 'photo' ][ 'data' ]);
2016-09-25 16:50:08 +00:00
} else {
2017-11-10 05:00:50 +00:00
unset ( $data [ 'photo' ][ 'datasize' ]); //needed only with scale param
2016-09-25 16:50:08 +00:00
}
2017-05-01 20:19:48 +00:00
if ( $type == " xml " ) {
2018-01-15 13:05:12 +00:00
$data [ 'photo' ][ 'links' ] = [];
2017-11-10 05:00:50 +00:00
for ( $k = intval ( $data [ 'photo' ][ 'minscale' ]); $k <= intval ( $data [ 'photo' ][ 'maxscale' ]); $k ++ ) {
2018-01-15 13:05:12 +00:00
$data [ 'photo' ][ 'links' ][ $k . " :link " ][ " @attributes " ] = [ " type " => $data [ 'photo' ][ 'type' ],
2017-11-10 05:00:50 +00:00
" scale " => $k ,
2018-01-15 13:05:12 +00:00
" href " => System :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]]];
2017-05-01 20:19:48 +00:00
}
} else {
2018-01-15 13:05:12 +00:00
$data [ 'photo' ][ 'link' ] = [];
2017-11-10 05:00:50 +00:00
// when we have profile images we could have only scales from 4 to 6, but index of array always needs to start with 0
$i = 0 ;
for ( $k = intval ( $data [ 'photo' ][ 'minscale' ]); $k <= intval ( $data [ 'photo' ][ 'maxscale' ]); $k ++ ) {
$data [ 'photo' ][ 'link' ][ $i ] = System :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]];
$i ++ ;
2017-05-01 20:19:48 +00:00
}
}
2017-11-10 05:00:50 +00:00
unset ( $data [ 'photo' ][ 'resource-id' ]);
unset ( $data [ 'photo' ][ 'minscale' ]);
unset ( $data [ 'photo' ][ 'maxscale' ]);
} else {
throw new NotFoundException ();
}
// retrieve item element for getting activities (like, dislike etc.) related to photo
$item = q (
" SELECT * FROM `item` WHERE `uid` = %d AND `resource-id` = '%s' AND `type` = 'photo' " ,
intval ( local_user ()),
dbesc ( $photo_id )
);
$data [ 'photo' ][ 'friendica_activities' ] = api_format_items_activities ( $item [ 0 ], $type );
// retrieve comments on photo
$r = q (
" SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact` . `name` , `contact` . `photo` , `contact` . `url` , `contact` . `rel` ,
`contact` . `network` , `contact` . `thumb` , `contact` . `dfrn-id` , `contact` . `self` ,
`contact` . `id` AS `cid`
FROM `item`
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `contact-id` AND `contact` . `uid` = `item` . `uid`
AND ( NOT `contact` . `blocked` OR `contact` . `pending` )
WHERE `item` . `parent` = % d AND `item` . `visible`
AND NOT `item` . `moderated` AND NOT `item` . `deleted`
AND `item` . `uid` = % d AND ( `item` . `verb` = '%s' OR `type` = 'photo' ) " ,
intval ( $item [ 0 ][ 'parent' ]),
intval ( api_user ()),
dbesc ( ACTIVITY_POST )
);
// prepare output of comments
$commentData = api_format_items ( $r , api_get_user ( get_app ()), false , $type );
2018-01-15 13:05:12 +00:00
$comments = [];
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$k = 0 ;
foreach ( $commentData as $comment ) {
$comments [ $k ++ . " :comment " ] = $comment ;
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
} else {
foreach ( $commentData as $comment ) {
$comments [] = $comment ;
}
}
$data [ 'photo' ][ 'friendica_comments' ] = $comments ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// include info if rights on photo and rights on item are mismatching
$rights_mismatch = $data [ 'photo' ][ 'allow_cid' ] != $item [ 0 ][ 'allow_cid' ] ||
$data [ 'photo' ][ 'deny_cid' ] != $item [ 0 ][ 'deny_cid' ] ||
$data [ 'photo' ][ 'allow_gid' ] != $item [ 0 ][ 'allow_gid' ] ||
$data [ 'photo' ][ 'deny_cid' ] != $item [ 0 ][ 'deny_cid' ];
$data [ 'photo' ][ 'rights_mismatch' ] = $rights_mismatch ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $data ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* Similar as / mod / redir . php
* redirect to 'url' after dfrn auth
*
* Why this when there is mod / redir . php already ?
* This use api_user () and api_login ()
*
* params
* c_url : url of remote contact to auth to
* url : string , url to redirect after auth
*/
function api_friendica_remoteauth ()
{
2017-12-22 23:00:49 +00:00
$url = ( x ( $_GET , 'url' ) ? $_GET [ 'url' ] : '' );
$c_url = ( x ( $_GET , 'c_url' ) ? $_GET [ 'c_url' ] : '' );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $url === '' || $c_url === '' ) {
throw new BadRequestException ( " Wrong parameters. " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$c_url = normalise_link ( $c_url );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// traditional DFRN
2016-09-25 16:50:08 +00:00
2018-01-11 08:26:30 +00:00
$contact = dba :: selectFirst ( 'contact' , [], [ 'uid' => api_user (), 'nurl' => $c_url ]);
2016-09-25 16:50:08 +00:00
2018-01-11 08:26:30 +00:00
if ( ! DBM :: is_result ( $contact ) || ( $contact [ 'network' ] !== NETWORK_DFRN )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( " Unknown contact " );
}
2018-01-11 08:26:30 +00:00
$cid = $contact [ 'id' ];
2017-11-10 05:00:50 +00:00
2018-01-11 08:26:30 +00:00
$dfrn_id = defaults ( $contact , 'issued-id' , $contact [ 'dfrn-id' ]);
2017-11-10 05:00:50 +00:00
2018-01-11 08:26:30 +00:00
if ( $contact [ 'duplex' ] && $contact [ 'issued-id' ]) {
$orig_id = $contact [ 'issued-id' ];
2017-11-10 05:00:50 +00:00
$dfrn_id = '1:' . $orig_id ;
}
2018-01-11 08:26:30 +00:00
if ( $contact [ 'duplex' ] && $contact [ 'dfrn-id' ]) {
$orig_id = $contact [ 'dfrn-id' ];
2017-11-10 05:00:50 +00:00
$dfrn_id = '0:' . $orig_id ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$sec = random_string ();
q (
" INSERT INTO `profile_check` ( `uid`, `cid`, `dfrn_id`, `sec`, `expire`)
VALUES ( % d , % s , '%s' , '%s' , % d ) " ,
intval ( api_user ()),
intval ( $cid ),
dbesc ( $dfrn_id ),
dbesc ( $sec ),
intval ( time () + 45 )
);
2018-01-11 08:26:30 +00:00
logger ( $contact [ 'name' ] . ' ' . $sec , LOGGER_DEBUG );
2017-12-22 23:00:49 +00:00
$dest = ( $url ? '&destination_url=' . $url : '' );
2017-11-10 05:00:50 +00:00
goaway (
2018-01-11 08:26:30 +00:00
$contact [ 'poll' ] . '?dfrn_id=' . $dfrn_id
2017-11-10 05:00:50 +00:00
. '&dfrn_version=' . DFRN_PROTOCOL_VERSION
. '&type=profile&sec=' . $sec . $dest . $quiet
);
}
api_register_func ( 'api/friendica/remoteauth' , 'api_friendica_remoteauth' , true );
/**
* @ brief Return the item shared , if the item contains only the [ share ] tag
*
* @ param array $item Sharer item
2017-12-23 00:36:55 +00:00
* @ return array | false Shared item or false if not a reshare
2017-11-10 05:00:50 +00:00
*/
function api_share_as_retweet ( & $item )
{
$body = trim ( $item [ " body " ]);
2017-11-23 19:01:58 +00:00
if ( Diaspora :: isReshare ( $body , false ) === false ) {
2017-11-10 05:00:50 +00:00
return false ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
/// @TODO "$1" should maybe mean '$1' ?
$attributes = preg_replace ( " / \ [share(.*?) \ ] \ s?(.*?) \ s? \ [ \ /share \ ] \ s?/ism " , " $ 1 " , $body );
/*
* Skip if there is no shared message in there
2017-11-23 19:01:58 +00:00
* we already checked this in diaspora :: isReshare ()
2017-11-10 05:00:50 +00:00
* but better one more than one less ...
*/
if ( $body == $attributes ) {
return false ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// build the fake reshared item
$reshared_item = $item ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$author = " " ;
preg_match ( " /author='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$author = html_entity_decode ( $matches [ 1 ], ENT_QUOTES , 'UTF-8' );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match ( '/author="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$author = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$profile = " " ;
preg_match ( " /profile='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$profile = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match ( '/profile="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$profile = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$avatar = " " ;
preg_match ( " /avatar='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$avatar = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match ( '/avatar="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$avatar = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$link = " " ;
preg_match ( " /link='(.*?)'/ism " , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$link = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match ( '/link="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$link = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$posted = " " ;
preg_match ( " /posted='(.*?)'/ism " , $attributes , $matches );
2017-12-23 23:27:45 +00:00
if ( $matches [ 1 ] != " " ) {
2017-11-10 05:00:50 +00:00
$posted = $matches [ 1 ];
2017-12-23 23:27:45 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
preg_match ( '/posted="(.*?)"/ism' , $attributes , $matches );
if ( $matches [ 1 ] != " " ) {
$posted = $matches [ 1 ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$shared_body = preg_replace ( " / \ [share(.*?) \ ] \ s?(.*?) \ s? \ [ \ /share \ ] \ s?/ism " , " $ 2 " , $body );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if (( $shared_body == " " ) || ( $profile == " " ) || ( $author == " " ) || ( $avatar == " " ) || ( $posted == " " )) {
return false ;
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$reshared_item [ " body " ] = $shared_body ;
$reshared_item [ " author-name " ] = $author ;
$reshared_item [ " author-link " ] = $profile ;
$reshared_item [ " author-avatar " ] = $avatar ;
$reshared_item [ " plink " ] = $link ;
$reshared_item [ " created " ] = $posted ;
$reshared_item [ " edited " ] = $posted ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $reshared_item ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $profile
*
* @ return string | false
* @ todo remove trailing junk from profile url
* @ todo pump . io check has to check the website
*/
2017-11-10 05:00:50 +00:00
function api_get_nick ( $profile )
{
$nick = " " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' " ,
dbesc ( normalise_link ( $profile ))
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$nick = $r [ 0 ][ " nick " ];
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $nick == " " ) {
$r = q (
" SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' " ,
dbesc ( normalise_link ( $profile ))
);
2017-04-05 20:07:55 +00:00
2017-11-08 03:57:46 +00:00
if ( DBM :: is_result ( $r )) {
2016-09-25 16:50:08 +00:00
$nick = $r [ 0 ][ " nick " ];
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $nick == " " ) {
$friendica = preg_replace ( " =https?://(.*)/profile/(.*)=ism " , " $ 2 " , $profile );
if ( $friendica != $profile ) {
$nick = $friendica ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $nick == " " ) {
$diaspora = preg_replace ( " =https?://(.*)/u/(.*)=ism " , " $ 2 " , $profile );
if ( $diaspora != $profile ) {
$nick = $diaspora ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $nick == " " ) {
$twitter = preg_replace ( " =https?://twitter.com/(.*)=ism " , " $ 1 " , $profile );
if ( $twitter != $profile ) {
$nick = $twitter ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( ! $nick == " " ) {
$StatusnetHost = preg_replace ( " =https?://(.*)/user/(.*)=ism " , " $ 1 " , $profile );
if ( $StatusnetHost != $profile ) {
$StatusnetUser = preg_replace ( " =https?://(.*)/user/(.*)=ism " , " $ 2 " , $profile );
if ( $StatusnetUser != $profile ) {
2018-01-27 16:13:41 +00:00
$UserData = Network :: fetchUrl ( " http:// " . $StatusnetHost . " /api/users/show.json?user_id= " . $StatusnetUser );
2017-11-10 05:00:50 +00:00
$user = json_decode ( $UserData );
if ( $user ) {
$nick = $user -> screen_name ;
2016-09-25 16:50:08 +00:00
}
}
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// To-Do: look at the page if its really a pumpio site
//if (!$nick == "") {
// $pumpio = preg_replace("=https?://(.*)/(.*)/=ism", "$2", $profile."/");
// if ($pumpio != $profile)
// $nick = $pumpio;
// <div class="media" id="profile-block" data-profile-id="acct:kabniel@microca.st">
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
//}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $nick != " " ) {
return $nick ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
return false ;
}
2016-11-04 22:45:20 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param array $item
*
* @ return array
*/
2017-11-10 05:00:50 +00:00
function api_in_reply_to ( $item )
{
2018-01-15 13:05:12 +00:00
$in_reply_to = [];
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
$in_reply_to [ 'status_id' ] = null ;
$in_reply_to [ 'user_id' ] = null ;
$in_reply_to [ 'status_id_str' ] = null ;
$in_reply_to [ 'user_id_str' ] = null ;
$in_reply_to [ 'screen_name' ] = null ;
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
if (( $item [ 'thr-parent' ] != $item [ 'uri' ]) && ( intval ( $item [ 'parent' ]) != intval ( $item [ 'id' ]))) {
2017-12-23 23:27:45 +00:00
$r = q (
" SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1 " ,
2017-11-10 05:00:50 +00:00
intval ( $item [ 'uid' ]),
2017-12-23 23:27:45 +00:00
dbesc ( $item [ 'thr-parent' ])
);
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
$in_reply_to [ 'status_id' ] = intval ( $r [ 0 ][ 'id' ]);
} else {
$in_reply_to [ 'status_id' ] = intval ( $item [ 'parent' ]);
}
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
$in_reply_to [ 'status_id_str' ] = ( string ) intval ( $in_reply_to [ 'status_id' ]);
2016-11-04 22:45:20 +00:00
2017-12-23 23:27:45 +00:00
$r = q (
" SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item
2017-11-10 05:00:50 +00:00
STRAIGHT_JOIN `contact` ON `contact` . `id` = `item` . `author-id`
WHERE `item` . `id` = % d LIMIT 1 " ,
intval ( $in_reply_to [ 'status_id' ])
);
2016-11-04 22:45:20 +00:00
2017-11-10 05:00:50 +00:00
if ( DBM :: is_result ( $r )) {
if ( $r [ 0 ][ 'nick' ] == " " ) {
$r [ 0 ][ 'nick' ] = api_get_nick ( $r [ 0 ][ " url " ]);
2016-11-04 22:45:20 +00:00
}
2017-11-10 05:00:50 +00:00
$in_reply_to [ 'screen_name' ] = (( $r [ 0 ][ 'nick' ]) ? $r [ 0 ][ 'nick' ] : $r [ 0 ][ 'name' ]);
$in_reply_to [ 'user_id' ] = intval ( $r [ 0 ][ 'id' ]);
$in_reply_to [ 'user_id_str' ] = ( string ) intval ( $r [ 0 ][ 'id' ]);
2016-11-04 22:45:20 +00:00
}
2017-11-10 05:00:50 +00:00
// There seems to be situation, where both fields are identical:
// https://github.com/friendica/friendica/issues/1010
// This is a bugfix for that.
if ( intval ( $in_reply_to [ 'status_id' ]) == intval ( $item [ 'id' ])) {
logger ( 'this message should never appear: id: ' . $item [ 'id' ] . ' similar to reply-to: ' . $in_reply_to [ 'status_id' ], LOGGER_DEBUG );
$in_reply_to [ 'status_id' ] = null ;
$in_reply_to [ 'user_id' ] = null ;
$in_reply_to [ 'status_id_str' ] = null ;
$in_reply_to [ 'user_id_str' ] = null ;
$in_reply_to [ 'screen_name' ] = null ;
}
2016-11-04 22:45:20 +00:00
}
2017-11-10 05:00:50 +00:00
return $in_reply_to ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $Text
*
* @ return string
*/
2017-11-10 05:00:50 +00:00
function api_clean_plain_items ( $Text )
{
$include_entities = strtolower ( x ( $_REQUEST , 'include_entities' ) ? $_REQUEST [ 'include_entities' ] : " false " );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$Text = bb_CleanPictureLinks ( $Text );
$URLSearchString = " ^ \ [ \ ] " ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$Text = preg_replace ( " /([!#@]) \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '$1$3' , $Text );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $include_entities == " true " ) {
$Text = preg_replace ( " / \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '[url=$1]$1[/url]' , $Text );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// Simplify "attachment" element
$Text = api_clean_attachments ( $Text );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return ( $Text );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief Removes most sharing information for API text export
*
* @ param string $body The original body
*
* @ return string Cleaned body
*/
function api_clean_attachments ( $body )
{
2018-01-27 01:01:32 +00:00
$data = BBCode :: getAttachmentData ( $body );
2016-09-25 16:50:08 +00:00
2017-12-22 23:10:32 +00:00
if ( ! $data ) {
2016-09-25 16:50:08 +00:00
return $body ;
2017-12-22 23:10:32 +00:00
}
2017-11-10 05:00:50 +00:00
$body = " " ;
2016-09-25 16:50:08 +00:00
2017-12-22 23:10:32 +00:00
if ( isset ( $data [ " text " ])) {
2017-11-10 05:00:50 +00:00
$body = $data [ " text " ];
2017-12-22 23:10:32 +00:00
}
if (( $body == " " ) && isset ( $data [ " title " ])) {
2017-11-10 05:00:50 +00:00
$body = $data [ " title " ];
2017-12-22 23:10:32 +00:00
}
if ( isset ( $data [ " url " ])) {
2017-11-10 05:00:50 +00:00
$body .= " \n " . $data [ " url " ];
2017-12-22 23:10:32 +00:00
}
2017-11-10 05:00:50 +00:00
$body .= $data [ " after " ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
return $body ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param array $contacts
*
* @ return array
*/
2017-11-10 05:00:50 +00:00
function api_best_nickname ( & $contacts )
{
2018-01-15 13:05:12 +00:00
$best_contact = [];
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( count ( $contact ) == 0 ) {
2017-11-10 05:00:50 +00:00
return ;
2017-12-23 23:27:45 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
foreach ( $contacts as $contact ) {
2017-11-10 05:00:50 +00:00
if ( $contact [ " network " ] == " " ) {
$contact [ " network " ] = " dfrn " ;
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-11-10 05:00:50 +00:00
}
2017-12-23 23:27:45 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( sizeof ( $best_contact ) == 0 ) {
foreach ( $contacts as $contact ) {
if ( $contact [ " network " ] == " dfrn " ) {
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-12-23 23:27:45 +00:00
}
}
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( sizeof ( $best_contact ) == 0 ) {
foreach ( $contacts as $contact ) {
if ( $contact [ " network " ] == " dspr " ) {
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-12-23 23:27:45 +00:00
}
}
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( sizeof ( $best_contact ) == 0 ) {
foreach ( $contacts as $contact ) {
if ( $contact [ " network " ] == " stat " ) {
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-12-23 23:27:45 +00:00
}
}
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( sizeof ( $best_contact ) == 0 ) {
foreach ( $contacts as $contact ) {
if ( $contact [ " network " ] == " pump " ) {
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-12-23 23:27:45 +00:00
}
}
}
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( sizeof ( $best_contact ) == 0 ) {
foreach ( $contacts as $contact ) {
if ( $contact [ " network " ] == " twit " ) {
2018-01-15 13:05:12 +00:00
$best_contact = [ $contact ];
2017-12-23 23:27:45 +00:00
}
}
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( sizeof ( $best_contact ) == 1 ) {
$contacts = $best_contact ;
} else {
2018-01-15 13:05:12 +00:00
$contacts = [ $contacts [ 0 ]];
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
* Return all or a specified group of the user with the containing contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_friendica_group_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$gid = ( x ( $_REQUEST , 'gid' ) ? $_REQUEST [ 'gid' ] : 0 );
$uid = $user_info [ 'uid' ];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// get data of the specified group id or all groups if not specified
if ( $gid != 0 ) {
$r = q (
" SELECT * FROM `group` WHERE `deleted` = 0 AND `uid` = %d AND `id` = %d " ,
2016-09-25 16:50:08 +00:00
intval ( $uid ),
2017-11-10 05:00:50 +00:00
intval ( $gid )
);
2016-09-25 16:50:08 +00:00
// error message if specified gid is not in database
2017-12-23 23:27:45 +00:00
if ( ! DBM :: is_result ( $r )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( " gid not available " );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
} else {
$r = q (
" SELECT * FROM `group` WHERE `deleted` = 0 AND `uid` = %d " ,
intval ( $uid )
);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// loop through all groups and retrieve all members for adding data in the user array
foreach ( $r as $rr ) {
2017-12-09 18:45:17 +00:00
$members = Contact :: getByGroupId ( $rr [ 'id' ]);
2018-01-15 13:05:12 +00:00
$users = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$user_element = " users " ;
$k = 0 ;
foreach ( $members as $member ) {
$user = api_get_user ( $a , $member [ 'nurl' ]);
$users [ $k ++. " :user " ] = $user ;
}
} else {
$user_element = " user " ;
foreach ( $members as $member ) {
$user = api_get_user ( $a , $member [ 'nurl' ]);
$users [] = $user ;
2016-09-25 16:50:08 +00:00
}
}
2018-01-15 13:05:12 +00:00
$grps [] = [ 'name' => $rr [ 'name' ], 'gid' => $rr [ 'id' ], $user_element => $users ];
2017-11-10 05:00:50 +00:00
}
2018-01-15 13:05:12 +00:00
return api_format_data ( " groups " , $type , [ 'group' => $grps ]);
2017-11-10 05:00:50 +00:00
}
api_register_func ( 'api/friendica/group_show' , 'api_friendica_group_show' , true );
2017-12-24 02:20:50 +00:00
/**
* Delete the specified group of the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_friendica_group_delete ( $type )
{
$a = get_app ();
2017-12-09 18:42:02 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$gid = ( x ( $_REQUEST , 'gid' ) ? $_REQUEST [ 'gid' ] : 0 );
$name = ( x ( $_REQUEST , 'name' ) ? $_REQUEST [ 'name' ] : " " );
$uid = $user_info [ 'uid' ];
// error if no gid specified
2017-12-09 18:42:02 +00:00
if ( $gid == 0 || $name == " " ) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'gid or name not specified' );
2017-12-09 18:42:02 +00:00
}
2017-11-10 05:00:50 +00:00
// get data of the specified group id
$r = q (
" SELECT * FROM `group` WHERE `uid` = %d AND `id` = %d " ,
intval ( $uid ),
intval ( $gid )
);
// error message if specified gid is not in database
2017-12-09 18:42:02 +00:00
if ( ! DBM :: is_result ( $r )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'gid not available' );
2017-12-09 18:42:02 +00:00
}
2017-11-10 05:00:50 +00:00
// get data of the specified group id and group name
$rname = q (
" SELECT * FROM `group` WHERE `uid` = %d AND `id` = %d AND `name` = '%s' " ,
intval ( $uid ),
intval ( $gid ),
dbesc ( $name )
);
// error message if specified gid is not in database
2017-12-09 18:42:02 +00:00
if ( ! DBM :: is_result ( $rname )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'wrong group name' );
2017-12-09 18:42:02 +00:00
}
2017-11-10 05:00:50 +00:00
// delete group
2017-12-09 18:45:17 +00:00
$ret = Group :: removeByName ( $uid , $name );
2017-11-10 05:00:50 +00:00
if ( $ret ) {
// return success
2018-01-15 13:05:12 +00:00
$success = [ 'success' => $ret , 'gid' => $gid , 'name' => $name , 'status' => 'deleted' , 'wrong users' => []];
return api_format_data ( " group_delete " , $type , [ 'result' => $success ]);
2017-11-10 05:00:50 +00:00
} else {
throw new BadRequestException ( 'other API error' );
}
}
api_register_func ( 'api/friendica/group_delete' , 'api_friendica_group_delete' , true , API_METHOD_DELETE );
2017-12-24 02:20:50 +00:00
/**
* Create the specified group with the posted array of contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_friendica_group_create ( $type )
{
$a = get_app ();
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$name = ( x ( $_REQUEST , 'name' ) ? $_REQUEST [ 'name' ] : " " );
$uid = $user_info [ 'uid' ];
$json = json_decode ( $_POST [ 'json' ], true );
$users = $json [ 'user' ];
// error if no name specified
2017-12-23 23:27:45 +00:00
if ( $name == " " ) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'group name not specified' );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// get data of the specified group name
$rname = q (
" SELECT * FROM `group` WHERE `uid` = %d AND `name` = '%s' AND `deleted` = 0 " ,
intval ( $uid ),
dbesc ( $name )
);
// error message if specified group name already exists
2017-12-23 23:27:45 +00:00
if ( DBM :: is_result ( $rname )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'group name already exists' );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// check if specified group name is a deleted group
$rname = q (
" SELECT * FROM `group` WHERE `uid` = %d AND `name` = '%s' AND `deleted` = 1 " ,
intval ( $uid ),
dbesc ( $name )
);
// error message if specified group name already exists
2017-12-23 23:27:45 +00:00
if ( DBM :: is_result ( $rname )) {
2017-11-10 05:00:50 +00:00
$reactivate_group = true ;
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// create group
2017-12-09 18:45:17 +00:00
$ret = Group :: create ( $uid , $name );
2017-11-10 05:00:50 +00:00
if ( $ret ) {
2017-12-09 18:45:17 +00:00
$gid = Group :: getIdByName ( $uid , $name );
2017-11-10 05:00:50 +00:00
} else {
throw new BadRequestException ( 'other API error' );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// add members
$erroraddinguser = false ;
2018-01-15 13:05:12 +00:00
$errorusers = [];
2017-11-10 05:00:50 +00:00
foreach ( $users as $user ) {
$cid = $user [ 'cid' ];
// check if user really exists as contact
$contact = q (
" SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d " ,
intval ( $cid ),
intval ( $uid )
);
2017-12-22 23:10:32 +00:00
if ( count ( $contact )) {
2018-01-04 01:54:35 +00:00
Group :: addMember ( $gid , $cid );
2017-12-22 23:10:32 +00:00
} else {
2017-11-10 05:00:50 +00:00
$erroraddinguser = true ;
$errorusers [] = $cid ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// return success message incl. missing users in array
$status = ( $erroraddinguser ? " missing user " : ( $reactivate_group ? " reactivated " : " ok " ));
2018-01-15 13:05:12 +00:00
$success = [ 'success' => true , 'gid' => $gid , 'name' => $name , 'status' => $status , 'wrong users' => $errorusers ];
return api_format_data ( " group_create " , $type , [ 'result' => $success ]);
2017-11-10 05:00:50 +00:00
}
api_register_func ( 'api/friendica/group_create' , 'api_friendica_group_create' , true , API_METHOD_POST );
2017-12-24 02:20:50 +00:00
/**
* Update the specified group with the posted array of contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_friendica_group_update ( $type )
{
$a = get_app ();
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$uid = $user_info [ 'uid' ];
$gid = ( x ( $_REQUEST , 'gid' ) ? $_REQUEST [ 'gid' ] : 0 );
$name = ( x ( $_REQUEST , 'name' ) ? $_REQUEST [ 'name' ] : " " );
$json = json_decode ( $_POST [ 'json' ], true );
$users = $json [ 'user' ];
// error if no name specified
2017-12-23 23:27:45 +00:00
if ( $name == " " ) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'group name not specified' );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// error if no gid specified
2017-12-23 23:27:45 +00:00
if ( $gid == " " ) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( 'gid not specified' );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
// remove members
2017-12-09 18:45:17 +00:00
$members = Contact :: getByGroupId ( $gid );
2017-11-10 05:00:50 +00:00
foreach ( $members as $member ) {
$cid = $member [ 'id' ];
2016-09-25 16:50:08 +00:00
foreach ( $users as $user ) {
2017-11-10 05:00:50 +00:00
$found = ( $user [ 'cid' ] == $cid ? true : false );
}
if ( ! $found ) {
2018-01-04 01:54:35 +00:00
Group :: removeMemberByName ( $uid , $name , $cid );
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
// add members
$erroraddinguser = false ;
2018-01-15 13:05:12 +00:00
$errorusers = [];
2017-11-10 05:00:50 +00:00
foreach ( $users as $user ) {
$cid = $user [ 'cid' ];
// check if user really exists as contact
$contact = q (
" SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d " ,
intval ( $cid ),
intval ( $uid )
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( count ( $contact )) {
2018-01-04 01:54:35 +00:00
Group :: addMember ( $gid , $cid );
2016-09-25 16:50:08 +00:00
} else {
2017-11-10 05:00:50 +00:00
$erroraddinguser = true ;
$errorusers [] = $cid ;
2016-09-25 16:50:08 +00:00
}
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// return success message incl. missing users in array
$status = ( $erroraddinguser ? " missing user " : " ok " );
2018-01-15 13:05:12 +00:00
$success = [ 'success' => true , 'gid' => $gid , 'name' => $name , 'status' => $status , 'wrong users' => $errorusers ];
return api_format_data ( " group_update " , $type , [ 'result' => $success ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/group_update' , 'api_friendica_group_update' , true , API_METHOD_POST );
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
*/
2017-11-10 05:00:50 +00:00
function api_friendica_activity ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-11-10 05:00:50 +00:00
$verb = strtolower ( $a -> argv [ 3 ]);
$verb = preg_replace ( " | \ ..* $ | " , " " , $verb );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$id = ( x ( $_REQUEST , 'id' ) ? $_REQUEST [ 'id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$res = do_like ( $id , $verb );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $res ) {
if ( $type == " xml " ) {
$ok = " true " ;
} else {
$ok = " ok " ;
}
2018-01-15 13:05:12 +00:00
return api_format_data ( 'ok' , $type , [ 'ok' => $ok ]);
2017-11-10 05:00:50 +00:00
} else {
throw new BadRequestException ( 'Error adding activity' );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/activity/like' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/dislike' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/attendyes' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/attendno' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/attendmaybe' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/unlike' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/undislike' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/unattendyes' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/unattendno' , 'api_friendica_activity' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/activity/unattendmaybe' , 'api_friendica_activity' , true , API_METHOD_POST );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief Returns notifications
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_friendica_notification ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
if ( $a -> argc !== 3 ) {
throw new BadRequestException ( " Invalid argument count " );
}
2017-11-10 05:00:50 +00:00
$nm = new NotificationsManager ();
2016-09-25 16:50:08 +00:00
2018-01-15 13:05:12 +00:00
$notes = $nm -> getAll ([], " +seen -date " , 50 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
2018-01-15 13:05:12 +00:00
$xmlnotes = [];
2017-12-23 23:27:45 +00:00
foreach ( $notes as $note ) {
2018-01-15 13:05:12 +00:00
$xmlnotes [] = [ " @attributes " => $note ];
2017-12-23 23:27:45 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$notes = $xmlnotes ;
2016-09-25 16:50:08 +00:00
}
2018-01-15 13:05:12 +00:00
return api_format_data ( " notes " , $type , [ 'note' => $notes ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* POST request with 'id' param as notification id
*
2017-12-24 02:20:50 +00:00
* @ brief Set notification as seen and returns associated item ( if possible )
*
2017-11-10 05:00:50 +00:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_friendica_notification_seen ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-12-23 23:27:45 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
if ( $a -> argc !== 4 ) {
throw new BadRequestException ( " Invalid argument count " );
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$id = ( x ( $_REQUEST , 'id' ) ? intval ( $_REQUEST [ 'id' ]) : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$nm = new NotificationsManager ();
$note = $nm -> getByID ( $id );
2017-12-23 23:27:45 +00:00
if ( is_null ( $note )) {
throw new BadRequestException ( " Invalid argument " );
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
$nm -> setSeen ( $note );
if ( $note [ 'otype' ] == 'item' ) {
// would be really better with an ItemsManager and $im->getByID() :-P
$r = q (
" SELECT * FROM `item` WHERE `id`=%d AND `uid`=%d " ,
intval ( $note [ 'iid' ]),
intval ( local_user ())
);
if ( $r !== false ) {
// we found the item, return it to the user
$user_info = api_get_user ( $a );
$ret = api_format_items ( $r , $user_info , false , $type );
2018-01-15 13:05:12 +00:00
$data = [ 'status' => $ret ];
2017-11-10 05:00:50 +00:00
return api_format_data ( " status " , $type , $data );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// the item can't be found, but we set the note as seen, so we count this as a success
}
2018-01-15 13:05:12 +00:00
return api_format_data ( 'result' , $type , [ 'result' => " success " ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/notification/seen' , 'api_friendica_notification_seen' , true , API_METHOD_POST );
api_register_func ( 'api/friendica/notification' , 'api_friendica_notification' , true , API_METHOD_GET );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief update a direct_message to seen state
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string ( success result = ok , error result = error with error message )
*/
function api_friendica_direct_messages_setseen ( $type )
{
$a = get_app ();
if ( api_user () === false ) {
throw new ForbiddenException ();
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$uid = $user_info [ 'uid' ];
$id = ( x ( $_REQUEST , 'id' ) ? $_REQUEST [ 'id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// return error if id is zero
if ( $id == " " ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'message id not specified' ];
return api_format_data ( " direct_messages_setseen " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// get data of the specified message id
$r = q (
" SELECT `id` FROM `mail` WHERE `id` = %d AND `uid` = %d " ,
intval ( $id ),
intval ( $uid )
);
// error message if specified id is not in database
if ( ! DBM :: is_result ( $r )) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'message id not in database' ];
return api_format_data ( " direct_messages_setseen " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// update seen indicator
$result = q (
" UPDATE `mail` SET `seen` = 1 WHERE `id` = %d AND `uid` = %d " ,
intval ( $id ),
intval ( $uid )
);
if ( $result ) {
// return success
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'ok' , 'message' => 'message set to seen' ];
return api_format_data ( " direct_message_setseen " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'unknown error' ];
return api_format_data ( " direct_messages_setseen " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
}
2016-11-04 22:45:20 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/direct_messages_setseen' , 'api_friendica_direct_messages_setseen' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief search for direct_messages containing a searchstring through api
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-24 02:20:50 +00:00
* @ return string ( success : success = true if found and search_result contains found messages ,
2017-11-10 05:00:50 +00:00
* success = false if nothing was found , search_result = 'nothing found' ,
* error : result = error with error message )
*/
function api_friendica_direct_messages_search ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// params
$user_info = api_get_user ( $a );
$searchstring = ( x ( $_REQUEST , 'searchstring' ) ? $_REQUEST [ 'searchstring' ] : " " );
$uid = $user_info [ 'uid' ];
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// error if no searchstring specified
if ( $searchstring == " " ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'searchstring not specified' ];
return api_format_data ( " direct_messages_search " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
// get data for the specified searchstring
$r = q (
" SELECT `mail`.*, `contact`.`nurl` AS `contact-url` FROM `mail`,`contact` WHERE `mail`.`contact-id` = `contact`.`id` AND `mail`.`uid`=%d AND `body` LIKE '%s' ORDER BY `mail`.`id` DESC " ,
intval ( $uid ),
dbesc ( '%' . $searchstring . '%' )
);
$profile_url = $user_info [ " url " ];
// message if nothing was found
if ( ! DBM :: is_result ( $r )) {
2018-01-15 13:05:12 +00:00
$success = [ 'success' => false , 'search_results' => 'problem with query' ];
2017-11-10 05:00:50 +00:00
} elseif ( count ( $r ) == 0 ) {
2018-01-15 13:05:12 +00:00
$success = [ 'success' => false , 'search_results' => 'nothing found' ];
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
$sender = api_get_user ( $a , normalise_link ( $item [ 'contact-url' ]));
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
$recipient = api_get_user ( $a , normalise_link ( $item [ 'contact-url' ]));
$sender = $user_info ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
2018-01-15 13:05:12 +00:00
$success = [ 'success' => true , 'search_results' => $ret ];
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2018-01-15 13:05:12 +00:00
return api_format_data ( " direct_message_search " , $type , [ '$result' => $success ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/direct_messages_search' , 'api_friendica_direct_messages_search' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
* @ brief return data of all the profiles a user has to the client
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string
*/
function api_friendica_profile_show ( $type )
{
$a = get_app ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( api_user () === false ) {
throw new ForbiddenException ();
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// input params
$profileid = ( x ( $_REQUEST , 'profile_id' ) ? $_REQUEST [ 'profile_id' ] : 0 );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// retrieve general information about profiles for user
2017-12-04 14:01:27 +00:00
$multi_profiles = Feature :: isEnabled ( api_user (), 'multi_profiles' );
2017-11-10 05:00:50 +00:00
$directory = Config :: get ( 'system' , 'directory' );
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// get data of the specified profile id or all profiles of the user if not specified
if ( $profileid != 0 ) {
$r = q (
" SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d " ,
intval ( api_user ()),
intval ( $profileid )
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// error message if specified gid is not in database
if ( ! DBM :: is_result ( $r )) {
throw new BadRequestException ( " profile_id not available " );
}
} else {
$r = q (
" SELECT * FROM `profile` WHERE `uid` = %d " ,
intval ( api_user ())
);
}
// loop through all returned profiles and retrieve data and users
$k = 0 ;
foreach ( $r as $rr ) {
2018-01-04 01:54:35 +00:00
$profile = api_format_items_profiles ( $rr );
2017-11-10 05:00:50 +00:00
// select all users from contact table, loop and prepare standard return for user data
2018-01-15 13:05:12 +00:00
$users = [];
2017-11-10 05:00:50 +00:00
$r = q (
" SELECT `id`, `nurl` FROM `contact` WHERE `uid`= %d AND `profile-id` = %d " ,
intval ( api_user ()),
intval ( $rr [ 'profile_id' ])
);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
foreach ( $r as $rr ) {
$user = api_get_user ( $a , $rr [ 'nurl' ]);
( $type == " xml " ) ? $users [ $k ++ . " :user " ] = $user : $users [] = $user ;
}
$profile [ 'users' ] = $users ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// add prepared profile data to array for final return
if ( $type == " xml " ) {
$profiles [ $k ++ . " :profile " ] = $profile ;
} else {
$profiles [] = $profile ;
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// return settings, authenticated user and profiles data
$self = q ( " SELECT `nurl` FROM `contact` WHERE `uid`= %d AND `self` LIMIT 1 " , intval ( api_user ()));
2017-03-25 14:16:21 +00:00
2018-01-15 13:05:12 +00:00
$result = [ 'multi_profiles' => $multi_profiles ? true : false ,
2017-11-10 05:00:50 +00:00
'global_dir' => $directory ,
'friendica_owner' => api_get_user ( $a , $self [ 0 ][ 'nurl' ]),
2018-01-15 13:05:12 +00:00
'profiles' => $profiles ];
return api_format_data ( " friendica_profiles " , $type , [ '$result' => $result ]);
2017-11-10 05:00:50 +00:00
}
api_register_func ( 'api/friendica/profile/show' , 'api_friendica_profile_show' , true , API_METHOD_GET );
2016-09-25 16:50:08 +00:00
2017-12-19 13:20:32 +00:00
/**
* Returns a list of saved searches .
*
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / get - saved_searches - list
*
* @ param string $type Return format : json or xml
*
* @ return string | array
*/
function api_saved_searches_list ( $type )
{
2018-01-15 13:05:12 +00:00
$terms = dba :: select ( 'search' , [ 'id' , 'term' ], [ 'uid' => local_user ()]);
2017-12-19 13:20:32 +00:00
2018-01-15 13:05:12 +00:00
$result = [];
2017-12-19 13:20:32 +00:00
while ( $term = $terms -> fetch ()) {
2018-01-15 13:05:12 +00:00
$result [] = [
2017-12-19 13:20:32 +00:00
'name' => $term [ 'term' ],
'query' => $term [ 'term' ],
'id_str' => $term [ 'id' ],
'id' => intval ( $term [ 'id' ])
2018-01-15 13:05:12 +00:00
];
2017-12-19 13:20:32 +00:00
}
2017-12-19 13:42:13 +00:00
dba :: close ( $terms );
2018-01-15 13:05:12 +00:00
return api_format_data ( " terms " , $type , [ 'terms' => $result ]);
2017-12-19 13:20:32 +00:00
}
2017-12-25 20:12:08 +00:00
/// @TODO move to top of file or somewhere better
2017-12-19 13:20:32 +00:00
api_register_func ( 'api/saved_searches/list' , 'api_saved_searches_list' , true );
2016-09-25 16:50:08 +00:00
/*
2017-04-05 20:07:55 +00:00
@ TODO Maybe open to implement ?
2016-09-25 16:50:08 +00:00
To . Do :
2017-12-23 23:27:45 +00:00
[ pagename ] => api / 1.1 / statuses / lookup . json
[ id ] => 605138389168451584
[ include_cards ] => true
[ cards_platform ] => Android - 12
[ include_entities ] => true
[ include_my_retweet ] => 1
[ include_rts ] => 1
[ include_reply_count ] => true
[ include_descendent_reply_count ] => true
2016-09-25 16:50:08 +00:00
( ? )
Not implemented by now :
statuses / retweets_of_me
friendships / create
friendships / destroy
friendships / exists
friendships / show
account / update_location
account / update_profile_background_image
blocks / create
blocks / destroy
friendica / profile / update
friendica / profile / create
friendica / profile / delete
Not implemented in status . net :
statuses / retweeted_to_me
statuses / retweeted_by_me
direct_messages / destroy
account / end_session
account / update_delivery_device
notifications / follow
notifications / leave
blocks / exists
blocks / blocking
lists
*/