2016-09-25 16:50:08 +00:00
< ? php
/**
2021-03-29 06:40:20 +00:00
* @ copyright Copyright ( C ) 2010 - 2021 , the Friendica project
2020-02-09 15:34:23 +00: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 16:50:08 +00:00
* Friendica implementation of statusnet / twitter API
*
2017-12-24 02:20:50 +00:00
* @ file include / api . php
2016-09-25 16:50:08 +00:00
* @ todo Automatically detect if incoming data is HTML or BBCode
*/
2018-01-25 02:08:45 +00:00
2017-04-30 04:07:00 +00:00
use Friendica\App ;
2018-01-27 01:01:32 +00:00
use Friendica\Content\Text\BBCode ;
2018-03-07 21:24:13 +00:00
use Friendica\Content\Text\HTML ;
2018-10-29 21:20:46 +00:00
use Friendica\Core\Logger ;
2018-07-01 18:42:38 +00:00
use Friendica\Core\Protocol ;
2018-01-25 02:08:45 +00:00
use Friendica\Core\System ;
2018-07-20 12:19:26 +00:00
use Friendica\Database\DBA ;
2019-12-15 22:28:01 +00:00
use Friendica\DI ;
2017-12-07 14:04:24 +00:00
use Friendica\Model\Contact ;
2017-12-09 18:45:17 +00:00
use Friendica\Model\Group ;
2018-01-25 02:08:45 +00:00
use Friendica\Model\Item ;
2018-01-15 17:14:09 +00:00
use Friendica\Model\Mail ;
2017-12-07 13:56:11 +00:00
use Friendica\Model\Photo ;
2021-01-16 04:11:28 +00:00
use Friendica\Model\Post ;
2021-06-15 11:12:44 +00:00
use Friendica\Model\Profile ;
2021-11-08 21:35:41 +00:00
use Friendica\Module\BaseApi ;
2017-11-24 04:48:15 +00:00
use Friendica\Network\HTTPException ;
use Friendica\Network\HTTPException\BadRequestException ;
use Friendica\Network\HTTPException\ForbiddenException ;
use Friendica\Network\HTTPException\InternalServerErrorException ;
use Friendica\Network\HTTPException\NotFoundException ;
use Friendica\Network\HTTPException\TooManyRequestsException ;
2018-01-25 02:08:45 +00:00
use Friendica\Network\HTTPException\UnauthorizedException ;
2017-12-07 13:56:11 +00:00
use Friendica\Object\Image ;
2018-01-27 02:38:34 +00:00
use Friendica\Util\DateTimeFormat ;
2019-10-18 01:26:15 +00:00
use Friendica\Util\Images ;
2018-11-08 13:45:46 +00:00
use Friendica\Util\Strings ;
2017-01-17 19:21:46 +00:00
2019-09-16 12:47:49 +00:00
require_once __DIR__ . '/../mod/item.php' ;
2017-04-05 20:07:55 +00:00
2018-01-15 13:05:12 +00:00
$API = [];
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
/**
2017-12-24 02:20:50 +00:00
* Register a function to be the endpoint for defined API path .
2017-11-10 05:00:50 +00:00
*
2019-12-30 22:00:08 +00:00
* @ param string $path API URL path , relative to DI :: baseUrl ()
2017-11-10 05:00:50 +00:00
* @ param string $func Function name to call on path request
*/
2021-11-26 07:55:02 +00:00
function api_register_func ( $path , $func )
2017-11-10 05:00:50 +00:00
{
global $API ;
2018-01-15 13:05:12 +00:00
$API [ $path ] = [
2017-11-10 05:00:50 +00:00
'func' => $func ,
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
// Workaround for hotot
$path = str_replace ( " api/ " , " api/1.1/ " , $path );
2018-01-15 13:05:12 +00:00
$API [ $path ] = [
2017-11-10 05:00:50 +00:00
'func' => $func ,
2018-01-15 13:05:12 +00:00
];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2020-01-19 06:05:23 +00:00
* Main API entry point
2017-11-10 05:00:50 +00:00
*
2020-01-19 06:05:23 +00:00
* Authenticate user , call registered API function , set HTTP headers
2017-12-24 02:20:50 +00:00
*
2019-12-16 00:35:26 +00:00
* @ param App\Arguments $args The app arguments ( optional , will retrieved by the DI - Container in case of missing )
2018-04-09 17:34:02 +00:00
* @ return string | array API call result
2019-01-07 17:24:01 +00:00
* @ throws Exception
2017-11-10 05:00:50 +00:00
*/
2021-11-26 07:55:02 +00:00
function api_call ( $command , $extension )
2017-11-10 05:00:50 +00:00
{
2021-11-18 14:49:12 +00:00
global $API ;
2016-09-25 16:50:08 +00:00
2021-11-26 07:55:02 +00:00
Logger :: info ( 'Legacy API call' , [ 'command' => $command , 'extension' => $extension ]);
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
try {
foreach ( $API as $p => $info ) {
2021-11-26 07:55:02 +00:00
if ( strpos ( $command , $p ) === 0 ) {
Logger :: debug ( BaseApi :: LOG_PREFIX . 'parameters' , [ 'module' => 'api' , 'action' => 'call' , 'parameters' => $_REQUEST ]);
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
$stamp = microtime ( true );
2021-11-26 07:55:02 +00:00
$return = call_user_func ( $info [ 'func' ], $extension );
2019-10-16 12:43:59 +00:00
$duration = floatval ( microtime ( true ) - $stamp );
2018-12-30 20:42:56 +00:00
2021-11-26 07:55:02 +00:00
Logger :: info ( BaseApi :: LOG_PREFIX . 'duration {duration}' , [ 'module' => 'api' , 'action' => 'call' , 'duration' => round ( $duration , 2 )]);
2016-09-25 16:50:08 +00:00
2021-11-26 07:55:02 +00:00
DI :: profiler () -> saveLog ( DI :: logger (), BaseApi :: LOG_PREFIX . 'performance' );
2016-11-04 22:45:20 +00:00
2018-01-04 01:54:35 +00:00
if ( false === $return ) {
2017-11-10 05:00:50 +00:00
/*
* api function returned false withour throw an
* exception . This should not happend , throw a 500
*/
throw new InternalServerErrorException ();
}
2016-09-25 16:50:08 +00:00
2021-11-26 07:55:02 +00:00
switch ( $extension ) {
2017-11-10 05:00:50 +00:00
case " xml " :
header ( " Content-Type: text/xml " );
break ;
case " json " :
header ( " Content-Type: application/json " );
2019-08-02 16:43:36 +00:00
if ( ! empty ( $return )) {
$json = json_encode ( end ( $return ));
if ( ! empty ( $_GET [ 'callback' ])) {
$json = $_GET [ 'callback' ] . " ( " . $json . " ) " ;
}
$return = $json ;
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
break ;
case " rss " :
header ( " Content-Type: application/rss+xml " );
2018-01-04 01:54:35 +00:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 05:00:50 +00:00
break ;
case " atom " :
header ( " Content-Type: application/atom+xml " );
2018-01-04 01:54:35 +00:00
$return = '<?xml version="1.0" encoding="UTF-8"?>' . " \n " . $return ;
2017-11-10 05:00:50 +00:00
break ;
2016-09-25 16:50:08 +00:00
}
2018-01-04 01:54:35 +00:00
return $return ;
2016-09-25 16:50:08 +00:00
}
}
2017-11-10 05:00:50 +00:00
2021-11-26 07:55:02 +00:00
Logger :: warning ( BaseApi :: LOG_PREFIX . 'not implemented' , [ 'module' => 'api' , 'action' => 'call' , 'query' => DI :: args () -> getQueryString ()]);
2020-11-11 20:28:36 +00:00
throw new NotFoundException ();
2017-11-10 05:00:50 +00:00
} catch ( HTTPException $e ) {
2021-11-26 07:55:02 +00:00
Logger :: notice ( BaseApi :: LOG_PREFIX . 'got exception' , [ 'module' => 'api' , 'action' => 'call' , 'query' => DI :: args () -> getQueryString (), 'error' => $e ]);
DI :: apiResponse () -> error ( $e -> getCode (), $e -> getDescription (), $e -> getMessage (), $extension );
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2019-01-07 17:24:01 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param array $item
* @ param array $recipient
* @ param array $sender
2017-12-24 02:20:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ return array
2019-01-07 17:24:01 +00:00
* @ throws InternalServerErrorException
2017-11-10 05:00:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_format_messages ( $item , $recipient , $sender )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
// standard meta information
$ret = [
'id' => $item [ 'id' ],
'sender_id' => $sender [ 'id' ],
'text' => " " ,
'recipient_id' => $recipient [ 'id' ],
'created_at' => DateTimeFormat :: utc ( $item [ 'created' ] ? ? 'now' , DateTimeFormat :: API ),
'sender_screen_name' => $sender [ 'screen_name' ],
'recipient_screen_name' => $recipient [ 'screen_name' ],
'sender' => $sender ,
'recipient' => $recipient ,
'title' => " " ,
'friendica_seen' => $item [ 'seen' ] ? ? 0 ,
'friendica_parent_uri' => $item [ 'parent-uri' ] ? ? '' ,
];
2017-11-10 05:00:50 +00:00
2021-11-21 20:14:48 +00:00
// "uid" is only needed for some internal stuff, so remove it from here
2021-11-24 06:44:25 +00:00
if ( isset ( $ret [ 'sender' ][ 'uid' ])) {
unset ( $ret [ 'sender' ][ 'uid' ]);
}
if ( isset ( $ret [ 'recipient' ][ 'uid' ])) {
unset ( $ret [ 'recipient' ][ 'uid' ]);
}
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
//don't send title to regular StatusNET requests to avoid confusing these apps
if ( ! empty ( $_GET [ 'getText' ])) {
$ret [ 'title' ] = $item [ 'title' ];
if ( $_GET [ 'getText' ] == 'html' ) {
$ret [ 'text' ] = BBCode :: convertForUriId ( $item [ 'uri-id' ], $item [ 'body' ], BBCode :: API );
} elseif ( $_GET [ 'getText' ] == 'plain' ) {
$ret [ 'text' ] = trim ( HTML :: toPlaintext ( BBCode :: convertForUriId ( $item [ 'uri-id' ], api_clean_plain_items ( $item [ 'body' ]), BBCode :: API ), 0 ));
}
} else {
$ret [ 'text' ] = $item [ 'title' ] . " \n " . HTML :: toPlaintext ( BBCode :: convertForUriId ( $item [ 'uri-id' ], api_clean_plain_items ( $item [ 'body' ]), BBCode :: API ), 0 );
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
if ( ! empty ( $_GET [ 'getUserObjects' ]) && $_GET [ 'getUserObjects' ] == 'false' ) {
unset ( $ret [ 'sender' ]);
unset ( $ret [ 'recipient' ]);
2016-09-25 16:50:08 +00:00
}
2021-11-24 06:44:25 +00:00
return $ret ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
*
2021-11-24 06:44:25 +00:00
* @ param string $acl_string
* @ param int $uid
* @ return bool
* @ throws Exception
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function check_acl_input ( $acl_string , $uid )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
if ( empty ( $acl_string )) {
return false ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$contact_not_found = false ;
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// split <x><y><z> into array of cid's
preg_match_all ( " /<[A-Za-z0-9]+>/ " , $acl_string , $array );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// 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 );
$condition = [ 'id' => $cid , 'uid' => $uid ];
$contact_not_found |= ! DBA :: exists ( 'contact' , $condition );
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
return $contact_not_found ;
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
/**
* @ param string $mediatype
* @ param array $media
* @ param string $type
* @ param string $album
* @ param string $allow_cid
* @ param string $deny_cid
* @ param string $allow_gid
* @ param string $deny_gid
* @ param string $desc
* @ param integer $phototype
* @ param boolean $visibility
* @ param string $photo_id
* @ param int $uid
* @ return array
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
* @ throws UnauthorizedException
*/
function save_media_to_database ( $mediatype , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , $phototype , $visibility , $photo_id , $uid )
{
$visitor = 0 ;
$src = " " ;
$filetype = " " ;
$filename = " " ;
$filesize = 0 ;
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
if ( is_array ( $media )) {
if ( is_array ( $media [ 'tmp_name' ])) {
$src = $media [ 'tmp_name' ][ 0 ];
} else {
$src = $media [ 'tmp_name' ];
}
if ( is_array ( $media [ 'name' ])) {
$filename = basename ( $media [ 'name' ][ 0 ]);
} else {
$filename = basename ( $media [ 'name' ]);
}
if ( is_array ( $media [ 'size' ])) {
$filesize = intval ( $media [ 'size' ][ 0 ]);
} else {
$filesize = intval ( $media [ 'size' ]);
}
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
}
}
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
$filetype = Images :: getMimeTypeBySource ( $src , $filename , $filetype );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
logger :: info (
" File upload src: " . $src . " - filename: " . $filename .
" - size: " . $filesize . " - type: " . $filetype );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// check if there was a php upload error
if ( $filesize == 0 && $media [ 'error' ] == 1 ) {
throw new InternalServerErrorException ( " image size exceeds PHP config settings, file was rejected by server " );
}
// check against max upload size within Friendica instance
$maximagesize = DI :: config () -> get ( 'system' , 'maximagesize' );
if ( $maximagesize && ( $filesize > $maximagesize )) {
$formattedBytes = Strings :: formatBytes ( $maximagesize );
throw new InternalServerErrorException ( " image size exceeds Friendica config setting (uploaded size: $formattedBytes ) " );
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// create Photo instance with the data of the image
$imagedata = @ file_get_contents ( $src );
$Image = new Image ( $imagedata , $filetype );
if ( ! $Image -> isValid ()) {
throw new InternalServerErrorException ( " unable to process image data " );
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// check orientation of image
$Image -> orient ( $src );
@ unlink ( $src );
// check max length of images on server
$max_length = DI :: config () -> get ( 'system' , 'max_image_length' );
if ( $max_length > 0 ) {
$Image -> scaleDown ( $max_length );
logger :: info ( " File upload: Scaling picture to new size " . $max_length );
}
$width = $Image -> getWidth ();
$height = $Image -> getHeight ();
// create a new resource-id if not already provided
$resource_id = ( $photo_id == null ) ? Photo :: newResource () : $photo_id ;
if ( $mediatype == " photo " ) {
// upload normal image (scales 0, 1, 2)
logger :: info ( " photo upload: starting new photo upload " );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 0 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: image upload with scale 0 (original size) failed " );
}
if ( $width > 640 || $height > 640 ) {
$Image -> scaleDown ( 640 );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 1 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: image upload with scale 1 (640x640) failed " );
2017-11-10 05:00:50 +00:00
}
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
if ( $width > 320 || $height > 320 ) {
$Image -> scaleDown ( 320 );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 2 , Photo :: DEFAULT , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: image upload with scale 2 (320x320) failed " );
}
}
logger :: info ( " photo upload: new photo upload ended " );
} elseif ( $mediatype == " profileimage " ) {
// upload profile image (scales 4, 5, 6)
logger :: info ( " photo upload: starting new profile image upload " );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
if ( $width > 300 || $height > 300 ) {
$Image -> scaleDown ( 300 );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 4 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: profile image upload with scale 4 (300x300) failed " );
}
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
if ( $width > 80 || $height > 80 ) {
$Image -> scaleDown ( 80 );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 5 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: profile image upload with scale 5 (80x80) failed " );
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
}
2021-11-24 06:44:25 +00:00
if ( $width > 48 || $height > 48 ) {
$Image -> scaleDown ( 48 );
$r = Photo :: store ( $Image , $uid , $visitor , $resource_id , $filename , $album , 6 , $phototype , $allow_cid , $allow_gid , $deny_cid , $deny_gid , $desc );
if ( ! $r ) {
logger :: notice ( " photo upload: profile image upload with scale 6 (48x48) failed " );
}
}
$Image -> __destruct ();
logger :: info ( " photo upload: new profile image upload ended " );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
if ( ! empty ( $r )) {
// create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo
if ( $photo_id == null && $mediatype == " photo " ) {
post_photo_item ( $resource_id , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility , $uid );
2017-04-05 20:07:55 +00:00
}
2021-11-24 06:44:25 +00:00
// on success return image data in json/xml format (like /api/friendica/photo does when no scale is given)
return prepare_photo_data ( $type , false , $resource_id , $uid );
} else {
throw new InternalServerErrorException ( " image upload failed " );
2021-11-21 20:52:36 +00:00
DI :: page () -> exit ( DI :: apiResponse ());
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
/**
*
* @ param string $hash
* @ param string $allow_cid
* @ param string $deny_cid
* @ param string $allow_gid
* @ param string $deny_gid
* @ param string $filetype
* @ param boolean $visibility
* @ param int $uid
* @ throws InternalServerErrorException
*/
function post_photo_item ( $hash , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $filetype , $visibility , $uid )
{
// get data about the api authenticated user
$uri = Item :: newURI ( intval ( $uid ));
$owner_record = DBA :: selectFirst ( 'contact' , [], [ 'uid' => $uid , 'self' => true ]);
2021-05-01 15:48:19 +00:00
2021-11-24 06:44:25 +00:00
$arr = [];
$arr [ 'guid' ] = System :: createUUID ();
$arr [ 'uid' ] = intval ( $uid );
$arr [ 'uri' ] = $uri ;
$arr [ 'type' ] = 'photo' ;
$arr [ 'wall' ] = 1 ;
$arr [ 'resource-id' ] = $hash ;
$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' ];
$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 ;
2021-05-22 21:45:15 +00:00
2021-11-24 06:44:25 +00:00
$typetoext = [
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
];
2021-05-22 21:45:15 +00:00
2021-11-24 06:44:25 +00:00
// adds link to the thumbnail scale photo
$arr [ 'body' ] = '[url=' . DI :: baseUrl () . '/photos/' . $owner_record [ 'nick' ] . '/image/' . $hash . ']'
. '[img]' . DI :: baseUrl () . '/photo/' . $hash . '-' . " 2 " . '.' . $typetoext [ $filetype ] . '[/img]'
. '[/url]' ;
2021-05-22 21:45:15 +00:00
2021-11-24 06:44:25 +00:00
// do the magic for storing the item in the database and trigger the federation to other contacts
Item :: insert ( $arr );
}
2021-05-01 15:48:19 +00:00
2021-11-24 06:44:25 +00:00
/**
*
* @ param string $type
* @ param int $scale
* @ param string $photo_id
*
* @ return array
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
* @ throws UnauthorizedException
*/
function prepare_photo_data ( $type , $scale , $photo_id , $uid )
{
$scale_sql = ( $scale === false ? " " : sprintf ( " AND scale=%d " , intval ( $scale )));
$data_sql = ( $scale === false ? " " : " data, " );
// added allow_cid, allow_gid, deny_cid, deny_gid to output as string like stored in database
// clients needs to convert this in their way for further processing
$r = DBA :: toArray ( DBA :: p (
" SELECT $data_sql `resource-id`, `created`, `edited`, `title`, `desc`, `album`, `filename`,
`type` , `height` , `width` , `datasize` , `profile` , `allow_cid` , `deny_cid` , `allow_gid` , `deny_gid` ,
MIN ( `scale` ) AS `minscale` , MAX ( `scale` ) AS `maxscale`
FROM `photo` WHERE `uid` = ? AND `resource-id` = ? $scale_sql GROUP BY
`resource-id` , `created` , `edited` , `title` , `desc` , `album` , `filename` ,
`type` , `height` , `width` , `datasize` , `profile` , `allow_cid` , `deny_cid` , `allow_gid` , `deny_gid` " ,
$uid ,
$photo_id
));
$typetoext = [
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
];
// prepare output data for photo
if ( DBA :: isResult ( $r )) {
$data = [ 'photo' => $r [ 0 ]];
$data [ 'photo' ][ 'id' ] = $data [ 'photo' ][ 'resource-id' ];
if ( $scale !== false ) {
$data [ 'photo' ][ 'data' ] = base64_encode ( $data [ 'photo' ][ 'data' ]);
} else {
unset ( $data [ 'photo' ][ 'datasize' ]); //needed only with scale param
2021-05-01 15:48:19 +00:00
}
2021-11-24 06:44:25 +00:00
if ( $type == " xml " ) {
$data [ 'photo' ][ 'links' ] = [];
for ( $k = intval ( $data [ 'photo' ][ 'minscale' ]); $k <= intval ( $data [ 'photo' ][ 'maxscale' ]); $k ++ ) {
$data [ 'photo' ][ 'links' ][ $k . " :link " ][ " @attributes " ] = [ " type " => $data [ 'photo' ][ 'type' ],
" scale " => $k ,
" href " => DI :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]]];
}
} else {
$data [ 'photo' ][ 'link' ] = [];
// when we have profile images we could have only scales from 4 to 6, but index of array always needs to start with 0
$i = 0 ;
for ( $k = intval ( $data [ 'photo' ][ 'minscale' ]); $k <= intval ( $data [ 'photo' ][ 'maxscale' ]); $k ++ ) {
$data [ 'photo' ][ 'link' ][ $i ] = DI :: baseUrl () . " /photo/ " . $data [ 'photo' ][ 'resource-id' ] . " - " . $k . " . " . $typetoext [ $data [ 'photo' ][ 'type' ]];
$i ++ ;
}
}
unset ( $data [ 'photo' ][ 'resource-id' ]);
unset ( $data [ 'photo' ][ 'minscale' ]);
unset ( $data [ 'photo' ][ 'maxscale' ]);
} else {
throw new NotFoundException ();
2021-05-01 15:48:19 +00:00
}
2021-11-24 06:44:25 +00:00
// retrieve item element for getting activities (like, dislike etc.) related to photo
$condition = [ 'uid' => $uid , 'resource-id' => $photo_id ];
2021-11-30 04:51:04 +00:00
$item = Post :: selectFirst ([ 'id' , 'uid' , 'uri' , 'uri-id' , 'parent' , 'allow_cid' , 'deny_cid' , 'allow_gid' , 'deny_gid' ], $condition );
2021-11-24 06:44:25 +00:00
if ( ! DBA :: isResult ( $item )) {
throw new NotFoundException ( 'Photo-related item not found.' );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 07:06:28 +00:00
$data [ 'photo' ][ 'friendica_activities' ] = DI :: friendicaActivities () -> createFromUriId ( $item [ 'uri-id' ], $item [ 'uid' ], $type );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// retrieve comments on photo
$condition = [ " `parent` = ? AND `uid` = ? AND `gravity` IN (?, ?) " ,
$item [ 'parent' ], $uid , GRAVITY_PARENT , GRAVITY_COMMENT ];
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$statuses = Post :: selectForUser ( $uid , [], $condition );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// prepare output of comments
$commentData = [];
while ( $status = DBA :: fetch ( $statuses )) {
$commentData [] = DI :: twitterStatus () -> createFromUriId ( $status [ 'uri-id' ], $status [ 'uid' ]) -> toArray ();
}
DBA :: close ( $statuses );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$comments = [];
if ( $type == " xml " ) {
$k = 0 ;
foreach ( $commentData as $comment ) {
$comments [ $k ++ . " :comment " ] = $comment ;
}
} else {
foreach ( $commentData as $comment ) {
$comments [] = $comment ;
2021-05-01 15:48:19 +00:00
}
}
2021-11-24 06:44:25 +00:00
$data [ 'photo' ][ 'friendica_comments' ] = $comments ;
2021-05-01 15:48:19 +00:00
2021-11-24 06:44:25 +00:00
// include info if rights on photo and rights on item are mismatching
$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' ];
$data [ 'photo' ][ 'rights_mismatch' ] = $rights_mismatch ;
return $data ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
/**
*
* @ param string $text
*
* @ return string
* @ throws InternalServerErrorException
*/
function api_clean_plain_items ( $text )
{
$include_entities = strtolower ( $_REQUEST [ 'include_entities' ] ? ? 'false' );
$text = BBCode :: cleanPictureLinks ( $text );
$URLSearchString = " ^ \ [ \ ] " ;
$text = preg_replace ( " /([!#@]) \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '$1$3' , $text );
if ( $include_entities == " true " ) {
$text = preg_replace ( " / \ [url \ =([ $URLSearchString ]*) \ ](.*?) \ [ \ /url \ ]/ism " , '[url=$1]$1[/url]' , $text );
}
// Simplify "attachment" element
$text = BBCode :: removeAttachment ( $text );
return $text ;
}
2016-09-25 16:50:08 +00:00
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Add a new group to the database .
*
* @ param string $name Group name
* @ param int $uid User ID
* @ param array $users List of users to add to the group
2017-12-24 02:20:50 +00:00
*
* @ return array
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function group_create ( $name , $uid , $users = [])
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
// error if no name specified
if ( $name == " " ) {
throw new BadRequestException ( 'group name not specified' );
}
2018-01-04 18:26:09 +00:00
2021-11-24 06:44:25 +00:00
// error message if specified group name already exists
if ( DBA :: exists ( 'group' , [ 'uid' => $uid , 'name' => $name , 'deleted' => false ])) {
throw new BadRequestException ( 'group name already exists' );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// Check if the group needs to be reactivated
if ( DBA :: exists ( 'group' , [ 'uid' => $uid , 'name' => $name , 'deleted' => true ])) {
$reactivate_group = true ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// create group
$ret = Group :: create ( $uid , $name );
if ( $ret ) {
$gid = Group :: getIdByName ( $uid , $name );
} else {
throw new BadRequestException ( 'other API error' );
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// add members
$erroraddinguser = false ;
$errorusers = [];
foreach ( $users as $user ) {
$cid = $user [ 'cid' ];
if ( DBA :: exists ( 'contact' , [ 'id' => $cid , 'uid' => $uid ])) {
Group :: addMember ( $gid , $cid );
} else {
$erroraddinguser = true ;
$errorusers [] = $cid ;
}
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// return success message incl. missing users in array
$status = ( $erroraddinguser ? " missing user " : (( isset ( $reactivate_group ) && $reactivate_group ) ? " reactivated " : " ok " ));
return [ 'success' => true , 'gid' => $gid , 'name' => $name , 'status' => $status , 'wrong users' => $errorusers ];
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2019-07-30 05:02:26 +00:00
/**
2021-11-24 06:44:25 +00:00
* TWITTER API
*/
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Updates the user’ s current status .
2017-12-24 02:20:50 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
2021-11-24 06:44:25 +00:00
* @ throws ForbiddenException
2019-01-07 17:24:01 +00:00
* @ throws ImagickException
* @ throws InternalServerErrorException
2021-11-24 06:44:25 +00:00
* @ throws TooManyRequestsException
2019-01-07 17:24:01 +00:00
* @ throws UnauthorizedException
2021-11-24 06:44:25 +00:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - update
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_statuses_update ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-24 06:44:25 +00:00
$a = DI :: app ();
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// convert $_POST array items to the form we use for web posts.
2021-11-24 21:01:07 +00:00
if ( ! empty ( $_REQUEST [ 'htmlstatus' ])) {
$txt = $_REQUEST [ 'htmlstatus' ];
2021-11-24 06:44:25 +00:00
if (( strpos ( $txt , '<' ) !== false ) || ( strpos ( $txt , '>' ) !== false )) {
$txt = HTML :: toBBCodeVideo ( $txt );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$config = HTMLPurifier_Config :: createDefault ();
$config -> set ( 'Cache.DefinitionImpl' , null );
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$purifier = new HTMLPurifier ( $config );
$txt = $purifier -> purify ( $txt );
$_REQUEST [ 'body' ] = HTML :: toBBCode ( $txt );
2017-04-05 20:07:55 +00:00
}
2017-11-10 05:00:50 +00:00
} else {
2021-11-24 21:01:07 +00:00
$_REQUEST [ 'body' ] = $_REQUEST [ 'status' ] ? ? null ;
2016-09-25 16:50:08 +00:00
}
2018-01-04 01:54:35 +00:00
2021-11-24 21:01:07 +00:00
$_REQUEST [ 'title' ] = $_REQUEST [ 'title' ] ? ? null ;
2016-09-25 16:50:08 +00:00
2021-11-24 21:01:07 +00:00
$parent = $_REQUEST [ 'in_reply_to_status_id' ] ? ? null ;
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// Twidere sends "-1" if it is no reply ...
if ( $parent == - 1 ) {
$parent = " " ;
}
2021-11-20 13:44:12 +00:00
2021-11-24 06:44:25 +00:00
if ( ctype_digit ( $parent )) {
$_REQUEST [ 'parent' ] = $parent ;
} else {
$_REQUEST [ 'parent_uri' ] = $parent ;
}
2017-12-19 10:37:55 +00:00
2021-11-24 21:01:07 +00:00
if ( ! empty ( $_REQUEST [ 'lat' ]) && ! empty ( $_REQUEST [ 'long' ])) {
$_REQUEST [ 'coord' ] = sprintf ( " %s %s " , $_REQUEST [ 'lat' ], $_REQUEST [ 'long' ]);
2021-11-24 06:44:25 +00:00
}
$_REQUEST [ 'profile_uid' ] = $uid ;
if ( ! $parent ) {
// Check for throttling (maximum posts per day, week and month)
$throttle_day = DI :: config () -> get ( 'system' , 'throttle_limit_day' );
if ( $throttle_day > 0 ) {
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 );
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
$posts_day = Post :: count ( $condition );
if ( $posts_day > $throttle_day ) {
logger :: info ( 'Daily posting limit reached for user ' . $uid );
// die(api_error($type, DI::l10n()->t("Daily posting limit of %d posts reached. The post was rejected.", $throttle_day));
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-12-19 10:37:55 +00:00
}
2017-12-18 22:51:03 +00:00
}
2021-11-24 06:44:25 +00:00
$throttle_week = DI :: config () -> get ( 'system' , 'throttle_limit_week' );
if ( $throttle_week > 0 ) {
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 * 7 );
2017-12-19 10:37:55 +00:00
2021-11-24 06:44:25 +00:00
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
$posts_week = Post :: count ( $condition );
2017-12-18 22:51:03 +00:00
2021-11-24 06:44:25 +00:00
if ( $posts_week > $throttle_week ) {
logger :: info ( 'Weekly posting limit reached for user ' . $uid );
// die(api_error($type, DI::l10n()->t("Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week)));
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-12-18 22:51:03 +00:00
2021-11-24 06:44:25 +00:00
$throttle_month = DI :: config () -> get ( 'system' , 'throttle_limit_month' );
if ( $throttle_month > 0 ) {
$datefrom = date ( DateTimeFormat :: MYSQL , time () - 24 * 60 * 60 * 30 );
2018-04-09 15:36:33 +00:00
2021-11-24 06:44:25 +00:00
$condition = [ " `gravity` = ? AND `uid` = ? AND `wall` AND `received` > ? " , GRAVITY_PARENT , $uid , $datefrom ];
$posts_month = Post :: count ( $condition );
2019-02-19 00:56:41 +00:00
2021-11-24 06:44:25 +00:00
if ( $posts_month > $throttle_month ) {
logger :: info ( 'Monthly posting limit reached for user ' . $uid );
// 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-12-18 01:59:11 +00:00
2021-11-24 21:01:07 +00:00
if ( ! empty ( $_REQUEST [ 'media_ids' ])) {
$ids = explode ( ',' , $_REQUEST [ 'media_ids' ]);
2021-11-24 06:44:25 +00:00
} elseif ( ! empty ( $_FILES [ 'media' ])) {
// upload the image if we have one
2021-11-27 09:42:05 +00:00
$picture = Photo :: upload ( $uid , $_FILES [ 'media' ]);
2021-11-24 06:44:25 +00:00
if ( is_array ( $picture )) {
$ids [] = $picture [ 'id' ];
}
2017-12-18 12:35:36 +00:00
}
2020-01-05 19:32:39 +00:00
2021-11-24 06:44:25 +00:00
$attachments = [];
$ressources = [];
2019-10-13 02:01:34 +00:00
2021-11-24 06:44:25 +00:00
if ( ! empty ( $ids )) {
foreach ( $ids as $id ) {
$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` = ?
ORDER BY `photo` . `width` DESC LIMIT 2 " , $id , $uid ));
2019-10-13 02:01:34 +00:00
2021-11-24 06:44:25 +00:00
if ( ! empty ( $media )) {
$ressources [] = $media [ 0 ][ 'resource-id' ];
$phototypes = Images :: supportedTypes ();
$ext = $phototypes [ $media [ 0 ][ 'type' ]];
2018-12-21 16:00:56 +00:00
2021-11-24 06:44:25 +00: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' ]];
2018-12-21 17:42:39 +00:00
2021-11-24 06:44:25 +00: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 ;
}
2018-12-21 17:42:39 +00:00
}
2021-11-24 06:44:25 +00:00
// We have to avoid that the post is rejected because of an empty body
if ( empty ( $_REQUEST [ 'body' ])) {
$_REQUEST [ 'body' ] = '[hr]' ;
2018-12-17 04:41:55 +00:00
}
2018-06-09 19:12:13 +00:00
}
2018-06-09 16:56:37 +00:00
2021-11-24 06:44:25 +00:00
if ( ! empty ( $attachments )) {
$_REQUEST [ 'attachments' ] = $attachments ;
}
2019-12-12 22:04:59 +00:00
2021-11-24 06:44:25 +00:00
// set this so that the item_post() function is quiet and doesn't redirect or emit json
2019-12-12 22:04:59 +00:00
2021-11-24 06:44:25 +00:00
$_REQUEST [ 'api_source' ] = true ;
if ( empty ( $_REQUEST [ 'source' ])) {
$_REQUEST [ 'source' ] = BaseApi :: getCurrentApplication ()[ 'name' ] ? : 'API' ;
2019-12-12 22:04:59 +00:00
}
2021-11-24 06:44:25 +00:00
// call out normal post function
$item_id = item_post ( $a );
2017-12-18 12:35:36 +00:00
2021-11-24 06:44:25 +00: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 ) {
Photo :: setPermissionForRessource ( $ressource , $uid , $item [ 'allow_cid' ], $item [ 'allow_gid' ], $item [ 'deny_cid' ], $item [ 'deny_gid' ]);
}
2021-11-20 23:38:52 +00:00
}
2017-12-18 12:35:36 +00:00
2021-11-24 06:44:25 +00:00
$include_entities = strtolower (( $_REQUEST [ 'include_entities' ] ? ? 'false' ) == 'true' );
2018-12-21 16:00:56 +00:00
2021-11-24 06:44:25 +00:00
// output the post that we just posted.
2021-11-27 09:42:05 +00:00
$status_info = DI :: twitterStatus () -> createFromItemId ( $item_id , $uid , $include_entities ) -> toArray ();
2021-11-24 06:44:25 +00:00
return DI :: apiResponse () -> formatData ( 'statuses' , $type , [ 'status' => $status_info ]);
2017-12-18 01:59:11 +00:00
}
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/statuses/update' , 'api_statuses_update' , true );
api_register_func ( 'api/statuses/update_with_media' , 'api_statuses_update' , true );
2021-11-27 13:41:49 +00:00
api_register_func ( 'api/statuses/mediap' , 'api_statuses_update' , true );
2017-12-18 01:59:11 +00:00
2017-11-10 05:00:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Repeats a status .
2017-11-10 05:00:50 +00:00
*
2017-12-24 02:20:50 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
*
2021-11-24 06:44:25 +00:00
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
2021-11-24 06:44:25 +00:00
* @ throws ForbiddenException
2019-01-07 17:24:01 +00:00
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2021-11-24 06:44:25 +00:00
* @ see https :// developer . twitter . com / en / docs / tweets / post - and - engage / api - reference / post - statuses - retweet - id
2017-11-10 05:00:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_statuses_repeat ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// params
$id = intval ( DI :: args () -> getArgv ()[ 3 ] ? ? 0 );
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
if ( $id == 0 ) {
$id = intval ( $_REQUEST [ 'id' ] ? ? 0 );
}
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// Hotot workaround
if ( $id == 0 ) {
$id = intval ( DI :: args () -> getArgv ()[ 4 ] ? ? 0 );
2017-11-10 05:00:50 +00:00
}
2017-09-14 05:16:23 +00:00
2021-11-24 06:44:25 +00:00
logger :: notice ( 'API: api_statuses_repeat: ' . $id );
$fields = [ 'uri-id' , 'network' , 'body' , 'title' , 'author-name' , 'author-link' , 'author-avatar' , 'guid' , 'created' , 'plink' ];
$item = Post :: selectFirst ( $fields , [ 'id' => $id , 'private' => [ Item :: PUBLIC , Item :: UNLISTED ]]);
if ( DBA :: isResult ( $item ) && ! empty ( $item [ 'body' ])) {
if ( in_array ( $item [ 'network' ], [ Protocol :: ACTIVITYPUB , Protocol :: DFRN , Protocol :: TWITTER ])) {
if ( ! Item :: performActivity ( $id , 'announce' , $uid )) {
throw new InternalServerErrorException ();
}
$item_id = $id ;
} else {
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' ]);
2018-06-18 20:36:34 +00:00
2021-11-24 06:44:25 +00:00
if ( ! empty ( $item [ 'title' ])) {
$post .= '[h3]' . $item [ 'title' ] . " [/h3] \n " ;
}
$post .= $item [ 'body' ];
$post .= " [/share] " ;
}
$_REQUEST [ 'body' ] = $post ;
$_REQUEST [ 'profile_uid' ] = $uid ;
$_REQUEST [ 'api_source' ] = true ;
if ( empty ( $_REQUEST [ 'source' ])) {
$_REQUEST [ 'source' ] = BaseApi :: getCurrentApplication ()[ 'name' ] ? : 'API' ;
2017-12-23 23:27:45 +00:00
}
2021-11-24 06:44:25 +00:00
$item_id = item_post ( DI :: app ());
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
} else {
throw new ForbiddenException ();
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$include_entities = strtolower (( $_REQUEST [ 'include_entities' ] ? ? 'false' ) == 'true' );
2017-06-08 02:00:59 +00:00
2021-11-24 06:44:25 +00:00
// output the post that we just posted.
2021-11-27 09:42:05 +00:00
$status_info = DI :: twitterStatus () -> createFromItemId ( $item_id , $uid , $include_entities ) -> toArray ();
2021-11-24 06:44:25 +00:00
return DI :: apiResponse () -> formatData ( 'statuses' , $type , [ 'status' => $status_info ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/statuses/retweet' , 'api_statuses_repeat' , true );
2016-09-25 16:50:08 +00:00
2017-12-18 22:51:03 +00:00
/**
2021-11-24 06:44:25 +00:00
* Returns all lists the user subscribes to .
2017-12-18 22:51:03 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
2017-12-18 22:51:03 +00:00
*
2021-11-24 06:44:25 +00:00
* @ return array | string
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - list
2017-12-18 22:51:03 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_lists_list ( $type )
2017-12-18 22:51:03 +00:00
{
2021-11-26 07:55:02 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-24 06:44:25 +00:00
$ret = [];
/// @TODO $ret is not filled here?
return DI :: apiResponse () -> formatData ( 'lists' , $type , [ " lists_list " => $ret ]);
2017-12-18 22:51:03 +00:00
}
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/lists/list' , 'api_lists_list' , true );
api_register_func ( 'api/lists/subscriptions' , 'api_lists_list' , true );
2017-12-18 22:51:03 +00:00
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Returns all groups the user owns .
2017-12-24 02:20:50 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2021-11-24 06:44:25 +00:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / get - lists - ownerships
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_lists_ownerships ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-17 22:44:52 +00:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-17 23:03:18 +00:00
2021-11-24 06:44:25 +00:00
// params
2021-11-24 20:47:37 +00:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ();
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$groups = DBA :: select ( 'group' , [], [ 'deleted' => 0 , 'uid' => $uid ]);
2018-07-01 18:43:22 +00:00
2021-11-24 06:44:25 +00:00
// loop through all groups
$lists = [];
foreach ( $groups as $group ) {
if ( $group [ 'visible' ]) {
$mode = 'public' ;
2017-04-05 20:07:55 +00:00
} else {
2021-11-24 06:44:25 +00:00
$mode = 'private' ;
2017-04-05 20:07:55 +00:00
}
2021-11-24 06:44:25 +00:00
$lists [] = [
'name' => $group [ 'name' ],
'id' => intval ( $group [ 'id' ]),
'id_str' => ( string ) $group [ 'id' ],
'user' => $user_info ,
'mode' => $mode
];
}
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => [ 'lists' => $lists ]]);
2017-11-10 05:00:50 +00:00
}
2017-04-05 20:07:55 +00:00
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/lists/ownerships' , 'api_lists_ownerships' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Sends a new direct message .
2017-11-10 05:00:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
2021-11-24 06:44:25 +00:00
* @ throws ImagickException
2019-01-07 17:24:01 +00:00
* @ throws InternalServerErrorException
* @ throws NotFoundException
2021-11-24 06:44:25 +00:00
* @ throws UnauthorizedException
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / new - message
2017-11-10 05:00:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_direct_messages_new ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 07:25:16 +00:00
2021-11-26 11:13:12 +00:00
if ( empty ( $_POST [ " text " ]) || empty ( $_REQUEST [ 'screen_name' ]) && empty ( $_REQUEST [ 'user_id' ])) {
2021-11-24 06:44:25 +00:00
return ;
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 20:47:37 +00:00
$sender = DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ();
2016-09-25 16:50:08 +00:00
2021-11-26 10:48:38 +00:00
$cid = BaseApi :: getContactIDForSearchterm ( $_REQUEST [ 'screen_name' ] ? ? '' , $_REQUEST [ 'profileurl' ] ? ? '' , $_REQUEST [ 'user_id' ] ? ? 0 , 0 );
2021-11-24 06:44:25 +00:00
if ( empty ( $cid )) {
throw new NotFoundException ( 'Recipient not found' );
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$replyto = '' ;
if ( ! empty ( $_REQUEST [ 'replyto' ])) {
$mail = DBA :: selectFirst ( 'mail' , [ 'parent-uri' , 'title' ], [ 'uid' => $uid , 'id' => $_REQUEST [ 'replyto' ]]);
$replyto = $mail [ 'parent-uri' ];
$sub = $mail [ 'title' ];
} else {
if ( ! empty ( $_REQUEST [ 'title' ])) {
$sub = $_REQUEST [ 'title' ];
} else {
$sub = (( strlen ( $_POST [ 'text' ]) > 10 ) ? substr ( $_POST [ 'text' ], 0 , 10 ) . " ... " : $_POST [ 'text' ]);
}
}
$cdata = Contact :: getPublicAndUserContactID ( $cid , $uid );
$id = Mail :: send ( $cdata [ 'user' ], $_POST [ 'text' ], $sub , $replyto );
if ( $id > - 1 ) {
$mail = DBA :: selectFirst ( 'mail' , [], [ 'id' => $id ]);
2021-11-24 20:47:37 +00:00
$ret = api_format_messages ( $mail , DI :: twitterUser () -> createFromContactId ( $cid , $uid , true ) -> toArray (), $sender );
2021-11-24 06:44:25 +00:00
} else {
$ret = [ " error " => $id ];
}
return DI :: apiResponse () -> formatData ( " direct-messages " , $type , [ 'direct_message' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/direct_messages/new' , 'api_direct_messages_new' , true );
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* delete a direct_message from mail table through api
2017-11-10 05:00:50 +00:00
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-04-09 17:34:02 +00:00
* @ return string | array
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
2021-11-24 06:44:25 +00:00
* @ throws UnauthorizedException
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / delete - message
2017-11-10 05:00:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_direct_messages_destroy ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-18 07:25:16 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-18 07:25:16 +00:00
2021-11-24 06:44:25 +00:00
//required
$id = $_REQUEST [ 'id' ] ? ? 0 ;
// optional
$parenturi = $_REQUEST [ 'friendica_parenturi' ] ? ? '' ;
$verbose = ( ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " );
/// @todo optional parameter 'include_entities' from Twitter API not yet implemented
2017-04-05 20:17:15 +00:00
2021-11-24 06:44:25 +00:00
// error if no id or parenturi specified (for clients posting parent-uri as well)
if ( $verbose == " true " && ( $id == 0 || $parenturi == " " )) {
$answer = [ 'result' => 'error' , 'message' => 'message id or parenturi not specified' ];
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2021-11-24 06:44:25 +00:00
// BadRequestException if no id specified (for clients using Twitter API)
if ( $id == 0 ) {
throw new BadRequestException ( 'Message id not specified' );
}
// add parent-uri to sql command if specified by calling app
$sql_extra = ( $parenturi != " " ? " AND `parent-uri` = ' " . DBA :: escape ( $parenturi ) . " ' " : " " );
// error message if specified id is not in database
if ( ! DBA :: exists ( 'mail' , [ " `uid` = ? AND `id` = ? " . $sql_extra , $uid , $id ])) {
if ( $verbose == " true " ) {
$answer = [ 'result' => 'error' , 'message' => 'message id not in database' ];
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
2016-09-25 16:50:08 +00:00
}
2021-11-24 06:44:25 +00:00
/// @todo BadRequestException ok for Twitter API clients?
throw new BadRequestException ( 'message id not in database' );
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2021-11-24 06:44:25 +00:00
// delete message
$result = DBA :: delete ( 'mail' , [ " `uid` = ? AND `id` = ? " . $sql_extra , $uid , $id ]);
if ( $verbose == " true " ) {
if ( $result ) {
// return success
$answer = [ 'result' => 'ok' , 'message' => 'message deleted' ];
return DI :: apiResponse () -> formatData ( " direct_message_delete " , $type , [ '$result' => $answer ]);
} else {
$answer = [ 'result' => 'error' , 'message' => 'unknown error' ];
return DI :: apiResponse () -> formatData ( " direct_messages_delete " , $type , [ '$result' => $answer ]);
}
2016-09-25 16:50:08 +00:00
}
2021-11-24 06:44:25 +00:00
/// @todo return JSON data like Twitter API not yet implemented
}
2017-11-10 05:00:50 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/direct_messages/destroy' , 'api_direct_messages_destroy' , true );
2021-11-24 06:44:25 +00:00
2017-12-22 23:46:01 +00:00
/**
*
2021-11-24 06:44:25 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
* @ param string $box
* @ param string $verbose
2017-12-22 23:46:01 +00:00
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-22 23:46:01 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_direct_messages_box ( $type , $box , $verbose )
2017-12-22 23:46:01 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2021-11-17 21:28:51 +00:00
2021-11-24 06:44:25 +00:00
// params
$count = $_GET [ 'count' ] ? ? 20 ;
$page = $_REQUEST [ 'page' ] ? ? 1 ;
2017-12-22 23:46:01 +00:00
2021-11-24 06:44:25 +00:00
$since_id = $_REQUEST [ 'since_id' ] ? ? 0 ;
$max_id = $_REQUEST [ 'max_id' ] ? ? 0 ;
$user_id = $_REQUEST [ 'user_id' ] ? ? '' ;
$screen_name = $_REQUEST [ 'screen_name' ] ? ? '' ;
2021-11-24 20:47:37 +00:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ();
2021-11-24 06:44:25 +00:00
$profile_url = $user_info [ " url " ];
// pagination
$start = max ( 0 , ( $page - 1 ) * $count );
$sql_extra = " " ;
// filters
if ( $box == " sentbox " ) {
$sql_extra = " `mail`.`from-url`=' " . DBA :: escape ( $profile_url ) . " ' " ;
} elseif ( $box == " conversation " ) {
$sql_extra = " `mail`.`parent-uri`=' " . DBA :: escape ( $_GET [ 'uri' ] ? ? '' ) . " ' " ;
} elseif ( $box == " all " ) {
$sql_extra = " true " ;
} elseif ( $box == " inbox " ) {
$sql_extra = " `mail`.`from-url`!=' " . DBA :: escape ( $profile_url ) . " ' " ;
2017-12-22 23:46:01 +00:00
}
2021-11-24 06:44:25 +00:00
if ( $max_id > 0 ) {
$sql_extra .= ' AND `mail`.`id` <= ' . intval ( $max_id );
2017-12-22 23:46:01 +00:00
}
2021-11-24 06:44:25 +00:00
if ( $user_id != " " ) {
$sql_extra .= ' AND `mail`.`contact-id` = ' . intval ( $user_id );
} elseif ( $screen_name != " " ) {
$sql_extra .= " AND `contact`.`nick` = ' " . DBA :: escape ( $screen_name ) . " ' " ;
}
2017-12-22 23:46:01 +00:00
2021-11-24 06:44:25 +00: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 ?,? " ,
$uid ,
$since_id ,
$start ,
$count
));
if ( $verbose == " true " && ! DBA :: isResult ( $r )) {
$answer = [ 'result' => 'error' , 'message' => 'no mails available' ];
return DI :: apiResponse () -> formatData ( " direct_messages_all " , $type , [ '$result' => $answer ]);
}
2017-12-22 23:46:01 +00:00
2021-11-24 06:44:25 +00:00
$ret = [];
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
2021-11-24 20:47:37 +00:00
$sender = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid , true ) -> toArray ();
2021-11-24 06:44:25 +00:00
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
2021-11-24 20:47:37 +00:00
$recipient = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid , true ) -> toArray ();
2021-11-24 06:44:25 +00:00
$sender = $user_info ;
}
if ( isset ( $recipient ) && isset ( $sender )) {
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
}
return DI :: apiResponse () -> formatData ( " direct-messages " , $type , [ 'direct_message' => $ret ], Contact :: getPublicIdByUserId ( $uid ));
}
2017-11-10 05:00:50 +00:00
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* Returns the most recent direct messages sent by the user .
2017-12-24 02:20:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - sent - message
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_direct_messages_sentbox ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-26 07:55:02 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-24 06:44:25 +00:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
return api_direct_messages_box ( $type , " sentbox " , $verbose );
}
2019-10-13 02:01:34 +00:00
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/direct_messages/sent' , 'api_direct_messages_sentbox' , true );
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
/**
* Returns the most recent direct messages sent to the user .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
* @ see https :// developer . twitter . com / en / docs / direct - messages / sending - and - receiving / api - reference / get - messages
*/
function api_direct_messages_inbox ( $type )
{
2021-11-26 07:55:02 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-24 06:44:25 +00:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
return api_direct_messages_box ( $type , " inbox " , $verbose );
}
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/direct_messages' , 'api_direct_messages_inbox' , true );
/**
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
* @ throws BadRequestException
* @ throws ForbiddenException
*/
function api_direct_messages_all ( $type )
{
2021-11-26 07:55:02 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-24 06:44:25 +00:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
return api_direct_messages_box ( $type , " all " , $verbose );
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/direct_messages/all' , 'api_direct_messages_all' , true );
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
2021-11-24 06:44:25 +00:00
*/
function api_direct_messages_conversation ( $type )
{
2021-11-26 07:55:02 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-24 06:44:25 +00:00
$verbose = ! empty ( $_GET [ 'friendica_verbose' ]) ? strtolower ( $_GET [ 'friendica_verbose' ]) : " false " ;
return api_direct_messages_box ( $type , " conversation " , $verbose );
}
api_register_func ( 'api/direct_messages/conversation' , 'api_direct_messages_conversation' , true );
/**
* list all photos of the authenticated user
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string | array
* @ throws ForbiddenException
2019-01-07 17:24:01 +00:00
* @ throws InternalServerErrorException
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_fr_photos_list ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
$r = DBA :: toArray ( DBA :: p (
" SELECT `resource-id`, MAX(scale) AS `scale`, `album`, `filename`, `type`, MAX(`created`) AS `created`,
MAX ( `edited` ) AS `edited` , MAX ( `desc` ) AS `desc` FROM `photo`
WHERE `uid` = ? AND NOT `photo-type` IN ( ? , ? ) GROUP BY `resource-id` , `album` , `filename` , `type` " ,
$uid , Photo :: CONTACT_AVATAR , Photo :: CONTACT_BANNER
));
$typetoext = [
'image/jpeg' => 'jpg' ,
'image/png' => 'png' ,
'image/gif' => 'gif'
];
$data = [ 'photo' => []];
if ( DBA :: isResult ( $r )) {
foreach ( $r as $rr ) {
$photo = [];
$photo [ 'id' ] = $rr [ 'resource-id' ];
$photo [ 'album' ] = $rr [ 'album' ];
$photo [ 'filename' ] = $rr [ 'filename' ];
$photo [ 'type' ] = $rr [ 'type' ];
$thumb = DI :: baseUrl () . " /photo/ " . $rr [ 'resource-id' ] . " - " . $rr [ 'scale' ] . " . " . $typetoext [ $rr [ 'type' ]];
$photo [ 'created' ] = $rr [ 'created' ];
$photo [ 'edited' ] = $rr [ 'edited' ];
$photo [ 'desc' ] = $rr [ 'desc' ];
if ( $type == " xml " ) {
$data [ 'photo' ][] = [ " @attributes " => $photo , " 1 " => $thumb ];
} else {
$photo [ 'thumb' ] = $thumb ;
$data [ 'photo' ][] = $photo ;
}
2017-05-01 20:19:48 +00:00
}
}
2021-11-24 06:44:25 +00:00
return DI :: apiResponse () -> formatData ( " photos " , $type , $data );
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/friendica/photos/list' , 'api_fr_photos_list' , true );
2020-04-01 05:42:44 +00:00
2021-11-24 06:44:25 +00:00
/**
* upload a new photo or change an existing photo
*
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string | array
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
*/
function api_fr_photo_create_update ( $type )
{
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// input params
$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 ;
2021-11-30 13:24:09 +00:00
// Pictures uploaded via API never get posted as a visible status
// See https://github.com/friendica/friendica/issues/10990
$visibility = false ;
2021-11-24 06:44:25 +00:00
// do several checks on input parameters
// we do not allow calls without album string
if ( $album == null ) {
throw new BadRequestException ( " no albumname specified " );
2017-05-01 20:19:48 +00:00
}
2021-11-24 06:44:25 +00:00
// if photo_id == null --> we are uploading a new photo
if ( $photo_id == null ) {
$mode = " create " ;
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
// error if no media posted in create-mode
if ( empty ( $_FILES [ 'media' ])) {
// Output error
throw new BadRequestException ( " no media data submitted " );
}
// album_new will be ignored in create-mode
$album_new = " " ;
} else {
$mode = " update " ;
// check if photo is existing in databasei
if ( ! Photo :: exists ([ 'resource-id' => $photo_id , 'uid' => $uid , 'album' => $album ])) {
throw new BadRequestException ( " photo not available " );
}
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
// checks on acl strings provided by clients
$acl_input_error = false ;
$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 );
if ( $acl_input_error ) {
throw new BadRequestException ( " acl data invalid " );
}
// now let's upload the new media in create-mode
if ( $mode == " create " ) {
$media = $_FILES [ 'media' ];
$data = save_media_to_database ( " photo " , $media , $type , $album , trim ( $allow_cid ), trim ( $deny_cid ), trim ( $allow_gid ), trim ( $deny_gid ), $desc , Photo :: DEFAULT , $visibility , null , $uid );
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
// return success of updating or error message
if ( ! is_null ( $data )) {
return DI :: apiResponse () -> formatData ( " photo_create " , $type , $data );
} else {
throw new InternalServerErrorException ( " unknown error - uploading photo failed, see Friendica log for more information " );
}
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
// now let's do the changes in update-mode
if ( $mode == " update " ) {
$updated_fields = [];
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $desc )) {
$updated_fields [ 'desc' ] = $desc ;
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $album_new )) {
$updated_fields [ 'album' ] = $album_new ;
2017-05-01 20:19:48 +00:00
}
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $allow_cid )) {
$allow_cid = trim ( $allow_cid );
$updated_fields [ 'allow_cid' ] = $allow_cid ;
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $deny_cid )) {
$deny_cid = trim ( $deny_cid );
$updated_fields [ 'deny_cid' ] = $deny_cid ;
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $allow_gid )) {
$allow_gid = trim ( $allow_gid );
$updated_fields [ 'allow_gid' ] = $allow_gid ;
2017-11-10 05:00:50 +00:00
}
2017-05-01 20:19:48 +00:00
2021-11-24 06:44:25 +00:00
if ( ! is_null ( $deny_gid )) {
$deny_gid = trim ( $deny_gid );
$updated_fields [ 'deny_gid' ] = $deny_gid ;
2017-05-01 20:19:48 +00:00
}
2021-11-24 06:44:25 +00:00
$result = false ;
if ( count ( $updated_fields ) > 0 ) {
$nothingtodo = false ;
$result = Photo :: update ( $updated_fields , [ 'uid' => $uid , 'resource-id' => $photo_id , 'album' => $album ]);
} else {
$nothingtodo = true ;
}
if ( ! empty ( $_FILES [ 'media' ])) {
$nothingtodo = false ;
$media = $_FILES [ 'media' ];
$data = save_media_to_database ( " photo " , $media , $type , $album , $allow_cid , $deny_cid , $allow_gid , $deny_gid , $desc , Photo :: DEFAULT , $visibility , $photo_id , $uid );
if ( ! is_null ( $data )) {
return DI :: apiResponse () -> formatData ( " photo_update " , $type , $data );
2017-05-01 20:19:48 +00:00
}
}
2021-11-24 06:44:25 +00:00
// return success of updating or error message
if ( $result ) {
$answer = [ 'result' => 'updated' , 'message' => 'Image id `' . $photo_id . '` has been updated.' ];
return DI :: apiResponse () -> formatData ( " photo_update " , $type , [ '$result' => $answer ]);
} else {
if ( $nothingtodo ) {
$answer = [ 'result' => 'cancelled' , 'message' => 'Nothing to update for image id `' . $photo_id . '`.' ];
return DI :: apiResponse () -> formatData ( " photo_update " , $type , [ '$result' => $answer ]);
}
throw new InternalServerErrorException ( " unknown error - update photo entry in database failed " );
2017-11-10 05:00:50 +00:00
}
}
2021-11-24 06:44:25 +00:00
throw new InternalServerErrorException ( " unknown error - this error on uploading or updating a photo should never happen " );
2017-11-10 05:00:50 +00:00
}
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/friendica/photo/create' , 'api_fr_photo_create_update' , true );
api_register_func ( 'api/friendica/photo/update' , 'api_fr_photo_create_update' , true );
2021-11-24 06:44:25 +00:00
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* returns the details of a specified photo id , if scale is given , returns the photo data in base 64
2017-12-24 02:20:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
* @ return string | array
* @ throws BadRequestException
* @ throws ForbiddenException
2019-01-07 17:24:01 +00:00
* @ throws InternalServerErrorException
2021-11-24 06:44:25 +00:00
* @ throws NotFoundException
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_fr_photo_detail ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-24 06:44:25 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
if ( empty ( $_REQUEST [ 'photo_id' ])) {
throw new BadRequestException ( " No photo id. " );
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
$scale = ( ! empty ( $_REQUEST [ 'scale' ]) ? intval ( $_REQUEST [ 'scale' ]) : false );
$photo_id = $_REQUEST [ 'photo_id' ];
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// prepare json/xml output with data from database for the requested photo
$data = prepare_photo_data ( $type , $scale , $photo_id , $uid );
return DI :: apiResponse () -> formatData ( " photo_detail " , $type , $data );
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
api_register_func ( 'api/friendica/photo' , 'api_fr_photo_detail' , true );
2017-12-24 02:20:50 +00:00
/**
2021-11-24 06:44:25 +00:00
* updates the profile image for the user ( either a specified profile or the default profile )
2017-12-24 02:20:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2017-12-24 02:20:50 +00:00
*
2021-11-24 06:44:25 +00:00
* @ return string | array
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws NotFoundException
2021-11-24 06:44:25 +00:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / manage - account - settings / api - reference / post - account - update_profile_image
2017-12-24 02:20:50 +00:00
*/
2021-11-24 06:44:25 +00:00
function api_account_update_profile_image ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-09 15:36:33 +00:00
2021-11-24 06:44:25 +00:00
// input params
$profile_id = $_REQUEST [ 'profile_id' ] ? ? 0 ;
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// error if image data is missing
if ( empty ( $_FILES [ 'image' ])) {
throw new BadRequestException ( " no media data submitted " );
}
2017-11-10 05:00:50 +00:00
2021-11-24 06:44:25 +00:00
// check if specified profile id is valid
if ( $profile_id != 0 ) {
$profile = DBA :: selectFirst ( 'profile' , [ 'is-default' ], [ 'uid' => $uid , 'id' => $profile_id ]);
// error message if specified profile id is not in database
if ( ! DBA :: isResult ( $profile )) {
throw new BadRequestException ( " profile_id not available " );
2017-05-01 20:19:48 +00:00
}
2021-11-24 06:44:25 +00:00
$is_default_profile = $profile [ 'is-default' ];
2017-11-10 05:00:50 +00:00
} else {
2021-11-24 06:44:25 +00:00
$is_default_profile = 1 ;
2017-11-10 05:00:50 +00:00
}
2021-11-24 06:44:25 +00:00
// get mediadata from image or media (Twitter call api/account/update_profile_image provides image)
$media = null ;
if ( ! empty ( $_FILES [ 'image' ])) {
$media = $_FILES [ 'image' ];
} elseif ( ! empty ( $_FILES [ 'media' ])) {
$media = $_FILES [ 'media' ];
2020-01-26 21:43:14 +00:00
}
2021-11-24 06:44:25 +00:00
// save new profile image
$data = save_media_to_database ( " profileimage " , $media , $type , DI :: l10n () -> t ( Photo :: PROFILE_PHOTOS ), " " , " " , " " , " " , " " , Photo :: USER_AVATAR , false , null , $uid );
2018-06-18 20:36:34 +00:00
2021-11-24 06:44:25 +00:00
// get filetype
if ( is_array ( $media [ 'type' ])) {
$filetype = $media [ 'type' ][ 0 ];
} else {
$filetype = $media [ 'type' ];
2021-11-20 23:38:52 +00:00
}
2021-11-24 06:44:25 +00:00
if ( $filetype == " image/jpeg " ) {
$fileext = " jpg " ;
} elseif ( $filetype == " image/png " ) {
$fileext = " png " ;
2017-11-10 05:00:50 +00:00
} else {
2021-11-24 06:44:25 +00:00
throw new InternalServerErrorException ( 'Unsupported filetype' );
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2021-11-24 06:44:25 +00:00
// change specified profile or all profiles to the new resource-id
if ( $is_default_profile ) {
$condition = [ " `profile` AND `resource-id` != ? AND `uid` = ? " , $data [ 'photo' ][ 'id' ], $uid ];
Photo :: update ([ 'profile' => false , 'photo-type' => Photo :: DEFAULT ], $condition );
} else {
$fields = [ 'photo' => DI :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-4.' . $fileext ,
'thumb' => DI :: baseUrl () . '/photo/' . $data [ 'photo' ][ 'id' ] . '-5.' . $fileext ];
DBA :: update ( 'profile' , $fields , [ 'id' => $_REQUEST [ 'profile' ], 'uid' => $uid ]);
2019-04-24 04:26:23 +00:00
}
2021-11-24 06:44:25 +00:00
Contact :: updateSelfFromUserID ( $uid , true );
2019-04-24 04:26:23 +00:00
2021-11-24 06:44:25 +00:00
// Update global directory in background
Profile :: publishUpdate ( $uid );
2019-04-24 04:26:23 +00:00
2021-11-24 06:44:25 +00:00
// output for client
if ( $data ) {
2021-11-24 23:03:34 +00:00
$skip_status = $_REQUEST [ 'skip_status' ] ? ? false ;
2021-11-25 06:00:58 +00:00
2021-11-24 23:03:34 +00:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid , $skip_status ) -> toArray ();
2021-11-25 06:00:58 +00:00
2021-11-24 23:03:34 +00:00
// "verified" isn't used here in the standard
unset ( $user_info [ " verified " ]);
2021-11-25 06:00:58 +00:00
2021-11-24 23:03:34 +00:00
// "uid" is only needed for some internal stuff, so remove it from here
unset ( $user_info [ 'uid' ]);
return DI :: apiResponse () -> formatData ( " user " , $type , [ 'user' => $user_info ]);
2021-11-24 06:44:25 +00:00
} else {
// SaveMediaToDatabase failed for some reason
throw new InternalServerErrorException ( " image upload failed " );
2019-04-24 04:26:23 +00:00
}
}
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/account/update_profile_image' , 'api_account_update_profile_image' , true );
2021-11-24 06:44:25 +00:00
2017-12-24 02:20:50 +00:00
/**
* Return all or a specified group of the user with the containing contacts .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-12-24 02:20:50 +00:00
*/
2017-11-10 05:00:50 +00:00
function api_friendica_group_show ( $type )
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// params
2019-10-13 02:01:34 +00:00
$gid = $_REQUEST [ 'gid' ] ? ? 0 ;
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
// get data of the specified group id or all groups if not specified
if ( $gid != 0 ) {
2021-10-03 15:02:20 +00:00
$groups = DBA :: selectToArray ( 'group' , [], [ 'deleted' => false , 'uid' => $uid , 'id' => $gid ]);
2016-09-25 16:50:08 +00:00
// error message if specified gid is not in database
2021-10-03 15:02:20 +00:00
if ( ! DBA :: isResult ( $groups )) {
2017-11-10 05:00:50 +00:00
throw new BadRequestException ( " gid not available " );
2017-12-23 23:27:45 +00:00
}
2017-11-10 05:00:50 +00:00
} else {
2021-10-03 15:02:20 +00:00
$groups = DBA :: selectToArray ( 'group' , [], [ 'deleted' => false , 'uid' => $uid ]);
2016-09-25 16:50:08 +00:00
}
2017-11-10 05:00:50 +00:00
// loop through all groups and retrieve all members for adding data in the user array
2018-04-09 19:34:53 +00:00
$grps = [];
2021-10-03 15:02:20 +00:00
foreach ( $groups as $rr ) {
2020-08-04 18:22:19 +00:00
$members = Contact\Group :: getById ( $rr [ 'id' ]);
2018-01-15 13:05:12 +00:00
$users = [];
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
if ( $type == " xml " ) {
$user_element = " users " ;
$k = 0 ;
foreach ( $members as $member ) {
2021-11-24 20:47:37 +00:00
$user = DI :: twitterUser () -> createFromContactId ( $member [ 'contact-id' ], $uid , true ) -> toArray ();
2017-11-10 05:00:50 +00:00
$users [ $k ++. " :user " ] = $user ;
}
} else {
$user_element = " user " ;
foreach ( $members as $member ) {
2021-11-24 20:47:37 +00:00
$user = DI :: twitterUser () -> createFromContactId ( $member [ 'contact-id' ], $uid , true ) -> toArray ();
2017-11-10 05:00:50 +00:00
$users [] = $user ;
2016-09-25 16:50:08 +00:00
}
}
2018-01-15 13:05:12 +00:00
$grps [] = [ 'name' => $rr [ 'name' ], 'gid' => $rr [ 'id' ], $user_element => $users ];
2017-11-10 05:00:50 +00:00
}
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " groups " , $type , [ 'group' => $grps ]);
2017-11-10 05:00:50 +00:00
}
2021-11-12 18:52:01 +00:00
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/group_show' , 'api_friendica_group_show' , true );
2017-12-24 02:20:50 +00:00
/**
2018-04-07 13:54:26 +00:00
* Delete a group .
2017-12-24 02:20:50 +00:00
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 13:54:26 +00:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / post - lists - destroy
2017-12-24 02:20:50 +00:00
*/
2018-04-07 13:54:26 +00:00
function api_lists_destroy ( $type )
2017-11-10 05:00:50 +00:00
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2017-11-10 05:00:50 +00:00
// params
2019-10-13 02:01:34 +00:00
$gid = $_REQUEST [ 'list_id' ] ? ? 0 ;
2017-11-10 05:00:50 +00:00
2018-04-07 13:54:26 +00: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 12:19:26 +00:00
$group = DBA :: selectFirst ( 'group' , [], [ 'uid' => $uid , 'id' => $gid ]);
2018-04-07 13:54:26 +00:00
// error message if specified gid is not in database
2018-04-07 17:55:41 +00:00
if ( ! $group ) {
2018-04-07 13:54:26 +00:00
throw new BadRequestException ( 'gid not available' );
}
if ( Group :: remove ( $gid )) {
2018-04-07 17:55:41 +00:00
$list = [
'name' => $group [ 'name' ],
2018-04-07 13:54:26 +00:00
'id' => intval ( $gid ),
'id_str' => ( string ) $gid ,
2021-11-24 20:47:37 +00:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ()
2018-04-07 13:54:26 +00:00
];
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $list ]);
2018-04-07 13:54:26 +00:00
}
}
2021-11-12 18:52:01 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/lists/destroy' , 'api_lists_destroy' , true );
2018-04-07 13:54:26 +00:00
/**
* 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 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 13:54:26 +00:00
*/
function api_friendica_group_create ( $type )
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 13:54:26 +00:00
// params
2019-10-13 02:01:34 +00:00
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 13:54:26 +00:00
$json = json_decode ( $_POST [ 'json' ], true );
$users = $json [ 'user' ];
$success = group_create ( $name , $uid , $users );
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " group_create " , $type , [ 'result' => $success ]);
2017-11-10 05:00:50 +00:00
}
2021-11-12 18:52:01 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/friendica/group_create' , 'api_friendica_group_create' , true );
2017-11-10 05:00:50 +00:00
2018-04-07 13:54:26 +00:00
/**
* Create a new group .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 13:54:26 +00:00
* @ see https :// developer . twitter . com / en / docs / accounts - and - users / create - manage - lists / api - reference / post - lists - create
*/
2018-04-07 20:15:35 +00:00
function api_lists_create ( $type )
2018-04-07 13:54:26 +00:00
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 13:54:26 +00:00
// params
2019-10-13 02:01:34 +00:00
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 13:54:26 +00:00
$success = group_create ( $name , $uid );
if ( $success [ 'success' ]) {
$grp = [
'name' => $success [ 'name' ],
'id' => intval ( $success [ 'gid' ]),
'id_str' => ( string ) $success [ 'gid' ],
2021-11-24 20:47:37 +00:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ()
2018-04-07 13:54:26 +00:00
];
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $grp ]);
2018-04-07 13:54:26 +00:00
}
}
2021-11-12 18:52:01 +00:00
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/lists/create' , 'api_lists_create' , true );
2017-11-10 05:00:50 +00:00
2018-04-07 13:54:26 +00:00
/**
* Update information about a group .
*
* @ param string $type Return type ( atom , rss , xml , json )
*
* @ return array | string
2019-01-07 17:24:01 +00:00
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2018-04-07 13:54:26 +00: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 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_WRITE );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2018-04-07 13:54:26 +00:00
// params
2019-10-13 02:01:34 +00:00
$gid = $_REQUEST [ 'list_id' ] ? ? 0 ;
$name = $_REQUEST [ 'name' ] ? ? '' ;
2018-04-07 13:54:26 +00: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 12:19:26 +00:00
$group = DBA :: selectFirst ( 'group' , [], [ 'uid' => $uid , 'id' => $gid ]);
2018-04-07 13:54:26 +00:00
// error message if specified gid is not in database
2018-04-07 17:55:41 +00:00
if ( ! $group ) {
2018-04-07 13:54:26 +00:00
throw new BadRequestException ( 'gid not available' );
}
if ( Group :: update ( $gid , $name )) {
2018-04-07 17:55:41 +00:00
$list = [
2018-04-07 13:54:26 +00:00
'name' => $name ,
'id' => intval ( $gid ),
'id_str' => ( string ) $gid ,
2021-11-24 20:47:37 +00:00
'user' => DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ()
2018-04-07 13:54:26 +00:00
];
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " lists " , $type , [ 'lists' => $list ]);
2018-04-07 13:54:26 +00:00
}
}
2021-11-26 07:55:02 +00:00
api_register_func ( 'api/lists/update' , 'api_lists_update' , true );
2018-04-07 13:54:26 +00:00
2017-11-10 05:00:50 +00:00
/**
2020-01-19 06:05:23 +00:00
* search for direct_messages containing a searchstring through api
2017-11-10 05:00:50 +00:00
*
2019-01-07 17:24:01 +00:00
* @ param string $type Known types are 'atom' , 'rss' , 'xml' and 'json'
2018-02-11 21:13:29 +00:00
* @ param string $box
2018-04-09 17:34:02 +00:00
* @ return string | array ( success : success = true if found and search_result contains found messages ,
2017-11-10 05:00:50 +00:00
* success = false if nothing was found , search_result = 'nothing found' ,
2019-01-07 17:24:01 +00:00
* error : result = error with error message )
* @ throws BadRequestException
* @ throws ForbiddenException
* @ throws ImagickException
* @ throws InternalServerErrorException
* @ throws UnauthorizedException
2017-11-10 05:00:50 +00:00
*/
2018-02-11 21:13:29 +00:00
function api_friendica_direct_messages_search ( $type , $box = " " )
2017-11-10 05:00:50 +00:00
{
2021-11-17 21:28:51 +00:00
BaseApi :: checkAllowedScope ( BaseApi :: SCOPE_READ );
2021-11-20 13:44:12 +00:00
$uid = BaseApi :: getCurrentUserID ();
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// params
2021-11-24 20:47:37 +00:00
$user_info = DI :: twitterUser () -> createFromUserId ( $uid , true ) -> toArray ();
2019-10-13 02:01:34 +00:00
$searchstring = $_REQUEST [ 'searchstring' ] ? ? '' ;
2017-04-05 20:07:55 +00:00
2017-11-10 05:00:50 +00:00
// error if no searchstring specified
if ( $searchstring == " " ) {
2018-01-15 13:05:12 +00:00
$answer = [ 'result' => 'error' , 'message' => 'searchstring not specified' ];
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " direct_messages_search " , $type , [ '$result' => $answer ]);
2017-11-10 05:00:50 +00:00
}
// get data for the specified searchstring
2021-10-09 21:16:15 +00: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 05:00:50 +00:00
$profile_url = $user_info [ " url " ];
// message if nothing was found
2018-07-21 12:46:04 +00:00
if ( ! DBA :: isResult ( $r )) {
2018-01-15 13:05:12 +00:00
$success = [ 'success' => false , 'search_results' => 'problem with query' ];
2017-11-10 05:00:50 +00:00
} elseif ( count ( $r ) == 0 ) {
2018-01-15 13:05:12 +00:00
$success = [ 'success' => false , 'search_results' => 'nothing found' ];
2017-11-10 05:00:50 +00:00
} else {
2018-01-15 13:05:12 +00:00
$ret = [];
2017-11-10 05:00:50 +00:00
foreach ( $r as $item ) {
if ( $box == " inbox " || $item [ 'from-url' ] != $profile_url ) {
$recipient = $user_info ;
2021-11-24 20:47:37 +00:00
$sender = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid , true ) -> toArray ();
2017-11-10 05:00:50 +00:00
} elseif ( $box == " sentbox " || $item [ 'from-url' ] == $profile_url ) {
2021-11-24 20:47:37 +00:00
$recipient = DI :: twitterUser () -> createFromContactId ( $item [ 'contact-id' ], $uid , true ) -> toArray ();
2017-11-10 05:00:50 +00:00
$sender = $user_info ;
2016-09-25 16:50:08 +00:00
}
2018-04-09 19:34:53 +00:00
if ( isset ( $recipient ) && isset ( $sender )) {
$ret [] = api_format_messages ( $item , $recipient , $sender );
}
2017-11-10 05:00:50 +00:00
}
2018-01-15 13:05:12 +00:00
$success = [ 'success' => true , 'search_results' => $ret ];
2016-09-25 16:50:08 +00:00
}
2017-04-05 20:07:55 +00:00
2021-11-12 18:59:16 +00:00
return DI :: apiResponse () -> formatData ( " direct_message_search " , $type , [ '$result' => $success ]);
2017-11-10 05:00:50 +00:00
}
2016-09-25 16:50:08 +00:00
2017-11-10 05:00:50 +00:00
api_register_func ( 'api/friendica/direct_messages_search' , 'api_friendica_direct_messages_search' , true );