2016-09-25 18:50:08 +02:00
< ? php
/**
2021-03-29 08:40:20 +02:00
* @ copyright Copyright ( C ) 2010 - 2021 , the Friendica project
2020-02-09 16:34:23 +01:00
*
* @ license GNU AGPL version 3 or any later version
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*
2016-09-25 18:50:08 +02:00
* Friendica implementation of statusnet / twitter API
*
2017-12-24 03:20:50 +01:00
* @ file include / api . php
2016-09-25 18:50:08 +02:00
* @ todo Automatically detect if incoming data is HTML or BBCode
*/
2018-01-25 03:08:45 +01:00
2017-04-30 06:07:00 +02:00
use Friendica\App ;
2018-01-27 02:01:32 +01:00
use Friendica\Content\Text\BBCode ;
2018-03-07 22:24:13 +01:00
use Friendica\Content\Text\HTML ;
2018-10-29 22:20:46 +01:00
use Friendica\Core\Logger ;
2018-07-01 20:42:38 +02:00
use Friendica\Core\Protocol ;
2018-01-25 03:08:45 +01:00
use Friendica\Core\System ;
2018-07-20 14:19:26 +02:00
use Friendica\Database\DBA ;
2019-12-15 23:28:01 +01:00
use Friendica\DI ;
2017-12-07 15:04:24 +01:00
use Friendica\Model\Contact ;
2017-12-09 19:45:17 +01:00
use Friendica\Model\Group ;
2018-01-25 03:08:45 +01:00
use Friendica\Model\Item ;
2018-01-15 18:14:09 +01:00
use Friendica\Model\Mail ;
2021-01-23 10:53:44 +01:00
use Friendica\Model\Notification ;
2017-12-07 14:56:11 +01:00
use Friendica\Model\Photo ;
2021-01-16 05:11:28 +01:00
use Friendica\Model\Post ;
2021-06-15 13:12:44 +02:00
use Friendica\Model\Profile ;
2017-11-26 20:46:08 +01:00
use Friendica\Model\User ;
2020-05-26 07:18:50 +02:00
use Friendica\Model\Verb ;
2021-11-08 22:35:41 +01:00
use Friendica\Module\BaseApi ;
2017-11-24 05:48:15 +01:00
use Friendica\Network\HTTPException ;
use Friendica\Network\HTTPException\BadRequestException ;
use Friendica\Network\HTTPException\ForbiddenException ;
use Friendica\Network\HTTPException\InternalServerErrorException ;
use Friendica\Network\HTTPException\MethodNotAllowedException ;
use Friendica\Network\HTTPException\NotFoundException ;
use Friendica\Network\HTTPException\TooManyRequestsException ;
2018-01-25 03:08:45 +01:00
use Friendica\Network\HTTPException\UnauthorizedException ;
2017-12-07 14:56:11 +01:00
use Friendica\Object\Image ;
2019-10-24 00:25:43 +02:00
use Friendica\Protocol\Activity ;
2021-11-08 22:35:41 +01:00
use Friendica\Security\BasicAuth ;
2018-01-27 03:38:34 +01:00
use Friendica\Util\DateTimeFormat ;
2019-10-18 03:26:15 +02:00
use Friendica\Util\Images ;
2018-01-27 05:09:48 +01:00
use Friendica\Util\Network ;
2018-11-08 14:45:46 +01:00
use Friendica\Util\Strings ;
2017-01-17 20:21:46 +01:00
2019-09-16 14:47:49 +02:00
require_once __DIR__ . '/../mod/item.php' ;
require_once __DIR__ . '/../mod/wall_upload.php' ;
2017-04-05 22:07:55 +02:00
define ( 'API_METHOD_ANY' , '*' );
define ( 'API_METHOD_GET' , 'GET' );
define ( 'API_METHOD_POST' , 'POST,PUT' );
define ( 'API_METHOD_DELETE' , 'POST,DELETE' );
2018-12-30 21:42:56 +01:00
define ( 'API_LOG_PREFIX' , 'API {action} - ' );
2018-01-15 14:05:12 +01:00
$API = [];
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* Get source name from API client
*
2017-11-10 06:00:50 +01:00
* 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 )
*
* @ return string
2019-01-07 18:24:01 +01:00
* Client source name , default to " api " if unset / unknown
* @ throws Exception
2017-11-10 06:00:50 +01:00
*/
function api_source ()
{
2021-06-11 08:09:08 +02:00
if ( requestdata ( 'source' )) {
return requestdata ( 'source' );
2016-09-25 18:50:08 +02:00
}
2021-06-11 08:09:08 +02:00
// Support for known clients that doesn't send a source name
if ( ! empty ( $_SERVER [ 'HTTP_USER_AGENT' ])) {
if ( strpos ( $_SERVER [ 'HTTP_USER_AGENT' ], " Twidere " ) !== false ) {
return " Twidere " ;
}
Logger :: info ( API_LOG_PREFIX . 'Unrecognized user-agent' , [ 'module' => 'api' , 'action' => 'source' , 'http_user_agent' => $_SERVER [ 'HTTP_USER_AGENT' ]]);
} else {
Logger :: info ( API_LOG_PREFIX . 'Empty user-agent' , [ 'module' => 'api' , 'action' => 'source' ]);
}
return " api " ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Register a function to be the endpoint for defined API path .
2017-11-10 06:00:50 +01:00
*
2019-12-30 23:00:08 +01:00
* @ param string $path API URL path , relative to DI :: baseUrl ()
2017-11-10 06:00:50 +01:00
* @ 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 14:05:12 +01:00
$API [ $path ] = [
2017-11-10 06:00:50 +01:00
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
2018-01-15 14:05:12 +01:00
];
2017-11-10 06:00:50 +01:00
// Workaround for hotot
$path = str_replace ( " api/ " , " api/1.1/ " , $path );
2018-01-15 14:05:12 +01:00
$API [ $path ] = [
2017-11-10 06:00:50 +01:00
'func' => $func ,
'auth' => $auth ,
'method' => $method ,
2018-01-15 14:05:12 +01:00
];
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* Main API entry point
2017-11-10 06:00:50 +01:00
*
2020-01-19 07:05:23 +01:00
* Authenticate user , call registered API function , set HTTP headers
2017-12-24 03:20:50 +01:00
*
2019-01-07 18:24:01 +01:00
* @ param App $a App
2019-12-16 01:35:26 +01:00
* @ param App\Arguments $args The app arguments ( optional , will retrieved by the DI - Container in case of missing )
2018-04-09 19:34:02 +02:00
* @ return string | array API call result
2019-01-07 18:24:01 +01:00
* @ throws Exception
2017-11-10 06:00:50 +01:00
*/
2019-12-16 01:35:26 +01:00
function api_call ( App $a , App\Arguments $args = null )
2017-11-10 06:00:50 +01:00
{
2021-11-18 15:49:12 +01:00
global $API ;
2016-09-25 18:50:08 +02:00
2019-12-16 01:35:26 +01:00
if ( $args == null ) {
$args = DI :: args ();
}
2017-11-10 06:00:50 +01:00
$type = " json " ;
2020-09-09 06:15:25 +02:00
if ( strpos ( $args -> getCommand (), " .xml " ) > 0 ) {
2017-11-10 06:00:50 +01:00
$type = " xml " ;
}
2020-09-09 06:15:25 +02:00
if ( strpos ( $args -> getCommand (), " .json " ) > 0 ) {
2017-04-05 22:07:55 +02:00
$type = " json " ;
2017-11-10 06:00:50 +01:00
}
2020-09-09 06:15:25 +02:00
if ( strpos ( $args -> getCommand (), " .rss " ) > 0 ) {
2017-11-10 06:00:50 +01:00
$type = " rss " ;
}
2020-09-09 06:15:25 +02:00
if ( strpos ( $args -> getCommand (), " .atom " ) > 0 ) {
2017-11-10 06:00:50 +01:00
$type = " atom " ;
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
try {
foreach ( $API as $p => $info ) {
2020-09-09 06:15:25 +02:00
if ( strpos ( $args -> getCommand (), $p ) === 0 ) {
2021-11-17 23:44:52 +01:00
if ( ! empty ( $info [ 'auth' ]) && BaseApi :: getCurrentUserID () === false ) {
2021-11-08 22:35:41 +01:00
BasicAuth :: getCurrentUserID ( true );
2021-08-09 21:48:39 +02:00
Logger :: info ( API_LOG_PREFIX . 'nickname {nickname}' , [ 'module' => 'api' , 'action' => 'call' , 'nickname' => $a -> getLoggedInUserNickname ()]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2018-12-30 21:42:56 +01:00
Logger :: debug ( API_LOG_PREFIX . 'parameters' , [ 'module' => 'api' , 'action' => 'call' , 'parameters' => $_REQUEST ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$stamp = microtime ( true );
2018-01-04 02:54:35 +01:00
$return = call_user_func ( $info [ 'func' ], $type );
2019-10-16 14:43:59 +02:00
$duration = floatval ( microtime ( true ) - $stamp );
2018-12-30 21:42:56 +01:00
2020-07-09 21:03:48 +02:00
Logger :: info ( API_LOG_PREFIX . 'duration {duration}' , [ 'module' => 'api' , 'action' => 'call' , 'duration' => round ( $duration , 2 )]);
2016-09-25 18:50:08 +02:00
2019-12-15 23:50:35 +01:00
DI :: profiler () -> saveLog ( DI :: logger (), API_LOG_PREFIX . 'performance' );
2016-11-04 23:45:20 +01:00
2018-01-04 02:54:35 +01:00
if ( false === $return ) {
2017-11-10 06:00:50 +01:00
/*
* api function returned false withour throw an
* exception . This should not happend , throw a 500
*/
throw new InternalServerErrorException ();
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
switch ( $type ) {
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2019-08-02 18:43:36 +02:00
if ( ! empty ( $return )) {
$json = json_encode ( end ( $return ));
if ( ! empty ( $_GET [ 'callback' ])) {
$json = $_GET [ 'callback' ] . " ( " . $json . " ) " ;
}
$return = $json ;
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
2018-01-04 02:54:35 +01:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 06:00:50 +01:00
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
2018-01-04 02:54:35 +01:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 06:00:50 +01:00
break ;
2016-09-25 18:50:08 +02:00
}
2018-01-04 02:54:35 +01:00
return $return ;
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
2019-12-16 01:30:34 +01:00
Logger :: warning ( API_LOG_PREFIX . 'not implemented' , [ 'module' => 'api' , 'action' => 'call' , 'query' => DI :: args () -> getQueryString ()]);
2020-11-11 21:28:36 +01:00
throw new NotFoundException ();
2017-11-10 06:00:50 +01:00
} catch ( HTTPException $e ) {
2021-11-19 21:15:12 +01:00
Logger :: notice ( API_LOG_PREFIX . 'got exception' , [ 'module' => 'api' , 'action' => 'call' , 'query' => DI :: args () -> getQueryString (), 'error' => $e ]);
2021-11-12 20:04:47 +01:00
DI :: apiResponse () -> error ( $e -> getCode (), $e -> getDescription (), $e -> getMessage (), $type );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* TWITTER API
*/
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
* Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful ;
* returns a 401 status code and an error message if not .
2019-01-07 18:24:01 +01:00
*
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / get - account - verify_credentials
*
* @ param string $type Return type ( atom , rss , xml , json )
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 06:00:50 +01:00
*/
function api_account_verify_credentials ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'user_id' ]);
unset ( $_GET [ 'user_id' ]);
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'screen_name' ]);
unset ( $_GET [ 'screen_name' ]);
2016-09-25 18:50:08 +02:00
2019-10-13 04:01:34 +02:00
$skip_status = $_REQUEST [ 'skip_status' ] ? ? false ;
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid , $skip_status ) -> toArray ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// "verified" isn't used here in the standard
unset ( $user_info [ " verified " ]);
2021-11-21 21:14:48 +01:00
// "uid" is only needed for some internal stuff, so remove it from here
2021-11-20 14:44:12 +01:00
unset ( $user_info [ 'uid' ]);
2021-11-21 21:14:48 +01:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " user " , $type , [ 'user' => $user_info ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/account/verify_credentials' , 'api_account_verify_credentials' , true );
/**
* Get data from $_POST or $_GET
2017-12-24 03:20:50 +01:00
*
* @ param string $k
2019-01-07 18:24:01 +01:00
* @ return null
2017-11-10 06:00:50 +01:00
*/
function requestdata ( $k )
{
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_POST [ $k ])) {
2017-11-10 06:00:50 +01:00
return $_POST [ $k ];
}
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_GET [ $k ])) {
2017-11-10 06:00:50 +01:00
return $_GET [ $k ];
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
return null ;
}
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
2018-06-05 07:42:26 +02:00
* Deprecated function to upload media .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_statuses_mediap ( $type )
{
2021-11-18 00:03:18 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 00:03:18 +01:00
2021-11-20 14:44:12 +01:00
$a = DI :: app ();
$_REQUEST [ 'profile_uid' ] = $uid ;
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'api_source' ] = true ;
2021-05-01 17:48:19 +02:00
$txt = requestdata ( 'status' ) ? ? '' ;
2017-11-10 06:00:50 +01:00
if (( strpos ( $txt , '<' ) !== false ) || ( strpos ( $txt , '>' ) !== false )) {
2018-11-06 12:34:32 +01:00
$txt = HTML :: toBBCodeVideo ( $txt );
2017-11-10 06:00:50 +01:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
2016-09-25 18:50:08 +02:00
}
2018-03-07 22:24:13 +01:00
$txt = HTML :: toBBCode ( $txt );
2016-09-25 18:50:08 +02:00
2018-06-05 07:42:26 +02:00
$picture = wall_upload_post ( $a , false );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// now that we have the img url in bbcode we can add it to the status and insert the wall item.
2018-06-05 07:42:26 +02:00
$_REQUEST [ 'body' ] = $txt . " \n \n " . '[url=' . $picture [ " albumpage " ] . '][img]' . $picture [ " preview " ] . " [/img][/url] " ;
2018-09-02 09:20:04 +02:00
$item_id = item_post ( $a );
2016-09-25 18:50:08 +02:00
2018-09-02 09:20:04 +02:00
// output the post that we just posted.
2021-11-23 22:54:19 +01:00
$status_info = DI :: twitterStatus () -> createFromItemId ( $item_id ) -> toArray ();
return DI :: apiResponse () -> formatData ( 'statuses' , $type , [ 'status' => $status_info ]);
2017-11-10 06:00:50 +01:00
}
/// @TODO move this to top of file or somewhere better!
api_register_func ( 'api/statuses/mediap' , 'api_statuses_mediap' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Updates the user’ s current status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws TooManyRequestsException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - update
*/
2017-11-10 06:00:50 +01:00
function api_statuses_update ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
$a = DI :: app ();
2018-01-04 19:26:09 +01:00
2017-11-10 06:00:50 +01:00
// convert $_POST array items to the form we use for web posts.
if ( requestdata ( 'htmlstatus' )) {
2021-05-01 17:48:19 +02:00
$txt = requestdata ( 'htmlstatus' ) ? ? '' ;
2017-11-10 06:00:50 +01:00
if (( strpos ( $txt , '<' ) !== false ) || ( strpos ( $txt , '>' ) !== false )) {
2018-11-06 12:34:32 +01:00
$txt = HTML :: toBBCodeVideo ( $txt );
2017-11-10 06:00:50 +01:00
2016-09-25 18:50:08 +02:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
2017-11-10 06:00:50 +01:00
2016-09-25 18:50:08 +02:00
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
2018-03-07 22:24:13 +01:00
$_REQUEST [ 'body' ] = HTML :: toBBCode ( $txt );
2017-11-10 06:00:50 +01:00
}
} else {
$_REQUEST [ 'body' ] = requestdata ( 'status' );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'title' ] = requestdata ( 'title' );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$parent = requestdata ( 'in_reply_to_status_id' );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Twidere sends "-1" if it is no reply ...
if ( $parent == - 1 ) {
$parent = " " ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( ctype_digit ( $parent )) {
$_REQUEST [ 'parent' ] = $parent ;
} else {
$_REQUEST [ 'parent_uri' ] = $parent ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( requestdata ( 'lat' ) && requestdata ( 'long' )) {
$_REQUEST [ 'coord' ] = sprintf ( " %s %s " , requestdata ( 'lat' ), requestdata ( 'long' ));
}
2021-11-20 14:44:12 +01:00
$_REQUEST [ 'profile_uid' ] = $uid ;
2017-11-10 06:00:50 +01:00
2018-07-19 15:52:05 +02:00
if ( ! $parent ) {
2017-11-10 06:00:50 +01:00
// Check for throttling (maximum posts per day, week and month)
2020-01-19 21:21:13 +01:00
$throttle_day = DI :: config () -> get ( 'system' , 'throttle_limit_day' );
2017-11-10 06:00:50 +01:00
if ( $throttle_day > 0 ) {
2018-01-27 03:38:34 +01:00
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 );
2017-11-10 06:00:50 +01:00
2021-11-20 14:44:12 +01:00
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
2021-02-04 06:51:25 +01:00
$posts_day = Post :: count ( $condition );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $posts_day > $throttle_day ) {
2021-11-20 14:44:12 +01:00
logger :: info ( 'Daily posting limit reached for user ' . $uid );
2020-01-18 20:52:34 +01:00
// die(api_error($type, DI::l10n()->t("Daily posting limit of %d posts reached. The post was rejected.", $throttle_day));
2020-01-18 20:53:01 +01:00
throw new TooManyRequestsException ( DI :: 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 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
}
2020-01-19 21:21:13 +01:00
$throttle_week = DI :: config () -> get ( 'system' , 'throttle_limit_week' );
2017-11-10 06:00:50 +01:00
if ( $throttle_week > 0 ) {
2018-01-27 03:38:34 +01:00
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 * 7 );
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
2021-02-04 06:51:25 +01:00
$posts_week = Post :: count ( $condition );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $posts_week > $throttle_week ) {
2021-11-20 14:44:12 +01:00
logger :: info ( 'Weekly posting limit reached for user ' . $uid );
2020-01-18 20:52:34 +01:00
// die(api_error($type, DI::l10n()->t("Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week)));
2020-01-18 20:53:01 +01:00
throw new TooManyRequestsException ( DI :: 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 06:00:50 +01:00
}
}
2016-09-25 18:50:08 +02:00
2020-01-19 21:21:13 +01:00
$throttle_month = DI :: config () -> get ( 'system' , 'throttle_limit_month' );
2017-11-10 06:00:50 +01:00
if ( $throttle_month > 0 ) {
2018-01-27 03:38:34 +01:00
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 * 30 );
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
2021-02-04 06:51:25 +01:00
$posts_month = Post :: count ( $condition );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $posts_month > $throttle_month ) {
2021-11-20 14:44:12 +01:00
logger :: info ( 'Monthly posting limit reached for user ' . $uid );
2020-01-18 20:52:34 +01:00
// die(api_error($type, DI::l10n()->t("Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month));
throw new TooManyRequestsException ( DI :: 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 06:00:50 +01:00
}
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-05-01 17:48:19 +02:00
if ( requestdata ( 'media_ids' )) {
$ids = explode ( ',' , requestdata ( 'media_ids' ) ? ? '' );
} elseif ( ! empty ( $_FILES [ 'media' ])) {
2017-11-10 06:00:50 +01:00
// upload the image if we have one
2018-06-05 07:42:26 +02:00
$picture = wall_upload_post ( $a , false );
2018-06-05 07:44:04 +02:00
if ( is_array ( $picture )) {
2021-05-01 17:48:19 +02:00
$ids [] = $picture [ 'id' ];
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-05-01 17:48:19 +02:00
$attachments = [];
$ressources = [];
if ( ! empty ( $ids )) {
2019-08-06 07:34:04 +02:00
foreach ( $ids as $id ) {
2021-05-01 17:48:19 +02:00
$media = DBA :: toArray ( DBA :: p ( " SELECT `resource-id`, `scale`, `nickname`, `type`, `desc`, `filename`, `datasize`, `width`, `height` FROM `photo`
INNER JOIN `user` ON `user` . `uid` = `photo` . `uid` WHERE `resource-id` IN
( SELECT `resource-id` FROM `photo` WHERE `id` = ? ) AND `photo` . `uid` = ?
2021-11-20 14:44:12 +01:00
ORDER BY `photo` . `width` DESC LIMIT 2 " , $id , $uid ));
2021-05-22 23:45:15 +02:00
2021-05-01 17:48:19 +02:00
if ( ! empty ( $media )) {
$ressources [] = $media [ 0 ][ 'resource-id' ];
2019-10-18 03:26:15 +02:00
$phototypes = Images :: supportedTypes ();
2021-05-01 17:48:19 +02:00
$ext = $phototypes [ $media [ 0 ][ 'type' ]];
2021-05-22 23:45:15 +02:00
2021-05-01 17:48:19 +02:00
$attachment = [ 'type' => Post\Media :: IMAGE , 'mimetype' => $media [ 0 ][ 'type' ],
'url' => DI :: baseUrl () . '/photo/' . $media [ 0 ][ 'resource-id' ] . '-' . $media [ 0 ][ 'scale' ] . '.' . $ext ,
'size' => $media [ 0 ][ 'datasize' ],
'name' => $media [ 0 ][ 'filename' ] ? : $media [ 0 ][ 'resource-id' ],
'description' => $media [ 0 ][ 'desc' ] ? ? '' ,
'width' => $media [ 0 ][ 'width' ],
'height' => $media [ 0 ][ 'height' ]];
2021-05-22 23:45:15 +02:00
2021-05-01 17:48:19 +02:00
if ( count ( $media ) > 1 ) {
$attachment [ 'preview' ] = DI :: baseUrl () . '/photo/' . $media [ 1 ][ 'resource-id' ] . '-' . $media [ 1 ][ 'scale' ] . '.' . $ext ;
$attachment [ 'preview-width' ] = $media [ 1 ][ 'width' ];
$attachment [ 'preview-height' ] = $media [ 1 ][ 'height' ];
}
$attachments [] = $attachment ;
2019-08-06 07:34:04 +02:00
}
2017-04-05 22:07:55 +02:00
}
2021-05-01 17:48:19 +02:00
// We have to avoid that the post is rejected because of an empty body
if ( empty ( $_REQUEST [ 'body' ])) {
2021-10-02 10:22:15 +02:00
$_REQUEST [ 'body' ] = '[hr]' ;
2021-05-01 17:48:19 +02:00
}
}
if ( ! empty ( $attachments )) {
$_REQUEST [ 'attachments' ] = $attachments ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// set this so that the item_post() function is quiet and doesn't redirect or emit json
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$_REQUEST [ 'api_source' ] = true ;
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
if ( empty ( $_REQUEST [ 'source' ])) {
2021-11-18 21:09:17 +01:00
$_REQUEST [ 'source' ] = api_source ();
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// call out normal post function
2018-09-02 09:20:04 +02:00
$item_id = item_post ( $a );
2016-09-25 18:50:08 +02:00
2021-05-01 17:48:19 +02:00
if ( ! empty ( $ressources ) && ! empty ( $item_id )) {
$item = Post :: selectFirst ([ 'uri-id' , 'allow_cid' , 'allow_gid' , 'deny_cid' , 'deny_gid' ], [ 'id' => $item_id ]);
foreach ( $ressources as $ressource ) {
2021-11-20 14:44:12 +01:00
Photo :: setPermissionForRessource ( $ressource , $uid , $item [ 'allow_cid' ], $item [ 'allow_gid' ], $item [ 'deny_cid' ], $item [ 'deny_gid' ]);
2021-05-01 17:48:19 +02:00
}
}
2018-09-02 09:20:04 +02:00
// output the post that we just posted.
2021-11-23 22:54:19 +01:00
$status_info = DI :: twitterStatus () -> createFromItemId ( $item_id ) -> toArray ();
return DI :: apiResponse () -> formatData ( 'statuses' , $type , [ 'status' => $status_info ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/statuses/update' , 'api_statuses_update' , true , API_METHOD_POST );
api_register_func ( 'api/statuses/update_with_media' , 'api_statuses_update' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Uploads an image to Friendica .
*
* @ return array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / media / upload - media / api - reference / post - media - upload
*/
2018-01-04 02:54:35 +01:00
function api_media_upload ()
2017-11-10 06:00:50 +01:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2018-01-04 19:26:09 +01:00
2018-11-30 15:06:22 +01:00
if ( empty ( $_FILES [ 'media' ])) {
2017-11-10 06:00:50 +01:00
// Output error
throw new BadRequestException ( " No media. " );
}
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$media = wall_upload_post ( DI :: app (), false );
2017-11-10 06:00:50 +01:00
if ( ! $media ) {
// Output error
throw new InternalServerErrorException ();
}
2016-09-25 18:50:08 +02:00
2018-01-15 14:05:12 +01:00
$returndata = [];
2017-11-10 06:00:50 +01:00
$returndata [ " media_id " ] = $media [ " id " ];
$returndata [ " media_id_string " ] = ( string ) $media [ " id " ];
$returndata [ " size " ] = $media [ " size " ];
2018-01-15 14:05:12 +01:00
$returndata [ " image " ] = [ " w " => $media [ " width " ],
2018-12-15 21:15:55 +01:00
" h " => $media [ " height " ],
" image_type " => $media [ " type " ],
2018-12-16 07:16:45 +01:00
" friendica_preview_url " => $media [ " preview " ]];
2016-09-25 18:50:08 +02:00
2020-06-29 22:22:00 +02:00
Logger :: info ( 'Media uploaded' , [ 'return' => $returndata ]);
2016-09-25 18:50:08 +02:00
2018-01-15 14:05:12 +01:00
return [ " media " => $returndata ];
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/media/upload' , 'api_media_upload' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2019-07-30 07:02:26 +02:00
/**
* Updates media meta data ( picture descriptions )
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws TooManyRequestsException
* @ throws UnauthorizedException
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - update
*
* @ todo Compare the corresponding Twitter function for correct return values
*/
function api_media_metadata_create ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2019-07-30 07:02:26 +02:00
2019-07-31 00:26:01 +02:00
$postdata = Network :: postdata ();
2019-07-30 07:02:26 +02:00
if ( empty ( $postdata )) {
throw new BadRequestException ( " No post data " );
}
$data = json_decode ( $postdata , true );
if ( empty ( $data )) {
throw new BadRequestException ( " Invalid post data " );
}
if ( empty ( $data [ 'media_id' ]) || empty ( $data [ 'alt_text' ])) {
throw new BadRequestException ( " Missing post data values " );
}
if ( empty ( $data [ 'alt_text' ][ 'text' ])) {
throw new BadRequestException ( " No alt text. " );
}
Logger :: info ( 'Updating metadata' , [ 'media_id' => $data [ 'media_id' ]]);
2021-11-20 14:44:12 +01:00
$condition = [ 'id' => $data [ 'media_id' ], 'uid' => $uid ];
2019-07-30 07:02:26 +02:00
$photo = DBA :: selectFirst ( 'photo' , [ 'resource-id' ], $condition );
if ( ! DBA :: isResult ( $photo )) {
throw new BadRequestException ( " Metadata not found. " );
}
DBA :: update ( 'photo' , [ 'desc' => $data [ 'alt_text' ][ 'text' ]], [ 'resource-id' => $photo [ 'resource-id' ]]);
}
api_register_func ( 'api/media/metadata/create' , 'api_media_metadata_create' , true , API_METHOD_POST );
2017-11-10 06:00:50 +01:00
/**
* Returns extended information of a given user , specified by ID or screen name as per the required id parameter .
* The author ' s most recent status will be returned inline .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - users - show
2017-11-10 06:00:50 +01:00
*/
function api_users_show ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
2021-11-23 22:54:19 +01:00
$condition = [
'author-id' => $user_info [ 'pid' ],
'uid' => $uid ,
'gravity' => [ GRAVITY_PARENT , GRAVITY_COMMENT ],
'private' => [ Item :: PUBLIC , Item :: UNLISTED ]
];
$item = Post :: selectFirst ([ 'uri-id' , 'id' ], $condition );
2019-11-21 23:40:54 +01:00
if ( ! empty ( $item )) {
2021-11-23 22:54:19 +01:00
$user_info [ 'status' ] = DI :: twitterStatus () -> createFromUriId ( $item [ 'uri-id' ], $item [ 'uid' ]) -> toArray ();
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-21 21:14:48 +01:00
// "uid" is only needed for some internal stuff, so remove it from here
2019-03-02 22:10:57 +01:00
unset ( $user_info [ 'uid' ]);
2016-09-25 18:50:08 +02:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'user' , $type , [ 'user' => $user_info ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/show' , 'api_users_show' );
api_register_func ( 'api/externalprofile/show' , 'api_users_show' );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Search a public user account .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / get - users - search
*/
2017-11-10 06:00:50 +01:00
function api_users_search ( $type )
{
2021-11-20 14:44:12 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
$uid = BaseApi :: getCurrentUserID ();
2018-01-15 14:05:12 +01:00
$userlist = [];
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_GET [ 'q' ])) {
2019-12-12 23:04:08 +01:00
$contacts = Contact :: selectToArray (
[ 'id' ],
[
'`uid` = 0 AND (`name` = ? OR `nick` = ? OR `url` = ? OR `addr` = ?)' ,
$_GET [ 'q' ],
$_GET [ 'q' ],
$_GET [ 'q' ],
$_GET [ 'q' ],
]
);
2016-09-25 18:50:08 +02:00
2019-12-12 23:04:08 +01:00
if ( DBA :: isResult ( $contacts )) {
2017-11-10 06:00:50 +01:00
$k = 0 ;
2019-12-12 23:04:08 +01:00
foreach ( $contacts as $contact ) {
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromContactId ( $contact [ 'id' ], $uid ) -> toArray ();
2016-09-25 18:50:08 +02:00
2019-12-12 23:04:08 +01:00
if ( $type == 'xml' ) {
$userlist [ $k ++ . ':user' ] = $user_info ;
2017-11-10 06:00:50 +01:00
} else {
$userlist [] = $user_info ;
}
}
2019-12-12 23:04:08 +01:00
$userlist = [ 'users' => $userlist ];
2017-11-10 06:00:50 +01:00
} else {
2019-12-12 23:04:08 +01:00
throw new NotFoundException ( 'User ' . $_GET [ 'q' ] . ' not found.' );
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
} else {
2019-12-12 23:04:08 +01:00
throw new BadRequestException ( 'No search term specified.' );
2016-09-25 18:50:08 +02:00
}
2018-01-04 02:54:35 +01:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'users' , $type , $userlist );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/search' , 'api_users_search' );
2016-09-25 18:50:08 +02:00
2017-12-18 23:51:03 +01:00
/**
* 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
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ImagickException
* @ throws InternalServerErrorException
2017-12-19 14:52:46 +01:00
* @ throws NotFoundException if the results are empty .
2019-01-07 18:24:01 +01:00
* @ throws UnauthorizedException
2017-12-18 23:51:03 +01:00
*/
function api_users_lookup ( $type )
{
2021-11-20 14:44:12 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
$uid = BaseApi :: getCurrentUserID ();
2018-01-15 14:05:12 +01:00
$users = [];
2017-12-19 11:37:55 +01:00
2018-07-01 10:03:57 +02:00
if ( ! empty ( $_REQUEST [ 'user_id' ])) {
2021-11-20 10:36:17 +01:00
foreach ( explode ( ',' , $_REQUEST [ 'user_id' ]) as $cid ) {
if ( ! empty ( $cid ) && is_numeric ( $cid )) {
2021-11-20 14:44:12 +01:00
$users [] = DI :: twitterUser () -> createFromContactId (( int ) $cid , $uid ) -> toArray ();
2017-12-19 11:37:55 +01:00
}
2017-12-18 23:51:03 +01:00
}
}
2017-12-19 11:37:55 +01:00
if ( empty ( $users )) {
throw new NotFoundException ;
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " users " , $type , [ 'users' => $users ]);
2017-12-18 23:51:03 +01:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/users/lookup' , 'api_users_lookup' , true );
2017-12-18 02:59:11 +01: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 14:52:46 +01:00
* @ throws BadRequestException if the " q " parameter is missing .
2019-01-07 18:24:01 +01:00
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-18 02:59:11 +01:00
*/
function api_search ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-09 17:36:33 +02:00
2019-02-19 01:56:41 +01:00
if ( empty ( $_REQUEST [ 'q' ])) {
throw new BadRequestException ( 'q parameter is required.' );
}
2018-12-17 05:41:55 +01:00
$searchTerm = trim ( rawurldecode ( $_REQUEST [ 'q' ]));
2017-12-18 02:59:11 +01:00
2018-12-16 17:11:55 +01:00
$data = [];
2018-12-21 18:42:39 +01:00
$data [ 'status' ] = [];
2018-12-16 17:11:55 +01:00
$count = 15 ;
2018-12-21 17:00:56 +01:00
$exclude_replies = ! empty ( $_REQUEST [ 'exclude_replies' ]);
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_REQUEST [ 'rpp' ])) {
2017-12-18 13:35:36 +01:00
$count = $_REQUEST [ 'rpp' ];
2018-11-30 15:06:22 +01:00
} elseif ( ! empty ( $_REQUEST [ 'count' ])) {
2017-12-18 13:35:36 +01:00
$count = $_REQUEST [ 'count' ];
}
2020-01-05 20:32:39 +01:00
2019-10-13 04:01:34 +02:00
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
$start = max ( 0 , ( $page - 1 ) * $count );
2018-12-16 17:11:55 +01:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2018-12-17 06:33:03 +01:00
if ( preg_match ( '/^#(\w+)$/' , $searchTerm , $matches ) === 1 && isset ( $matches [ 1 ])) {
2018-12-17 05:41:55 +01:00
$searchTerm = $matches [ 1 ];
2021-11-20 14:44:12 +01:00
$condition = [ " `iid` > ? AND `name` = ? AND (NOT `private` OR (`private` AND `uid` = ?)) " , $since_id , $searchTerm , $uid ];
2020-05-01 11:41:17 +02:00
$tags = DBA :: select ( 'tag-search-view' , [ 'uri-id' ], $condition );
$uriids = [];
while ( $tag = DBA :: fetch ( $tags )) {
$uriids [] = $tag [ 'uri-id' ];
2018-12-21 18:42:39 +01:00
}
2020-05-01 11:41:17 +02:00
DBA :: close ( $tags );
2018-12-21 17:00:56 +01:00
2020-05-01 11:41:17 +02:00
if ( empty ( $uriids )) {
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'statuses' , $type , $data );
2018-12-21 18:42:39 +01:00
}
2020-05-01 11:41:17 +02:00
$condition = [ 'uri-id' => $uriids ];
2018-12-21 18:42:39 +01:00
if ( $exclude_replies ) {
2020-05-01 11:41:17 +02:00
$condition [ 'gravity' ] = GRAVITY_PARENT ;
2018-12-21 18:42:39 +01:00
}
2020-05-01 11:41:17 +02:00
$params [ 'group_by' ] = [ 'uri-id' ];
2018-12-17 05:41:55 +01:00
} else {
2020-01-05 20:32:39 +01:00
$condition = [ " `id` > ?
2020-05-27 14:19:06 +02:00
" . ( $exclude_replies ? " AND `gravity` = " . GRAVITY_PARENT : ' ') . "
2018-12-17 05:41:55 +01:00
AND ( `uid` = 0 OR ( `uid` = ? AND NOT `global` ))
AND `body` LIKE CONCAT ( '%' , ? , '%' ) " ,
2021-11-20 14:44:12 +01:00
$since_id , $uid , $_REQUEST [ 'q' ]];
2018-12-17 05:41:55 +01:00
if ( $max_id > 0 ) {
2018-12-22 04:39:16 +01:00
$condition [ 0 ] .= ' AND `id` <= ?' ;
2018-12-17 05:41:55 +01:00
$condition [] = $max_id ;
}
2018-06-09 21:12:13 +02:00
}
2018-06-09 18:56:37 +02:00
2019-12-12 23:04:59 +01:00
$statuses = [];
if ( parse_url ( $searchTerm , PHP_URL_SCHEME ) != '' ) {
2021-11-20 14:44:12 +01:00
$id = Item :: fetchByLink ( $searchTerm , $uid );
2019-12-12 23:04:59 +01:00
if ( ! $id ) {
// Public post
$id = Item :: fetchByLink ( $searchTerm );
}
if ( ! empty ( $id )) {
2021-01-16 23:37:27 +01:00
$statuses = Post :: select ([], [ 'id' => $id ]);
2019-12-12 23:04:59 +01:00
}
}
2021-11-20 14:44:12 +01:00
$statuses = $statuses ? : Post :: selectForUser ( $uid , [], $condition , $params );
2017-12-18 13:35:36 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2017-12-18 13:35:36 +01:00
2021-11-21 00:38:52 +01:00
$data [ 'status' ] = $ret ;
2018-12-21 17:00:56 +01:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'statuses' , $type , $data );
2017-12-18 02:59:11 +01:00
}
/// @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 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Returns the most recent statuses posted by the user and the users they follow .
*
2019-01-07 18:24:01 +01:00
* @ see https :// developer . twitter . com / en / docs / tweets / timelines / api - reference / get - statuses - home_timeline
2017-11-10 06:00:50 +01:00
*
2017-12-24 03:20:50 +01:00
* @ param string $type Return type ( atom , rss , xml , json )
2017-11-10 06:00:50 +01:00
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ todo Optional parameters
* @ todo Add reply info
2017-11-10 06:00:50 +01:00
*/
function api_statuses_home_timeline ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 00:03:18 +01:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'user_id' ]);
unset ( $_GET [ 'user_id' ]);
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'screen_name' ]);
unset ( $_GET [ 'screen_name' ]);
2016-09-25 18:50:08 +02:00
2018-04-07 22:37:57 +02:00
// get last network messages
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$count = $_REQUEST [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 0 ;
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2018-11-30 15:06:22 +01:00
$exclude_replies = ! empty ( $_REQUEST [ 'exclude_replies' ]);
2019-10-13 04:01:34 +02:00
$conversation_id = $_REQUEST [ 'conversation_id' ] ? ? 0 ;
2016-09-25 18:50:08 +02:00
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2021-01-16 23:57:36 +01:00
$condition = [ " `uid` = ? AND `gravity` IN (?, ?) AND `id` > ? " ,
2021-11-20 14:44:12 +01:00
$uid , GRAVITY_PARENT , GRAVITY_COMMENT , $since_id ];
2018-06-09 18:56:37 +02:00
2017-11-10 06:00:50 +01:00
if ( $max_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $max_id ;
2017-11-10 06:00:50 +01:00
}
2018-11-30 15:06:22 +01:00
if ( $exclude_replies ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= ' AND `gravity` = ?' ;
2020-05-28 18:02:36 +02:00
$condition [] = GRAVITY_PARENT ;
2017-11-10 06:00:50 +01:00
}
if ( $conversation_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `parent` = ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $conversation_id ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-11-10 06:00:50 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
2018-01-15 14:05:12 +01:00
$idarray = [];
2021-11-21 00:38:52 +01:00
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
$idarray [] = intval ( $status [ 'id' ]);
2017-11-10 06:00:50 +01:00
}
2021-11-21 00:38:52 +01:00
DBA :: close ( $statuses );
2016-09-25 18:50:08 +02:00
2018-05-02 21:26:15 +02:00
if ( ! empty ( $idarray )) {
2021-01-16 05:11:28 +01:00
$unseen = Post :: exists ([ 'unseen' => true , 'id' => $idarray ]);
2017-11-10 06:00:50 +01:00
if ( $unseen ) {
2018-05-02 21:26:15 +02:00
Item :: update ([ 'unseen' => false ], [ 'unseen' => true , 'id' => $idarray ]);
2016-09-25 18:50:08 +02:00
}
}
2019-04-24 06:26:23 +02:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2018-12-21 17:00:56 +01:00
2017-11-10 06:00:50 +01: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 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Returns the most recent statuses from public users .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_statuses_public_timeline ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2018-04-07 22:37:57 +02:00
// get last network messages
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$count = $_REQUEST [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2018-11-30 15:06:22 +01:00
$exclude_replies = ( ! empty ( $_REQUEST [ 'exclude_replies' ]) ? 1 : 0 );
2019-10-13 04:01:34 +02:00
$conversation_id = $_REQUEST [ 'conversation_id' ] ? ? 0 ;
2016-09-25 18:50:08 +02:00
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2017-12-17 18:47:15 +01:00
if ( $exclude_replies && ! $conversation_id ) {
2021-02-09 18:56:17 +01:00
$condition = [ " `gravity` = ? AND `id` > ? AND `private` = ? AND `wall` AND NOT `author-hidden` " ,
GRAVITY_PARENT , $since_id , Item :: PUBLIC ];
2016-09-25 18:50:08 +02:00
2018-06-09 21:12:13 +02:00
if ( $max_id > 0 ) {
2021-02-09 18:56:17 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $max_id ;
}
2018-06-09 18:56:37 +02:00
2021-02-09 18:56:17 +01:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-12-17 18:47:15 +01:00
} else {
2021-01-16 23:57:36 +01:00
$condition = [ " `gravity` IN (?, ?) AND `id` > ? AND `private` = ? AND `wall` AND `origin` AND NOT `author-hidden` " ,
2020-03-02 08:57:23 +01:00
GRAVITY_PARENT , GRAVITY_COMMENT , $since_id , Item :: PUBLIC ];
2017-12-17 18:47:15 +01:00
2018-06-09 21:12:13 +02:00
if ( $max_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $max_id ;
}
if ( $conversation_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `parent` = ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $conversation_id ;
}
2018-06-09 18:56:37 +02:00
2018-06-09 21:12:13 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-12-17 18:47:15 +01:00
}
2017-11-10 06:00:50 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-12-21 17:00:56 +01:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/public_timeline' , 'api_statuses_public_timeline' , true );
2016-09-25 18:50:08 +02:00
2017-12-16 21:41:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Returns the most recent statuses posted by users this node knows about .
*
2017-12-16 21:41:50 +01:00
* @ param string $type Return format : json , xml , atom , rss
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
2017-12-16 21:41:50 +01:00
* @ throws ForbiddenException
2019-01-07 18:24:01 +01:00
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-16 21:41:50 +01:00
*/
function api_statuses_networkpublic_timeline ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2017-12-16 21:41:50 +01:00
2021-11-20 14:44:12 +01:00
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2017-12-16 21:41:50 +01:00
// pagination
2019-10-13 04:01:34 +02:00
$count = $_REQUEST [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
$start = max ( 0 , ( $page - 1 ) * $count );
2017-12-16 21:41:50 +01:00
2021-02-04 23:51:33 +01:00
$condition = [ " `uid` = 0 AND `gravity` IN (?, ?) AND `id` > ? AND `private` = ? " ,
2020-03-02 08:57:23 +01:00
GRAVITY_PARENT , GRAVITY_COMMENT , $since_id , Item :: PUBLIC ];
2017-12-16 21:41:50 +01:00
2018-06-09 21:12:13 +02:00
if ( $max_id > 0 ) {
2021-02-04 23:51:33 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $max_id ;
}
2017-12-16 21:41:50 +01:00
2021-02-04 23:51:33 +01:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-21 00:38:52 +01:00
$statuses = Post :: selectForUser ( $uid , Item :: DISPLAY_FIELDLIST , $condition , $params );
2021-02-05 08:14:09 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-12-21 17:00:56 +01:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-12-16 21:41:50 +01:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/networkpublic_timeline' , 'api_statuses_networkpublic_timeline' , true );
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Returns a single status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / get - statuses - show - id
2017-11-10 06:00:50 +01:00
*/
function api_statuses_show ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// params
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 3 ] ? ? 0 );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $id == 0 ) {
2019-10-13 04:01:34 +02:00
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Hotot workaround
if ( $id == 0 ) {
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 4 ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-10-03 21:43:49 +02:00
logger :: notice ( 'API: api_statuses_show: ' . $id );
2016-09-25 18:50:08 +02:00
2018-07-01 11:17:59 +02:00
$conversation = ! empty ( $_REQUEST [ 'conversation' ]);
2016-09-25 18:50:08 +02:00
2018-05-10 12:13:48 +02:00
// try to fetch the item for the local user - or the public item, if there is no local one
2021-01-17 13:49:53 +01:00
$uri_item = Post :: selectFirst ([ 'uri-id' ], [ 'id' => $id ]);
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $uri_item )) {
2021-01-17 13:49:53 +01:00
throw new BadRequestException ( sprintf ( " There is no status with the id %d " , $id ));
2018-05-10 12:13:48 +02:00
}
2021-11-20 14:44:12 +01:00
$item = Post :: selectFirst ([ 'id' ], [ 'uri-id' => $uri_item [ 'uri-id' ], 'uid' => [ 0 , $uid ]], [ 'order' => [ 'uid' => true ]]);
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $item )) {
2021-01-17 13:49:53 +01:00
throw new BadRequestException ( sprintf ( " There is no status with the uri-id %d for the given user. " , $uri_item [ 'uri-id' ]));
2018-05-10 12:13:48 +02:00
}
$id = $item [ 'id' ];
2018-06-09 18:56:37 +02:00
if ( $conversation ) {
2018-06-27 20:09:33 +02:00
$condition = [ 'parent' => $id , 'gravity' => [ GRAVITY_PARENT , GRAVITY_COMMENT ]];
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ]];
} else {
2018-06-27 20:09:33 +02:00
$condition = [ 'id' => $id , 'gravity' => [ GRAVITY_PARENT , GRAVITY_COMMENT ]];
2018-06-09 18:56:37 +02:00
$params = [];
}
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-11-10 06:00:50 +01:00
/// @TODO How about copying this to above methods which don't check $r ?
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $statuses )) {
2021-01-17 13:49:53 +01:00
throw new BadRequestException ( sprintf ( " There is no status or conversation with the id %d. " , $id ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $conversation ) {
2018-01-15 14:05:12 +01:00
$data = [ 'status' => $ret ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , $data );
2017-11-10 06:00:50 +01:00
} else {
2018-01-15 14:05:12 +01:00
$data = [ 'status' => $ret [ 0 ]];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " status " , $type , $data );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/show' , 'api_statuses_show' , true );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ todo nothing to say ?
2017-11-10 06:00:50 +01:00
*/
function api_conversation_show ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// params
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 3 ] ? ? 0 );
2019-10-13 04:01:34 +02:00
$since_id = intval ( $_REQUEST [ 'since_id' ] ? ? 0 );
$max_id = intval ( $_REQUEST [ 'max_id' ] ? ? 0 );
$count = intval ( $_REQUEST [ 'count' ] ? ? 20 );
$page = intval ( $_REQUEST [ 'page' ] ? ? 1 );
2016-09-25 18:50:08 +02:00
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $id == 0 ) {
2019-10-13 04:01:34 +02:00
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Hotot workaround
if ( $id == 0 ) {
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 4 ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2018-12-30 21:42:56 +01:00
Logger :: info ( API_LOG_PREFIX . '{subaction}' , [ 'module' => 'api' , 'action' => 'conversation' , 'subaction' => 'show' , 'id' => $id ]);
2016-09-25 18:50:08 +02:00
2018-05-10 12:13:48 +02:00
// try to fetch the item for the local user - or the public item, if there is no local one
2021-01-17 15:57:55 +01:00
$item = Post :: selectFirst ([ 'parent-uri-id' ], [ 'id' => $id ]);
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $item )) {
2021-11-08 08:23:18 +01:00
throw new BadRequestException ( " There is no status with the id $id . " );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$parent = Post :: selectFirst ([ 'id' ], [ 'uri-id' => $item [ 'parent-uri-id' ], 'uid' => [ 0 , $uid ]], [ 'order' => [ 'uid' => true ]]);
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $parent )) {
2018-05-10 12:13:48 +02:00
throw new BadRequestException ( " There is no status with this id. " );
}
$id = $parent [ 'id' ];
2021-01-16 23:57:36 +01:00
$condition = [ " `parent` = ? AND `uid` IN (0, ?) AND `gravity` IN (?, ?) AND `id` > ? " ,
2021-11-20 14:44:12 +01:00
$id , $uid , GRAVITY_PARENT , GRAVITY_COMMENT , $since_id ];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $max_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $max_id ;
}
2017-11-10 06:00:50 +01:00
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2018-06-09 18:56:37 +02:00
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $statuses )) {
2018-06-09 18:56:37 +02:00
throw new BadRequestException ( " There is no status with id $id . " );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2016-09-25 18:50:08 +02:00
2018-01-15 14:05:12 +01:00
$data = [ 'status' => $ret ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , $data );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/conversation/show' , 'api_conversation_show' , true );
api_register_func ( 'api/statusnet/conversation' , 'api_conversation_show' , true );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Repeats a status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - retweet - id
2017-11-10 06:00:50 +01:00
*/
function api_statuses_repeat ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-01-04 19:26:09 +01:00
2017-11-10 06:00:50 +01:00
// params
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 3 ] ? ? 0 );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $id == 0 ) {
2019-10-13 04:01:34 +02:00
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Hotot workaround
if ( $id == 0 ) {
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 4 ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-10-03 21:49:55 +02:00
logger :: notice ( 'API: api_statuses_repeat: ' . $id );
2017-11-10 06:00:50 +01:00
2020-11-07 09:22:59 +01:00
$fields = [ 'uri-id' , 'network' , 'body' , 'title' , 'author-name' , 'author-link' , 'author-avatar' , 'guid' , 'created' , 'plink' ];
2021-01-17 21:56:15 +01:00
$item = Post :: selectFirst ( $fields , [ 'id' => $id , 'private' => [ Item :: PUBLIC , Item :: UNLISTED ]]);
2021-04-26 08:50:12 +02:00
2021-01-17 22:24:58 +01:00
if ( DBA :: isResult ( $item ) && ! empty ( $item [ 'body' ])) {
2020-11-07 09:22:59 +01:00
if ( in_array ( $item [ 'network' ], [ Protocol :: ACTIVITYPUB , Protocol :: DFRN , Protocol :: TWITTER ])) {
2021-11-20 14:44:12 +01:00
if ( ! Item :: performActivity ( $id , 'announce' , $uid )) {
2020-11-07 09:22:59 +01:00
throw new InternalServerErrorException ();
}
2021-04-26 08:50:12 +02:00
2020-11-07 09:22:59 +01:00
$item_id = $id ;
2017-11-10 06:00:50 +01:00
} else {
2020-11-07 09:22:59 +01:00
if ( strpos ( $item [ 'body' ], " [/share] " ) !== false ) {
$pos = strpos ( $item [ 'body' ], " [share " );
$post = substr ( $item [ 'body' ], $pos );
} else {
$post = BBCode :: getShareOpeningTag ( $item [ 'author-name' ], $item [ 'author-link' ], $item [ 'author-avatar' ], $item [ 'plink' ], $item [ 'created' ], $item [ 'guid' ]);
if ( ! empty ( $item [ 'title' ])) {
$post .= '[h3]' . $item [ 'title' ] . " [/h3] \n " ;
}
2016-09-25 18:50:08 +02:00
2020-11-07 09:22:59 +01:00
$post .= $item [ 'body' ];
$post .= " [/share] " ;
2019-12-05 06:24:29 +01:00
}
2020-11-07 09:22:59 +01:00
$_REQUEST [ 'body' ] = $post ;
2021-11-20 14:44:12 +01:00
$_REQUEST [ 'profile_uid' ] = $uid ;
2020-11-07 09:22:59 +01:00
$_REQUEST [ 'api_source' ] = true ;
2019-12-05 06:24:29 +01:00
2020-11-07 09:22:59 +01:00
if ( empty ( $_REQUEST [ 'source' ])) {
2021-11-18 21:09:17 +01:00
$_REQUEST [ 'source' ] = api_source ();
2020-11-07 09:22:59 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$item_id = item_post ( DI :: app ());
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
} else {
2021-01-17 22:57:50 +01:00
throw new ForbiddenException ();
2016-09-25 18:50:08 +02:00
}
2018-09-02 09:35:12 +02:00
// output the post that we just posted.
2021-11-23 22:54:19 +01:00
$status_info = DI :: twitterStatus () -> createFromItemId ( $item_id ) -> toArray ();
return DI :: apiResponse () -> formatData ( 'statuses' , $type , [ 'status' => $status_info ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/retweet' , 'api_statuses_repeat' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Destroys a specific status .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - destroy - id
2017-11-10 06:00:50 +01:00
*/
function api_statuses_destroy ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-01-04 19:26:09 +01:00
2017-11-10 06:00:50 +01:00
// params
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 3 ] ? ? 0 );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $id == 0 ) {
2019-10-13 04:01:34 +02:00
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// Hotot workaround
if ( $id == 0 ) {
2021-07-25 16:27:13 +02:00
$id = intval ( DI :: args () -> getArgv ()[ 4 ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-10-03 21:49:55 +02:00
logger :: notice ( 'API: api_statuses_destroy: ' . $id );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
$ret = api_statuses_show ( $type );
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
Item :: deleteForUser ([ 'id' => $id ], $uid );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $ret ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @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 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Returns the most recent mentions .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see http :// developer . twitter . com / doc / get / statuses / mentions
2017-11-10 06:00:50 +01:00
*/
function api_statuses_mentions ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'user_id' ]);
unset ( $_GET [ 'user_id' ]);
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'screen_name' ]);
unset ( $_GET [ 'screen_name' ]);
2016-09-25 18:50:08 +02:00
2018-04-07 22:37:57 +02:00
// get last network messages
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// params
2020-11-27 12:24:31 +01:00
$since_id = intval ( $_REQUEST [ 'since_id' ] ? ? 0 );
$max_id = intval ( $_REQUEST [ 'max_id' ] ? ? 0 );
$count = intval ( $_REQUEST [ 'count' ] ? ? 20 );
$page = intval ( $_REQUEST [ 'page' ] ? ? 1 );
2016-09-25 18:50:08 +02:00
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2021-02-01 21:11:25 +01:00
$query = " `gravity` IN (?, ?) AND `uri-id` IN
( SELECT `uri-id` FROM `post-user-notification` WHERE `uid` = ? AND `notification-type` & ? != 0 ORDER BY `uri-id` )
AND ( `uid` = 0 OR ( `uid` = ? AND NOT `global` )) AND `id` > ? " ;
2021-01-17 14:10:32 +01:00
2021-09-18 04:14:32 +02:00
$condition = [
GRAVITY_PARENT , GRAVITY_COMMENT ,
2021-11-20 14:44:12 +01:00
$uid ,
2021-09-18 04:14:32 +02:00
Post\UserNotification :: TYPE_EXPLICIT_TAGGED | Post\UserNotification :: TYPE_IMPLICIT_TAGGED |
Post\UserNotification :: TYPE_THREAD_COMMENT | Post\UserNotification :: TYPE_DIRECT_COMMENT |
Post\UserNotification :: TYPE_DIRECT_THREAD_COMMENT ,
2021-11-20 14:44:12 +01:00
$uid , $since_id ,
2021-09-18 04:14:32 +02:00
];
2018-02-11 22:13:29 +01:00
2017-11-10 06:00:50 +01:00
if ( $max_id > 0 ) {
2021-01-31 19:32:22 +01:00
$query .= " AND `id` <= ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $max_id ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-01-17 14:10:32 +01:00
array_unshift ( $condition , $query );
2020-01-05 20:32:39 +01:00
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-11-10 06:00:50 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2017-11-10 06:00:50 +01:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/statuses/mentions' , 'api_statuses_mentions' , true );
api_register_func ( 'api/statuses/replies' , 'api_statuses_mentions' , true );
2016-09-25 18:50:08 +02:00
2017-12-16 17:34:44 +01:00
/**
2017-12-24 03:20:50 +01:00
* Returns the most recent statuses posted by the user .
*
2017-12-16 17:34:44 +01:00
* @ param string $type Either " json " or " xml "
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
2017-12-16 17:34:44 +01:00
* @ throws ForbiddenException
2019-01-07 18:24:01 +01:00
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
* @ see https :// developer . twitter . com / en / docs / tweets / timelines / api - reference / get - statuses - user_timeline
2017-12-16 17:34:44 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_statuses_user_timeline ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 10:36:17 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
Logger :: info ( 'api_statuses_user_timeline' , [ 'api_user' => $uid , '_REQUEST' => $_REQUEST ]);
2017-11-10 06:00:50 +01:00
2021-11-20 10:36:17 +01:00
$cid = BaseApi :: getContactIDForSearchterm ( $_REQUEST [ 'screen_name' ] ? ? '' , $_REQUEST [ 'user_id' ] ? ? 0 , $uid );
2019-10-13 04:01:34 +02:00
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2018-11-30 15:06:22 +01:00
$exclude_replies = ! empty ( $_REQUEST [ 'exclude_replies' ]);
2019-10-13 04:01:34 +02:00
$conversation_id = $_REQUEST [ 'conversation_id' ] ? ? 0 ;
2016-09-25 18:50:08 +02:00
2017-12-16 17:34:44 +01:00
// pagination
2019-10-13 04:01:34 +02:00
$count = $_REQUEST [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$condition = [ " (`uid` = ? OR (`uid` = ? AND NOT `global`)) AND `gravity` IN (?, ?) AND `id` > ? AND `author-id` = ? " ,
0 , $uid , GRAVITY_PARENT , GRAVITY_COMMENT , $since_id , $cid ];
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
if ( $exclude_replies ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= ' AND `gravity` = ?' ;
2020-05-28 18:02:36 +02:00
$condition [] = GRAVITY_PARENT ;
2017-11-10 06:00:50 +01:00
}
2017-12-16 17:34:44 +01:00
2017-11-10 06:00:50 +01:00
if ( $conversation_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `parent` = ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $conversation_id ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-16 17:34:44 +01:00
if ( $max_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 18:56:37 +02:00
$condition [] = $max_id ;
2017-12-16 17:34:44 +01:00
}
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 10:36:17 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2017-11-10 06:00:50 +01:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-12-21 17:00:56 +01:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-12-24 00:27:45 +01:00
api_register_func ( 'api/statuses/user_timeline' , 'api_statuses_user_timeline' , true );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2017-12-24 03:20:50 +01:00
* Star / unstar an item .
2017-11-10 06:00:50 +01:00
* param : id : id of the item
*
2017-12-24 03:20:50 +01:00
* @ param string $type Return type ( atom , rss , xml , json )
*
2019-01-07 18:24:01 +01:00
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// web . archive . org / web / 20131019055350 / https :// dev . twitter . com / docs / api / 1 / post / favorites / create /% 3 Aid
2017-11-10 06:00:50 +01:00
*/
function api_favorites_create_destroy ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// for versioned api.
/// @TODO We need a better global soluton
$action_argv_id = 2 ;
2021-07-25 16:27:13 +02:00
if ( count ( DI :: args () -> getArgv ()) > 1 && DI :: args () -> getArgv ()[ 1 ] == " 1.1 " ) {
2017-11-10 06:00:50 +01:00
$action_argv_id = 3 ;
}
2016-09-25 18:50:08 +02:00
2021-07-25 16:27:13 +02:00
if ( DI :: args () -> getArgc () <= $action_argv_id ) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " Invalid request. " );
}
2021-07-25 16:27:13 +02:00
$action = str_replace ( " . " . $type , " " , DI :: args () -> getArgv ()[ $action_argv_id ]);
if ( DI :: args () -> getArgc () == $action_argv_id + 2 ) {
$itemid = intval ( DI :: args () -> getArgv ()[ $action_argv_id + 1 ] ? ? 0 );
2017-11-10 06:00:50 +01:00
} else {
2019-10-13 04:01:34 +02:00
$itemid = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$item = Post :: selectFirstForUser ( $uid , [], [ 'id' => $itemid , 'uid' => $uid ]);
2016-09-25 18:50:08 +02:00
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $item )) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " Invalid item. " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
switch ( $action ) {
case " create " :
2018-06-09 18:56:37 +02:00
$item [ 'starred' ] = 1 ;
2017-11-10 06:00:50 +01:00
break ;
case " destroy " :
2018-06-09 18:56:37 +02:00
$item [ 'starred' ] = 0 ;
2017-11-10 06:00:50 +01:00
break ;
default :
throw new BadRequestException ( " Invalid action " . $action );
}
2016-09-25 18:50:08 +02:00
2018-06-09 18:56:37 +02:00
$r = Item :: update ([ 'starred' => $item [ 'starred' ]], [ 'id' => $itemid ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $r === false ) {
throw new InternalServerErrorException ( " DB error " );
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2021-11-23 22:54:19 +01:00
$ret = DI :: twitterStatus () -> createFromUriId ( $item [ 'uri-id' ], $item [ 'uid' ]) -> toArray ();
2016-09-25 18:50:08 +02:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " status " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/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 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
* Returns the most recent favorite statuses .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_favorites ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 06:00:50 +01:00
// in friendica starred item are private
// return favorites only for self
2021-11-20 10:36:17 +01:00
Logger :: info ( API_LOG_PREFIX . 'for {self}' , [ 'module' => 'api' , 'action' => 'favorites' ]);
2017-11-10 06:00:50 +01:00
2021-11-20 10:36:17 +01:00
// params
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
$count = $_GET [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$condition = [ " `uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `starred` " ,
2021-11-20 14:44:12 +01:00
$uid , GRAVITY_PARENT , GRAVITY_COMMENT , $since_id ];
2018-06-09 18:56:37 +02:00
2021-11-20 10:36:17 +01:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2018-06-09 18:56:37 +02:00
2021-11-20 10:36:17 +01:00
if ( $max_id > 0 ) {
$condition [ 0 ] .= " AND `id` <= ? " ;
$condition [] = $max_id ;
}
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2016-09-25 18:50:08 +02:00
2021-11-21 00:38:52 +01:00
$ret = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$ret [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-12-21 17:00:56 +01:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/favorites' , 'api_favorites' , true );
2017-12-24 03:20:50 +01:00
/**
*
* @ param array $item
* @ param array $recipient
* @ param array $sender
*
* @ return array
2019-01-07 18:24:01 +01:00
* @ throws InternalServerErrorException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_format_messages ( $item , $recipient , $sender )
{
// standard meta information
2018-01-15 14:05:12 +01:00
$ret = [
2018-07-01 20:42:38 +02:00
'id' => $item [ 'id' ],
2018-10-01 19:36:23 +02:00
'sender_id' => $sender [ 'id' ],
2018-07-01 20:42:38 +02:00
'text' => " " ,
'recipient_id' => $recipient [ 'id' ],
2021-11-19 06:05:58 +01:00
'created_at' => DateTimeFormat :: utc ( $item [ 'created' ] ? ? 'now' , DateTimeFormat :: API ),
2018-07-01 20:42:38 +02:00
'sender_screen_name' => $sender [ 'screen_name' ],
'recipient_screen_name' => $recipient [ 'screen_name' ],
'sender' => $sender ,
'recipient' => $recipient ,
'title' => " " ,
2019-10-13 04:01:34 +02:00
'friendica_seen' => $item [ 'seen' ] ? ? 0 ,
'friendica_parent_uri' => $item [ 'parent-uri' ] ? ? '' ,
2018-01-15 14:05:12 +01:00
];
2017-11-10 06:00:50 +01:00
2021-11-21 21:14:48 +01:00
// "uid" is only needed for some internal stuff, so remove it from here
2018-07-01 20:42:38 +02:00
if ( isset ( $ret [ 'sender' ][ 'uid' ])) {
unset ( $ret [ 'sender' ][ 'uid' ]);
}
if ( isset ( $ret [ 'recipient' ][ 'uid' ])) {
unset ( $ret [ 'recipient' ][ 'uid' ]);
}
2017-11-10 06:00:50 +01:00
//don't send title to regular StatusNET requests to avoid confusing these apps
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_GET [ 'getText' ])) {
2017-11-10 06:00:50 +01:00
$ret [ 'title' ] = $item [ 'title' ];
if ( $_GET [ 'getText' ] == 'html' ) {
2021-07-10 14:58:48 +02:00
$ret [ 'text' ] = BBCode :: convertForUriId ( $item [ 'uri-id' ], $item [ 'body' ], BBCode :: API );
2017-11-10 06:00:50 +01:00
} elseif ( $_GET [ 'getText' ] == 'plain' ) {
2021-07-10 14:58:48 +02:00
$ret [ 'text' ] = trim ( HTML :: toPlaintext ( BBCode :: convertForUriId ( $item [ 'uri-id' ], api_clean_plain_items ( $item [ 'body' ]), BBCode :: API ), 0 ));
2017-11-10 06:00:50 +01:00
}
} else {
2021-07-10 14:58:48 +02:00
$ret [ 'text' ] = $item [ 'title' ] . " \n " . HTML :: toPlaintext ( BBCode :: convertForUriId ( $item [ 'uri-id' ], api_clean_plain_items ( $item [ 'body' ]), BBCode :: API ), 0 );
2017-11-10 06:00:50 +01:00
}
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_GET [ 'getUserObjects' ]) && $_GET [ 'getUserObjects' ] == 'false' ) {
2017-11-10 06:00:50 +01:00
unset ( $ret [ 'sender' ]);
unset ( $ret [ 'recipient' ]);
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $ret ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* return likes , dislikes and attend status for item
2017-11-10 06:00:50 +01:00
*
2019-01-07 18:24:01 +01:00
* @ param array $item array
2017-12-24 03:20:50 +01:00
* @ param string $type Return type ( atom , rss , xml , json )
*
2017-11-10 06:00:50 +01:00
* @ return array
2019-01-07 18:24:01 +01:00
* likes => int count ,
* dislikes => int count
* @ throws BadRequestException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 06:00:50 +01:00
*/
2018-10-01 20:16:19 +02:00
function api_format_items_activities ( $item , $type = " json " )
2017-11-10 06:00:50 +01:00
{
2018-01-15 14:05:12 +01:00
$activities = [
'like' => [],
'dislike' => [],
'attendyes' => [],
'attendno' => [],
'attendmaybe' => [],
2019-12-19 08:19:03 +01:00
'announce' => [],
2018-01-15 14:05:12 +01:00
];
2017-11-10 06:00:50 +01:00
2019-12-19 08:19:03 +01:00
$condition = [ 'uid' => $item [ 'uid' ], 'thr-parent' => $item [ 'uri' ], 'gravity' => GRAVITY_ACTIVITY ];
2021-01-16 23:37:27 +01:00
$ret = Post :: selectForUser ( $item [ 'uid' ], [ 'author-id' , 'verb' ], $condition );
2017-11-10 06:00:50 +01:00
2021-01-17 13:49:53 +01:00
while ( $parent_item = Post :: fetch ( $ret )) {
2017-11-10 06:00:50 +01:00
// 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
2021-11-20 14:44:12 +01:00
$user = DI :: twitterUser () -> createFromContactId ( $parent_item [ 'author-id' ], $item [ 'uid' ]) -> toArray ();
2018-10-01 20:16:19 +02:00
switch ( $parent_item [ 'verb' ]) {
2019-10-24 00:25:43 +02:00
case Activity :: LIKE :
2017-11-10 06:00:50 +01:00
$activities [ 'like' ][] = $user ;
break ;
2019-10-24 00:25:43 +02:00
case Activity :: DISLIKE :
2017-11-10 06:00:50 +01:00
$activities [ 'dislike' ][] = $user ;
break ;
2019-10-24 00:25:43 +02:00
case Activity :: ATTEND :
2017-11-10 06:00:50 +01:00
$activities [ 'attendyes' ][] = $user ;
break ;
2019-10-24 00:25:43 +02:00
case Activity :: ATTENDNO :
2017-11-10 06:00:50 +01:00
$activities [ 'attendno' ][] = $user ;
break ;
2019-10-24 00:25:43 +02:00
case Activity :: ATTENDMAYBE :
2017-11-10 06:00:50 +01:00
$activities [ 'attendmaybe' ][] = $user ;
break ;
2019-12-19 08:19:03 +01:00
case Activity :: ANNOUNCE :
$activities [ 'announce' ][] = $user ;
break ;
2017-11-10 06:00:50 +01:00
default :
break ;
2017-09-14 07:16:23 +02:00
}
2017-11-10 06:00:50 +01:00
}
2017-09-14 07:16:23 +02:00
2018-07-20 14:19:26 +02:00
DBA :: close ( $ret );
2018-06-18 22:36:34 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
2018-01-15 14:05:12 +01:00
$xml_activities = [];
2017-11-10 06:00:50 +01: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-24 00:27:45 +01:00
foreach ( $v as $user ) {
2017-11-10 06:00:50 +01:00
$xml_activities [ " friendica: " . $k ][ $k_user ++. " :user " ] = $user ;
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
}
$activities = $xml_activities ;
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $activities ;
}
2017-06-08 04:00:59 +02:00
2017-12-24 03:20:50 +01:00
/**
2018-04-07 15:54:26 +02:00
* Returns all lists the user subscribes to .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - list
2017-12-24 03:20:50 +01:00
*/
2018-04-07 15:54:26 +02:00
function api_lists_list ( $type )
2017-11-10 06:00:50 +01:00
{
2018-01-15 14:05:12 +01:00
$ret = [];
2017-11-10 06:00:50 +01:00
/// @TODO $ret is not filled here?
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'lists' , $type , [ " lists_list " => $ret ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2018-04-07 15:54:26 +02:00
api_register_func ( 'api/lists/list' , 'api_lists_list' , true );
api_register_func ( 'api/lists/subscriptions' , 'api_lists_list' , true );
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01:00
/**
2018-04-07 15:54:26 +02:00
* Returns all groups the user owns .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - ownerships
2017-12-24 03:20:50 +01:00
*/
2018-04-07 15:54:26 +02:00
function api_lists_ownerships ( $type )
2017-11-10 06:00:50 +01:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 15:54:26 +02:00
// params
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2018-04-07 15:54:26 +02:00
2018-07-20 14:19:26 +02:00
$groups = DBA :: select ( 'group' , [], [ 'deleted' => 0 , 'uid' => $uid ]);
2018-04-07 15:54:26 +02:00
// loop through all groups
2018-04-07 19:55:41 +02:00
$lists = [];
foreach ( $groups as $group ) {
if ( $group [ 'visible' ]) {
2018-04-07 15:54:26 +02:00
$mode = 'public' ;
} else {
$mode = 'private' ;
}
2018-04-07 19:55:41 +02:00
$lists [] = [
'name' => $group [ 'name' ],
'id' => intval ( $group [ 'id' ]),
'id_str' => ( string ) $group [ 'id' ],
2018-04-07 15:54:26 +02:00
'user' => $user_info ,
'mode' => $mode
];
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => [ 'lists' => $lists ]]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2018-04-07 15:54:26 +02:00
api_register_func ( 'api/lists/ownerships' , 'api_lists_ownerships' , true );
/**
* Returns recent statuses from users in the specified group .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - ownerships
*/
function api_lists_statuses ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 15:54:26 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'user_id' ]);
unset ( $_GET [ 'user_id' ]);
2018-04-07 15:54:26 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'screen_name' ]);
unset ( $_GET [ 'screen_name' ]);
2018-04-07 15:54:26 +02:00
2018-04-08 00:55:05 +02:00
if ( empty ( $_REQUEST [ 'list_id' ])) {
2018-04-07 22:36:54 +02:00
throw new BadRequestException ( 'list_id not specified' );
}
2018-04-07 15:54:26 +02:00
// params
2019-10-13 04:01:34 +02:00
$count = $_REQUEST [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2018-11-30 15:06:22 +01:00
$exclude_replies = ( ! empty ( $_REQUEST [ 'exclude_replies' ]) ? 1 : 0 );
2019-10-13 04:01:34 +02:00
$conversation_id = $_REQUEST [ 'conversation_id' ] ? ? 0 ;
2018-04-07 15:54:26 +02:00
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2018-04-07 15:54:26 +02:00
2021-01-18 23:26:17 +01:00
$groups = DBA :: selectToArray ( 'group_member' , [ 'contact-id' ], [ 'gid' => 1 ]);
$gids = array_column ( $groups , 'contact-id' );
2021-11-20 14:44:12 +01:00
$condition = [ 'uid' => $uid , 'gravity' => [ GRAVITY_PARENT , GRAVITY_COMMENT ], 'group-id' => $gids ];
2021-01-18 23:26:17 +01:00
$condition = DBA :: mergeConditions ( $condition , [ " `id` > ? " , $since_id ]);
2018-04-07 15:54:26 +02:00
2018-06-09 21:12:13 +02:00
if ( $max_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `id` <= ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $max_id ;
}
if ( $exclude_replies > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= ' AND `gravity` = ?' ;
2020-05-28 18:02:36 +02:00
$condition [] = GRAVITY_PARENT ;
2018-06-09 21:12:13 +02:00
}
if ( $conversation_id > 0 ) {
2021-01-16 23:57:36 +01:00
$condition [ 0 ] .= " AND `parent` = ? " ;
2018-06-09 21:12:13 +02:00
$condition [] = $conversation_id ;
}
2018-06-09 18:56:37 +02:00
$params = [ 'order' => [ 'id' => true ], 'limit' => [ $start , $count ]];
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition , $params );
2018-04-07 15:54:26 +02:00
2021-11-21 00:38:52 +01:00
$items = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$items [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-04-07 15:54:26 +02:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " statuses " , $type , [ 'status' => $items ], Contact :: getPublicIdByUserId ( $uid ));
2018-04-07 15:54:26 +02:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/lists/statuses' , 'api_lists_statuses' , true );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* Returns either the friends of the follower list
*
2017-12-24 03:20:50 +01:00
* Considers friends and followers lists to be private and won ' t return
2017-12-16 16:16:25 +01:00
* anything if any user_id parameter is passed .
*
* @ param string $qtype Either " friends " or " followers "
* @ return boolean | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
2017-12-16 16:16:25 +01:00
* @ throws ForbiddenException
2019-01-07 18:24:01 +01:00
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 06:00:50 +01:00
*/
2017-12-16 16:16:25 +01:00
function api_statuses_f ( $qtype )
2017-11-10 06:00:50 +01:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-12-16 16:16:25 +01:00
// pagination
2019-10-13 04:01:34 +02:00
$count = $_GET [ 'count' ] ? ? 20 ;
$page = $_GET [ 'page' ] ? ? 1 ;
$start = max ( 0 , ( $page - 1 ) * $count );
2017-12-16 16:16:25 +01:00
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_GET [ 'cursor' ]) && $_GET [ 'cursor' ] == 'undefined' ) {
2017-11-10 06:00:50 +01: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 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/* $ret = Array ();
return array ( '$users' => $ret ); */
return false ;
}
2016-09-25 18:50:08 +02:00
2017-12-23 01:30:50 +01:00
$sql_extra = '' ;
2017-11-10 06:00:50 +01:00
if ( $qtype == 'friends' ) {
2018-07-25 04:53:46 +02:00
$sql_extra = sprintf ( " AND ( `rel` = %d OR `rel` = %d ) " , intval ( Contact :: SHARING ), intval ( Contact :: FRIEND ));
2017-12-23 01:30:50 +01:00
} elseif ( $qtype == 'followers' ) {
2018-07-25 04:53:46 +02:00
$sql_extra = sprintf ( " AND ( `rel` = %d OR `rel` = %d ) " , intval ( Contact :: FOLLOWER ), intval ( Contact :: FRIEND ));
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-18 15:18:31 +01:00
if ( $qtype == 'blocks' ) {
2017-12-18 23:51:03 +01:00
$sql_filter = 'AND `blocked` AND NOT `pending`' ;
} elseif ( $qtype == 'incoming' ) {
$sql_filter = 'AND `pending`' ;
2017-12-18 15:18:31 +01:00
} else {
2017-12-18 23:51:03 +01:00
$sql_filter = 'AND (NOT `blocked` OR `pending`)' ;
2017-12-18 15:18:31 +01:00
}
2021-10-09 23:16:15 +02:00
// @todo This query most likely can be replaced with a Contact::select...
$r = DBA :: toArray ( DBA :: p (
2021-11-17 22:28:51 +01:00
" SELECT `id`
2017-12-16 16:16:25 +01:00
FROM `contact`
2021-10-09 23:16:15 +02:00
WHERE `uid` = ?
2017-12-16 16:16:25 +01:00
AND NOT `self`
2017-12-18 23:51:03 +01:00
$sql_filter
2017-12-16 16:16:25 +01:00
$sql_extra
ORDER BY `nick`
2021-10-09 23:16:15 +02:00
LIMIT ? , ? " ,
2021-11-20 14:44:12 +01:00
$uid ,
2021-10-09 23:16:15 +02:00
$start ,
$count
));
2016-09-25 18:50:08 +02:00
2018-01-15 14:05:12 +01:00
$ret = [];
2017-11-10 06:00:50 +01:00
foreach ( $r as $cid ) {
2021-11-20 14:44:12 +01:00
$user = DI :: twitterUser () -> createFromContactId ( $cid [ 'id' ], $uid ) -> toArray ();
2021-11-21 21:14:48 +01:00
// "uid" is only needed for some internal stuff, so remove it from here
2021-11-20 14:44:12 +01:00
unset ( $user [ 'uid' ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $user ) {
$ret [] = $user ;
2016-09-25 18:50:08 +02:00
}
}
2018-01-15 14:05:12 +01:00
return [ 'user' => $ret ];
2017-11-10 06:00:50 +01:00
}
2017-01-16 21:59:16 +01:00
2017-12-16 16:16:25 +01:00
/**
2020-01-19 07:05:23 +01:00
* Returns the list of friends of the provided user
2017-12-16 16:16:25 +01:00
*
* @ deprecated By Twitter API in favor of friends / list
*
* @ param string $type Either " json " or " xml "
* @ return boolean | string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-16 16:16:25 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_statuses_friends ( $type )
{
2017-12-16 16:16:25 +01:00
$data = api_statuses_f ( " friends " );
2017-11-10 06:00:50 +01:00
if ( $data === false ) {
return false ;
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " users " , $type , $data );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-16 16:16:25 +01:00
/**
2020-01-19 07:05:23 +01:00
* Returns the list of followers of the provided user
2017-12-16 16:16:25 +01:00
*
* @ deprecated By Twitter API in favor of friends / list
*
* @ param string $type Either " json " or " xml "
* @ return boolean | string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-16 16:16:25 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_statuses_followers ( $type )
{
2017-12-16 16:16:25 +01:00
$data = api_statuses_f ( " followers " );
2017-11-10 06:00:50 +01:00
if ( $data === false ) {
return false ;
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " users " , $type , $data );
2017-11-10 06:00:50 +01:00
}
/// @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 15:18:31 +01: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
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-18 15:18:31 +01:00
*/
function api_blocks_list ( $type )
{
$data = api_statuses_f ( 'blocks' );
if ( $data === false ) {
return false ;
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " users " , $type , $data );
2017-12-18 15:18:31 +01:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/blocks/list' , 'api_blocks_list' , true );
2017-12-18 23:51:03 +01: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
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-18 23:51:03 +01:00
*/
function api_friendships_incoming ( $type )
{
$data = api_statuses_f ( 'incoming' );
if ( $data === false ) {
return false ;
}
2018-01-15 14:05:12 +01:00
$ids = [];
2017-12-18 23:51:03 +01:00
foreach ( $data [ 'user' ] as $user ) {
$ids [] = $user [ 'id' ];
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " ids " , $type , [ 'id' => $ids ]);
2017-12-18 23:51:03 +01:00
}
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/friendships/incoming' , 'api_friendships_incoming' , true );
2017-12-24 03:20:50 +01:00
/**
* Sends a new direct message .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / new - message
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_new ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-17 23:44:52 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 00:03:18 +01:00
2021-11-18 21:09:17 +01:00
if ( empty ( $_POST [ " text " ]) || empty ( $_POST [ 'screen_name' ]) && empty ( $_POST [ 'user_id' ])) {
2017-12-24 00:27:45 +01:00
return ;
}
2016-09-25 18:50:08 +02:00
2021-11-17 22:28:51 +01:00
$sender = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2016-09-25 18:50:08 +02:00
2021-11-20 10:36:17 +01:00
$cid = BaseApi :: getContactIDForSearchterm ( $_POST [ 'screen_name' ] ? ? '' , $_POST [ 'user_id' ] ? ? 0 , $uid );
if ( empty ( $cid )) {
2018-07-01 20:43:22 +02:00
throw new NotFoundException ( 'Recipient not found' );
}
2017-11-10 06:00:50 +01:00
$replyto = '' ;
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_REQUEST [ 'replyto' ])) {
2021-11-21 06:40:48 +01:00
$mail = DBA :: selectFirst ( 'mail' , [ 'parent-uri' , 'title' ], [ 'uid' => $uid , 'id' => $_REQUEST [ 'replyto' ]]);
2021-10-03 17:02:20 +02:00
$replyto = $mail [ 'parent-uri' ];
$sub = $mail [ 'title' ];
2017-11-10 06:00:50 +01:00
} else {
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_REQUEST [ 'title' ])) {
2017-11-10 06:00:50 +01:00
$sub = $_REQUEST [ 'title' ];
2017-04-05 22:07:55 +02:00
} else {
2017-11-10 06:00:50 +01:00
$sub = (( strlen ( $_POST [ 'text' ]) > 10 ) ? substr ( $_POST [ 'text' ], 0 , 10 ) . " ... " : $_POST [ 'text' ]);
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2021-11-21 06:40:48 +01:00
$cdata = Contact :: getPublicAndUserContactID ( $cid , $uid );
$id = Mail :: send ( $cdata [ 'user' ], $_POST [ 'text' ], $sub , $replyto );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $id > - 1 ) {
2021-10-03 17:02:20 +02:00
$mail = DBA :: selectFirst ( 'mail' , [], [ 'id' => $id ]);
2021-11-20 10:36:17 +01:00
$ret = api_format_messages ( $mail , DI :: twitterUser () -> createFromContactId ( $cid , $uid ) -> toArray (), $sender );
2017-11-10 06:00:50 +01:00
} else {
2021-10-03 17:02:20 +02:00
$ret = [ " error " => $id ];
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " direct-messages " , $type , [ 'direct_message' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01: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 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* delete a direct_message from mail table through api
2017-11-10 06:00:50 +01:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-04-09 19:34:02 +02:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / delete - message
2017-11-10 06:00:50 +01:00
*/
function api_direct_messages_destroy ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
//required
2019-10-13 04:01:34 +02:00
$id = $_REQUEST [ 'id' ] ? ? 0 ;
2017-11-10 06:00:50 +01:00
// optional
2019-10-13 04:01:34 +02:00
$parenturi = $_REQUEST [ 'friendica_parenturi' ] ? ? '' ;
2018-11-30 15:06:22 +01:00
$verbose = ( ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
2017-11-10 06:00:50 +01:00
/// @todo optional parameter 'include_entities' from Twitter API not yet implemented
// error if no id or parenturi specified (for clients posting parent-uri as well)
if ( $verbose == " true " && ( $id == 0 || $parenturi == " " )) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'error' , 'message' => 'message id or parenturi not specified' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-11-10 06:00:50 +01:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// BadRequestException if no id specified (for clients using Twitter API)
if ( $id == 0 ) {
throw new BadRequestException ( 'Message id not specified' );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// add parent-uri to sql command if specified by calling app
2018-07-21 15:10:13 +02:00
$sql_extra = ( $parenturi != " " ? " AND `parent-uri` = ' " . DBA :: escape ( $parenturi ) . " ' " : " " );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// error message if specified id is not in database
2021-10-08 12:01:15 +02:00
if ( ! DBA :: exists ( 'mail' , [ " `uid` = ? AND `id` = ? " . $sql_extra , $uid , $id ])) {
2017-11-10 06:00:50 +01:00
if ( $verbose == " true " ) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'error' , 'message' => 'message id not in database' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-04-05 22:17:15 +02:00
}
2017-11-10 06:00:50 +01:00
/// @todo BadRequestException ok for Twitter API clients?
throw new BadRequestException ( 'message id not in database' );
}
// delete message
2021-10-08 12:01:15 +02:00
$result = DBA :: delete ( 'mail' , [ " `uid` = ? AND `id` = ? " . $sql_extra , $uid , $id ]);
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $verbose == " true " ) {
if ( $result ) {
// return success
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'ok' , 'message' => 'message deleted' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_message_delete " , $type , [ '$result' => $answer ]);
2017-11-10 06:00:50 +01:00
} else {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'error' , 'message' => 'unknown error' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2017-04-05 22:17:15 +02:00
}
2017-11-10 06:00:50 +01:00
}
/// @todo return JSON data like Twitter API not yet implemented
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/// @TODO move to top of file or somewhere better
api_register_func ( 'api/direct_messages/destroy' , 'api_direct_messages_destroy' , true , API_METHOD_DELETE );
2016-09-25 18:50:08 +02:00
2018-09-14 19:35:24 +02:00
/**
* Unfollow Contact
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string | array
2021-09-26 16:30:44 +02:00
* @ throws HTTPException\BadRequestException
* @ throws HTTPException\ExpectationFailedException
* @ throws HTTPException\ForbiddenException
* @ throws HTTPException\InternalServerErrorException
* @ throws HTTPException\NotFoundException
2019-01-07 18:24:01 +01:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / follow - search - get - users / api - reference / post - friendships - destroy . html
2018-09-14 19:35:24 +02:00
*/
2018-09-13 23:23:53 +02:00
function api_friendships_destroy ( $type )
{
2021-11-18 08:25:16 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-17 23:44:52 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-09-14 09:28:14 +02:00
2021-09-26 16:30:44 +02:00
$owner = User :: getOwnerDataById ( $uid );
if ( ! $owner ) {
Logger :: notice ( API_LOG_PREFIX . 'No owner {uid} found' , [ 'module' => 'api' , 'action' => 'friendships_destroy' , 'uid' => $uid ]);
throw new HTTPException\NotFoundException ( 'Error Processing Request' );
2018-09-14 09:28:14 +02:00
}
2018-09-13 23:23:53 +02:00
2019-10-13 04:01:34 +02:00
$contact_id = $_REQUEST [ 'user_id' ] ? ? 0 ;
2018-09-13 23:23:53 +02:00
2018-09-15 11:06:55 +02:00
if ( empty ( $contact_id )) {
2018-12-30 21:42:56 +01:00
Logger :: notice ( API_LOG_PREFIX . 'No user_id specified' , [ 'module' => 'api' , 'action' => 'friendships_destroy' ]);
2021-09-26 16:30:44 +02:00
throw new HTTPException\BadRequestException ( 'no user_id specified' );
2018-09-14 09:28:14 +02:00
}
2018-09-13 23:23:53 +02:00
2018-09-13 23:32:26 +02:00
// Get Contact by given id
2018-09-14 09:28:14 +02:00
$contact = DBA :: selectFirst ( 'contact' , [ 'url' ], [ 'id' => $contact_id , 'uid' => 0 , 'self' => false ]);
2018-09-13 23:23:53 +02:00
if ( ! DBA :: isResult ( $contact )) {
2021-09-26 16:30:44 +02:00
Logger :: notice ( API_LOG_PREFIX . 'No public contact found for ID {contact}' , [ 'module' => 'api' , 'action' => 'friendships_destroy' , 'contact' => $contact_id ]);
throw new HTTPException\NotFoundException ( 'no contact found to given ID' );
2018-09-13 23:23:53 +02:00
}
2021-09-26 16:30:44 +02:00
$url = $contact [ 'url' ];
2018-09-13 23:23:53 +02:00
$condition = [ " `uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?) " ,
2018-11-08 17:28:29 +01:00
$uid , Contact :: SHARING , Contact :: FRIEND , Strings :: normaliseLink ( $url ),
Strings :: normaliseLink ( $url ), $url ];
2018-09-13 23:23:53 +02:00
$contact = DBA :: selectFirst ( 'contact' , [], $condition );
if ( ! DBA :: isResult ( $contact )) {
2018-12-30 21:42:56 +01:00
Logger :: notice ( API_LOG_PREFIX . 'Not following contact' , [ 'module' => 'api' , 'action' => 'friendships_destroy' ]);
2021-09-26 16:30:44 +02:00
throw new HTTPException\NotFoundException ( 'Not following Contact' );
2018-09-13 23:23:53 +02:00
}
2021-09-26 16:30:44 +02:00
try {
2021-10-02 21:48:20 +02:00
$result = Contact :: terminateFriendship ( $owner , $contact );
2018-09-13 23:23:53 +02:00
2021-09-26 16:30:44 +02:00
if ( $result === null ) {
Logger :: notice ( API_LOG_PREFIX . 'Not supported for {network}' , [ 'module' => 'api' , 'action' => 'friendships_destroy' , 'network' => $contact [ 'network' ]]);
throw new HTTPException\ExpectationFailedException ( 'Unfollowing is currently not supported by this contact\'s network.' );
}
if ( $result === false ) {
throw new HTTPException\ServiceUnavailableException ( 'Unable to unfollow this contact, please retry in a few minutes or contact your administrator.' );
}
} catch ( Exception $e ) {
2021-10-02 21:48:20 +02:00
Logger :: error ( API_LOG_PREFIX . $e -> getMessage (), [ 'owner' => $owner , 'contact' => $contact ]);
2021-09-26 16:30:44 +02:00
throw new HTTPException\InternalServerErrorException ( 'Unable to unfollow this contact, please contact your administrator' );
2018-09-13 23:23:53 +02:00
}
2021-11-21 21:14:48 +01:00
// "uid" is only needed for some internal stuff, so remove it from here
2021-09-26 16:30:44 +02:00
unset ( $contact [ 'uid' ]);
2018-09-16 19:36:25 +02:00
// Set screen_name since Twidere requests it
2021-09-26 16:30:44 +02:00
$contact [ 'screen_name' ] = $contact [ 'nick' ];
2018-09-16 19:36:25 +02:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'friendships-destroy' , $type , [ 'user' => $contact ]);
2018-09-13 23:23:53 +02:00
}
2021-11-12 19:52:01 +01:00
2018-09-13 23:23:53 +02:00
api_register_func ( 'api/friendships/destroy' , 'api_friendships_destroy' , true , API_METHOD_POST );
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
* @ param string $box
* @ param string $verbose
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_box ( $type , $box , $verbose )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-17 22:28:51 +01:00
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$count = $_GET [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
2017-04-05 22:17:15 +02:00
2019-10-13 04:01:34 +02:00
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
2017-04-05 22:17:15 +02:00
2019-10-13 04:01:34 +02:00
$user_id = $_REQUEST [ 'user_id' ] ? ? '' ;
$screen_name = $_REQUEST [ 'screen_name' ] ? ? '' ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// caller user info
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'user_id' ]);
unset ( $_GET [ 'user_id' ]);
2016-09-25 18:50:08 +02:00
2021-11-18 21:09:17 +01:00
unset ( $_REQUEST [ 'screen_name' ]);
unset ( $_GET [ 'screen_name' ]);
2016-09-25 18:50:08 +02:00
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2021-11-17 22:28:51 +01:00
2017-11-10 06:00:50 +01:00
$profile_url = $user_info [ " url " ];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// pagination
2019-10-13 04:01:34 +02:00
$start = max ( 0 , ( $page - 1 ) * $count );
2016-09-25 18:50:08 +02:00
2018-02-11 22:13:29 +01:00
$sql_extra = " " ;
2017-11-10 06:00:50 +01:00
// filters
if ( $box == " sentbox " ) {
2018-07-21 15:10:13 +02:00
$sql_extra = " `mail`.`from-url`=' " . DBA :: escape ( $profile_url ) . " ' " ;
2017-11-10 06:00:50 +01:00
} elseif ( $box == " conversation " ) {
2019-10-13 04:01:34 +02:00
$sql_extra = " `mail`.`parent-uri`=' " . DBA :: escape ( $_GET [ 'uri' ] ? ? '' ) . " ' " ;
2017-11-10 06:00:50 +01:00
} elseif ( $box == " all " ) {
$sql_extra = " true " ;
} elseif ( $box == " inbox " ) {
2018-07-21 15:10:13 +02:00
$sql_extra = " `mail`.`from-url`!=' " . DBA :: escape ( $profile_url ) . " ' " ;
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:17:15 +02:00
2017-11-10 06:00:50 +01:00
if ( $max_id > 0 ) {
$sql_extra .= ' AND `mail`.`id` <= ' . intval ( $max_id );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $user_id != " " ) {
$sql_extra .= ' AND `mail`.`contact-id` = ' . intval ( $user_id );
} elseif ( $screen_name != " " ) {
2018-07-21 15:10:13 +02:00
$sql_extra .= " AND `contact`.`nick` = ' " . DBA :: escape ( $screen_name ) . " ' " ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-10-08 06:10:45 +02:00
$r = DBA :: toArray ( DBA :: p (
" SELECT `mail`.*, `contact`.`nurl` AS `contact-url` FROM `mail`,`contact` WHERE `mail`.`contact-id` = `contact`.`id` AND `mail`.`uid` = ? AND $sql_extra AND `mail`.`id` > ? ORDER BY `mail`.`id` DESC LIMIT ?,? " ,
2021-11-20 14:44:12 +01:00
$uid ,
2021-10-08 06:10:45 +02:00
$since_id ,
$start ,
$count
));
2018-07-21 14:46:04 +02:00
if ( $verbose == " true " && ! DBA :: isResult ( $r )) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'error' , 'message' => 'no mails available' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_messages_all " , $type , [ '$result' => $answer ]);
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:17:15 +02:00
2018-01-15 14:05:12 +01:00
$ret = [];
2017-11-10 06:00:50 +01:00
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
2021-11-20 14:44:12 +01:00
$sender = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
2021-11-20 14:44:12 +01:00
$recipient = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
$sender = $user_info ;
}
2016-09-25 18:50:08 +02:00
2018-04-09 21:34:53 +02:00
if ( isset ( $recipient ) && isset ( $sender )) {
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2021-11-21 01:26:35 +01:00
return DI :: apiResponse () -> formatData ( " direct-messages " , $type , [ 'direct_message' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 06:00:50 +01:00
}
2017-12-24 03:20:50 +01:00
/**
* Returns the most recent direct messages sent by the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - sent - message
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_sentbox ( $type )
{
2018-11-30 15:06:22 +01:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
2017-11-10 06:00:50 +01:00
return api_direct_messages_box ( $type , " sentbox " , $verbose );
}
2017-12-24 03:20:50 +01:00
/**
* Returns the most recent direct messages sent to the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-24 03:20:50 +01:00
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - messages
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_inbox ( $type )
{
2018-11-30 15:06:22 +01:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
2017-11-10 06:00:50 +01:00
return api_direct_messages_box ( $type , " inbox " , $verbose );
}
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_all ( $type )
{
2018-11-30 15:06:22 +01:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
2017-11-10 06:00:50 +01:00
return api_direct_messages_box ( $type , " all " , $verbose );
}
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_direct_messages_conversation ( $type )
{
2018-11-30 15:06:22 +01:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
2017-11-10 06:00:50 +01:00
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 );
/**
2020-01-19 07:05:23 +01:00
* list all photos of the authenticated user
2017-11-10 06:00:50 +01:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-04-09 19:34:02 +02:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws ForbiddenException
* @ throws InternalServerErrorException
2017-11-10 06:00:50 +01:00
*/
function api_fr_photos_list ( $type )
{
2021-11-18 08:25:16 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 08:25:16 +01:00
2021-10-08 06:10:45 +02:00
$r = DBA :: toArray ( DBA :: p (
2017-11-10 06:00:50 +01:00
" SELECT `resource-id`, MAX(scale) AS `scale`, `album`, `filename`, `type`, MAX(`created`) AS `created`,
MAX ( `edited` ) AS `edited` , MAX ( `desc` ) AS `desc` FROM `photo`
2021-10-11 16:21:10 +02:00
WHERE `uid` = ? AND NOT `photo-type` IN ( ? , ? ) GROUP BY `resource-id` , `album` , `filename` , `type` " ,
2021-11-20 14:44:12 +01:00
$uid , Photo :: CONTACT_AVATAR , Photo :: CONTACT_BANNER
2021-10-08 06:10:45 +02:00
));
2018-01-15 14:05:12 +01:00
$typetoext = [
2017-11-10 06:00:50 +01:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 14:05:12 +01:00
];
$data = [ 'photo' => []];
2018-07-21 14:46:04 +02:00
if ( DBA :: isResult ( $r )) {
2017-11-10 06:00:50 +01:00
foreach ( $r as $rr ) {
2018-01-15 14:05:12 +01:00
$photo = [];
2017-11-10 06:00:50 +01:00
$photo [ 'id' ] = $rr [ 'resource-id' ];
$photo [ 'album' ] = $rr [ 'album' ];
$photo [ 'filename' ] = $rr [ 'filename' ];
$photo [ 'type' ] = $rr [ 'type' ];
2019-12-30 23:00:08 +01:00
$thumb = DI :: baseUrl () . " /photo/ " . $rr [ 'resource-id' ] . " - " . $rr [ 'scale' ] . " . " . $typetoext [ $rr [ 'type' ]];
2017-11-10 06:00:50 +01:00
$photo [ 'created' ] = $rr [ 'created' ];
$photo [ 'edited' ] = $rr [ 'edited' ];
$photo [ 'desc' ] = $rr [ 'desc' ];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
2018-01-15 14:05:12 +01:00
$data [ 'photo' ][] = [ " @attributes " => $photo , " 1 " => $thumb ];
2017-04-05 22:07:55 +02:00
} else {
2017-11-10 06:00:50 +01:00
$photo [ 'thumb' ] = $thumb ;
$data [ 'photo' ][] = $photo ;
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photos " , $type , $data );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* upload a new photo or change an existing photo
2017-11-10 06:00:50 +01:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-04-09 19:34:02 +02:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
2017-11-10 06:00:50 +01:00
*/
function api_fr_photo_create_update ( $type )
{
2021-11-18 08:25:16 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 08:25:16 +01:00
2017-11-10 06:00:50 +01:00
// input params
2019-10-13 04:01:34 +02:00
$photo_id = $_REQUEST [ 'photo_id' ] ? ? null ;
$desc = $_REQUEST [ 'desc' ] ? ? null ;
$album = $_REQUEST [ 'album' ] ? ? null ;
$album_new = $_REQUEST [ 'album_new' ] ? ? null ;
$allow_cid = $_REQUEST [ 'allow_cid' ] ? ? null ;
$deny_cid = $_REQUEST [ 'deny_cid' ] ? ? null ;
$allow_gid = $_REQUEST [ 'allow_gid' ] ? ? null ;
$deny_gid = $_REQUEST [ 'deny_gid' ] ? ? null ;
2020-12-22 04:21:42 +01:00
$visibility = ! $allow_cid && ! $deny_cid && ! $allow_gid && ! $deny_gid ;
2017-11-10 06:00:50 +01:00
// 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 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// error if no media posted in create-mode
2018-11-30 15:06:22 +01:00
if ( empty ( $_FILES [ 'media' ])) {
2017-11-10 06:00:50 +01:00
// Output error
throw new BadRequestException ( " no media data submitted " );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// album_new will be ignored in create-mode
$album_new = " " ;
} else {
$mode = " update " ;
2016-09-25 18:50:08 +02:00
2018-12-11 20:03:29 +01:00
// check if photo is existing in databasei
2021-11-20 14:44:12 +01:00
if ( ! Photo :: exists ([ 'resource-id' => $photo_id , 'uid' => $uid , 'album' => $album ])) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " photo not available " );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// checks on acl strings provided by clients
$acl_input_error = false ;
2021-11-20 14:44:12 +01:00
$acl_input_error |= check_acl_input ( $allow_cid , $uid );
$acl_input_error |= check_acl_input ( $deny_cid , $uid );
$acl_input_error |= check_acl_input ( $allow_gid , $uid );
$acl_input_error |= check_acl_input ( $deny_gid , $uid );
2017-11-10 06:00:50 +01:00
if ( $acl_input_error ) {
throw new BadRequestException ( " acl data invalid " );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// now let's upload the new media in create-mode
if ( $mode == " create " ) {
$media = $_FILES [ 'media' ];
2021-11-20 14:44:12 +01:00
$data = save_media_to_database ( " photo " , $media , $type , $album , trim ( $allow_cid ), trim ( $deny_cid ), trim ( $allow_gid ), trim ( $deny_gid ), $desc , Photo :: DEFAULT , $visibility , null , $uid );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// return success of updating or error message
if ( ! is_null ( $data )) {
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photo_create " , $type , $data );
2017-11-10 06:00:50 +01:00
} else {
throw new InternalServerErrorException ( " unknown error - uploading photo failed, see Friendica log for more information " );
}
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// now let's do the changes in update-mode
if ( $mode == " update " ) {
2018-12-11 20:03:29 +01:00
$updated_fields = [];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $desc )) {
2018-12-11 20:03:29 +01:00
$updated_fields [ 'desc' ] = $desc ;
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $album_new )) {
2018-12-11 20:03:29 +01:00
$updated_fields [ 'album' ] = $album_new ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $allow_cid )) {
$allow_cid = trim ( $allow_cid );
2018-12-11 20:03:29 +01:00
$updated_fields [ 'allow_cid' ] = $allow_cid ;
2017-04-05 22:07:55 +02:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $deny_cid )) {
$deny_cid = trim ( $deny_cid );
2018-12-11 20:03:29 +01:00
$updated_fields [ 'deny_cid' ] = $deny_cid ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $allow_gid )) {
$allow_gid = trim ( $allow_gid );
2018-12-11 20:03:29 +01:00
$updated_fields [ 'allow_gid' ] = $allow_gid ;
2017-11-10 06:00:50 +01:00
}
2017-01-09 13:09:01 +01:00
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $deny_gid )) {
$deny_gid = trim ( $deny_gid );
2018-12-11 20:03:29 +01:00
$updated_fields [ 'deny_gid' ] = $deny_gid ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
$result = false ;
2018-12-11 20:03:29 +01:00
if ( count ( $updated_fields ) > 0 ) {
2017-11-10 06:00:50 +01:00
$nothingtodo = false ;
2021-11-20 14:44:12 +01:00
$result = Photo :: update ( $updated_fields , [ 'uid' => $uid , 'resource-id' => $photo_id , 'album' => $album ]);
2017-11-10 06:00:50 +01:00
} else {
$nothingtodo = true ;
}
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_FILES [ 'media' ])) {
2017-11-10 06:00:50 +01:00
$nothingtodo = false ;
$media = $_FILES [ 'media' ];
2021-11-20 14:44:12 +01:00
$data = save_media_to_database ( " photo " , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , Photo :: DEFAULT , $visibility , $photo_id , $uid );
2017-11-10 06:00:50 +01:00
if ( ! is_null ( $data )) {
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photo_update " , $type , $data );
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
// return success of updating or error message
if ( $result ) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'updated' , 'message' => 'Image id `' . $photo_id . '` has been updated.' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photo_update " , $type , [ '$result' => $answer ]);
2017-11-10 06:00:50 +01:00
} else {
if ( $nothingtodo ) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'cancelled' , 'message' => 'Nothing to update for image id `' . $photo_id . '`.' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photo_update " , $type , [ '$result' => $answer ]);
2017-11-10 06:00:50 +01:00
}
throw new InternalServerErrorException ( " unknown error - update photo entry in database failed " );
}
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
throw new InternalServerErrorException ( " unknown error - this error on uploading or updating a photo should never happen " );
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* returns the details of a specified photo id , if scale is given , returns the photo data in base 64
2017-11-10 06:00:50 +01:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-25 21:14:02 +01:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws InternalServerErrorException
* @ throws NotFoundException
2017-11-10 06:00:50 +01:00
*/
function api_fr_photo_detail ( $type )
{
2021-11-18 08:25:16 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2018-11-30 15:06:22 +01:00
if ( empty ( $_REQUEST [ 'photo_id' ])) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " No photo id. " );
}
2016-09-25 18:50:08 +02:00
2018-11-30 15:06:22 +01:00
$scale = ( ! empty ( $_REQUEST [ 'scale' ]) ? intval ( $_REQUEST [ 'scale' ]) : false );
2017-11-10 06:00:50 +01:00
$photo_id = $_REQUEST [ 'photo_id' ];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// prepare json/xml output with data from database for the requested photo
$data = prepare_photo_data ( $type , $scale , $photo_id );
2016-09-25 18:50:08 +02:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " photo_detail " , $type , $data );
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* updates the profile image for the user ( either a specified profile or the default profile )
2017-11-10 06:00:50 +01:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-24 03:20:50 +01:00
*
2018-04-09 19:34:02 +02:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / post - account - update_profile_image
2017-11-10 06:00:50 +01:00
*/
function api_account_update_profile_image ( $type )
{
2021-11-18 08:25:16 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 08:25:16 +01:00
2017-11-10 06:00:50 +01:00
// input params
2019-10-13 04:01:34 +02:00
$profile_id = $_REQUEST [ 'profile_id' ] ? ? 0 ;
2017-04-05 22:17:15 +02:00
2017-11-10 06:00:50 +01:00
// error if image data is missing
2018-11-30 15:06:22 +01:00
if ( empty ( $_FILES [ 'image' ])) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " no media data submitted " );
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// check if specified profile id is valid
2018-05-04 23:43:29 +02:00
if ( $profile_id != 0 ) {
2021-11-20 14:44:12 +01:00
$profile = DBA :: selectFirst ( 'profile' , [ 'is-default' ], [ 'uid' => $uid , 'id' => $profile_id ]);
2017-11-10 06:00:50 +01:00
// error message if specified profile id is not in database
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $profile )) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " profile_id not available " );
2016-09-25 18:50:08 +02:00
}
2018-05-04 08:33:36 +02:00
$is_default_profile = $profile [ 'is-default' ];
2017-11-10 06:00:50 +01:00
} else {
$is_default_profile = 1 ;
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// get mediadata from image or media (Twitter call api/account/update_profile_image provides image)
$media = null ;
2018-11-30 15:06:22 +01:00
if ( ! empty ( $_FILES [ 'image' ])) {
2017-11-10 06:00:50 +01:00
$media = $_FILES [ 'image' ];
2018-11-30 15:06:22 +01:00
} elseif ( ! empty ( $_FILES [ 'media' ])) {
2017-11-10 06:00:50 +01:00
$media = $_FILES [ 'media' ];
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// save new profile image
2021-11-20 14:44:12 +01:00
$data = save_media_to_database ( " profileimage " , $media , $type , DI :: l10n () -> t ( Photo :: PROFILE_PHOTOS ), " " , " " , " " , " " , " " , Photo :: USER_AVATAR , false , null , $uid );
2017-11-10 06:00:50 +01:00
// get filetype
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
if ( $filetype == " image/jpeg " ) {
$fileext = " jpg " ;
} elseif ( $filetype == " image/png " ) {
$fileext = " png " ;
2018-04-09 21:34:53 +02:00
} else {
throw new InternalServerErrorException ( 'Unsupported filetype' );
2017-05-01 22:19:48 +02:00
}
2018-05-13 16:46:58 +02:00
2017-11-10 06:00:50 +01:00
// change specified profile or all profiles to the new resource-id
if ( $is_default_profile ) {
2021-11-20 14:44:12 +01:00
$condition = [ " `profile` AND `resource-id` != ? AND `uid` = ? " , $data [ 'photo' ][ 'id' ], $uid ];
2021-10-11 16:21:10 +02:00
Photo :: update ([ 'profile' => false , 'photo-type' => Photo :: DEFAULT ], $condition );
2017-11-10 06:00:50 +01:00
} else {
2019-12-30 23:00:08 +01:00
$fields = [ 'photo' => DI :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-4.' . $fileext ,
'thumb' => DI :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-5.' . $fileext ];
2021-11-20 14:44:12 +01:00
DBA :: update ( 'profile' , $fields , [ 'id' => $_REQUEST [ 'profile' ], 'uid' => $uid ]);
2016-09-25 18:50:08 +02:00
}
2021-11-20 14:44:12 +01:00
Contact :: updateSelfFromUserID ( $uid , true );
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
// Update global directory in background
2021-11-20 14:44:12 +01:00
Profile :: publishUpdate ( $uid );
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01: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 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
}
// place api-register for photoalbum calls before 'api/friendica/photo', otherwise this function is never reached
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' , 'api_fr_photo_detail' , true );
api_register_func ( 'api/account/update_profile_image' , 'api_account_update_profile_image' , true , API_METHOD_POST );
2017-12-23 00:46:01 +01:00
/**
* Update user profile
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-23 00:46:01 +01:00
*/
function api_account_update_profile ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-17 22:28:51 +01:00
2021-11-20 14:44:12 +01:00
$api_user = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2017-12-23 00:46:01 +01:00
2017-12-26 01:05:00 +01:00
if ( ! empty ( $_POST [ 'name' ])) {
2021-11-20 14:44:12 +01:00
DBA :: update ( 'profile' , [ 'name' => $_POST [ 'name' ]], [ 'uid' => $uid ]);
DBA :: update ( 'user' , [ 'username' => $_POST [ 'name' ]], [ 'uid' => $uid ]);
Contact :: update ([ 'name' => $_POST [ 'name' ]], [ 'uid' => $uid , 'self' => 1 ]);
2021-09-10 20:21:19 +02:00
Contact :: update ([ 'name' => $_POST [ 'name' ]], [ 'id' => $api_user [ 'id' ]]);
2017-12-23 00:46:01 +01:00
}
2017-12-26 01:05:00 +01:00
if ( isset ( $_POST [ 'description' ])) {
2021-11-20 14:44:12 +01:00
DBA :: update ( 'profile' , [ 'about' => $_POST [ 'description' ]], [ 'uid' => $uid ]);
Contact :: update ([ 'about' => $_POST [ 'description' ]], [ 'uid' => $uid , 'self' => 1 ]);
2021-09-10 20:21:19 +02:00
Contact :: update ([ 'about' => $_POST [ 'description' ]], [ 'id' => $api_user [ 'id' ]]);
2017-12-23 00:46:01 +01:00
}
2021-11-20 14:44:12 +01:00
Profile :: publishUpdate ( $uid );
2017-12-23 00:46:01 +01: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 06:00:50 +01:00
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $acl_string
2021-11-20 14:44:12 +01:00
* @ param int $uid
2019-01-07 18:24:01 +01:00
* @ return bool
* @ throws Exception
2017-12-24 03:20:50 +01:00
*/
2021-11-20 14:44:12 +01:00
function check_acl_input ( $acl_string , $uid )
2017-11-10 06:00:50 +01:00
{
2019-10-13 04:01:34 +02:00
if ( empty ( $acl_string )) {
2017-11-10 06:00:50 +01:00
return false ;
2017-05-01 22:19:48 +02:00
}
2019-10-13 04:01:34 +02:00
2017-11-10 06:00:50 +01: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 );
2021-11-20 14:44:12 +01:00
$condition = [ 'id' => $cid , 'uid' => $uid ];
2018-08-19 14:46:11 +02:00
$contact_not_found |= ! DBA :: exists ( 'contact' , $condition );
2017-11-10 06:00:50 +01:00
}
return $contact_not_found ;
}
2017-12-24 03:20:50 +01: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
2021-10-11 16:21:10 +02:00
* @ param integer $phototype
2017-12-24 03:20:50 +01:00
* @ param boolean $visibility
* @ param string $photo_id
2021-11-20 14:44:12 +01:00
* @ param int $uid
2019-01-07 18:24:01 +01:00
* @ return array
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
2019-10-13 04:01:34 +02:00
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2021-11-20 14:44:12 +01:00
function save_media_to_database ( $mediatype , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , $phototype , $visibility , $photo_id , $uid )
2017-11-10 06:00:50 +01:00
{
$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 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
if ( is_array ( $media [ 'name' ])) {
$filename = basename ( $media [ 'name' ][ 0 ]);
2017-05-01 22:19:48 +02:00
} else {
2017-11-10 06:00:50 +01:00
$filename = basename ( $media [ 'name' ]);
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
if ( is_array ( $media [ 'size' ])) {
$filesize = intval ( $media [ 'size' ][ 0 ]);
} else {
$filesize = intval ( $media [ 'size' ]);
2017-05-01 22:19:48 +02:00
}
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
}
}
2020-04-01 07:42:44 +02:00
$filetype = Images :: getMimeTypeBySource ( $src , $filename , $filetype );
2021-10-03 21:43:49 +02:00
logger :: info (
2017-11-10 06:00:50 +01:00
" File upload src: " . $src . " - filename: " . $filename .
2021-10-03 21:43:49 +02:00
" - size: " . $filesize . " - type: " . $filetype );
2017-11-10 06:00:50 +01: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
2020-01-19 21:21:13 +01:00
$maximagesize = DI :: config () -> get ( 'system' , 'maximagesize' );
2017-12-23 00:10:32 +01:00
if ( $maximagesize && ( $filesize > $maximagesize )) {
2018-11-08 16:28:49 +01:00
$formattedBytes = Strings :: formatBytes ( $maximagesize );
2017-11-10 06:00:50 +01:00
throw new InternalServerErrorException ( " image size exceeds Friendica config setting (uploaded size: $formattedBytes ) " );
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
// create Photo instance with the data of the image
$imagedata = @ file_get_contents ( $src );
2017-12-07 14:56:11 +01:00
$Image = new Image ( $imagedata , $filetype );
2018-10-01 19:36:23 +02:00
if ( ! $Image -> isValid ()) {
2017-11-10 06:00:50 +01:00
throw new InternalServerErrorException ( " unable to process image data " );
}
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
// check orientation of image
2017-12-07 14:56:11 +01:00
$Image -> orient ( $src );
2017-11-10 06:00:50 +01:00
@ unlink ( $src );
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
// check max length of images on server
2020-01-19 21:21:13 +01:00
$max_length = DI :: config () -> get ( 'system' , 'max_image_length' );
2017-11-10 06:00:50 +01:00
if ( $max_length > 0 ) {
2017-12-07 14:56:11 +01:00
$Image -> scaleDown ( $max_length );
2021-10-03 21:43:49 +02:00
logger :: info ( " File upload: Scaling picture to new size " . $max_length );
2017-11-10 06:00:50 +01:00
}
2017-12-07 14:56:11 +01:00
$width = $Image -> getWidth ();
$height = $Image -> getHeight ();
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
// create a new resource-id if not already provided
2019-10-26 15:05:35 +02:00
$resource_id = ( $photo_id == null ) ? Photo :: newResource () : $photo_id ;
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
if ( $mediatype == " photo " ) {
// upload normal image (scales 0, 1, 2)
2021-10-03 21:43:49 +02:00
logger :: info ( " photo upload: starting new photo upload " );
2017-05-01 22:19:48 +02:00
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 0 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: image upload with scale 0 (original size) failed " );
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
if ( $width > 640 || $height > 640 ) {
2017-12-07 14:56:11 +01:00
$Image -> scaleDown ( 640 );
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 1 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: image upload with scale 1 (640x640) failed " );
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
}
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
if ( $width > 320 || $height > 320 ) {
2017-12-07 14:56:11 +01:00
$Image -> scaleDown ( 320 );
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 2 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: image upload with scale 2 (320x320) failed " );
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
}
2021-10-03 21:43:49 +02:00
logger :: info ( " photo upload: new photo upload ended " );
2017-11-10 06:00:50 +01:00
} elseif ( $mediatype == " profileimage " ) {
// upload profile image (scales 4, 5, 6)
2021-10-03 21:43:49 +02:00
logger :: info ( " photo upload: starting new profile image upload " );
2017-05-01 22:19:48 +02:00
2018-10-23 16:36:57 +02:00
if ( $width > 300 || $height > 300 ) {
$Image -> scaleDown ( 300 );
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 4 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: profile image upload with scale 4 (300x300) failed " );
2017-05-01 22:19:48 +02:00
}
2017-11-10 06:00:50 +01:00
}
2017-05-01 22:19:48 +02:00
2017-11-10 06:00:50 +01:00
if ( $width > 80 || $height > 80 ) {
2017-12-07 14:56:11 +01:00
$Image -> scaleDown ( 80 );
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 5 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: profile image upload with scale 5 (80x80) failed " );
2017-05-01 22:19:48 +02:00
}
}
2017-11-10 06:00:50 +01:00
if ( $width > 48 || $height > 48 ) {
2017-12-07 14:56:11 +01:00
$Image -> scaleDown ( 48 );
2021-11-20 14:44:12 +01:00
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 6 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
2018-10-01 19:36:23 +02:00
if ( ! $r ) {
2021-10-03 21:43:49 +02:00
logger :: notice ( " photo upload: profile image upload with scale 6 (48x48) failed " );
2017-05-01 22:19:48 +02:00
}
}
2017-12-07 14:56:11 +01:00
$Image -> __destruct ();
2021-10-03 21:43:49 +02:00
logger :: info ( " photo upload: new profile image upload ended " );
2017-05-01 22:19:48 +02:00
}
2020-06-24 14:11:47 +02:00
if ( ! empty ( $r )) {
2017-11-10 06:00:50 +01:00
// create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo
if ( $photo_id == null && $mediatype == " photo " ) {
2021-11-20 14:44:12 +01:00
post_photo_item ( $resource_id , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility , $uid );
2017-11-10 06:00:50 +01:00
}
// on success return image data in json/xml format (like /api/friendica/photo does when no scale is given)
2019-10-26 15:05:35 +02:00
return prepare_photo_data ( $type , false , $resource_id );
2017-11-10 06:00:50 +01:00
} else {
throw new InternalServerErrorException ( " image upload failed " );
}
}
2017-12-24 03:20:50 +01: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
2021-11-20 14:44:12 +01:00
* @ param int $uid
2019-01-07 18:24:01 +01:00
* @ throws InternalServerErrorException
2017-12-24 03:20:50 +01:00
*/
2021-11-20 14:44:12 +01:00
function post_photo_item ( $hash , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility , $uid )
2017-11-10 06:00:50 +01:00
{
// get data about the api authenticated user
2021-11-20 14:44:12 +01:00
$uri = Item :: newURI ( intval ( $uid ));
$owner_record = DBA :: selectFirst ( 'contact' , [], [ 'uid' => $uid , 'self' => true ]);
2017-11-10 06:00:50 +01:00
2018-01-15 14:05:12 +01:00
$arr = [];
2018-09-27 13:52:15 +02:00
$arr [ 'guid' ] = System :: createUUID ();
2021-11-20 14:44:12 +01:00
$arr [ 'uid' ] = intval ( $uid );
2017-11-10 06:00:50 +01:00
$arr [ 'uri' ] = $uri ;
$arr [ 'type' ] = 'photo' ;
$arr [ 'wall' ] = 1 ;
$arr [ 'resource-id' ] = $hash ;
2018-08-19 14:46:11 +02:00
$arr [ 'contact-id' ] = $owner_record [ 'id' ];
$arr [ 'owner-name' ] = $owner_record [ 'name' ];
$arr [ 'owner-link' ] = $owner_record [ 'url' ];
$arr [ 'owner-avatar' ] = $owner_record [ 'thumb' ];
$arr [ 'author-name' ] = $owner_record [ 'name' ];
$arr [ 'author-link' ] = $owner_record [ 'url' ];
$arr [ 'author-avatar' ] = $owner_record [ 'thumb' ];
2017-11-10 06:00:50 +01:00
$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 14:05:12 +01:00
$typetoext = [
2017-04-05 22:07:55 +02:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 14:05:12 +01:00
];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// adds link to the thumbnail scale photo
2019-12-30 23:00:08 +01:00
$arr [ 'body' ] = '[url=' . DI :: baseUrl () . '/photos/' . $owner_record [ 'nick' ] . '/image/' . $hash . ']'
. '[img]' . DI :: baseUrl () . '/photo/' . $hash . '-' . " 2 " . '.' . $typetoext [ $filetype ] . '[/img]'
2017-11-10 06:00:50 +01:00
. '[/url]' ;
// do the magic for storing the item in the database and trigger the federation to other contacts
2018-01-28 12:18:08 +01:00
Item :: insert ( $arr );
2017-11-10 06:00:50 +01:00
}
2017-12-24 03:20:50 +01:00
/**
*
* @ param string $type
* @ param int $scale
* @ param string $photo_id
*
* @ return array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function prepare_photo_data ( $type , $scale , $photo_id )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-09 17:36:33 +02:00
2017-11-10 06:00:50 +01:00
$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
2021-10-09 23:16:15 +02:00
$r = DBA :: toArray ( DBA :: p (
2021-10-09 23:30:14 +02:00
" SELECT $data_sql `resource-id`, `created`, `edited`, `title`, `desc`, `album`, `filename`,
2017-11-10 06:00:50 +01:00
`type` , `height` , `width` , `datasize` , `profile` , `allow_cid` , `deny_cid` , `allow_gid` , `deny_gid` ,
MIN ( `scale` ) AS `minscale` , MAX ( `scale` ) AS `maxscale`
2021-10-09 23:16:15 +02:00
FROM `photo` WHERE `uid` = ? AND `resource-id` = ? $scale_sql GROUP BY
2021-11-09 22:41:37 +01:00
`resource-id` , `created` , `edited` , `title` , `desc` , `album` , `filename` ,
`type` , `height` , `width` , `datasize` , `profile` , `allow_cid` , `deny_cid` , `allow_gid` , `deny_gid` " ,
2021-11-20 14:44:12 +01:00
$uid ,
2021-10-09 23:16:15 +02:00
$photo_id
));
2017-11-10 06:00:50 +01:00
2018-01-15 14:05:12 +01:00
$typetoext = [
2017-11-10 06:00:50 +01:00
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
2018-01-15 14:05:12 +01:00
];
2017-11-10 06:00:50 +01:00
// prepare output data for photo
2018-07-21 14:46:04 +02:00
if ( DBA :: isResult ( $r )) {
2018-01-15 14:05:12 +01:00
$data = [ 'photo' => $r [ 0 ]];
2017-11-10 06:00:50 +01:00
$data [ 'photo' ][ 'id' ] = $data [ 'photo' ][ 'resource-id' ];
if ( $scale !== false ) {
$data [ 'photo' ][ 'data' ] = base64_encode ( $data [ 'photo' ][ 'data' ]);
2016-09-25 18:50:08 +02:00
} else {
2017-11-10 06:00:50 +01:00
unset ( $data [ 'photo' ][ 'datasize' ]); //needed only with scale param
2016-09-25 18:50:08 +02:00
}
2017-05-01 22:19:48 +02:00
if ( $type == " xml " ) {
2018-01-15 14:05:12 +01:00
$data [ 'photo' ][ 'links' ] = [];
2017-11-10 06:00:50 +01:00
for ( $k = intval ( $data [ 'photo' ][ 'minscale' ]); $k <= intval ( $data [ 'photo' ][ 'maxscale' ]); $k ++ ) {
2018-01-15 14:05:12 +01:00
$data [ 'photo' ][ 'links' ][ $k . " :link " ][ " @attributes " ] = [ " type " => $data [ 'photo' ][ 'type' ],
2017-11-10 06:00:50 +01:00
" scale " => $k ,
2019-12-30 23:00:08 +01:00
" href " => DI :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]]];
2017-05-01 22:19:48 +02:00
}
} else {
2018-01-15 14:05:12 +01:00
$data [ 'photo' ][ 'link' ] = [];
2017-11-10 06:00:50 +01: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 ++ ) {
2019-12-30 23:00:08 +01:00
$data [ 'photo' ][ 'link' ][ $i ] = DI :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]];
2017-11-10 06:00:50 +01:00
$i ++ ;
2017-05-01 22:19:48 +02:00
}
}
2017-11-10 06:00:50 +01: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
2021-11-20 14:44:12 +01:00
$condition = [ 'uid' => $uid , 'resource-id' => $photo_id ];
2021-01-16 05:11:28 +01:00
$item = Post :: selectFirst ([ 'id' , 'uid' , 'uri' , 'parent' , 'allow_cid' , 'deny_cid' , 'allow_gid' , 'deny_gid' ], $condition );
2020-01-26 22:43:14 +01:00
if ( ! DBA :: isResult ( $item )) {
throw new NotFoundException ( 'Photo-related item not found.' );
}
2018-06-18 22:36:34 +02:00
$data [ 'photo' ][ 'friendica_activities' ] = api_format_items_activities ( $item , $type );
2017-11-10 06:00:50 +01:00
// retrieve comments on photo
2021-03-07 23:40:47 +01:00
$condition = [ " `parent` = ? AND `uid` = ? AND `gravity` IN (?, ?) " ,
2021-11-20 14:44:12 +01:00
$item [ 'parent' ], $uid , GRAVITY_PARENT , GRAVITY_COMMENT ];
2018-06-09 18:56:37 +02:00
2021-11-20 14:44:12 +01:00
$statuses = Post :: selectForUser ( $uid , [], $condition );
2017-11-10 06:00:50 +01:00
// prepare output of comments
2021-11-21 00:38:52 +01:00
$commentData = [];
while ( $status = DBA :: fetch ( $statuses )) {
2021-11-23 22:54:19 +01:00
$commentData [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
2021-11-21 00:38:52 +01:00
}
DBA :: close ( $statuses );
2018-01-15 14:05:12 +01:00
$comments = [];
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
$k = 0 ;
foreach ( $commentData as $comment ) {
$comments [ $k ++ . " :comment " ] = $comment ;
2017-04-05 22:07:55 +02:00
}
2017-11-10 06:00:50 +01:00
} else {
foreach ( $commentData as $comment ) {
$comments [] = $comment ;
}
}
$data [ 'photo' ][ 'friendica_comments' ] = $comments ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// include info if rights on photo and rights on item are mismatching
2020-06-24 14:11:47 +02:00
$rights_mismatch = $data [ 'photo' ][ 'allow_cid' ] != $item [ 'allow_cid' ] ||
$data [ 'photo' ][ 'deny_cid' ] != $item [ 'deny_cid' ] ||
$data [ 'photo' ][ 'allow_gid' ] != $item [ 'allow_gid' ] ||
$data [ 'photo' ][ 'deny_gid' ] != $item [ 'deny_gid' ];
2017-11-10 06:00:50 +01:00
$data [ 'photo' ][ 'rights_mismatch' ] = $rights_mismatch ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
return $data ;
}
2016-09-25 18:50:08 +02:00
2019-04-24 06:26:23 +02:00
/**
* Return an item with announcer data if it had been announced
*
* @ param array $item Item array
* @ return array Item array with announce data
*/
function api_get_announce ( $item )
{
// Quit if the item already has got a different owner and author
if ( $item [ 'owner-id' ] != $item [ 'author-id' ]) {
return [];
}
// Don't change original or Diaspora posts
if ( $item [ 'origin' ] || in_array ( $item [ 'network' ], [ Protocol :: DIASPORA ])) {
return [];
}
// Quit if we do now the original author and it had been a post from a native network
if ( ! empty ( $item [ 'contact-uid' ]) && in_array ( $item [ 'network' ], Protocol :: NATIVE_SUPPORT )) {
return [];
}
$fields = [ 'author-id' , 'author-name' , 'author-link' , 'author-avatar' ];
2020-05-26 07:18:50 +02:00
$condition = [ 'parent-uri' => $item [ 'uri' ], 'gravity' => GRAVITY_ACTIVITY , 'uid' => [ 0 , $item [ 'uid' ]], 'vid' => Verb :: getID ( Activity :: ANNOUNCE )];
2021-01-16 23:37:27 +01:00
$announce = Post :: selectFirstForUser ( $item [ 'uid' ], $fields , $condition , [ 'order' => [ 'received' => true ]]);
2019-04-24 06:26:23 +02:00
if ( ! DBA :: isResult ( $announce )) {
return [];
}
return array_merge ( $item , $announce );
}
2017-12-24 03:20:50 +01:00
/**
*
2018-05-10 15:13:08 +02:00
* @ param string $text
2017-12-24 03:20:50 +01:00
*
* @ return string
2019-01-07 18:24:01 +01:00
* @ throws InternalServerErrorException
2017-12-24 03:20:50 +01:00
*/
2018-05-10 15:13:08 +02:00
function api_clean_plain_items ( $text )
2017-11-10 06:00:50 +01:00
{
2019-10-13 04:01:34 +02:00
$include_entities = strtolower ( $_REQUEST [ 'include_entities' ] ? ? 'false' );
2016-09-25 18:50:08 +02:00
2018-05-10 15:13:08 +02:00
$text = BBCode :: cleanPictureLinks ( $text );
2017-11-10 06:00:50 +01:00
$URLSearchString = " ^ \ [ \ ] " ;
2016-09-25 18:50:08 +02:00
2018-05-10 15:13:08 +02:00
$text = preg_replace ( " /([!#@]) \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '$1$3' , $text );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $include_entities == " true " ) {
2018-05-10 15:13:08 +02:00
$text = preg_replace ( " / \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '[url=$1]$1[/url]' , $text );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// Simplify "attachment" element
2019-12-02 22:19:47 +01:00
$text = BBCode :: removeAttachment ( $text );
2016-09-25 18:50:08 +02:00
2018-05-10 15:13:08 +02:00
return $text ;
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-24 03:20:50 +01: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
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_friendica_group_show ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$gid = $_REQUEST [ 'gid' ] ? ? 0 ;
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// get data of the specified group id or all groups if not specified
if ( $gid != 0 ) {
2021-10-03 17:02:20 +02:00
$groups = DBA :: selectToArray ( 'group' , [], [ 'deleted' => false , 'uid' => $uid , 'id' => $gid ]);
2016-09-25 18:50:08 +02:00
// error message if specified gid is not in database
2021-10-03 17:02:20 +02:00
if ( ! DBA :: isResult ( $groups )) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( " gid not available " );
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
} else {
2021-10-03 17:02:20 +02:00
$groups = DBA :: selectToArray ( 'group' , [], [ 'deleted' => false , 'uid' => $uid ]);
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// loop through all groups and retrieve all members for adding data in the user array
2018-04-09 21:34:53 +02:00
$grps = [];
2021-10-03 17:02:20 +02:00
foreach ( $groups as $rr ) {
2020-08-04 20:22:19 +02:00
$members = Contact\Group :: getById ( $rr [ 'id' ]);
2018-01-15 14:05:12 +01:00
$users = [];
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
if ( $type == " xml " ) {
$user_element = " users " ;
$k = 0 ;
foreach ( $members as $member ) {
2021-11-20 14:44:12 +01:00
$user = DI :: twitterUser () -> createFromContactId ( $member [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
$users [ $k ++. " :user " ] = $user ;
}
} else {
$user_element = " user " ;
foreach ( $members as $member ) {
2021-11-20 14:44:12 +01:00
$user = DI :: twitterUser () -> createFromContactId ( $member [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
$users [] = $user ;
2016-09-25 18:50:08 +02:00
}
}
2018-01-15 14:05:12 +01:00
$grps [] = [ 'name' => $rr [ 'name' ], 'gid' => $rr [ 'id' ], $user_element => $users ];
2017-11-10 06:00:50 +01:00
}
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " groups " , $type , [ 'group' => $grps ]);
2017-11-10 06:00:50 +01:00
}
2021-11-12 19:52:01 +01:00
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/friendica/group_show' , 'api_friendica_group_show' , true );
2017-12-24 03:20:50 +01:00
/**
2018-04-07 15:54:26 +02:00
* Delete a group .
2017-12-24 03:20:50 +01:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / post - lists - destroy
2017-12-24 03:20:50 +01:00
*/
2018-04-07 15:54:26 +02:00
function api_lists_destroy ( $type )
2017-11-10 06:00:50 +01:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$gid = $_REQUEST [ 'list_id' ] ? ? 0 ;
2017-11-10 06:00:50 +01:00
2018-04-07 15:54:26 +02:00
// error if no gid specified
if ( $gid == 0 ) {
throw new BadRequestException ( 'gid not specified' );
}
// get data of the specified group id
2018-07-20 14:19:26 +02:00
$group = DBA :: selectFirst ( 'group' , [], [ 'uid' => $uid , 'id' => $gid ]);
2018-04-07 15:54:26 +02:00
// error message if specified gid is not in database
2018-04-07 19:55:41 +02:00
if ( ! $group ) {
2018-04-07 15:54:26 +02:00
throw new BadRequestException ( 'gid not available' );
}
if ( Group :: remove ( $gid )) {
2018-04-07 19:55:41 +02:00
$list = [
'name' => $group [ 'name' ],
2018-04-07 15:54:26 +02:00
'id' => intval ( $gid ),
'id_str' => ( string ) $gid ,
2021-11-20 14:44:12 +01:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ()
2018-04-07 15:54:26 +02:00
];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $list ]);
2018-04-07 15:54:26 +02:00
}
}
2021-11-12 19:52:01 +01:00
2018-04-07 15:54:26 +02:00
api_register_func ( 'api/lists/destroy' , 'api_lists_destroy' , true , API_METHOD_DELETE );
/**
* Add a new group to the database .
*
* @ param string $name Group name
2019-01-07 18:24:01 +01:00
* @ param int $uid User ID
2018-04-07 15:54:26 +02:00
* @ param array $users List of users to add to the group
*
* @ return array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
2018-04-07 15:54:26 +02:00
*/
function group_create ( $name , $uid , $users = [])
{
2017-11-10 06:00:50 +01:00
// error if no name specified
2017-12-24 00:27:45 +01:00
if ( $name == " " ) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( 'group name not specified' );
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
2021-10-09 23:16:15 +02:00
// error message if specified group name already exists
2021-10-03 17:02:20 +02:00
if ( DBA :: exists ( 'group' , [ 'uid' => $uid , 'name' => $name , 'deleted' => false ])) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( 'group name already exists' );
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
2021-10-03 17:02:20 +02:00
// Check if the group needs to be reactivated
if ( DBA :: exists ( 'group' , [ 'uid' => $uid , 'name' => $name , 'deleted' => true ])) {
2017-11-10 06:00:50 +01:00
$reactivate_group = true ;
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
// create group
2017-12-09 19:45:17 +01:00
$ret = Group :: create ( $uid , $name );
2017-11-10 06:00:50 +01:00
if ( $ret ) {
2017-12-09 19:45:17 +01:00
$gid = Group :: getIdByName ( $uid , $name );
2017-11-10 06:00:50 +01:00
} else {
throw new BadRequestException ( 'other API error' );
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
// add members
$erroraddinguser = false ;
2018-01-15 14:05:12 +01:00
$errorusers = [];
2017-11-10 06:00:50 +01:00
foreach ( $users as $user ) {
$cid = $user [ 'cid' ];
2021-10-03 17:02:20 +02:00
if ( DBA :: exists ( 'contact' , [ 'id' => $cid , 'uid' => $uid ])) {
2018-01-04 02:54:35 +01:00
Group :: addMember ( $gid , $cid );
2017-12-23 00:10:32 +01:00
} else {
2017-11-10 06:00:50 +01:00
$erroraddinguser = true ;
$errorusers [] = $cid ;
2016-09-25 18:50:08 +02:00
}
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
// return success message incl. missing users in array
2018-04-09 21:34:53 +02:00
$status = ( $erroraddinguser ? " missing user " : (( isset ( $reactivate_group ) && $reactivate_group ) ? " reactivated " : " ok " ));
2018-04-07 15:54:26 +02:00
return [ 'success' => true , 'gid' => $gid , 'name' => $name , 'status' => $status , 'wrong users' => $errorusers ];
}
/**
* Create the specified group with the posted array of contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
*/
function api_friendica_group_create ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 15:54:26 +02:00
// params
2019-10-13 04:01:34 +02:00
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 15:54:26 +02:00
$json = json_decode ( $_POST [ 'json' ], true );
$users = $json [ 'user' ];
$success = group_create ( $name , $uid , $users );
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " group_create " , $type , [ 'result' => $success ]);
2017-11-10 06:00:50 +01:00
}
2021-11-12 19:52:01 +01:00
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/friendica/group_create' , 'api_friendica_group_create' , true , API_METHOD_POST );
2018-04-07 15:54:26 +02:00
/**
* Create a new group .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / post - lists - create
*/
2018-04-07 22:15:35 +02:00
function api_lists_create ( $type )
2018-04-07 15:54:26 +02:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 15:54:26 +02:00
// params
2019-10-13 04:01:34 +02:00
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 15:54:26 +02:00
$success = group_create ( $name , $uid );
if ( $success [ 'success' ]) {
$grp = [
'name' => $success [ 'name' ],
'id' => intval ( $success [ 'gid' ]),
'id_str' => ( string ) $success [ 'gid' ],
2021-11-20 14:44:12 +01:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ()
2018-04-07 15:54:26 +02:00
];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $grp ]);
2018-04-07 15:54:26 +02:00
}
}
2021-11-12 19:52:01 +01:00
2018-04-07 22:15:35 +02:00
api_register_func ( 'api/lists/create' , 'api_lists_create' , true , API_METHOD_POST );
2017-11-10 06:00:50 +01:00
2017-12-24 03:20:50 +01:00
/**
* Update the specified group with the posted array of contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 03:20:50 +01:00
*/
2017-11-10 06:00:50 +01:00
function api_friendica_group_update ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 06:00:50 +01:00
// params
2019-10-13 04:01:34 +02:00
$gid = $_REQUEST [ 'gid' ] ? ? 0 ;
$name = $_REQUEST [ 'name' ] ? ? '' ;
2017-11-10 06:00:50 +01:00
$json = json_decode ( $_POST [ 'json' ], true );
$users = $json [ 'user' ];
// error if no name specified
2017-12-24 00:27:45 +01:00
if ( $name == " " ) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( 'group name not specified' );
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
// error if no gid specified
2017-12-24 00:27:45 +01:00
if ( $gid == " " ) {
2017-11-10 06:00:50 +01:00
throw new BadRequestException ( 'gid not specified' );
2017-12-24 00:27:45 +01:00
}
2017-11-10 06:00:50 +01:00
// remove members
2020-08-04 20:22:19 +02:00
$members = Contact\Group :: getById ( $gid );
2017-11-10 06:00:50 +01:00
foreach ( $members as $member ) {
$cid = $member [ 'id' ];
2016-09-25 18:50:08 +02:00
foreach ( $users as $user ) {
2017-11-10 06:00:50 +01:00
$found = ( $user [ 'cid' ] == $cid ? true : false );
}
2018-04-09 21:34:53 +02:00
if ( ! isset ( $found ) || ! $found ) {
2021-11-07 15:00:47 +01:00
$gid = Group :: getIdByName ( $uid , $name );
Group :: removeMember ( $gid , $cid );
2016-09-25 18:50:08 +02:00
}
}
2017-11-10 06:00:50 +01:00
// add members
$erroraddinguser = false ;
2018-01-15 14:05:12 +01:00
$errorusers = [];
2017-11-10 06:00:50 +01:00
foreach ( $users as $user ) {
$cid = $user [ 'cid' ];
2016-09-25 18:50:08 +02:00
2021-10-03 17:02:20 +02:00
if ( DBA :: exists ( 'contact' , [ 'id' => $cid , 'uid' => $uid ])) {
2018-01-04 02:54:35 +01:00
Group :: addMember ( $gid , $cid );
2016-09-25 18:50:08 +02:00
} else {
2017-11-10 06:00:50 +01:00
$erroraddinguser = true ;
$errorusers [] = $cid ;
2016-09-25 18:50:08 +02:00
}
}
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// return success message incl. missing users in array
$status = ( $erroraddinguser ? " missing user " : " ok " );
2018-01-15 14:05:12 +01:00
$success = [ 'success' => true , 'gid' => $gid , 'name' => $name , 'status' => $status , 'wrong users' => $errorusers ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " group_update " , $type , [ 'result' => $success ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/friendica/group_update' , 'api_friendica_group_update' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2018-04-07 15:54:26 +02:00
/**
* Update information about a group .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 15:54:26 +02:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / post - lists - update
*/
function api_lists_update ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 15:54:26 +02:00
// params
2019-10-13 04:01:34 +02:00
$gid = $_REQUEST [ 'list_id' ] ? ? 0 ;
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 15:54:26 +02:00
// error if no gid specified
if ( $gid == 0 ) {
throw new BadRequestException ( 'gid not specified' );
}
// get data of the specified group id
2018-07-20 14:19:26 +02:00
$group = DBA :: selectFirst ( 'group' , [], [ 'uid' => $uid , 'id' => $gid ]);
2018-04-07 15:54:26 +02:00
// error message if specified gid is not in database
2018-04-07 19:55:41 +02:00
if ( ! $group ) {
2018-04-07 15:54:26 +02:00
throw new BadRequestException ( 'gid not available' );
}
if ( Group :: update ( $gid , $name )) {
2018-04-07 19:55:41 +02:00
$list = [
2018-04-07 15:54:26 +02:00
'name' => $name ,
'id' => intval ( $gid ),
'id_str' => ( string ) $gid ,
2021-11-20 14:44:12 +01:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ()
2018-04-07 15:54:26 +02:00
];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $list ]);
2018-04-07 15:54:26 +02:00
}
}
api_register_func ( 'api/lists/update' , 'api_lists_update' , true , API_METHOD_POST );
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* Set notification as seen and returns associated item ( if possible )
2017-11-10 06:00:50 +01:00
*
2020-01-19 07:05:23 +01:00
* POST request with 'id' param as notification id
2017-12-24 03:20:50 +01:00
*
2017-11-10 06:00:50 +01:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-04-09 19:34:02 +02:00
* @ return string | array
2019-01-07 18:24:01 +01:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 06:00:50 +01:00
*/
function api_friendica_notification_seen ( $type )
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 18:50:08 +02:00
2021-07-25 16:27:13 +02:00
if ( DI :: args () -> getArgc () !== 4 ) {
2021-09-18 07:08:29 +02:00
throw new BadRequestException ( 'Invalid argument count' );
2017-12-24 00:27:45 +01:00
}
2016-09-25 18:50:08 +02:00
2021-09-18 07:08:29 +02:00
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
2016-09-25 18:50:08 +02:00
2020-01-25 02:01:49 +01:00
try {
2021-09-18 07:08:29 +02:00
$Notify = DI :: notify () -> selectOneById ( $id );
2021-11-20 14:44:12 +01:00
if ( $Notify -> uid !== $uid ) {
2021-09-18 07:08:29 +02:00
throw new NotFoundException ();
}
2020-01-25 02:01:49 +01:00
2021-09-18 07:08:29 +02:00
if ( $Notify -> uriId ) {
2021-09-18 06:03:32 +02:00
DI :: notification () -> setAllSeenForUser ( $Notify -> uid , [ 'target-uri-id' => $Notify -> uriId ]);
2021-09-18 07:08:29 +02:00
}
$Notify -> setSeen ();
DI :: notify () -> save ( $Notify );
2020-01-25 02:01:49 +01:00
2021-09-18 07:08:29 +02:00
if ( $Notify -> otype === Notification\ObjectType :: ITEM ) {
2021-11-20 14:44:12 +01:00
$item = Post :: selectFirstForUser ( $uid , [], [ 'id' => $Notify -> iid , 'uid' => $uid ]);
2020-01-25 02:01:49 +01:00
if ( DBA :: isResult ( $item )) {
// we found the item, return it to the user
2021-11-23 22:54:19 +01:00
$ret = [ DI :: twitterStatus () -> createFromUriId ( $item [ 'uri-id' ], $item [ 'uid' ]) -> toArray ()];
2020-01-25 02:01:49 +01:00
$data = [ 'status' => $ret ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'status' , $type , $data );
2020-01-25 02:01:49 +01:00
}
// the item can't be found, but we set the notification as seen, so we count this as a success
2016-09-25 18:50:08 +02:00
}
2021-09-18 07:08:29 +02:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( 'result' , $type , [ 'result' => 'success' ]);
2020-01-25 02:01:49 +01:00
} catch ( NotFoundException $e ) {
2020-01-31 22:25:09 +01:00
throw new BadRequestException ( 'Invalid argument' , $e );
2020-01-31 21:34:12 +01:00
} catch ( Exception $e ) {
2020-01-31 22:25:09 +01:00
throw new InternalServerErrorException ( 'Internal Server exception' , $e );
2017-11-10 06:00:50 +01:00
}
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/friendica/notification/seen' , 'api_friendica_notification_seen' , true , API_METHOD_POST );
2016-09-25 18:50:08 +02:00
2017-11-10 06:00:50 +01:00
/**
2020-01-19 07:05:23 +01:00
* search for direct_messages containing a searchstring through api
2017-11-10 06:00:50 +01:00
*
2019-01-07 18:24:01 +01:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-02-11 22:13:29 +01:00
* @ param string $box
2018-04-09 19:34:02 +02:00
* @ return string | array ( success : success = true if found and search_result contains found messages ,
2017-11-10 06:00:50 +01:00
* success = false if nothing was found , search_result = 'nothing found' ,
2019-01-07 18:24:01 +01:00
* error : result = error with error message )
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 06:00:50 +01:00
*/
2018-02-11 22:13:29 +01:00
function api_friendica_direct_messages_search ( $type , $box = " " )
2017-11-10 06:00:50 +01:00
{
2021-11-17 22:28:51 +01:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 14:44:12 +01:00
$uid = BaseApi :: getCurrentUserID ();
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// params
2021-11-20 14:44:12 +01:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid ) -> toArray ();
2019-10-13 04:01:34 +02:00
$searchstring = $_REQUEST [ 'searchstring' ] ? ? '' ;
2017-04-05 22:07:55 +02:00
2017-11-10 06:00:50 +01:00
// error if no searchstring specified
if ( $searchstring == " " ) {
2018-01-15 14:05:12 +01:00
$answer = [ 'result' => 'error' , 'message' => 'searchstring not specified' ];
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_messages_search " , $type , [ '$result' => $answer ]);
2017-11-10 06:00:50 +01:00
}
// get data for the specified searchstring
2021-10-09 23:16:15 +02:00
$r = DBA :: toArray ( DBA :: p (
" SELECT `mail`.*, `contact`.`nurl` AS `contact-url` FROM `mail`,`contact` WHERE `mail`.`contact-id` = `contact`.`id` AND `mail`.`uid` = ? AND `body` LIKE ? ORDER BY `mail`.`id` DESC " ,
$uid ,
'%' . $searchstring . '%'
));
2017-11-10 06:00:50 +01:00
$profile_url = $user_info [ " url " ];
// message if nothing was found
2018-07-21 14:46:04 +02:00
if ( ! DBA :: isResult ( $r )) {
2018-01-15 14:05:12 +01:00
$success = [ 'success' => false , 'search_results' => 'problem with query' ];
2017-11-10 06:00:50 +01:00
} elseif ( count ( $r ) == 0 ) {
2018-01-15 14:05:12 +01:00
$success = [ 'success' => false , 'search_results' => 'nothing found' ];
2017-11-10 06:00:50 +01:00
} else {
2018-01-15 14:05:12 +01:00
$ret = [];
2017-11-10 06:00:50 +01:00
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
2021-11-20 14:44:12 +01:00
$sender = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
2021-11-20 14:44:12 +01:00
$recipient = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid ) -> toArray ();
2017-11-10 06:00:50 +01:00
$sender = $user_info ;
2016-09-25 18:50:08 +02:00
}
2018-04-09 21:34:53 +02:00
if ( isset ( $recipient ) && isset ( $sender )) {
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
2017-11-10 06:00:50 +01:00
}
2018-01-15 14:05:12 +01:00
$success = [ 'success' => true , 'search_results' => $ret ];
2016-09-25 18:50:08 +02:00
}
2017-04-05 22:07:55 +02:00
2021-11-12 19:59:16 +01:00
return DI :: apiResponse () -> formatData ( " direct_message_search " , $type , [ '$result' => $success ]);
2017-11-10 06:00:50 +01:00
}
2016-09-25 18:50:08 +02:00
2017-12-25 21:12:08 +01:00
/// @TODO move to top of file or somewhere better
2017-11-10 06:00:50 +01:00
api_register_func ( 'api/friendica/direct_messages_search' , 'api_friendica_direct_messages_search' , true );